Beispiel #1
0
    def sendrecv(self, data, throw=True):
        #throw variable indicates wether to create an exception when a kerberos error happens or just return the kerberos error"
        #for any other exceptions types (eg. connection related errors) an exception will be raised regardless

        self.create_soc()
        try:
            if self.soc_type == KerberosSocketType.TCP:
                length = len(data).to_bytes(4, byteorder='big', signed=False)
                self.soc.sendall(length + data)
                buff = b''
                total_length = -1
                while True:
                    temp = b''
                    temp = self.soc.recv(4096)
                    if temp == b'':
                        break
                    buff += temp
                    if total_length == -1:
                        if len(buff) > 4:
                            total_length = int.from_bytes(buff[:4],
                                                          byteorder='big',
                                                          signed=False)
                            if total_length == 0:
                                raise Exception(
                                    'Returned data length is 0! This means the server did not understand our message'
                                )

                    if total_length != -1:
                        if len(buff) == total_length + 4:
                            buff = buff[4:]
                            break
                        elif len(buff) > total_length + 4:
                            raise Exception('Got too much data somehow')
                        else:
                            continue

            elif self.soc_type == KerberosSocketType.UDP:
                self.soc.sendto(data, (self.dst_ip, self.dst_port))
                while True:
                    buff, addr = self.soc.recvfrom(65535)
                    if addr[0] == self.dst_ip:
                        break
                    else:
                        # got a message from a different IP than the target, strange!
                        # continuing, but this might result in an infinite loop
                        continue
            if buff == b'':
                raise Exception('Server closed the connection!')
            krb_message = KerberosResponse.load(buff)
            if krb_message.name == 'KRB_ERROR' and throw == True:
                raise KerberosError(krb_message)
            return krb_message
        finally:
            self.soc.close()
    async def sendrecv(self, data):
        self.out_queue = asyncio.Queue()
        self.in_queue = asyncio.Queue()
        comms = SocksQueueComms(self.out_queue, self.in_queue)

        self.client = SOCKSClient(comms, self.target.proxy.target)
        proxy_coro = await self.client.run(True)
        self.proxy_task = asyncio.create_task(proxy_coro)
        await self.client.proxy_running_evt.wait()
        #self.proxy_task = asyncio.create_task(self.client.run())

        length = len(data).to_bytes(4, byteorder='big', signed=False)
        await self.out_queue.put(length + data)

        resp_data = b''
        resp_data_len = -1
        while True:
            data, err = await self.in_queue.get()
            if data is None:
                break
            if err is not None:
                raise err
            resp_data += data
            if resp_data_len == -1:
                if len(resp_data) > 4:
                    resp_data_len = int.from_bytes(resp_data[:4],
                                                   byteorder='big',
                                                   signed=False)
                    if resp_data_len == 0:
                        raise Exception(
                            'Returned data length is 0! This means the server did not understand our message'
                        )

            if resp_data_len != -1:
                if len(resp_data) == resp_data_len + 4:
                    resp_data = resp_data[4:]
                    break
                elif len(resp_data) > resp_data_len + 4:
                    raise Exception('Got too much data somehow')
                else:
                    continue

        await self.out_queue.put(None)
        if resp_data == b'':
            raise Exception('Connection returned no data!')

        krb_message = KerberosResponse.load(resp_data)
        return krb_message
    async def sendrecv(self, data):
        self.out_queue = asyncio.Queue()
        self.in_queue = asyncio.Queue()
        self.proxy_client = WSNetworkTCP(self.target.ip, int(self.target.port),
                                         self.in_queue, self.out_queue)
        _, err = await self.proxy_client.run()
        if err is not None:
            raise err

        length = len(data).to_bytes(4, byteorder='big', signed=False)
        await self.out_queue.put(length + data)

        resp_data = b''
        resp_data_len = -1
        while True:
            data, err = await self.in_queue.get()
            if data is None:
                break
            if err is not None:
                raise err
            resp_data += data
            if resp_data_len == -1:
                if len(resp_data) > 4:
                    resp_data_len = int.from_bytes(resp_data[:4],
                                                   byteorder='big',
                                                   signed=False)
                    if resp_data_len == 0:
                        raise Exception(
                            'Returned data length is 0! This means the server did not understand our message'
                        )

            if resp_data_len != -1:
                if len(resp_data) == resp_data_len + 4:
                    resp_data = resp_data[4:]
                    break
                elif len(resp_data) > resp_data_len + 4:
                    raise Exception('Got too much data somehow')
                else:
                    continue

        await self.out_queue.put(None)
        if resp_data == b'':
            raise Exception('Connection returned no data!')

        krb_message = KerberosResponse.load(resp_data)
        return krb_message
    async def sendrecv(self, data, throw=False):
        await self.create_soc()
        try:
            if self.soc_type == KerberosSocketType.TCP:
                length = len(data).to_bytes(4, byteorder='big', signed=False)
                self.writer.write(length + data)
                await self.writer.drain()

                t = await self.reader.readexactly(4)
                length = int.from_bytes(t, byteorder='big', signed=False)
                data = await self.reader.readexactly(length)

            elif self.soc_type == KerberosSocketType.UDP:
                raise Exception('Not implemented!')

            krb_message = KerberosResponse.load(data)
            return krb_message
        finally:
            self.writer.close()
            self.reader = None
            self.writer = None
def decrypt_pk_dh(data, diffieHellmanExchange):
    try:
        rep = SPNEGO_PKINIT_AS_REP.load(bytes.fromhex(data)).native
    except:
        krb_message = KerberosResponse.load(bytes.fromhex(data))
        raise KerberosError(krb_message)

    relevantPadata = None
    for padata in rep['Kerberos']['padata']:
        if padata['padata-type'] == 17:
            relevantPadata = PA_PK_AS_REP.load(padata['padata-value']).native
            break

    if not relevantPadata:
        raise Exception('No PAdata found with type 17')
    keyinfo = SignedData.load(
        relevantPadata['dhSignedData']).native['encap_content_info']
    if keyinfo['content_type'] != '1.3.6.1.5.2.3.2':
        raise Exception('Keyinfo content type unexpected value')
    authdata = KDCDHKeyInfo.load(keyinfo['content']).native
    pubkey = int(
        ''.join(['1'] + [str(x) for x in authdata['subjectPublicKey']]), 2)

    pubkey = int.from_bytes(core.BitString(
        authdata['subjectPublicKey']).dump()[7:],
                            'big',
                            signed=False)
    shared_key = diffieHellmanExchange.exchange(pubkey)

    server_nonce = relevantPadata['serverDHNonce']
    fullKey = shared_key + diffieHellmanExchange.dh_nonce + server_nonce

    etype = rep['Kerberos']['enc-part']['etype']
    cipher = _enctype_table[etype]
    if etype == Enctype.AES256:
        t_key = truncate(fullKey, 32)
    elif etype == Enctype.AES128:
        t_key = truncate(fullKey, 16)
    elif etype == Enctype.RC4:
        raise NotImplementedError(
            'RC4 key truncation documentation missing. it is different from AES'
        )

    key = Key(cipher.enctype, t_key)
    enc_data = rep['Kerberos']['enc-part']['cipher']
    dec_data = cipher.decrypt(key, 3, enc_data)
    encasrep = EncASRepPart.load(dec_data).native
    cipher = _enctype_table[int(encasrep['key']['keytype'])]
    session_key = Key(cipher.enctype, encasrep['key']['keyvalue'])

    return session_key, cipher, rep

    # remove Octet String manualy
    padata = str(rep['padata'][0]['padata-value']).encode('hex')
    parsedPadata = decode(padata.decode('hex'), asn1Spec=AS_REP_Padata())[0]
    decoded = parsedPadata['DHRepInfo']['dhSignedData']
    kdcSignedDataResponse = decode(decoded, asn1Spec=SignedData())[0]
    kdcDHKeyInfo = str(kdcSignedDataResponse['encapContentInfo']
                       ['id-pkinit-authData-value']).encode('hex')
    d = decode(kdcDHKeyInfo.decode('hex'), asn1Spec=KDCDHKeyInfo())[0]
    dcPublicKey = int(encode(d['subjectPublicKey']).encode('hex')[20:], 16)

    dcPublicNumbers = dh.DHPublicNumbers(dcPublicKey, diffieHellmanExchange[2])

    backend = default_backend()

    dcPublicKey = backend.load_dh_public_numbers(dcPublicNumbers)
    shared_key = diffieHellmanExchange[1].exchange(dcPublicKey)
    sharedHexKey = shared_key.encode('hex')

    clientDHNonce = '6B328FA66EEBDFD3D69ED34E5007776AB30832A2ED1DCB1699781BFE0BEDF87A'
    serverDHNonce = encode(
        parsedPadata['DHRepInfo']['encKeyPack']).encode('hex')[8:]

    fullKey = sharedHexKey + clientDHNonce + serverDHNonce

    etype = rep['enc-part']['etype']
    cipher = _enctype_table[etype]
    if etype == Enctype.AES256:
        truncateKey = truncate(fullKey, 32)
        key = Key(cipher.enctype, truncateKey)

    elif etype == Enctype.AES128:
        truncateKey = truncate(fullKey, 16)
        key = Key(cipher.enctype, truncateKey)

    elif etype == Enctype.RC4:
        truncateKey = truncate(fullKey, 16)
        key = Key(cipher.enctype, truncateKey)

    cipherText = rep['enc-part']['cipher'].asOctets()
    plainText = cipher.decrypt(key, 3, cipherText)
    encASRepPart = decode(plainText, asn1Spec=EncASRepPart())[0]
    cipher = _enctype_table[int(encASRepPart['key']['keytype'])]
    session_key = Key(cipher.enctype,
                      encASRepPart['key']['keyvalue'].asOctets())
    return session_key, cipher, rep