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