aboutsummaryrefslogtreecommitdiff
path: root/tests/python_dependencies/impacket/ntlm.py
diff options
context:
space:
mode:
authorMax Dymond <max.dymond@metaswitch.com>2017-06-30 13:53:19 +0100
committerDaniel Stenberg <daniel@haxx.se>2017-07-04 10:36:06 +0200
commitf1609155d54c82b535f50a6b4693b2be47d272aa (patch)
tree57545c4cf2c182c2a2a57df587006f8f22db4f83 /tests/python_dependencies/impacket/ntlm.py
parentfc2e81c38b19ebe9651cda28a2395a0244125f52 (diff)
test: add impacket for SMB testing
Import impacket 0.9.15 for use in SMB testing. This was generated by doing "pip2.7 install -t . impacket" Unnecessary files for current testing were deleted.
Diffstat (limited to 'tests/python_dependencies/impacket/ntlm.py')
-rw-r--r--tests/python_dependencies/impacket/ntlm.py971
1 files changed, 971 insertions, 0 deletions
diff --git a/tests/python_dependencies/impacket/ntlm.py b/tests/python_dependencies/impacket/ntlm.py
new file mode 100644
index 000000000..8376644bd
--- /dev/null
+++ b/tests/python_dependencies/impacket/ntlm.py
@@ -0,0 +1,971 @@
+# Copyright (c) 2003-2016 CORE Security Technologies:
+#
+# This software is provided under under a slightly modified version
+# of the Apache Software License. See the accompanying LICENSE file
+# for more information.
+#
+import base64
+import struct
+import calendar
+import time
+import hashlib
+import random
+import string
+import binascii
+
+from impacket.structure import Structure
+from impacket import LOG
+
+
+# This is important. NTLMv2 is not negotiated by the client or server.
+# It is used if set locally on both sides. Change this item if you don't want to use
+# NTLMv2 by default and fall back to NTLMv1 (with EXTENDED_SESSION_SECURITY or not)
+# Check the following links:
+# http://davenport.sourceforge.net/ntlm.html
+# http://blogs.msdn.com/b/openspecification/archive/2010/04/20/ntlm-keys-and-sundry-stuff.aspx
+# http://social.msdn.microsoft.com/Forums/en-US/os_interopscenarios/thread/c8f488ed-1b96-4e06-bd65-390aa41138d1/
+# So I'm setting a global variable to control this, this can also be set programmatically
+
+USE_NTLMv2 = True # if false will fall back to NTLMv1 (or NTLMv1 with ESS a.k.a NTLM2)
+
+
+def computeResponse(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='', nthash='',
+ use_ntlmv2=USE_NTLMv2):
+ if use_ntlmv2:
+ return computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password,
+ lmhash, nthash, use_ntlmv2=use_ntlmv2)
+ else:
+ return computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password,
+ lmhash, nthash, use_ntlmv2=use_ntlmv2)
+try:
+ POW = None
+ from Crypto.Cipher import ARC4
+ from Crypto.Cipher import DES
+ from Crypto.Hash import MD4
+except Exception:
+ try:
+ import POW
+ except Exception:
+ LOG.critical("Warning: You don't have any crypto installed. You need PyCrypto")
+ LOG.critical("See http://www.pycrypto.org/")
+
+NTLM_AUTH_NONE = 1
+NTLM_AUTH_CONNECT = 2
+NTLM_AUTH_CALL = 3
+NTLM_AUTH_PKT = 4
+NTLM_AUTH_PKT_INTEGRITY = 5
+NTLM_AUTH_PKT_PRIVACY = 6
+
+# If set, requests 56-bit encryption. If the client sends NTLMSSP_NEGOTIATE_SEAL or NTLMSSP_NEGOTIATE_SIGN
+# with NTLMSSP_NEGOTIATE_56 to the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_56 to
+# the client in the CHALLENGE_MESSAGE. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128
+# are requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be
+# returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_56 if it is
+# supported. An alternate name for this field is NTLMSSP_NEGOTIATE_56.
+NTLMSSP_NEGOTIATE_56 = 0x80000000
+
+# If set, requests an explicit key exchange. This capability SHOULD be used because it improves security for message
+# integrity or confidentiality. See sections 3.2.5.1.2, 3.2.5.2.1, and 3.2.5.2.2 for details. An alternate name for
+# this field is NTLMSSP_NEGOTIATE_KEY_EXCH.
+NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000
+
+# If set, requests 128-bit session key negotiation. An alternate name for this field is NTLMSSP_NEGOTIATE_128.
+# If the client sends NTLMSSP_NEGOTIATE_128 to the server in the NEGOTIATE_MESSAGE, the server MUST return
+# NTLMSSP_NEGOTIATE_128 to the client in the CHALLENGE_MESSAGE only if the client sets NTLMSSP_NEGOTIATE_SEAL or
+# NTLMSSP_NEGOTIATE_SIGN. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are
+# requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be
+# returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_128 if it
+# is supported. An alternate name for this field is NTLMSSP_NEGOTIATE_128
+NTLMSSP_NEGOTIATE_128 = 0x20000000
+
+NTLMSSP_RESERVED_1 = 0x10000000
+NTLMSSP_RESERVED_2 = 0x08000000
+NTLMSSP_RESERVED_3 = 0x04000000
+
+# If set, requests the protocol version number. The data corresponding to this flag is provided in the Version field
+# of the NEGOTIATE_MESSAGE, the CHALLENGE_MESSAGE, and the AUTHENTICATE_MESSAGE.<22> An alternate name for this field
+# is NTLMSSP_NEGOTIATE_VERSION
+NTLMSSP_NEGOTIATE_VERSION = 0x02000000
+NTLMSSP_RESERVED_4 = 0x01000000
+
+# If set, indicates that the TargetInfo fields in the CHALLENGE_MESSAGE (section 2.2.1.2) are populated.
+# An alternate name for this field is NTLMSSP_NEGOTIATE_TARGET_INFO.
+NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000
+
+# If set, requests the usage of the LMOWF (section 3.3). An alternate name for this field is
+# NTLMSSP_REQUEST_NON_NT_SESSION_KEY.
+NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000
+NTLMSSP_RESERVED_5 = 0x00200000
+
+# If set, requests an identify level token. An alternate name for this field is NTLMSSP_NEGOTIATE_IDENTIFY
+NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000
+
+# If set, requests usage of the NTLM v2 session security. NTLM v2 session security is a misnomer because it is not
+# NTLM v2. It is NTLM v1 using the extended session security that is also in NTLM v2. NTLMSSP_NEGOTIATE_LM_KEY and
+# NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
+# and NTLMSSP_NEGOTIATE_LM_KEY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be returned to the
+# client. NTLM v2 authentication session key generation MUST be supported by both the client and the DC in order to be
+# used, and extended session security signing and sealing requires support from the client and the server in order to
+# be used.<23> An alternate name for this field is NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
+NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000
+NTLMSSP_NEGOTIATE_NTLM2 = 0x00080000
+NTLMSSP_TARGET_TYPE_SHARE = 0x00040000
+
+# If set, TargetName MUST be a server name. The data corresponding to this flag is provided by the server in the
+# TargetName field of the CHALLENGE_MESSAGE. If this bit is set, then NTLMSSP_TARGET_TYPE_DOMAIN MUST NOT be set.
+# This flag MUST be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field
+# is NTLMSSP_TARGET_TYPE_SERVER
+NTLMSSP_TARGET_TYPE_SERVER = 0x00020000
+
+# If set, TargetName MUST be a domain name. The data corresponding to this flag is provided by the server in the
+# TargetName field of the CHALLENGE_MESSAGE. If set, then NTLMSSP_TARGET_TYPE_SERVER MUST NOT be set. This flag MUST
+# be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field is
+# NTLMSSP_TARGET_TYPE_DOMAIN.
+NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000
+
+# If set, requests the presence of a signature block on all messages. NTLMSSP_NEGOTIATE_ALWAYS_SIGN MUST be set in the
+# NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. NTLMSSP_NEGOTIATE_ALWAYS_SIGN is overridden
+# by NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL, if they are supported. An alternate name for this field is
+# NTLMSSP_NEGOTIATE_ALWAYS_SIGN.
+NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000 # forces the other end to sign packets
+NTLMSSP_RESERVED_6 = 0x00004000
+
+# This flag indicates whether the Workstation field is present. If this flag is not set, the Workstation field MUST be
+# ignored. If this flag is set, the length field of the Workstation field specifies whether the workstation name is
+# nonempty or not.<24> An alternate name for this field is NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED.
+NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000
+
+# If set, the domain name is provided (section 2.2.1.1).<25> An alternate name for this field is
+# NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
+NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000
+NTLMSSP_RESERVED_7 = 0x00000800
+
+
+# If set, LM authentication is not allowed and only NT authentication is used.
+NTLMSSP_NEGOTIATE_NT_ONLY = 0x00000400
+
+# If set, requests usage of the NTLM v1 session security protocol. NTLMSSP_NEGOTIATE_NTLM MUST be set in the
+# NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate name for this field is
+# NTLMSSP_NEGOTIATE_NTLM
+NTLMSSP_NEGOTIATE_NTLM = 0x00000200
+NTLMSSP_RESERVED_8 = 0x00000100
+
+# If set, requests LAN Manager (LM) session key computation. NTLMSSP_NEGOTIATE_LM_KEY and
+# NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_LM_KEY and
+# NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be
+# returned to the client. NTLM v2 authentication session key generation MUST be supported by both the client and the
+# DC in order to be used, and extended session security signing and sealing requires support from the client and the
+# server to be used. An alternate name for this field is NTLMSSP_NEGOTIATE_LM_KEY.
+NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080
+
+# If set, requests connectionless authentication. If NTLMSSP_NEGOTIATE_DATAGRAM is set, then NTLMSSP_NEGOTIATE_KEY_EXCH
+# MUST always be set in the AUTHENTICATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate
+# name for this field is NTLMSSP_NEGOTIATE_DATAGRAM.
+NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040
+
+# If set, requests session key negotiation for message confidentiality. If the client sends NTLMSSP_NEGOTIATE_SEAL to
+# the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SEAL to the client in the
+# CHALLENGE_MESSAGE. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD always set NTLMSSP_NEGOTIATE_56 and
+# NTLMSSP_NEGOTIATE_128, if they are supported. An alternate name for this field is NTLMSSP_NEGOTIATE_SEAL.
+NTLMSSP_NEGOTIATE_SEAL = 0x00000020
+
+# If set, requests session key negotiation for message signatures. If the client sends NTLMSSP_NEGOTIATE_SIGN to the
+# server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SIGN to the client in the CHALLENGE_MESSAGE.
+# An alternate name for this field is NTLMSSP_NEGOTIATE_SIGN.
+NTLMSSP_NEGOTIATE_SIGN = 0x00000010 # means packet is signed, if verifier is wrong it fails
+NTLMSSP_RESERVED_9 = 0x00000008
+
+# If set, a TargetName field of the CHALLENGE_MESSAGE (section 2.2.1.2) MUST be supplied. An alternate name for this
+# field is NTLMSSP_REQUEST_TARGET.
+NTLMSSP_REQUEST_TARGET = 0x00000004
+
+# If set, requests OEM character set encoding. An alternate name for this field is NTLM_NEGOTIATE_OEM. See bit A for
+# details.
+NTLM_NEGOTIATE_OEM = 0x00000002
+
+# If set, requests Unicode character set encoding. An alternate name for this field is NTLMSSP_NEGOTIATE_UNICODE.
+NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
+
+# AV_PAIR constants
+NTLMSSP_AV_EOL = 0x00
+NTLMSSP_AV_HOSTNAME = 0x01
+NTLMSSP_AV_DOMAINNAME = 0x02
+NTLMSSP_AV_DNS_HOSTNAME = 0x03
+NTLMSSP_AV_DNS_DOMAINNAME = 0x04
+NTLMSSP_AV_DNS_TREENAME = 0x05
+NTLMSSP_AV_FLAGS = 0x06
+NTLMSSP_AV_TIME = 0x07
+NTLMSSP_AV_RESTRICTIONS = 0x08
+NTLMSSP_AV_TARGET_NAME = 0x09
+NTLMSSP_AV_CHANNEL_BINDINGS = 0x0a
+
+class AV_PAIRS():
+ def __init__(self, data = None):
+ self.fields = {}
+ if data is not None:
+ self.fromString(data)
+
+ def __setitem__(self,key,value):
+ self.fields[key] = (len(value),value)
+
+ def __getitem__(self, key):
+ if self.fields.has_key(key):
+ return self.fields[key]
+ return None
+
+ def __delitem__(self, key):
+ del self.fields[key]
+
+ def __len__(self):
+ return len(self.getData())
+
+ def __str__(self):
+ return len(self.getData())
+
+ def fromString(self, data):
+ tInfo = data
+ fType = 0xff
+ while fType is not NTLMSSP_AV_EOL:
+ fType = struct.unpack('<H',tInfo[:struct.calcsize('<H')])[0]
+ tInfo = tInfo[struct.calcsize('<H'):]
+ length = struct.unpack('<H',tInfo[:struct.calcsize('<H')])[0]
+ tInfo = tInfo[struct.calcsize('<H'):]
+ content = tInfo[:length]
+ self.fields[fType]=(length,content)
+ tInfo = tInfo[length:]
+
+ def dump(self):
+ for i in self.fields.keys():
+ print "%s: {%r}" % (i,self[i])
+
+ def getData(self):
+ if self.fields.has_key(NTLMSSP_AV_EOL):
+ del self.fields[NTLMSSP_AV_EOL]
+ ans = ''
+ for i in self.fields.keys():
+ ans+= struct.pack('<HH', i, self[i][0])
+ ans+= self[i][1]
+
+ # end with a NTLMSSP_AV_EOL
+ ans += struct.pack('<HH', NTLMSSP_AV_EOL, 0)
+
+ return ans
+
+class NTLMAuthMixin:
+ def get_os_version(self):
+ if self['os_version'] == '':
+ return None
+ else:
+ mayor_v = struct.unpack('B',self['os_version'][0])[0]
+ minor_v = struct.unpack('B',self['os_version'][1])[0]
+ build_v = struct.unpack('H',self['os_version'][2:4])
+ return (mayor_v,minor_v,build_v)
+
+class NTLMAuthNegotiate(Structure, NTLMAuthMixin):
+
+ structure = (
+ ('','"NTLMSSP\x00'),
+ ('message_type','<L=1'),
+ ('flags','<L'),
+ ('domain_len','<H-domain_name'),
+ ('domain_max_len','<H-domain_name'),
+ ('domain_offset','<L=0'),
+ ('host_len','<H-host_name'),
+ ('host_maxlen','<H-host_name'),
+ ('host_offset','<L=0'),
+ ('os_version',':'),
+ ('host_name',':'),
+ ('domain_name',':'))
+
+ def __init__(self):
+ Structure.__init__(self)
+ self['flags']= (
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH|
+ # NTLMSSP_LM_KEY |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_UNICODE |
+ # NTLMSSP_ALWAYS_SIGN |
+ NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_SEAL |
+ # NTLMSSP_TARGET |
+ 0)
+ self['host_name']=''
+ self['domain_name']=''
+ self['os_version']=''
+
+ def getData(self):
+ if len(self.fields['host_name']) > 0:
+ self['flags'] |= NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
+ if len(self.fields['domain_name']) > 0:
+ self['flags'] |= NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
+ if len(self.fields['os_version']) > 0:
+ self['flags'] |= NTLMSSP_NEGOTIATE_VERSION
+ if (self['flags'] & NTLMSSP_NEGOTIATE_VERSION) == NTLMSSP_NEGOTIATE_VERSION:
+ version_len = 8
+ else:
+ version_len = 0
+ if (self['flags'] & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) == NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED:
+ self['host_offset']=32 + version_len
+ if (self['flags'] & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED) == NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED:
+ self['domain_offset']=32+len(self['host_name']) + version_len
+ return Structure.getData(self)
+
+ def fromString(self,data):
+ Structure.fromString(self,data)
+
+ domain_offset = self['domain_offset']
+ domain_end = self['domain_len'] + domain_offset
+ self['domain_name'] = data[ domain_offset : domain_end ]
+
+ host_offset = self['host_offset']
+ host_end = self['host_len'] + host_offset
+ self['host_name'] = data[ host_offset : host_end ]
+
+ hasOsInfo = self['flags'] & NTLMSSP_NEGOTIATE_VERSION
+ if len(data) >= 36 and hasOsInfo:
+ self['os_version'] = data[32:40]
+ else:
+ self['os_version'] = ''
+
+class NTLMAuthChallenge(Structure):
+
+ structure = (
+ ('','"NTLMSSP\x00'),
+ ('message_type','<L=2'),
+ ('domain_len','<H-domain_name'),
+ ('domain_max_len','<H-domain_name'),
+ ('domain_offset','<L=40'),
+ ('flags','<L=0'),
+ ('challenge','8s'),
+ ('reserved','8s=""'),
+ ('TargetInfoFields_len','<H-TargetInfoFields'),
+ ('TargetInfoFields_max_len','<H-TargetInfoFields'),
+ ('TargetInfoFields_offset','<L'),
+ ('VersionLen','_-Version','self.checkVersion(self["flags"])'),
+ ('Version',':'),
+ ('domain_name',':'),
+ ('TargetInfoFields',':'))
+
+ def checkVersion(self, flags):
+ if flags is not None:
+ if flags & NTLMSSP_NEGOTIATE_VERSION == 0:
+ return 0
+ return 8
+
+ def getData(self):
+ if self['TargetInfoFields'] is not None and type(self['TargetInfoFields']) is not str:
+ raw_av_fields = self['TargetInfoFields'].getData()
+ self['TargetInfoFields'] = raw_av_fields
+ return Structure.getData(self)
+
+ def fromString(self,data):
+ Structure.fromString(self,data)
+ # Just in case there's more data after the TargetInfoFields
+ self['TargetInfoFields'] = self['TargetInfoFields'][:self['TargetInfoFields_len']]
+ # We gotta process the TargetInfoFields
+ #if self['TargetInfoFields_len'] > 0:
+ # av_pairs = AV_PAIRS(self['TargetInfoFields'][:self['TargetInfoFields_len']])
+ # self['TargetInfoFields'] = av_pairs
+
+ return self
+
+class NTLMAuthChallengeResponse(Structure, NTLMAuthMixin):
+
+ structure = (
+ ('','"NTLMSSP\x00'),
+ ('message_type','<L=3'),
+ ('lanman_len','<H-lanman'),
+ ('lanman_max_len','<H-lanman'),
+ ('lanman_offset','<L'),
+ ('ntlm_len','<H-ntlm'),
+ ('ntlm_max_len','<H-ntlm'),
+ ('ntlm_offset','<L'),
+ ('domain_len','<H-domain_name'),
+ ('domain_max_len','<H-domain_name'),
+ ('domain_offset','<L'),
+ ('user_len','<H-user_name'),
+ ('user_max_len','<H-user_name'),
+ ('user_offset','<L'),
+ ('host_len','<H-host_name'),
+ ('host_max_len','<H-host_name'),
+ ('host_offset','<L'),
+ ('session_key_len','<H-session_key'),
+ ('session_key_max_len','<H-session_key'),
+ ('session_key_offset','<L'),
+ ('flags','<L'),
+ ('VersionLen','_-Version','self.checkVersion(self["flags"])'),
+ ('Version',':=""'),
+ ('MICLen','_-MIC','self.checkMIC(self["flags"])'),
+ ('MIC',':=""'),
+ ('domain_name',':'),
+ ('user_name',':'),
+ ('host_name',':'),
+ ('lanman',':'),
+ ('ntlm',':'),
+ ('session_key',':'))
+
+ def __init__(self, username = '', password = '', challenge = '', lmhash = '', nthash = '', flags = 0):
+ Structure.__init__(self)
+ self['session_key']=''
+ self['user_name']=username.encode('utf-16le')
+ self['domain_name']='' #"CLON".encode('utf-16le')
+ self['host_name']='' #"BETS".encode('utf-16le')
+ self['flags'] = ( #authResp['flags']
+ # we think (beto & gera) that his flags force a memory conten leakage when a windows 2000 answers using uninitializaed verifiers
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_KEY_EXCH|
+ # NTLMSSP_LM_KEY |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_NEGOTIATE_UNICODE |
+ # NTLMSSP_ALWAYS_SIGN |
+ NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_SEAL |
+ # NTLMSSP_TARGET |
+ 0)
+ # Here we do the stuff
+ if username and ( lmhash != '' or nthash != ''):
+ self['lanman'] = get_ntlmv1_response(lmhash, challenge)
+ self['ntlm'] = get_ntlmv1_response(nthash, challenge)
+ elif (username and password):
+ lmhash = compute_lmhash(password)
+ nthash = compute_nthash(password)
+ self['lanman']=get_ntlmv1_response(lmhash, challenge)
+ self['ntlm']=get_ntlmv1_response(nthash, challenge) # This is not used for LM_KEY nor NTLM_KEY
+ else:
+ self['lanman'] = ''
+ self['ntlm'] = ''
+ if not self['host_name']:
+ self['host_name'] = 'NULL'.encode('utf-16le') # for NULL session there must be a hostname
+
+ def checkVersion(self, flags):
+ if flags is not None:
+ if flags & NTLMSSP_NEGOTIATE_VERSION == 0:
+ return 0
+ return 8
+
+ def checkMIC(self, flags):
+ # TODO: Find a proper way to check the MIC is in there
+ if flags is not None:
+ if flags & NTLMSSP_NEGOTIATE_VERSION == 0:
+ return 0
+ return 16
+
+ def getData(self):
+ self['domain_offset']=64+self.checkMIC(self["flags"])+self.checkVersion(self["flags"])
+ self['user_offset']=64+self.checkMIC(self["flags"])+self.checkVersion(self["flags"])+len(self['domain_name'])
+ self['host_offset']=self['user_offset']+len(self['user_name'])
+ self['lanman_offset']=self['host_offset']+len(self['host_name'])
+ self['ntlm_offset']=self['lanman_offset']+len(self['lanman'])
+ self['session_key_offset']=self['ntlm_offset']+len(self['ntlm'])
+ return Structure.getData(self)
+
+ def fromString(self,data):
+ Structure.fromString(self,data)
+ # [MS-NLMP] page 27
+ # Payload data can be present in any order within the Payload field,
+ # with variable-length padding before or after the data
+
+ domain_offset = self['domain_offset']
+ domain_end = self['domain_len'] + domain_offset
+ self['domain_name'] = data[ domain_offset : domain_end ]
+
+ host_offset = self['host_offset']
+ host_end = self['host_len'] + host_offset
+ self['host_name'] = data[ host_offset: host_end ]
+
+ user_offset = self['user_offset']
+ user_end = self['user_len'] + user_offset
+ self['user_name'] = data[ user_offset: user_end ]
+
+ ntlm_offset = self['ntlm_offset']
+ ntlm_end = self['ntlm_len'] + ntlm_offset
+ self['ntlm'] = data[ ntlm_offset : ntlm_end ]
+
+ lanman_offset = self['lanman_offset']
+ lanman_end = self['lanman_len'] + lanman_offset
+ self['lanman'] = data[ lanman_offset : lanman_end]
+
+ #if len(data) >= 36:
+ # self['os_version'] = data[32:36]
+ #else:
+ # self['os_version'] = ''
+
+class ImpacketStructure(Structure):
+ def set_parent(self, other):
+ self.parent = other
+
+ def get_packet(self):
+ return str(self)
+
+ def get_size(self):
+ return len(self)
+
+class ExtendedOrNotMessageSignature(Structure):
+ def __init__(self, flags = 0, **kargs):
+ if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
+ self.structure = self.extendedMessageSignature
+ else:
+ self.structure = self.MessageSignature
+ return Structure.__init__(self, **kargs)
+
+class NTLMMessageSignature(ExtendedOrNotMessageSignature):
+ extendedMessageSignature = (
+ ('Version','<L=1'),
+ ('Checksum','<q'),
+ ('SeqNum','<i'),
+ )
+
+ MessageSignature = (
+ ('Version','<L=1'),
+ ('RandomPad','<i=0'),
+ ('Checksum','<i'),
+ ('SeqNum','<i'),
+ )
+
+KNOWN_DES_INPUT = "KGS!@#$%"
+
+def __expand_DES_key( key):
+ # Expand the key from a 7-byte password key into a 8-byte DES key
+ key = key[:7]
+ key += '\x00'*(7-len(key))
+ s = chr(((ord(key[0]) >> 1) & 0x7f) << 1)
+ s = s + chr(((ord(key[0]) & 0x01) << 6 | ((ord(key[1]) >> 2) & 0x3f)) << 1)
+ s = s + chr(((ord(key[1]) & 0x03) << 5 | ((ord(key[2]) >> 3) & 0x1f)) << 1)
+ s = s + chr(((ord(key[2]) & 0x07) << 4 | ((ord(key[3]) >> 4) & 0x0f)) << 1)
+ s = s + chr(((ord(key[3]) & 0x0f) << 3 | ((ord(key[4]) >> 5) & 0x07)) << 1)
+ s = s + chr(((ord(key[4]) & 0x1f) << 2 | ((ord(key[5]) >> 6) & 0x03)) << 1)
+ s = s + chr(((ord(key[5]) & 0x3f) << 1 | ((ord(key[6]) >> 7) & 0x01)) << 1)
+ s = s + chr((ord(key[6]) & 0x7f) << 1)
+ return s
+
+def __DES_block(key, msg):
+ if POW:
+ cipher = POW.Symmetric(POW.DES_ECB)
+ cipher.encryptInit(__expand_DES_key(key))
+ return cipher.update(msg)
+ else:
+ cipher = DES.new(__expand_DES_key(key),DES.MODE_ECB)
+ return cipher.encrypt(msg)
+
+def ntlmssp_DES_encrypt(key, challenge):
+ answer = __DES_block(key[:7], challenge)
+ answer += __DES_block(key[7:14], challenge)
+ answer += __DES_block(key[14:], challenge)
+ return answer
+
+# High level functions to use NTLMSSP
+
+def getNTLMSSPType1(workstation='', domain='', signingRequired = False, use_ntlmv2 = USE_NTLMv2):
+ # Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with
+ # international characters.
+ import sys
+ encoding = sys.getfilesystemencoding()
+ if encoding is not None:
+ try:
+ workstation.encode('utf-16le')
+ except:
+ workstation = workstation.decode(encoding)
+ try:
+ domain.encode('utf-16le')
+ except:
+ domain = domain.decode(encoding)
+
+ # Let's prepare a Type 1 NTLMSSP Message
+ auth = NTLMAuthNegotiate()
+ auth['flags']=0
+ if signingRequired:
+ auth['flags'] = NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL
+ if use_ntlmv2:
+ auth['flags'] |= NTLMSSP_NEGOTIATE_TARGET_INFO
+ auth['flags'] |= NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_56
+ auth['domain_name'] = domain.encode('utf-16le')
+ return auth
+
+def getNTLMSSPType3(type1, type2, user, password, domain, lmhash = '', nthash = '', use_ntlmv2 = USE_NTLMv2):
+
+ # Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with
+ # international characters.
+ import sys
+ encoding = sys.getfilesystemencoding()
+ if encoding is not None:
+ try:
+ user.encode('utf-16le')
+ except:
+ user = user.decode(encoding)
+ try:
+ password.encode('utf-16le')
+ except:
+ password = password.decode(encoding)
+ try:
+ domain.encode('utf-16le')
+ except:
+ domain = user.decode(encoding)
+
+ ntlmChallenge = NTLMAuthChallenge(type2)
+
+ # Let's start with the original flags sent in the type1 message
+ responseFlags = type1['flags']
+
+ # Token received and parsed. Depending on the authentication
+ # method we will create a valid ChallengeResponse
+ ntlmChallengeResponse = NTLMAuthChallengeResponse(user, password, ntlmChallenge['challenge'])
+
+ clientChallenge = "".join([random.choice(string.digits+string.letters) for i in xrange(8)])
+
+ serverName = ntlmChallenge['TargetInfoFields']
+
+ ntResponse, lmResponse, sessionBaseKey = computeResponse(ntlmChallenge['flags'], ntlmChallenge['challenge'], clientChallenge, serverName, domain, user, password, lmhash, nthash, use_ntlmv2 )
+
+ # Let's check the return flags
+ if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) == 0:
+ # No extended session security, taking it out
+ responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
+ if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_128 ) == 0:
+ # No support for 128 key len, taking it out
+ responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_128
+ if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH) == 0:
+ # No key exchange supported, taking it out
+ responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_KEY_EXCH
+ if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_SEAL) == 0:
+ # No sign available, taking it out
+ responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_SEAL
+ if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_SIGN) == 0:
+ # No sign available, taking it out
+ responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_SIGN
+ if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) == 0:
+ # No sign available, taking it out
+ responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_ALWAYS_SIGN
+
+ keyExchangeKey = KXKEY(ntlmChallenge['flags'],sessionBaseKey, lmResponse, ntlmChallenge['challenge'], password, lmhash, nthash,use_ntlmv2)
+
+ # Special case for anonymous login
+ if user == '' and password == '' and lmhash == '' and nthash == '':
+ keyExchangeKey = '\x00'*16
+
+ # If we set up key exchange, let's fill the right variables
+ if ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH:
+ # not exactly what I call random tho :\
+ # exportedSessionKey = this is the key we should use to sign
+ exportedSessionKey = "".join([random.choice(string.digits+string.letters) for i in xrange(16)])
+ #exportedSessionKey = "A"*16
+ #print "keyExchangeKey %r" % keyExchangeKey
+ # Let's generate the right session key based on the challenge flags
+ #if responseFlags & NTLMSSP_NTLM2_KEY:
+ # Extended session security enabled
+ # if responseFlags & NTLMSSP_KEY_128:
+ # Full key
+ # exportedSessionKey = exportedSessionKey
+ # elif responseFlags & NTLMSSP_KEY_56:
+ # Only 56-bit key
+ # exportedSessionKey = exportedSessionKey[:7]
+ # else:
+ # exportedSessionKey = exportedSessionKey[:5]
+ #elif responseFlags & NTLMSSP_KEY_56:
+ # No extended session security, just 56 bits key
+ # exportedSessionKey = exportedSessionKey[:7] + '\xa0'
+ #else:
+ # exportedSessionKey = exportedSessionKey[:5] + '\xe5\x38\xb0'
+
+ encryptedRandomSessionKey = generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey)
+ else:
+ encryptedRandomSessionKey = None
+ # [MS-NLMP] page 46
+ exportedSessionKey = keyExchangeKey
+
+ ntlmChallengeResponse['flags'] = responseFlags
+ ntlmChallengeResponse['domain_name'] = domain.encode('utf-16le')
+ ntlmChallengeResponse['lanman'] = lmResponse
+ ntlmChallengeResponse['ntlm'] = ntResponse
+ if encryptedRandomSessionKey is not None:
+ ntlmChallengeResponse['session_key'] = encryptedRandomSessionKey
+
+ return ntlmChallengeResponse, exportedSessionKey
+
+
+# NTLMv1 Algorithm
+
+def generateSessionKeyV1(password, lmhash, nthash):
+ if POW:
+ hash = POW.Digest(POW.MD4_DIGEST)
+ else:
+ hash = MD4.new()
+ hash.update(NTOWFv1(password, lmhash, nthash))
+ return hash.digest()
+
+def computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='', nthash='', use_ntlmv2 = USE_NTLMv2):
+ if (user == '' and password == ''):
+ # Special case for anonymous authentication
+ lmResponse = ''
+ ntResponse = ''
+ else:
+ lmhash = LMOWFv1(password, lmhash, nthash)
+ nthash = NTOWFv1(password, lmhash, nthash)
+ if flags & NTLMSSP_NEGOTIATE_LM_KEY:
+ ntResponse = ''
+ lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
+ elif flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
+ md5 = hashlib.new('md5')
+ chall = (serverChallenge + clientChallenge)
+ md5.update(chall)
+ ntResponse = ntlmssp_DES_encrypt(nthash, md5.digest()[:8])
+ lmResponse = clientChallenge + '\x00'*16
+ else:
+ ntResponse = get_ntlmv1_response(nthash,serverChallenge)
+ lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
+
+ sessionBaseKey = generateSessionKeyV1(password, lmhash, nthash)
+ return ntResponse, lmResponse, sessionBaseKey
+
+def compute_lmhash(password):
+ # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
+ password = password.upper()
+ lmhash = __DES_block(password[:7], KNOWN_DES_INPUT)
+ lmhash += __DES_block(password[7:14], KNOWN_DES_INPUT)
+ return lmhash
+
+def NTOWFv1(password, lmhash = '', nthash=''):
+ if nthash != '':
+ return nthash
+ return compute_nthash(password)
+
+def LMOWFv1(password, lmhash = '', nthash=''):
+ if lmhash != '':
+ return lmhash
+ return compute_lmhash(password)
+
+def compute_nthash(password):
+ # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
+ try:
+ password = unicode(password).encode('utf_16le')
+ except UnicodeDecodeError:
+ import sys
+ password = password.decode(sys.getfilesystemencoding()).encode('utf_16le')
+
+ if POW:
+ hash = POW.Digest(POW.MD4_DIGEST)
+ else:
+ hash = MD4.new()
+ hash.update(password)
+ return hash.digest()
+
+def get_ntlmv1_response(key, challenge):
+ return ntlmssp_DES_encrypt(key, challenge)
+
+# NTLMv2 Algorithm - as described in MS-NLMP Section 3.3.2
+
+# Crypto Stuff
+
+def MAC(flags, handle, signingKey, seqNum, message):
+ # [MS-NLMP] Section 3.4.4
+ # Returns the right messageSignature depending on the flags
+ messageSignature = NTLMMessageSignature(flags)
+ if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
+ if flags & NTLMSSP_NEGOTIATE_KEY_EXCH:
+ messageSignature['Version'] = 1
+ messageSignature['Checksum'] = struct.unpack('<q',handle(hmac_md5(signingKey, struct.pack('<i',seqNum)+message)[:8]))[0]
+ messageSignature['SeqNum'] = seqNum
+ seqNum += 1
+ else:
+ messageSignature['Version'] = 1
+ messageSignature['Checksum'] = struct.unpack('<q',hmac_md5(signingKey, struct.pack('<i',seqNum)+message)[:8])[0]
+ messageSignature['SeqNum'] = seqNum
+ seqNum += 1
+ else:
+ messageSignature['Version'] = 1
+ messageSignature['Checksum'] = struct.pack('<i',binascii.crc32(message))
+ messageSignature['RandomPad'] = 0
+ messageSignature['RandomPad'] = handle(struct.pack('<i',messageSignature['RandomPad']))
+ messageSignature['Checksum'] = struct.unpack('<i',handle(messageSignature['Checksum']))[0]
+ messageSignature['SeqNum'] = handle('\x00\x00\x00\x00')
+ messageSignature['SeqNum'] = struct.unpack('<i',messageSignature['SeqNum'])[0] ^ seqNum
+ messageSignature['RandomPad'] = 0
+
+ return messageSignature
+
+def SEAL(flags, signingKey, sealingKey, messageToSign, messageToEncrypt, seqNum, handle):
+ sealedMessage = handle(messageToEncrypt)
+ signature = MAC(flags, handle, signingKey, seqNum, messageToSign)
+ return sealedMessage, signature
+
+def SIGN(flags, signingKey, message, seqNum, handle):
+ return MAC(flags, handle, signingKey, seqNum, message)
+
+def SIGNKEY(flags, randomSessionKey, mode = 'Client'):
+ if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
+ if mode == 'Client':
+ md5 = hashlib.new('md5')
+ md5.update(randomSessionKey + "session key to client-to-server signing key magic constant\x00")
+ signKey = md5.digest()
+ else:
+ md5 = hashlib.new('md5')
+ md5.update(randomSessionKey + "session key to server-to-client signing key magic constant\x00")
+ signKey = md5.digest()
+ else:
+ signKey = None
+ return signKey
+
+def SEALKEY(flags, randomSessionKey, mode = 'Client'):
+ if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
+ if flags & NTLMSSP_NEGOTIATE_128:
+ sealKey = randomSessionKey
+ elif flags & NTLMSSP_NEGOTIATE_56:
+ sealKey = randomSessionKey[:7]
+ else:
+ sealKey = randomSessionKey[:5]
+
+ if mode == 'Client':
+ md5 = hashlib.new('md5')
+ md5.update(sealKey + 'session key to client-to-server sealing key magic constant\x00')
+ sealKey = md5.digest()
+ else:
+ md5 = hashlib.new('md5')
+ md5.update(sealKey + 'session key to server-to-client sealing key magic constant\x00')
+ sealKey = md5.digest()
+
+ elif flags & NTLMSSP_NEGOTIATE_56:
+ sealKey = randomSessionKey[:7] + '\xa0'
+ else:
+ sealKey = randomSessionKey[:5] + '\xe5\x38\xb0'
+
+ return sealKey
+
+
+def generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey):
+ if POW:
+ cipher = POW.Symmetric(POW.RC4)
+ cipher.encryptInit(keyExchangeKey)
+ cipher_encrypt = cipher.update
+ else:
+ cipher = ARC4.new(keyExchangeKey)
+ cipher_encrypt = cipher.encrypt
+
+ sessionKey = cipher_encrypt(exportedSessionKey)
+ return sessionKey
+
+def KXKEY(flags, sessionBaseKey, lmChallengeResponse, serverChallenge, password, lmhash, nthash, use_ntlmv2 = USE_NTLMv2):
+ if use_ntlmv2:
+ return sessionBaseKey
+
+ if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
+ if flags & NTLMSSP_NEGOTIATE_NTLM:
+ keyExchangeKey = hmac_md5(sessionBaseKey, serverChallenge + lmChallengeResponse[:8])
+ else:
+ keyExchangeKey = sessionBaseKey
+ elif flags & NTLMSSP_NEGOTIATE_NTLM:
+ if flags & NTLMSSP_NEGOTIATE_LM_KEY:
+ keyExchangeKey = __DES_block(LMOWFv1(password,lmhash)[:7], lmChallengeResponse[:8]) + __DES_block(LMOWFv1(password,lmhash)[7] + '\xBD\xBD\xBD\xBD\xBD\xBD', lmChallengeResponse[:8])
+ elif flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY:
+ keyExchangeKey = LMOWFv1(password,lmhash)[:8] + '\x00'*8
+ else:
+ keyExchangeKey = sessionBaseKey
+ else:
+ raise "Can't create a valid KXKEY!"
+
+ return keyExchangeKey
+
+def hmac_md5(key, data):
+ if POW:
+ h = POW.Hmac(POW.MD5_DIGEST, key)
+ h.update(data)
+ result = h.mac()
+ else:
+ import hmac
+ h = hmac.new(key)
+ h.update(data)
+ result = h.digest()
+ return result
+
+def NTOWFv2( user, password, domain, hash = ''):
+ if hash != '':
+ theHash = hash
+ else:
+ theHash = compute_nthash(password)
+ return hmac_md5(theHash, user.upper().encode('utf-16le') + domain.encode('utf-16le'))
+
+def LMOWFv2( user, password, domain, lmhash = ''):
+ return NTOWFv2( user, password, domain, lmhash)
+
+
+def computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash = '', nthash = '', use_ntlmv2 = USE_NTLMv2):
+
+ responseServerVersion = '\x01'
+ hiResponseServerVersion = '\x01'
+ responseKeyNT = NTOWFv2(user, password, domain, nthash)
+ responseKeyLM = LMOWFv2(user, password, domain, lmhash)
+
+ # If you're running test-ntlm, comment the following lines and uncoment the ones that are commented. Don't forget to turn it back after the tests!
+ ######################
+ av_pairs = AV_PAIRS(serverName)
+ # In order to support SPN target name validation, we have to add this to the serverName av_pairs. Otherwise we will get access denied
+ # This is set at Local Security Policy -> Local Policies -> Security Options -> Server SPN target name validation level
+ av_pairs[NTLMSSP_AV_TARGET_NAME] = 'cifs/'.encode('utf-16le') + av_pairs[NTLMSSP_AV_HOSTNAME][1]
+ if av_pairs[NTLMSSP_AV_TIME] is not None:
+ aTime = av_pairs[NTLMSSP_AV_TIME][1]
+ else:
+ aTime = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
+ #aTime = '\x00'*8
+ av_pairs[NTLMSSP_AV_TIME] = aTime
+ serverName = av_pairs.getData()
+
+ ######################
+ #aTime = '\x00'*8
+ ######################
+ temp = responseServerVersion + hiResponseServerVersion + '\x00' * 6 + aTime + clientChallenge + '\x00' * 4 + serverName + '\x00' * 4
+
+ ntProofStr = hmac_md5(responseKeyNT, serverChallenge + temp)
+
+ ntChallengeResponse = ntProofStr + temp
+ lmChallengeResponse = hmac_md5(responseKeyNT, serverChallenge + clientChallenge) + clientChallenge
+ sessionBaseKey = hmac_md5(responseKeyNT, ntProofStr)
+
+ if (user == '' and password == ''):
+ # Special case for anonymous authentication
+ ntChallengeResponse = ''
+ lmChallengeResponse = ''
+
+ return ntChallengeResponse, lmChallengeResponse, sessionBaseKey
+
+class NTLM_HTTP(object):
+ '''Parent class for NTLM HTTP classes.'''
+ MSG_TYPE = None
+
+ @classmethod
+ def get_instace(cls,msg_64):
+ msg = None
+ msg_type = 0
+ if msg_64 != '':
+ msg = base64.b64decode(msg_64[5:]) # Remove the 'NTLM '
+ msg_type = ord(msg[8])
+
+ for _cls in NTLM_HTTP.__subclasses__():
+ if msg_type == _cls.MSG_TYPE:
+ instance = _cls()
+ instance.fromString(msg)
+ return instance
+
+
+class NTLM_HTTP_AuthRequired(NTLM_HTTP):
+ commonHdr = ()
+ # Message 0 means the first HTTP request e.g. 'GET /bla.png'
+ MSG_TYPE = 0
+
+ def fromString(self,data):
+ pass
+
+
+class NTLM_HTTP_AuthNegotiate(NTLM_HTTP, NTLMAuthNegotiate):
+ commonHdr = ()
+ MSG_TYPE = 1
+
+ def __init__(self):
+ NTLMAuthNegotiate.__init__(self)
+
+
+class NTLM_HTTP_AuthChallengeResponse(NTLM_HTTP, NTLMAuthChallengeResponse):
+ commonHdr = ()
+ MSG_TYPE = 3
+
+ def __init__(self):
+ NTLMAuthChallengeResponse.__init__(self)
+