Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [day] [month] [year] [list]
Date: Tue, 29 Jan 2013 12:34:37 -0600
From: "jfoug" <jfoug@....net>
To: "'Dhiru Kholia'" <dhiru.kholia@...il.com>,
	<john-dev@...ts.openwall.com>
Subject: RE: [john-users] can't get jtr to ID this

Here is the C code. This 'should' work.  I would have rather kept it in c++,
but I can live with this.

Also, like I said, this is NOT really prime time ready.  Yes, I have gotten
this to work, but I am not 100% sure it is right for all cases. There may be
cases where there is a valid handshake, that can be converted into a JtR
hash, but this program fails to find it.  I believe that this would be the
case for a msg1/4 and msg3/4 pair.  But in that case, I am not fully sure if
I can make the eapol object.  Currently, the eapol object is the
Authentication object of the msg2 (in original format, i.e. no swapping),
and with the MIC zero'd out.   To recreated that with a 1/4 or 3/4 pair, I
would need to figure out what to do.  What I need to do, is to capture some
FULL 4 packet 4way handshakes.  That way, I can see just what is in the 4
packet, compared to the 2 packet.

At this time, I get the SSID from the beacon, the MAC's from the msg1/2 or
msg2/3 packets nonc2 from packet 1 or 3 (they are the same).  All other data
comes from packet 2.

Here are the issues that I am aware of:

1. It may not be able to use all 'valid' handshakes.  We do handle 1/2 and
2/3 if they are matched.  NOTE, the timestamp should also be used when
making a match (it currently is not). this should not IRL be that big of an
issue.

2. it should be made smarter, take the last handshake in the file (the cap
file may be built over days, weeks or months).

3. the current program will simply output all valid 4way parts, even if they
are multiples and the same.

4. it should handle pcap files, and iv files, and tigershark files (or
others).

5. it does swapping 'smartly' of the pcap header. However, it is NOT doing
smart swapping of the Authentication packet.  The smart swapping, in the
pcap is based upon the magic.  If the magic is 0xD4C3B2A1, then the header
needs to be swapped.  It does not matter if your computer is BE or LE.  It
simply shows that the capture session was obtained from a machine that had
different endianity than the machine we are now running on.  The swapping
that happens when processing the Authentication packet (around line 180),
should be done ONLY on LE systems, since the data is in BE format.

6. it should probably be able to handle *.cap  Right now, it only handles
one.

7. it needs a lot more testing, (probably does not work right), when there
are multiple clients connected to an AP, and they are all handshaking.

8. it should have code added to auto-detect a client that does not have the
proper password. This is seen by multiple 1/2.  There is NO way to determine
whether a client has the right password or not, other than to heuristically
watch the communications.   If there are a battery of msg1/msg2, with no
msg3/4 in there, between a client and AP, and then the AP deauths later,
then it is very likely that the client does not have the proper password,
and thus ALL 4-ways seen during that session should be ignored.  This would
be seen at run time from this tool, by quite a few of the 1/2 types in a
row.  That is IF airdump-ng continues to capture the 4ways after it things
it has one of them.

Jim.

-----Original Message-----
From: Dhiru Kholia [mailto:dhiru.kholia@...il.com] 
Sent: Tuesday, January 29, 2013 9:44
To: jfoug@....net
Subject: Re: [john-users] can't get jtr to ID this

On Tue, Jan 29, 2013 at 8:28 PM,  <jfoug@....net> wrote:
> ---- Dhiru Kholia <dhiru.kholia@...il.com> wrote:
>> :-(. I wrote a similar patch few days back.
>
> I believe your code also has bugs when building the hash file, building
invalid hashes. It appears you cut the code (along with bugs) from aircrack.
I will get some cap file built that displays this problem.

I did not write it. I just patched an existing program.

> Ok, I have include 2 .cap files. They are from the same session. The
DeJong-1.cap is filtered to contain the beacon, and all eapol packets.  The
'correct' 4way, is the msg2/msg3 pair.  The DeJong-1a.cap is the beacon, and
just the msg2/msg3 pair, all other eapol have been removed.

I have added these files to the wiki
(http://openwall.info/wiki/john/sample-non-hashes).

> I have included the source I have written.  NOTE, it may not have 'all'
ways of producing a correct hash.  But so far, all situations I have thrown
at it HAVE found valid results.

Awesome! I have done a quick port to C and committed it to bleeding-jumbo.
It will receive more testing this way (including from me). Can you please
check if I have made any mistakes in porting stuff?

--
Dhiru

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "wpapcap2john.h"

int GetNextPacket(FILE *in);
int ProcessPacket();
void HandleBeacon();
void Handle4Way(int bIsQOS);
void DumpKey(int idx, int one_three, int bIsQOS);

uint32 start_t, start_u, cur_t, cur_u;
pcaprec_hdr_t pkt_hdr;
uint8 packet[65535];
static int bROT;
WPA4way_t wpa[1000];
int nwpa=0;
char itoa64[65] = 	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

int Process(FILE *in, const char *InFName) {
	pcap_hdr_t main_hdr;
	if (fread(&main_hdr, 1, sizeof(pcap_hdr_t), in) != sizeof(pcap_hdr_t)) {
		fprintf(stderr, "Error, could not read enough bytes to get a common 'main' pcap header\n");
		return 0;
	}
	if (main_hdr.magic_number ==  0xa1b2c3d4) bROT = 0;
	else if (main_hdr.magic_number ==  0xd4c3b2a1) bROT = 1;
	else { fprintf(stderr, "Error, Invalid pcap magic number, (not a pcap file!)\n");  return 0; }
	if(bROT) {
		main_hdr.magic_number = swap32u(main_hdr.magic_number);
		main_hdr.version_major = swap16u(main_hdr.version_major);
		main_hdr.version_minor = swap16u(main_hdr.version_minor);
		main_hdr.sigfigs = swap32u(main_hdr.sigfigs);
		main_hdr.snaplen = swap32u(main_hdr.snaplen);
		main_hdr.network = swap32u(main_hdr.network);
	}
	if (main_hdr.network != 105) {
		fprintf(stderr, "This program will only read 802.11 wireless traffic\n");
		return 0;
	}

	while (GetNextPacket(in)) {
		if (!ProcessPacket())
			return 1;
	}
	return 1;
}

int GetNextPacket(FILE *in) {
	if (fread(&pkt_hdr, 1, sizeof(pkt_hdr), in) != sizeof(pkt_hdr)) return 0;
	if(bROT) {
		pkt_hdr.ts_sec = swap32u(pkt_hdr.ts_sec);
		pkt_hdr.ts_usec = swap32u(pkt_hdr.ts_usec);
		pkt_hdr.incl_len = swap32u(pkt_hdr.incl_len);
		pkt_hdr.orig_len = swap32u(pkt_hdr.orig_len);
	}
	if (!start_t) {
		start_t = pkt_hdr.ts_sec;
		start_u = pkt_hdr.ts_usec;
	}
	cur_t = pkt_hdr.ts_sec-start_t;
	if (start_u > pkt_hdr.ts_usec) {
		--cur_t;
		cur_u = 1000000-(start_u-pkt_hdr.ts_usec);
	} else
		cur_u = pkt_hdr.ts_usec-start_u;

	fread(packet, 1, pkt_hdr.incl_len, in);
	return 1;
}

// Ok, this function is the main packet processor.  NOTE, when we are done
// reading packets (i.e. we have done what we want), we return 0, and
// the program will exit gracefully.  It is not an error, it is just an
// indication we have completed (or that the data we want is not here).
int ProcessPacket() {
	// our data is in packet[] with pkt_hdr being the pcap packet header for this packet.
	ether_frame_hdr_t *pkt = (ether_frame_hdr_t*)packet;
	ether_frame_ctl_t *ctl = (ether_frame_ctl_t *)&pkt->frame_ctl;

	if (ctl->type == 0 && ctl->subtype == 8) { // beacon  Type 0 is management, subtype 8 is beacon
		HandleBeacon();
		return 1;
	}
	// if not beacon, then only look data, looking for EAPOL 'type'
	if (ctl->type == 2) { // type 2 is data
		uint8 *p = packet;
		int bQOS = (ctl->subtype & 8) != 0;
		if ( (ctl->toDS ^ ctl->fromDS) != 1)// eapol will ONLY be direct toDS or direct fromDS.
			return 1;
		// Ok, find out if this is a EAPOL packet or not.

		p += sizeof(ether_frame_hdr_t);
		if (bQOS)
			p += 2;
		// p now points to the start of the LLC (logical link control) structure.
		// this is 8 bytes long, and the last 2 bytes are the 'type' field.  What
		// we are looking for is 802.11X authentication packets. These are 0x888e
		// in value.  We are running from an LE system, so should look for 0x8e88
		p += 6;
		if (*((uint16*)p) == 0x8e88)
			Handle4Way(bQOS);	// this packet was a eapol packet.
	}

	return 1;
}

void to_bssid(char ssid[18], uint8 *p) {
	sprintf(ssid, "%02X:%02X:%02X:%02X:%02X:%02X",p[0],p[1],p[2],p[3],p[4],p[5]);
}

void HandleBeacon() {
	// addr1 should be broadcast
	// addr2 is source addr (should be same as BSSID
	// addr3 is BSSID (routers MAC)
	ether_frame_hdr_t *pkt = (ether_frame_hdr_t*)packet;
	int i;

	ether_beacon_data_t *pDat = (ether_beacon_data_t*)&packet[sizeof(ether_frame_hdr_t)];
	ether_beacon_tag_t *tag = pDat->tags;
	// ok, walk the tags
	uint8 *pFinal = &packet[pkt_hdr.incl_len];
	char ssid[36];
	char essid[18];
	memset(ssid, 0, sizeof(ssid));
	while (((uint8*)tag) < pFinal) {
		char *x = (char*)tag;
		if (tag->tagtype == 0) { // essid
			memcpy(ssid, tag->tag, tag->taglen);
		}
		x += tag->taglen + 2;
		tag = (ether_beacon_tag_t *)x;
	}
	to_bssid(essid, pkt->addr3);
	for (i = 0; i < nwpa; ++i) {
		if (!strcmp(essid, wpa[i].essid) && !strcmp(ssid, wpa[i].ssid))
			return;
	}
	if (nwpa==999) return;
	strcpy(wpa[nwpa].ssid, ssid);
	strcpy(wpa[nwpa].essid, essid);
	++nwpa;
}
void Handle4Way(int bIsQOS) {
	ether_frame_hdr_t *pkt = (ether_frame_hdr_t*)packet;
	int i, ess=-1;
	uint8 orig_2[512];
	uint8 *p = (uint8*)&packet[sizeof(ether_frame_hdr_t)];
	ether_auto_802_1x_t *auth;
	int msg = 0;

	// ok, first thing, find the beacon.  If we can NOT find the beacon, then
	// do not proceed.  Also, if we find the becon, we may determine that
	// we already HAVE fully cracked this

	char essid[18];
	to_bssid(essid, pkt->addr3);
	for (i = 0; i < nwpa; ++i) {
		if (!strcmp(essid, wpa[i].essid)) {
			ess=i;
			break;
		}
	}
	if (ess==-1) return;
	if (wpa[ess].fully_cracked)
		return;  // no reason to go on.

	memcpy(orig_2, packet, pkt_hdr.orig_len);

	// Ok, after pkt,  uint16 QOS control (should be 00 00)
	if (bIsQOS)
		p += 2;
	// we are now at Logical-Link Control. (8 bytes long).
	// LLC check not needed here any more.  We do it in the packet cracker section, b4
	// calling this function.  We just need to skip the 8 byte LLC.
	//if (memcmp(p, "\xaa\xaa\x3\0\0\0\x88\x8e", 8)) return; // not a 4way
	p += 8;
	// p now points to the 802.1X Authentication structure.
	auth = (ether_auto_802_1x_t*)p;
	auth->length = swap16u(auth->length);
	*(uint16*)&(auth->key_info) = swap16u(*(uint16*)&(auth->key_info));
	auth->key_len  = swap16u(auth->key_len);
	auth->replay_cnt  = swap64u(auth->replay_cnt);
	auth->wpa_keydatlen  = swap16u(auth->wpa_keydatlen);

	if (!auth->key_info.KeyACK) {
		// msg 2 or 4
		if (auth->key_info.Secure) {
			msg = 4;
			// is this useful?
			return;
		}
		else
			msg = 2;
	} else {
		if (auth->key_info.Install)
			msg = 3;
		else
			msg = 1;
	}

	// Ok, we look for a 1 followed immediately by a 2 which have exact same replay_cnt, we have
	// a 'likely' key. Or we want a 2 followed by a 3 that are 1 replay count apart)  which means
	// we DO have a key.  The 3 is not returned unless the 2 (which came from the client), IS
	// valid. So, we get the anonce from either the 1 or the 3 packet.

	// for our first run, we output ALL valid keys found in the file. That way, I can validate that
	// any keys which were produced by aircrack-ng are 'valid' or not.  aircrack-ng WILL generate some
	// invalid keys.  Also, I want to flag "unknown" keys as just that, unk.  These are 1-2's which
	// do not have valid 3 4's.  They 'may' be valid, but may also be a client with the wrong password.

	if (msg == 1) {
		if(wpa[ess].packet1) free(wpa[ess].packet1);
		wpa[ess].packet1 = (uint8 *)malloc(sizeof(uint8) * pkt_hdr.orig_len);
		memcpy(wpa[ess].packet1, packet, pkt_hdr.orig_len);
		if (wpa[ess].packet2) free(wpa[ess].packet2);  wpa[ess].packet2 = NULL;
		if (wpa[ess].orig_2)  free(wpa[ess].orig_2);   wpa[ess].orig_2 = NULL;
		if (wpa[ess].packet3) free(wpa[ess].packet3);  wpa[ess].packet3 = NULL;
		if (wpa[ess].packet4) free(wpa[ess].packet4);  wpa[ess].packet4 = NULL;
	}
	if (msg == 2) {
		// see if we have a msg1 that 'matches'.
		if (wpa[ess].packet3) free(wpa[ess].packet3);  wpa[ess].packet3 = NULL;
		if (wpa[ess].packet4) free(wpa[ess].packet4);  wpa[ess].packet4 = NULL;
		wpa[ess].packet2 = (uint8 *)malloc(sizeof(uint8) * pkt_hdr.orig_len);
		wpa[ess].orig_2  = (uint8 *)malloc(sizeof(uint8) * pkt_hdr.orig_len);
		memcpy(wpa[ess].packet2, packet, pkt_hdr.orig_len);
		memcpy(wpa[ess].orig_2, orig_2, pkt_hdr.orig_len);
		wpa[ess].eapol_sz = pkt_hdr.orig_len-8-sizeof(ether_frame_hdr_t);
		if (bIsQOS) wpa[ess].eapol_sz -= 2;
		if (wpa[ess].packet1) {
			ether_auto_802_1x_t *auth2 = auth, *auth1;
			p = (uint8*)wpa[ess].packet1;
			if (bIsQOS)
				p += 2;
			p += 8;
			p += sizeof(ether_frame_hdr_t);
			auth1 = (ether_auto_802_1x_t*)p;
			if (auth1->replay_cnt == auth2->replay_cnt) {
				fprintf (stderr, "Key1/Key2 hit (hopful hit), for SSID:%s\n", wpa[ess].ssid);
				DumpKey(ess, 1, bIsQOS);
			}
			// we no longer want to know about this packet 1.
			if (wpa[ess].packet1) free(wpa[ess].packet1);  wpa[ess].packet1 = NULL;
		}
	}
	if (msg == 3) {
		// see if we have a msg2 that 'matches',  which is 1 less than our replay count.
		if (wpa[ess].packet1) free(wpa[ess].packet1);  wpa[ess].packet1 = NULL;
		if (wpa[ess].packet4) free(wpa[ess].packet4);  wpa[ess].packet4 = NULL;
		wpa[ess].packet3 = (uint8 *)malloc(sizeof(uint8) * pkt_hdr.orig_len);
		memcpy(wpa[ess].packet3, packet, pkt_hdr.orig_len);
		if (wpa[ess].packet2) {
			ether_auto_802_1x_t *auth3 = auth, *auth2;
			p = (uint8*)wpa[ess].packet2;
			if (bIsQOS)
				p += 2;
			p += 8;
			p += sizeof(ether_frame_hdr_t);
			auth2 = (ether_auto_802_1x_t*)p;
			if (auth2->replay_cnt+1 == auth3->replay_cnt) {
				fprintf (stderr, "Key2/Key3 hit (SURE hit), for SSID:%s\n", wpa[ess].ssid);
				DumpKey(ess, 3, bIsQOS);
			}
		}
		// clear this, so we do not hit the same 3 packet and output exact same 2/3 combo.
		if (wpa[ess].packet3) free(wpa[ess].packet3);  wpa[ess].packet3 = NULL;
		if (wpa[ess].packet2) free(wpa[ess].packet2);  wpa[ess].packet2 = NULL;
		if (wpa[ess].orig_2)  free(wpa[ess].orig_2);   wpa[ess].orig_2 = NULL;
	}
	if (msg == 4) {
		if (wpa[ess].packet1) free(wpa[ess].packet1);  wpa[ess].packet1 = NULL;
		if (wpa[ess].packet2) free(wpa[ess].packet2);  wpa[ess].packet2 = NULL;
		if (wpa[ess].orig_2)  free(wpa[ess].orig_2);   wpa[ess].orig_2 = NULL;
		if (wpa[ess].packet3) free(wpa[ess].packet3);  wpa[ess].packet3 = NULL;
		if (wpa[ess].packet4) free(wpa[ess].packet4);  wpa[ess].packet4 = NULL;
	}
}

// These 2 functions output data properly for JtR, in base-64 format. These
// were taken from hccap2john.c source, and modified for this project.
static void code_block(unsigned char *in, unsigned char b)
{
	putchar(itoa64[in[0] >> 2]);
	putchar(itoa64[((in[0] & 0x03) << 4) | (in[1] >> 4)]);
	if (b) {
		putchar(itoa64[((in[1] & 0x0f) << 2) | (in[2] >> 6)]);
		putchar(itoa64[in[2] & 0x3f]);
	} else
		putchar(itoa64[((in[1] & 0x0f) << 2)]);
}

void DumpKey(int ess, int one_three, int bIsQOS) {
	ether_auto_802_1x_t *auth13, *auth2;
	uint8 *p = (uint8*)wpa[ess].packet2;
	uint8 *pkt2 = p;
	uint8 *p13;
	hccap_t	hccap;
	int i;
	uint8 *w;
	fprintf (stderr, "Dumping key %d at time:  %d.%d\n", one_three, cur_t, cur_u);
	printf ("$WPAPSK$%s#", wpa[ess].ssid);
	if (!wpa[ess].packet2) { printf ("ERROR, msg2 null\n"); return; }
	if (bIsQOS)
		p += 2;
	p += 8;
	p += sizeof(ether_frame_hdr_t);
	auth2 = (ether_auto_802_1x_t*)p;
	if (one_three==1) {
		if (!wpa[ess].packet1) { printf ("ERROR, msg1 null\n"); return; }
		p = wpa[ess].packet1;
	} else  {
		if (!wpa[ess].packet3) { printf ("ERROR, msg3 null\n"); return; }
		p = wpa[ess].packet3;
	}
	p13 = p;
	if (bIsQOS)
		p += 2;
	p += 8;
	p += sizeof(ether_frame_hdr_t);
	auth13 = (ether_auto_802_1x_t*)p;

	memset(&hccap, 0, sizeof(hccap_t));
	hccap.keyver = auth2->key_info.KeyDescr;
	memcpy(hccap.mac1, ((ether_frame_hdr_t*)pkt2)->addr1, 6);
	memcpy(hccap.mac2, ((ether_frame_hdr_t*)(p13))->addr1, 6);
	memcpy(hccap.nonce1, auth2->wpa_nonce,32);
	memcpy(hccap.nonce2, auth13->wpa_nonce,32);
	memcpy(hccap.keymic, auth2->wpa_keymic, 16);
	p = wpa[ess].orig_2;
	if (bIsQOS)
		p += 2;
	p += 8;
	p += sizeof(ether_frame_hdr_t);
	auth2 = (ether_auto_802_1x_t*)p;
	memset(auth2->wpa_keymic, 0, 16);
	memcpy(hccap.eapol, auth2, wpa[ess].eapol_sz);
	hccap.eapol_size = wpa[ess].eapol_sz;

	w = (uint8 *)&hccap;
	for (i = 36; i + 3 < sizeof(hccap_t); i += 3)
		code_block(&w[i], 1);
	code_block(&w[i], 0);
	printf("\n");
	fprintf(stderr, "keyver=%d\n\n",hccap.keyver);
}

int main(int argc, char **argv) {
	FILE *in;
	if (argc != 2) return !!fprintf(stderr, "Usage wpacpap2john cpap_filename\n");
	in = fopen(argv[1], "rb");
	if (in) {
		Process(in, argv[1]);
		fclose(in);
	} else
		fprintf(stderr, "Error, file %s not found\n", argv[1]);
	return 0;
}

// structs and data (from wireshark, and ethernet structures)
//
//

#ifdef _MSC_VER
#define inline _inline
#endif

typedef unsigned long long uint64;
typedef   signed long long int64;
typedef unsigned int       uint32;
typedef   signed int       int32;
typedef unsigned short     uint16;
typedef   signed short     int16;
typedef unsigned char      uint8;
typedef   signed char      int8;

// All data structures MUST be byte aligned, since we work on 'raw' data in structures
// and do not load structures record by record.
#pragma pack(1)

// PCAP main file header
typedef struct pcap_hdr_s {
    uint32 magic_number;   /* magic number 0xA1B2C3D4 (or 0xD4C3B2A1 if file in BE format) */
    uint16 version_major;  /* major version number 0x0200 */
    uint16 version_minor;  /* minor version number 0x0400 */
    int32  thiszone;       /* GMT to local correction */
    uint32 sigfigs;        /* accuracy of timestamps */
    uint32 snaplen;        /* max length of captured packets, in octets */
    uint32 network;        /* data link type */
} pcap_hdr_t;
// PCAP packet header
typedef struct pcaprec_hdr_s {
    uint32 ts_sec;         /* timestamp seconds */
    uint32 ts_usec;        /* timestamp microseconds */
    uint32 incl_len;       /* number of octets of packet saved in file */
    uint32 orig_len;       /* actual length of packet */
} pcaprec_hdr_t;

// Ok, here are the struct we need to decode 802.11 for JtR
typedef struct ether_frame_hdr_s {
	uint16 frame_ctl;
	uint16 duration;
	uint8  addr1[6];
	uint8  addr2[6];
	uint8  addr3[6];
	uint16 seq;
//	int8   addr[6]; // optional (if X then it is set)
//	uint16 qos_ctl; // optional (if X then it is set)
//	uint16 ht_ctl;  // optional (if X then it is set)
//	int8   body[1];
} ether_frame_hdr_t;

typedef struct ether_frame_ctl_s { // bitmap of the ether_frame_hdr_s.frame_ctl
	uint16 version  : 2;
	uint16 type     : 2;
	uint16 subtype  : 4;
	uint16 toDS     : 1;
	uint16 fromDS   : 1;
	uint16 morefrag : 1;
	uint16 retry    : 1;
	uint16 powman   : 1;
	uint16 moredata : 1;
	uint16 protfram : 1;
	uint16 order    : 1;
} ether_frame_ctl_t;

// THIS is the structure for the EAPOL data within the packet.
typedef struct ether_auto_802_1x_s {
	uint8 ver; // 1 ?
	uint8 key;
	uint16 length;  // in BE format
	uint8 key_descr; // should be 2 for EAPOL RSN KEY ?
	struct {
		uint16 KeyDescr	: 3; //
		uint16 KeyType	: 1; // 1 is pairwise key
		uint16 KeyIdx	: 2; // should be 0
		uint16 Install	: 1; // should be 0
		uint16 KeyACK	: 1; // 1=set 0=nope
		uint16 KeyMIC	: 1; // 1 set, 0 nope
		uint16 Secure	: 1;
		uint16 Error	: 1;
		uint16 Reqst	: 1;
		uint16 EncKeyDat: 1;
	}key_info;
	uint16 key_len;
	uint64 replay_cnt;
	uint8 wpa_nonce[32];
	uint8 wpa_keyiv[16];
	uint8 wpa_keyrsc[8];
	uint8 wpa_keyid[8];
	uint8 wpa_keymic[16];
	uint16 wpa_keydatlen;
} ether_auto_802_1x_t;

typedef struct ether_beacon_tag_s {
	uint8  tagtype;
	uint8  taglen;
	uint8  tag[1];
	// we have to 'walk' from 1 tag to next, since the tag itself is
	// var length.
} ether_beacon_tag_t;

// This is the structure for a 802.11 control 'beacon' packet.
// NOTE, we only use this packet to get the SSID.
typedef struct ether_beacon_data_s {
	uint32 time1;
	uint32 time2;
	uint16 interval;
	uint16 caps;
	// ok, now here we have a array of 'tagged params'.
	// these are variable sized, so we have to 'specially' walk them.
	ether_beacon_tag_t tags[1];
} ether_beacon_data_t;
#pragma pack()

inline uint16 swap16u(uint16 v) {
	return ((v>>8)|((v&0xFF)<<8));
}
inline uint32 swap32u(uint32 v) {
	return ((v>>24)|((v&0xFF)<<24) | ((v&0xFF0000)>>8) | ((v&0xFF00)<<8));
}
inline uint64 swap64u(uint64 v) {
	uint32 h,l;
	h = ((uint32*)&v)[0];
	l = ((uint32*)&v)[1];
	h = ((h>>24)|((h&0xFF)<<24) | ((h&0xFF0000)>>8) | ((h&0xFF00)<<8));
	l = ((l>>24)|((l&0xFF)<<24) | ((l&0xFF0000)>>8) | ((l&0xFF00)<<8));
	((uint32*)&v)[0] = l;
	((uint32*)&v)[1] = h;
	return v;
}

// This type structure is used to keep track of EAPOL packets, as they are read
// from a PCAP file.  we need to get certain 'paired' packets, to be able to create
// the input file for JtR (i.e. the 4-way to make the hash input for JtR). The packets
// that are needed are:   msg1 and msg2  or msg2 and msg3.  These MUST be paired, and
// matched to each other.  The match 'rules' are:
// the packets MUST be sequential (only eapol messages being looked at, so sequential epol's)
// if the match is a msg1-msg2, then both MUST have exact same If a msg1-msg2 pair,
//   they BOTH must have the exact same ether_auto_802_1x_t.replay_cnt
// if the match is a msg2-msg3, then the msg2 ether_auto_802_1x_t.replay_cnt must be exactly
//   one less than the ether_auto_802_1x_t.replay_cnt in the msg3.
// if any of the above 3 rules (actually only 2 of the 3, since the msg1-msg2 and msg2-msg3
//   rules are only used in proper context), then we do NOT have a valid 4-way.
// During run, every time we see a msg1, we 'forget' all other packets.  When we see a msg2,
//   we forget all msg3 and msg4's.  Also, for a msg2, we see if we have a msg1.  If so, we
//   see if that msg1 satisfies the replay_cnt rule.  If that is the case, then we have a
//   'possible' valid 4-way. We do write the results.  However, at this time, we are not
//   100% 'sure' we have a valid 4-way.  We CAN get a msg1/msg2 pair, even if the AP trying
//   to validate, did not know the password.  If all we see is the msg1/msg2, then we do not
//   KNOW for sure, if that AP was able to validate itself.   If there was a msg1 but it did
//   not match, we simply drop it.  Finally, when we get a msg3, we dump the msg1 and msg4's.
//   We check for a msg2 that is valid.  If the msg2 is valid, then we are SURE that we have
//   a valid 4-way.  The msg3 would not be sent, unless the router was happy that the
//   the connecting AP knows the PW, unless the router was written to always 'fake' reply,
//   but that is likely against 802.11 rules.  The only thing I could think might do this,
//   is some honey-pot router, looking for hackers. A real router is not going to give a
//   msg3 unless the 4-way is going along fine.
typedef struct WPA4way_s {
	char ssid[36];
	char essid[18];
	char bssid[18];
	uint8 *packet1;
	uint8 *packet2;
	uint8 *orig_2;
	uint8 *packet3;
	uint8 *packet4;
	int fully_cracked;
	int hopefully_cracked; // we have a 1 & 2
	int eapol_sz;
}WPA4way_t;

// Here are the structures needed to store the data that make up the 4-way handshake.
// we harvest this data to make JtR input strings.

// this struct IS the struct in JtR. So we load it up, the do a base-64 convert to save.
typedef struct
{
  char          essid[36];  // Note, we do not 'write' this one, it is the salt.
  unsigned char mac1[6];    // the base-64 data we write, starts from this element forward.
  unsigned char mac2[6];
  unsigned char nonce1[32];
  unsigned char nonce2[32];
  unsigned char eapol[256];
  int           eapol_size;
  int           keyver;
  unsigned char keymic[16];
} hccap_t;

Powered by blists - more mailing lists

Your e-mail address:

Powered by Openwall GNU/*/Linux - Powered by OpenVZ