Files correlati : utilma verione di curl git-svn-id: svn://10.65.10.50/branches/R_10_00@24159 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			972 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			972 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # 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)
 | |
| 
 |