nexmon – Rev 1
?pathlinks?
/*
* coWPAtty - Brute-force dictionary attack against WPA-PSK.
*
* Copyright (c) 2004-2009, Joshua Wright <jwright@hasborg.com>
*
* $Id: cowpatty.c 264 2009-07-03 15:15:50Z jwright $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING for more
* details.
*
* coWPAtty is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* Significant code is graciously taken from the following:
* wpa_supplicant by Jouni Malinen. This tool would have been MUCH more
* difficult for me if not for this code. Thanks Jouni.
*/
/*
* Right off the bat, this code isn't very useful. The PBKDF2 function makes
* 4096 SHA-1 passes for each passphrase, which takes quite a bit of time. On
* my Pentium II development system, I'm getting ~2.5 passphrases/second.
* I've done my best to optimize the PBKDF2 function, but it's still pretty
* slow.
*/
#define PROGNAME "cowpatty"
#define VER "4.6"
#define MAXPASSPHRASE 256
#define DOT1X_LLCTYPE "\x88\x8e"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pcap.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include "cowpatty.h"
#include "common.h"
#include "utils.h"
#include "sha1.h"
#include "md5.h"
#include "radiotap.h"
/* Globals */
pcap_t *p = NULL;
unsigned char *packet;
struct pcap_pkthdr *h;
char errbuf[PCAP_ERRBUF_SIZE];
int sig = 0; /* Used for handling signals */
char *words;
/* temporary storage for the password from the hash record, instead of
malloc/free for each entry. */
char password_buf[65];
unsigned long wordstested = 0;
/* Prototypes */
void wpa_pmk_to_ptk(u8 * pmk, u8 * addr1, u8 * addr2,
u8 * nonce1, u8 * nonce2, u8 * ptk, size_t ptk_len);
void hexdump(unsigned char *data, int len);
void usage(char *message);
void testopts(struct user_opt *opt);
void cleanup();
void parseopts(struct user_opt *opt, int argc, char **argv);
void closepcap(struct capture_data *capdata);
void handle_dot1x(struct crack_data *cdata, struct capture_data *capdata,
struct user_opt *opt);
void dump_all_fields(struct crack_data cdata, struct user_opt *opt);
void printstats(struct timeval start, struct timeval end,
unsigned long int wordcount);
int nextdictword(char *word, FILE * fp);
int nexthashrec(FILE * fp, struct hashdb_rec *rec);
void usage(char *message)
{
if (strlen(message) > 0) {
printf("%s: %s\n", PROGNAME, message);
}
printf("\nUsage: %s [options]\n", PROGNAME);
printf("\n"
"\t-f \tDictionary file\n"
"\t-d \tHash file (genpmk)\n"
"\t-r \tPacket capture file\n"
"\t-s \tNetwork SSID (enclose in quotes if SSID includes spaces)\n"
"\t-2 \tUse frames 1 and 2 or 2 and 3 for key attack (nonstrict mode)\n"
"\t-c \tCheck for valid 4-way frames, does not crack\n"
"\t-h \tPrint this help information and exit\n"
"\t-v \tPrint verbose information (more -v for more verbosity)\n"
"\t-V \tPrint program version and exit\n" "\n");
}
void cleanup()
{
/* lame-o-meter++ */
sig = 1;
}
void wpa_pmk_to_ptk(u8 * pmk, u8 * addr1, u8 * addr2,
u8 * nonce1, u8 * nonce2, u8 * ptk, size_t ptk_len)
{
u8 data[2 * ETH_ALEN + 2 * 32];
memset(&data, 0, sizeof(data));
/* PTK = PRF-X(PMK, "Pairwise key expansion",
* Min(AA, SA) || Max(AA, SA) ||
* Min(ANonce, SNonce) || Max(ANonce, SNonce)) */
if (memcmp(addr1, addr2, ETH_ALEN) < 0) {
memcpy(data, addr1, ETH_ALEN);
memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
} else {
memcpy(data, addr2, ETH_ALEN);
memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
}
if (memcmp(nonce1, nonce2, 32) < 0) {
memcpy(data + 2 * ETH_ALEN, nonce1, 32);
memcpy(data + 2 * ETH_ALEN + 32, nonce2, 32);
} else {
memcpy(data + 2 * ETH_ALEN, nonce2, 32);
memcpy(data + 2 * ETH_ALEN + 32, nonce1, 32);
}
sha1_prf(pmk, 32, "Pairwise key expansion", data, sizeof(data),
ptk, ptk_len);
}
void hexdump(unsigned char *data, int len)
{
int i;
for (i = 0; i < len; i++) {
printf("%02x ", data[i]);
}
}
void parseopts(struct user_opt *opt, int argc, char **argv)
{
int c;
while ((c = getopt(argc, argv, "f:r:s:d:c2nhvV")) != EOF) {
switch (c) {
case 'f':
strncpy(opt->dictfile, optarg, sizeof(opt->dictfile));
break;
case 'r':
strncpy(opt->pcapfile, optarg, sizeof(opt->pcapfile));
break;
case 's':
strncpy(opt->ssid, optarg, sizeof(opt->ssid));
break;
case 'd':
strncpy(opt->hashfile, optarg, sizeof(opt->hashfile));
break;
case 'n':
case '2':
opt->nonstrict++;
break;
case 'c':
opt->checkonly++;
break;
case 'h':
usage("");
exit(0);
break;
case 'v':
opt->verbose++;
break;
case 'V':
printf
("$Id: cowpatty.c 264 2009-07-03 15:15:50Z jwright $\n");
exit(0);
break;
default:
usage("");
exit(-1);
}
}
}
void testopts(struct user_opt *opt)
{
struct stat teststat;
/* Test for a pcap file */
if (IsBlank(opt->pcapfile)) {
usage("Must supply a pcap file with -r");
exit(-1);
}
if (opt->checkonly == 1) {
/* Special case where we only need pcap file */
return;
}
/* test for required parameters */
if (IsBlank(opt->dictfile) && IsBlank(opt->hashfile)) {
usage("Must supply a list of passphrases in a file with -f "
"or a hash file\n\t with -d. "
"Use \"-f -\" to accept words on stdin.");
exit(-1);
}
if (IsBlank(opt->ssid)) {
usage("Must supply the SSID for the network with -s");
exit(-1);
}
/* Test that the files specified exist and are greater than 0 bytes */
if (!IsBlank(opt->hashfile) && strncmp(opt->hashfile, "-", 1) != 0) {
if (stat(opt->hashfile, &teststat)) {
usage("Could not stat hashfile. Check file path.");
exit(-1);
} else if (teststat.st_size == 0) {
usage("Empty hashfile (0 bytes). Check file contents.");
exit(-1);
}
}
if (!IsBlank(opt->dictfile) && strncmp(opt->dictfile, "-", 1) != 0) {
if (stat(opt->dictfile, &teststat)) {
usage
("Could not stat the dictionary file. Check file path.");
exit(-1);
} else if (teststat.st_size == 0) {
usage
("Empty dictionary file (0 bytes). Check file contents.");
exit(-1);
}
}
if (stat(opt->pcapfile, &teststat) && strncmp(opt->hashfile, "-", 1) != 0) {
usage("Could not stat the pcap file. Check file path.");
exit(-1);
} else if (teststat.st_size == 0) {
usage("Empty pcap file (0 bytes). Check file contents.");
exit(-1);
}
}
int openpcap(struct capture_data *capdata)
{
/* Assume for now it's a libpcap file */
p = pcap_open_offline(capdata->pcapfilename, errbuf);
if (p == NULL) {
perror("Unable to open capture file");
return (-1);
}
/* Determine link type */
capdata->pcaptype = pcap_datalink(p);
/* Determine offset to EAP frame based on link type */
switch (capdata->pcaptype) {
case DLT_NULL:
case DLT_EN10MB:
case DLT_IEEE802_11:
case DLT_PRISM_HEADER:
case DLT_IEEE802_11_RADIO:
break;
default:
/* Unknown/unsupported pcap type */
return (1);
}
return (0);
}
void closepcap(struct capture_data *capdata)
{
/* Assume it's a libpcap file for now */
pcap_close(p);
}
/* Populates global *packet, returns status */
int getpacket(struct capture_data *capdata)
{
/* Assume it's a libpcap file for now */
int ret;
struct ieee80211_radiotap_header *rtaphdr;
int rtaphdrlen=0;
struct dot11hdr *dot11 = NULL;
/* Loop on pcap_next_ex until we get a packet we want, return from
* this while loop. This is kinda hack.
*/
while ((ret = pcap_next_ex(p, &h, (const u_char **)&packet))
&& ret > 0) {
/* Determine offset to EAP frame based on link type */
switch (capdata->pcaptype) {
case DLT_NULL:
case DLT_EN10MB:
/* Standard ethernet header */
capdata->dot1x_offset = 14;
capdata->l2type_offset = 12;
capdata->dstmac_offset = 0;
capdata->srcmac_offset = 6;
return(ret);
break;
case DLT_IEEE802_11:
/* If this is not a data packet, get the next frame */
dot11 = (struct dot11hdr *)packet;
if (dot11->u1.fc.type != DOT11_FC_TYPE_DATA) {
continue;
}
capdata->dstmac_offset = 4;
capdata->srcmac_offset = 10;
/* differentiate QoS data and non-QoS data frames */
if (dot11->u1.fc.subtype == DOT11_FC_SUBTYPE_QOSDATA) {
/* 26 bytes 802.11 header, 8 for 802.2 header */
capdata->dot1x_offset = 34;
capdata->l2type_offset = 32;
} else if (dot11->u1.fc.subtype == DOT11_FC_SUBTYPE_DATA) {
/* 24 bytes 802.11 header, 8 for 802.2 header */
capdata->dot1x_offset = 32;
capdata->l2type_offset = 30;
} else {
/* Not a data frame we support */
continue;
}
return(ret);
break;
case DLT_PRISM_HEADER:
/* 802.11 frames with AVS header, AVS header is 144
* bytes */
/* If this is not a data packet, get the next frame */
dot11 = ((struct dot11hdr *)(packet+144));
if (dot11->u1.fc.type != DOT11_FC_TYPE_DATA) {
continue;
}
capdata->dstmac_offset = 4 + 144;
capdata->srcmac_offset = 10 + 144;
/* differentiate QoS data and non-QoS data frames */
if (dot11->u1.fc.subtype == DOT11_FC_SUBTYPE_QOSDATA) {
capdata->dot1x_offset = 34 + 144;
capdata->l2type_offset = 32 + 144;
} else if (dot11->u1.fc.subtype == DOT11_FC_SUBTYPE_DATA) {
capdata->dot1x_offset = 32 + 144;
capdata->l2type_offset = 30 + 144;
} else {
/* Not a data frame we support */
continue;
}
return(ret);
break;
case DLT_IEEE802_11_RADIO:
/* Radiotap header, need to calculate offset to payload
on a per-packet basis.
*/
rtaphdr = (struct ieee80211_radiotap_header *)packet;
/* rtap is LE */
rtaphdrlen = le16_to_cpu(rtaphdr->it_len);
/* Sanity check on header length, 10 bytes is min
802.11 len */
if (rtaphdrlen > (h->len - 10)) {
return -2; /* Bad radiotap data */
}
capdata->dstmac_offset = 4 + rtaphdrlen;
capdata->srcmac_offset = 10 + rtaphdrlen;
dot11 = ((struct dot11hdr *)(packet+rtaphdrlen));
/* differentiate QoS data and non-QoS data frames */
if (dot11->u1.fc.subtype == DOT11_FC_SUBTYPE_QOSDATA) {
capdata->dot1x_offset = 34 + rtaphdrlen;
capdata->l2type_offset = 32 + rtaphdrlen;
} else if (dot11->u1.fc.subtype ==
DOT11_FC_SUBTYPE_DATA) {
capdata->dot1x_offset = 32 + rtaphdrlen;
capdata->l2type_offset = 30 + rtaphdrlen;
} else {
/* Not a data frame we support */
continue;
}
return(ret);
break;
default:
/* Unknown/unsupported pcap type */
return (1);
}
}
return (ret);
}
void handle_dot1x(struct crack_data *cdata, struct capture_data *capdata,
struct user_opt *opt)
{
struct ieee8021x *dot1xhdr;
struct wpa_eapol_key *eapolkeyhdr;
int eapolkeyoffset;
int key_info, index;
/* We're going after the last three frames in the 4-way handshake.
In the last frame of the TKIP exchange, the authenticator nonce is
omitted. In cases where there is a unicast and a multicast key
distributed, frame 4 will include the authenticator nonce. In some
cases however, there is no multicast key distribution, so frame 4 has
no authenticator nonce. For this reason, we need to capture information
from the 2nd, 3rd and 4th frames to accommodate cases where there is no
multicast key delivery. Suckage.
*/
dot1xhdr = (struct ieee8021x *)&packet[capdata->dot1x_offset];
eapolkeyoffset = capdata->dot1x_offset + sizeof(struct ieee8021x);
eapolkeyhdr = (struct wpa_eapol_key *)&packet[eapolkeyoffset];
/* Bitwise fields in the key_info field of the EAPOL-Key header */
key_info = be_to_host16(eapolkeyhdr->key_info);
cdata->ver = key_info & WPA_KEY_INFO_TYPE_MASK;
index = key_info & WPA_KEY_INFO_KEY_INDEX_MASK;
if (opt->nonstrict == 0) {
/* Check for EAPOL version 1, type EAPOL-Key */
if (dot1xhdr->version != 1 || dot1xhdr->type != 3) {
return;
}
} else {
/* Check for type EAPOL-Key */
if (dot1xhdr->type != 3) {
return;
}
}
if (cdata->ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
cdata->ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
return;
}
if (cdata->ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
/* Check for WPA key, and pairwise key type */
if (eapolkeyhdr->type != 254 ||
(key_info & WPA_KEY_INFO_KEY_TYPE) == 0) {
return;
}
} else if (cdata->ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (eapolkeyhdr->type != 2 ||
(key_info & WPA_KEY_INFO_KEY_TYPE) == 0) {
return;
}
}
if (opt->nonstrict == 0) {
/* Check for frame 2 of the 4-way handshake */
if ((key_info & WPA_KEY_INFO_MIC)
&& (key_info & WPA_KEY_INFO_ACK) == 0
&& (key_info & WPA_KEY_INFO_INSTALL) == 0
&& eapolkeyhdr->key_data_length > 0) {
/* All we need from this frame is the authenticator nonce */
memcpy(cdata->snonce, eapolkeyhdr->key_nonce,
sizeof(cdata->snonce));
cdata->snonceset = 1;
/* Check for frame 3 of the 4-way handshake */
} else if ((key_info & WPA_KEY_INFO_MIC)
&& (key_info & WPA_KEY_INFO_INSTALL)
&& (key_info & WPA_KEY_INFO_ACK)) {
memcpy(cdata->spa, &packet[capdata->dstmac_offset],
sizeof(cdata->spa));
memcpy(cdata->aa, &packet[capdata->srcmac_offset],
sizeof(cdata->aa));
memcpy(cdata->anonce, eapolkeyhdr->key_nonce,
sizeof(cdata->anonce));
cdata->aaset = 1;
cdata->spaset = 1;
cdata->anonceset = 1;
/* We save the replay counter value in the 3rd frame to match
against the 4th frame of the four-way handshake */
memcpy(cdata->replay_counter,
eapolkeyhdr->replay_counter, 8);
/* Check for frame 4 of the four-way handshake */
} else if ((key_info & WPA_KEY_INFO_MIC)
&& (key_info & WPA_KEY_INFO_ACK) == 0
&& (key_info & WPA_KEY_INFO_INSTALL) == 0
&& (memcmp (cdata->replay_counter,
eapolkeyhdr->replay_counter, 8) == 0)) {
memcpy(cdata->keymic, eapolkeyhdr->key_mic,
sizeof(cdata->keymic));
memcpy(cdata->eapolframe, &packet[capdata->dot1x_offset],
sizeof(cdata->eapolframe));
cdata->keymicset = 1;
cdata->eapolframeset = 1;
}
} else {
/* Check for frame 1 of the 4-way handshake */
if ((key_info & WPA_KEY_INFO_MIC) == 0
&& (key_info & WPA_KEY_INFO_ACK)
&& (key_info & WPA_KEY_INFO_INSTALL) == 0 ) {
/* All we need from this frame is the authenticator nonce */
memcpy(cdata->anonce, eapolkeyhdr->key_nonce,
sizeof(cdata->anonce));
cdata->anonceset = 1;
/* Check for frame 2 of the 4-way handshake */
} else if ((key_info & WPA_KEY_INFO_MIC)
&& (key_info & WPA_KEY_INFO_INSTALL) == 0
&& (key_info & WPA_KEY_INFO_ACK) == 0
&& eapolkeyhdr->key_data_length > 0) {
cdata->eapolframe_size = ( packet[capdata->dot1x_offset + 2] << 8 )
+ packet[capdata->dot1x_offset + 3] + 4;
memcpy(cdata->spa, &packet[capdata->dstmac_offset],
sizeof(cdata->spa));
cdata->spaset = 1;
memcpy(cdata->aa, &packet[capdata->srcmac_offset],
sizeof(cdata->aa));
cdata->aaset = 1;
memcpy(cdata->snonce, eapolkeyhdr->key_nonce,
sizeof(cdata->snonce));
cdata->snonceset = 1;
memcpy(cdata->keymic, eapolkeyhdr->key_mic,
sizeof(cdata->keymic));
cdata->keymicset = 1;
memcpy(cdata->eapolframe, &packet[capdata->dot1x_offset],
cdata->eapolframe_size);
cdata->eapolframeset = 1;
/* Check for frame 3 of the 4-way handshake */
} else if ((key_info & WPA_KEY_INFO_MIC)
&& (key_info & WPA_KEY_INFO_ACK)
&& (key_info & WPA_KEY_INFO_INSTALL)) {
/* All we need from this frame is the authenticator nonce */
memcpy(cdata->anonce, eapolkeyhdr->key_nonce,
sizeof(cdata->anonce));
cdata->anonceset = 1;
}
}
}
void dump_all_fields(struct crack_data cdata, struct user_opt *opt)
{
printf("AA is:");
lamont_hdump(cdata.aa, 6);
printf("\n");
printf("SPA is:");
lamont_hdump(cdata.spa, 6);
printf("\n");
printf("snonce is:");
lamont_hdump(cdata.snonce, 32);
printf("\n");
printf("anonce is:");
lamont_hdump(cdata.anonce, 32);
printf("\n");
printf("keymic is:");
lamont_hdump(cdata.keymic, 16);
printf("\n");
printf("eapolframe is:");
if (opt->nonstrict == 0) {
lamont_hdump(cdata.eapolframe, 99);
} else {
lamont_hdump(cdata.eapolframe, 125);
}
printf("\n");
}
void printstats(struct timeval start, struct timeval end,
unsigned long int wordcount)
{
float elapsed = 0;
if (end.tv_usec < start.tv_usec) {
end.tv_sec -= 1;
end.tv_usec += 1000000;
}
end.tv_sec -= start.tv_sec;
end.tv_usec -= start.tv_usec;
elapsed = end.tv_sec + end.tv_usec / 1000000.0;
printf("\n%lu passphrases tested in %.2f seconds: %.2f passphrases/"
"second\n", wordcount, elapsed, wordcount / elapsed);
}
int nexthashrec(FILE * fp, struct hashdb_rec *rec)
{
int recordlength, wordlen;
if (fread(&rec->rec_size, sizeof(rec->rec_size), 1, fp) != 1) {
perror("fread");
return -1;
}
recordlength = abs(rec->rec_size);
wordlen = recordlength - (sizeof(rec->pmk) + sizeof(rec->rec_size));
if (wordlen > 63 || wordlen < 8) {
fprintf(stderr, "Invalid word length: %d\n", wordlen);
return -1;
}
/* hackity, hack, hack, hack */
rec->word = password_buf;
if (fread(rec->word, wordlen, 1, fp) != 1) {
perror("fread");
return -1;
}
if (fread(rec->pmk, sizeof(rec->pmk), 1, fp) != 1) {
perror("fread");
return -1;
}
return recordlength;
}
int nextdictword(char *word, FILE * fp)
{
if (fgets(word, MAXPASSLEN + 1, fp) == NULL) {
return (-1);
}
/* Remove newline */
word[strlen(word) - 1] = '\0';
if (feof(fp)) {
return (-1);
}
return (strlen(word));
}
void hmac_hash(int ver, u8 *key, int hashlen, u8 *buf, int buflen, u8 *mic)
{
u8 hash[SHA1_MAC_LEN];
if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
hmac_md5(key, hashlen, buf, buflen, mic);
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
hmac_sha1(key, hashlen, buf, buflen, hash, NOCACHED);
memcpy(mic, hash, MD5_DIGEST_LENGTH); /* only 16 bytes, not 20 */
}
}
int hashfile_attack(struct user_opt *opt, char *passphrase,
struct crack_data *cdata)
{
FILE *fp;
int reclen, wordlen;
u8 pmk[32];
u8 ptk[64];
u8 keymic[16];
struct wpa_ptk *ptkset;
struct hashdb_rec rec;
struct hashdb_head hf_head;
char headerssid[33];
/* Open the hash file */
if (*opt->hashfile == '-') {
printf("Using STDIN for hashfile contents.\n");
fp = stdin;
} else {
fp = fopen(opt->hashfile, "rb");
if (fp == NULL) {
perror("fopen");
return(-1);
}
}
/* Read the record header contents */
if (fread(&hf_head, sizeof(hf_head), 1, fp) != 1) {
perror("fread");
return(-1);
}
/* Ensure selected SSID matches what's stored in the header record */
if (memcmp(hf_head.ssid, opt->ssid, hf_head.ssidlen) != 0) {
memcpy(&headerssid, hf_head.ssid, hf_head.ssidlen);
headerssid[hf_head.ssidlen] = 0; /* NULL terminate string */
fprintf(stderr, "\nSSID in hashfile (\"%s\") does not match "
"SSID specified on the \n"
"command line (\"%s\"). You cannot "
"mix and match SSID's for this\nattack.\n\n",
headerssid, opt->ssid);
return(-1);
}
while (feof(fp) == 0 && sig == 0) {
/* Populate the hashdb_rec with the next record */
reclen = nexthashrec(fp, &rec);
/* nexthashrec returns the length of the record, test to ensure
passphrase is greater than 8 characters */
wordlen = rec.rec_size -
(sizeof(rec.pmk) + sizeof(rec.rec_size));
if (wordlen < 8) {
printf("Found a record that was too short, this "
"shouldn't happen in practice!\n");
return(-1);
}
/* Populate passphrase with the record contents */
memcpy(passphrase, rec.word, wordlen);
/* NULL terminate passphrase string */
passphrase[wordlen] = 0;
if (opt->verbose > 1) {
printf("Testing passphrase: %s\n", passphrase);
}
/* Increment the words tested counter */
wordstested++;
/* Status display */
if ((wordstested % 10000) == 0) {
printf("key no. %ld: %s\n", wordstested, passphrase);
fflush(stdout);
}
if (opt->verbose > 1) {
printf("Calculating PTK for \"%s\".\n", passphrase);
}
if (opt->verbose > 2) {
printf("PMK is");
lamont_hdump(pmk, sizeof(pmk));
}
if (opt->verbose > 1) {
printf("Calculating PTK with collected data and "
"PMK.\n");
}
wpa_pmk_to_ptk(rec.pmk, cdata->aa, cdata->spa, cdata->anonce,
cdata->snonce, ptk, sizeof(ptk));
if (opt->verbose > 2) {
printf("Calculated PTK for \"%s\" is", passphrase);
lamont_hdump(ptk, sizeof(ptk));
}
ptkset = (struct wpa_ptk *)ptk;
if (opt->verbose > 1) {
printf("Calculating hmac-MD5 Key MIC for this "
"frame.\n");
}
if (opt->nonstrict == 0) {
hmac_hash(cdata->ver, ptkset->mic_key, 16, cdata->eapolframe,
sizeof(cdata->eapolframe), keymic);
} else {
hmac_hash(cdata->ver, ptkset->mic_key, 16, cdata->eapolframe,
cdata->eapolframe_size, keymic);
}
if (opt->verbose > 2) {
printf("Calculated MIC with \"%s\" is", passphrase);
lamont_hdump(keymic, sizeof(keymic));
}
if (memcmp(&cdata->keymic, &keymic, sizeof(keymic)) == 0) {
return 0;
} else {
continue;
}
}
return 1;
}
int dictfile_attack(struct user_opt *opt, char *passphrase,
struct crack_data *cdata)
{
FILE *fp;
int fret;
u8 pmk[32];
u8 ptk[64];
u8 keymic[16];
struct wpa_ptk *ptkset;
/* Open the dictionary file */
if (*opt->dictfile == '-') {
printf("Using STDIN for words.\n");
fp = stdin;
} else {
fp = fopen(opt->dictfile, "r");
if (fp == NULL) {
perror("fopen");
exit(-1);
}
}
while (feof(fp) == 0 && sig == 0) {
/* Populate "passphrase" with the next word */
fret = nextdictword(passphrase, fp);
if (fret < 0) {
break;
}
if (opt->verbose > 1) {
printf("Testing passphrase: %s\n", passphrase);
}
/*
* Test length of word. IEEE 802.11i indicates the passphrase
* must be at least 8 characters in length, and no more than 63
* characters in length.
*/
if (fret < 8 || fret > 63) {
if (opt->verbose) {
printf("Invalid passphrase length: %s (%u).\n",
passphrase, strlen(passphrase));
}
continue;
} else {
/* This word is good, increment the words tested
counter */
wordstested++;
}
/* Status display */
if ((wordstested % 1000) == 0) {
printf("key no. %ld: %s\n", wordstested, passphrase);
fflush(stdout);
}
if (opt->verbose > 1) {
printf("Calculating PMK for \"%s\".\n", passphrase);
}
pbkdf2_sha1(passphrase, opt->ssid, strlen(opt->ssid), 4096,
pmk, sizeof(pmk), USECACHED);
if (opt->verbose > 2) {
printf("PMK is");
lamont_hdump(pmk, sizeof(pmk));
}
if (opt->verbose > 1) {
printf("Calculating PTK with collected data and "
"PMK.\n");
}
wpa_pmk_to_ptk(pmk, cdata->aa, cdata->spa, cdata->anonce,
cdata->snonce, ptk, sizeof(ptk));
if (opt->verbose > 2) {
printf("Calculated PTK for \"%s\" is", passphrase);
lamont_hdump(ptk, sizeof(ptk));
}
ptkset = (struct wpa_ptk *)ptk;
if (opt->verbose > 1) {
printf("Calculating hmac-MD5 Key MIC for this "
"frame.\n");
}
if (opt->nonstrict == 0) {
hmac_hash(cdata->ver, ptkset->mic_key, 16, cdata->eapolframe,
sizeof(cdata->eapolframe), keymic);
} else {
hmac_hash(cdata->ver, ptkset->mic_key, 16, cdata->eapolframe,
cdata->eapolframe_size, keymic);
}
if (opt->verbose > 2) {
printf("Calculated MIC with \"%s\" is", passphrase);
lamont_hdump(keymic, sizeof(keymic));
}
if (memcmp(&cdata->keymic, &keymic, sizeof(keymic)) == 0) {
return 0;
} else {
continue;
}
}
return 1;
}
int main(int argc, char **argv)
{
struct user_opt opt;
struct crack_data cdata;
struct capture_data capdata;
struct wpa_eapol_key *eapkeypacket;
u8 eapolkey_nomic[99];
struct timeval start, end;
int ret;
char passphrase[MAXPASSLEN + 1];
printf("%s %s - WPA-PSK dictionary attack. <jwright@hasborg.com>\n",
PROGNAME, VER);
memset(&opt, 0, sizeof(struct user_opt));
memset(&capdata, 0, sizeof(struct capture_data));
memset(&cdata, 0, sizeof(struct crack_data));
memset(&eapolkey_nomic, 0, sizeof(eapolkey_nomic));
/* Collect and test command-line arguments */
parseopts(&opt, argc, argv);
testopts(&opt);
printf("\n");
/* Populate capdata struct */
strncpy(capdata.pcapfilename, opt.pcapfile,
sizeof(capdata.pcapfilename));
if (openpcap(&capdata) != 0) {
printf("Unsupported or unrecognized pcap file.\n");
exit(-1);
}
/* populates global *packet */
while (getpacket(&capdata) > 0) {
if (opt.verbose > 2) {
lamont_hdump(packet, h->len);
}
/* test packet for data that we are looking for */
if (memcmp(&packet[capdata.l2type_offset], DOT1X_LLCTYPE, 2) ==
0 && (h->len >
capdata.l2type_offset + sizeof(struct wpa_eapol_key))) {
/* It's a dot1x frame, process it */
handle_dot1x(&cdata, &capdata, &opt);
if (cdata.aaset && cdata.spaset && cdata.snonceset &&
cdata.anonceset && cdata.keymicset
&& cdata.eapolframeset) {
/* We've collected everything we need. */
break;
}
}
}
closepcap(&capdata);
if (!(cdata.aaset && cdata.spaset && cdata.snonceset &&
cdata.anonceset && cdata.keymicset && cdata.eapolframeset)) {
printf("End of pcap capture file, incomplete four-way handshake "
"exchange. Try using a\ndifferent capture.\n");
exit(-1);
} else {
if (cdata.ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
printf("Collected all necessary data to mount crack"
" against WPA2/PSK passphrase.\n");
} else if (cdata.ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
printf("Collected all necessary data to mount crack"
" against WPA/PSK passphrase.\n");
}
}
if (opt.verbose > 1) {
dump_all_fields(cdata, &opt);
}
if (opt.checkonly) {
/* Don't attack the PSK, just return non-error return code */
return 0;
}
/* Zero mic and length data for hmac-md5 calculation */
eapkeypacket =
(struct wpa_eapol_key *)&cdata.eapolframe[EAPDOT1XOFFSET];
memset(&eapkeypacket->key_mic, 0, sizeof(eapkeypacket->key_mic));
if (opt.nonstrict == 0) {
eapkeypacket->key_data_length = 0;
}
printf("Starting dictionary attack. Please be patient.\n");
fflush(stdout);
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
signal(SIGQUIT, cleanup);
gettimeofday(&start, 0);
if (!IsBlank(opt.hashfile)) {
ret = hashfile_attack(&opt, passphrase, &cdata);
} else if (!IsBlank(opt.dictfile)) {
ret = dictfile_attack(&opt, passphrase, &cdata);
} else {
usage("Must specify dictfile or hashfile (-f or -d)");
exit(-1);
}
if (ret == 0) {
printf("\nThe PSK is \"%s\".\n", passphrase);
gettimeofday(&end, 0);
printstats(start, end, wordstested);
return 0;
} else {
printf("Unable to identify the PSK from the dictionary file. "
"Try expanding your\npassphrase list, and double-check"
" the SSID. Sorry it didn't work out.\n");
gettimeofday(&end, 0);
printstats(start, end, wordstested);
return 1;
}
return 1;
}