def negotiateSession(self, preferredDialect=None, negSessionResponse=None): # Let's store some data for later use self._Connection['ClientSecurityMode'] = SMB2_NEGOTIATE_SIGNING_ENABLED if self.RequireMessageSigning is True: self._Connection[ 'ClientSecurityMode'] |= SMB2_NEGOTIATE_SIGNING_REQUIRED self._Connection['Capabilities'] = SMB2_GLOBAL_CAP_ENCRYPTION currentDialect = SMB2_DIALECT_WILDCARD # Do we have a negSessionPacket already? if negSessionResponse is not None: # Yes, let's store the dialect answered back negResp = SMB2Negotiate_Response(negSessionResponse['Data']) currentDialect = negResp['DialectRevision'] if currentDialect == SMB2_DIALECT_WILDCARD: # Still don't know the chosen dialect, let's send our options packet = self.SMB_PACKET() packet['Command'] = SMB2_NEGOTIATE negSession = SMB2Negotiate() negSession['SecurityMode'] = self._Connection['ClientSecurityMode'] negSession['Capabilities'] = self._Connection['Capabilities'] negSession['ClientGuid'] = self.ClientGuid if preferredDialect is not None: negSession['Dialects'] = [preferredDialect] if preferredDialect == SMB2_DIALECT_311: # Build the Contexts contextData = SMB311ContextData() contextData['NegotiateContextOffset'] = 64 + 38 + 2 contextData['NegotiateContextCount'] = 0 # Add an SMB2_NEGOTIATE_CONTEXT with ContextType as SMB2_PREAUTH_INTEGRITY_CAPABILITIES # to the negotiate request as specified in section 2.2.3.1: negotiateContext = SMB2NegotiateContext() negotiateContext[ 'ContextType'] = SMB2_PREAUTH_INTEGRITY_CAPABILITIES preAuthIntegrityCapabilities = SMB2PreAuthIntegrityCapabilities( ) preAuthIntegrityCapabilities['HashAlgorithmCount'] = 1 preAuthIntegrityCapabilities['SaltLength'] = 32 preAuthIntegrityCapabilities[ 'HashAlgorithms'] = b'\x01\x00' preAuthIntegrityCapabilities['Salt'] = ''.join([ rand.choice(string.ascii_letters) for _ in range( preAuthIntegrityCapabilities['SaltLength']) ]) negotiateContext[ 'Data'] = preAuthIntegrityCapabilities.getData() negotiateContext['DataLength'] = len( negotiateContext['Data']) contextData['NegotiateContextCount'] += 1 pad = b'\xFF' * (8 - (negotiateContext['DataLength'] % 8)) negotiateContext2 = SMB2NegotiateContext() negotiateContext2[ 'ContextType'] = SMB2_COMPRESSION_CAPABILITIES compressionCapabilities = SMB2CompressionCapabilities() compressionCapabilities['CompressionAlgorithmCount'] = 1 compressionCapabilities['Padding'] = 0 compressionCapabilities['Flags'] = 0 compressionCapabilities[ 'CompressionAlgorithms'] = b'\x01\x00' negotiateContext2[ 'Data'] = compressionCapabilities.getData() negotiateContext2['DataLength'] = len( negotiateContext2['Data']) contextData['NegotiateContextCount'] += 1 negSession['ClientStartTime'] = contextData.getData() negSession['Padding'] = b'\xFF\xFF' # Subsequent negotiate contexts MUST appear at the first 8-byte aligned offset following the # previous negotiate context. negSession[ 'NegotiateContextList'] = negotiateContext.getData( ) + pad + negotiateContext2.getData() else: negSession['Dialects'] = [ SMB2_DIALECT_002, SMB2_DIALECT_21, SMB2_DIALECT_30 ] negSession['DialectCount'] = len(negSession['Dialects']) packet['Data'] = negSession packetID = self.sendSMB(packet) ans = self.recvSMB(packetID) if ans.isValidAnswer(STATUS_SUCCESS): negResp = SMB2Negotiate_Response(ans['Data']) self._Connection['MaxTransactSize'] = min(0x100000, negResp['MaxTransactSize']) self._Connection['MaxReadSize'] = min(0x100000, negResp['MaxReadSize']) self._Connection['MaxWriteSize'] = min(0x100000, negResp['MaxWriteSize']) self._Connection['ServerGuid'] = negResp['ServerGuid'] self._Connection['GSSNegotiateToken'] = negResp['Buffer'] self._Connection['Dialect'] = negResp['DialectRevision'] if (negResp['SecurityMode'] & SMB2_NEGOTIATE_SIGNING_REQUIRED) == SMB2_NEGOTIATE_SIGNING_REQUIRED or \ self._Connection['Dialect'] == SMB2_DIALECT_311: self._Connection['RequireSigning'] = True if self._Connection['Dialect'] == SMB2_DIALECT_311: # Always Sign self._Connection['RequireSigning'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_LEASING) == SMB2_GLOBAL_CAP_LEASING: self._Connection['SupportsFileLeasing'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_LARGE_MTU) == SMB2_GLOBAL_CAP_LARGE_MTU: self._Connection['SupportsMultiCredit'] = True if self._Connection['Dialect'] >= SMB2_DIALECT_30: # Switching to the right packet format self.SMB_PACKET = SMB3Packet if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_DIRECTORY_LEASING ) == SMB2_GLOBAL_CAP_DIRECTORY_LEASING: self._Connection['SupportsDirectoryLeasing'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_MULTI_CHANNEL ) == SMB2_GLOBAL_CAP_MULTI_CHANNEL: self._Connection['SupportsMultiChannel'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ) == SMB2_GLOBAL_CAP_PERSISTENT_HANDLES: self._Connection['SupportsPersistentHandles'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_ENCRYPTION) == SMB2_GLOBAL_CAP_ENCRYPTION: self._Connection['SupportsEncryption'] = True self._Connection['ServerCapabilities'] = negResp['Capabilities'] self._Connection['ServerSecurityMode'] = negResp['SecurityMode']
def negotiateSession(self, preferredDialect=None, negSessionResponse=None): # We DON'T want to sign self._Connection['ClientSecurityMode'] = 0 if self.RequireMessageSigning is True: LOG.error('Signing is required, attack won\'t work!') return self._Connection['Capabilities'] = SMB2_GLOBAL_CAP_ENCRYPTION currentDialect = SMB2_DIALECT_WILDCARD # Do we have a negSessionPacket already? if negSessionResponse is not None: # Yes, let's store the dialect answered back negResp = SMB2Negotiate_Response(negSessionResponse['Data']) currentDialect = negResp['DialectRevision'] if currentDialect == SMB2_DIALECT_WILDCARD: # Still don't know the chosen dialect, let's send our options packet = self.SMB_PACKET() packet['Command'] = SMB2_NEGOTIATE negSession = SMB2Negotiate() negSession['SecurityMode'] = self._Connection['ClientSecurityMode'] negSession['Capabilities'] = self._Connection['Capabilities'] negSession['ClientGuid'] = self.ClientGuid if preferredDialect is not None: negSession['Dialects'] = [preferredDialect] else: negSession['Dialects'] = [ SMB2_DIALECT_002, SMB2_DIALECT_21, SMB2_DIALECT_30 ] negSession['DialectCount'] = len(negSession['Dialects']) packet['Data'] = negSession packetID = self.sendSMB(packet) ans = self.recvSMB(packetID) if ans.isValidAnswer(STATUS_SUCCESS): negResp = SMB2Negotiate_Response(ans['Data']) self._Connection['MaxTransactSize'] = min(0x100000, negResp['MaxTransactSize']) self._Connection['MaxReadSize'] = min(0x100000, negResp['MaxReadSize']) self._Connection['MaxWriteSize'] = min(0x100000, negResp['MaxWriteSize']) self._Connection['ServerGuid'] = negResp['ServerGuid'] self._Connection['GSSNegotiateToken'] = negResp['Buffer'] self._Connection['Dialect'] = negResp['DialectRevision'] if (negResp['SecurityMode'] & SMB2_NEGOTIATE_SIGNING_REQUIRED ) == SMB2_NEGOTIATE_SIGNING_REQUIRED: LOG.error('Signing is required, attack won\'t work!') return if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_LEASING) == SMB2_GLOBAL_CAP_LEASING: self._Connection['SupportsFileLeasing'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_LARGE_MTU) == SMB2_GLOBAL_CAP_LARGE_MTU: self._Connection['SupportsMultiCredit'] = True if self._Connection['Dialect'] == SMB2_DIALECT_30: # Switching to the right packet format self.SMB_PACKET = SMB3Packet if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_DIRECTORY_LEASING ) == SMB2_GLOBAL_CAP_DIRECTORY_LEASING: self._Connection['SupportsDirectoryLeasing'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_MULTI_CHANNEL ) == SMB2_GLOBAL_CAP_MULTI_CHANNEL: self._Connection['SupportsMultiChannel'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ) == SMB2_GLOBAL_CAP_PERSISTENT_HANDLES: self._Connection['SupportsPersistentHandles'] = True if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_ENCRYPTION) == SMB2_GLOBAL_CAP_ENCRYPTION: self._Connection['SupportsEncryption'] = True self._Connection['ServerCapabilities'] = negResp['Capabilities'] self._Connection['ServerSecurityMode'] = negResp['SecurityMode']
def getNegoAnswer(self, recvPacket): if self.isSMB2 is False: smbCommand = SMBCommand(recvPacket['Data'][0]) respSMBCommand = SMBCommand(SMB.SMB_COM_NEGOTIATE) resp = NewSMBPacket() resp['Flags1'] = SMB.FLAGS1_REPLY resp['Pid'] = recvPacket['Pid'] resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] dialects = smbCommand['Data'].split('\x02') index = dialects.index('NT LM 0.12\x00') - 1 # Let's fill the data for NTLM if recvPacket['Flags2'] & SMB.FLAGS2_EXTENDED_SECURITY: resp[ 'Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_UNICODE _dialects_data = SMBExtended_Security_Data() _dialects_data['ServerGUID'] = 'A' * 16 blob = SPNEGO_NegTokenInit() blob['MechTypes'] = [ TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider'] ] _dialects_data['SecurityBlob'] = blob.getData() _dialects_parameters = SMBExtended_Security_Parameters() _dialects_parameters[ 'Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_NT_SMBS | SMB.CAP_UNICODE _dialects_parameters['ChallengeLength'] = 0 else: resp['Flags2'] = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_UNICODE _dialects_parameters = SMBNTLMDialect_Parameters() _dialects_data = SMBNTLMDialect_Data() _dialects_data['Payload'] = '' _dialects_data[ 'Challenge'] = '\x11\x22\x33\x44\x55\x66\x77\x88' _dialects_parameters['ChallengeLength'] = 8 _dialects_parameters[ 'Capabilities'] = SMB.CAP_USE_NT_ERRORS | SMB.CAP_NT_SMBS _dialects_parameters['Capabilities'] |= SMB.CAP_RPC_REMOTE_APIS _dialects_parameters['DialectIndex'] = index _dialects_parameters[ 'SecurityMode'] = SMB.SECURITY_AUTH_ENCRYPTED | SMB.SECURITY_SHARE_USER _dialects_parameters['MaxMpxCount'] = 1 _dialects_parameters['MaxNumberVcs'] = 1 _dialects_parameters['MaxBufferSize'] = 64000 _dialects_parameters['MaxRawSize'] = 65536 _dialects_parameters['SessionKey'] = 0 _dialects_parameters['LowDateTime'] = 0 _dialects_parameters['HighDateTime'] = 0 _dialects_parameters['ServerTimeZone'] = 0 respSMBCommand['Data'] = _dialects_data respSMBCommand['Parameters'] = _dialects_parameters resp.addCommand(respSMBCommand) else: resp = SMB2Packet() resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR resp['Status'] = STATUS_SUCCESS resp['CreditRequestResponse'] = 1 resp['CreditCharge'] = 1 resp['Command'] = SMB2_NEGOTIATE resp['SessionID'] = 0 resp['MessageID'] = 0 resp['TreeID'] = 0 respSMBCommand = SMB2Negotiate_Response() respSMBCommand['SecurityMode'] = 1 if isinstance(recvPacket, NewSMBPacket): respSMBCommand['DialectRevision'] = SMB2_DIALECT_WILDCARD else: respSMBCommand['DialectRevision'] = self.serverDialect resp['MessageID'] = 1 respSMBCommand['ServerGuid'] = ''.join( [random.choice(string.letters) for _ in range(16)]) respSMBCommand['Capabilities'] = 0x7 respSMBCommand['MaxTransactSize'] = 65536 respSMBCommand['MaxReadSize'] = 65536 respSMBCommand['MaxWriteSize'] = 65536 respSMBCommand['SystemTime'] = getFileTime( calendar.timegm(time.gmtime())) respSMBCommand['ServerStartTime'] = getFileTime( calendar.timegm(time.gmtime())) respSMBCommand['SecurityBufferOffset'] = 0x80 blob = SPNEGO_NegTokenInit() blob['MechTypes'] = [ TypesMech[ 'NEGOEX - SPNEGO Extended Negotiation Security Mechanism'], TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] ] respSMBCommand['Buffer'] = blob.getData() respSMBCommand['SecurityBufferLength'] = len( respSMBCommand['Buffer']) resp['Data'] = respSMBCommand return resp