|
|
|
|
|
/** |
|
* Name........: cap2hccapx.c |
|
* Autor.......: Jens Steube <jens.steube@gmail.com>, Philipp "philsmd" Schmidt <philsmd@hashcat.net> |
|
* License.....: MIT |
|
*/ |
|
|
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <stdint.h> |
|
#include <stdbool.h> |
|
#include <search.h> |
|
#include <errno.h> |
|
#include <inttypes.h> |
|
|
|
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
|
#define BIG_ENDIAN_HOST |
|
#endif |
|
|
|
#if defined (_WIN32) || defined (_WIN64) |
|
typedef unsigned int lsearch_cnt_t; |
|
#else |
|
typedef size_t lsearch_cnt_t; |
|
#endif |
|
|
|
#pragma pack(1) |
|
|
|
|
|
|
|
typedef uint8_t u8; |
|
typedef uint16_t u16; |
|
typedef uint32_t u32; |
|
typedef uint64_t u64; |
|
|
|
// from pcap.h |
|
|
|
#define TCPDUMP_MAGIC 0xa1b2c3d4 |
|
#define TCPDUMP_CIGAM 0xd4c3b2a1 |
|
|
|
#define TCPDUMP_DECODE_LEN 65535 |
|
|
|
#define DLT_NULL 0 /* BSD loopback encapsulation */ |
|
#define DLT_EN10MB 1 /* Ethernet (10Mb) */ |
|
#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ |
|
#define DLT_AX25 3 /* Amateur Radio AX.25 */ |
|
#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ |
|
#define DLT_CHAOS 5 /* Chaos */ |
|
#define DLT_IEEE802 6 /* IEEE 802 Networks */ |
|
#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ |
|
#define DLT_SLIP 8 /* Serial Line IP */ |
|
#define DLT_PPP 9 /* Point-to-point Protocol */ |
|
#define DLT_FDDI 10 /* FDDI */ |
|
#define DLT_RAW 12 /* Raw headers (no link layer) */ |
|
#define DLT_RAW2 14 |
|
#define DLT_RAW3 101 |
|
|
|
#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ |
|
#define DLT_IEEE802_11_PRISM 119 |
|
#define DLT_IEEE802_11_RADIO 127 |
|
#define DLT_IEEE802_11_PPI_HDR 192 |
|
|
|
struct pcap_file_header { |
|
u32 magic; |
|
u16 version_major; |
|
u16 version_minor; |
|
u32 thiszone; /* gmt to local correction */ |
|
u32 sigfigs; /* accuracy of timestamps */ |
|
u32 snaplen; /* max length saved portion of each pkt */ |
|
u32 linktype; /* data link type (LINKTYPE_*) */ |
|
}; |
|
|
|
struct pcap_pkthdr { |
|
u32 tv_sec; /* timestamp seconds */ |
|
u32 tv_usec; /* timestamp microseconds */ |
|
u32 caplen; /* length of portion present */ |
|
u32 len; /* length this packet (off wire) */ |
|
}; |
|
|
|
typedef struct pcap_file_header pcap_file_header_t; |
|
typedef struct pcap_pkthdr pcap_pkthdr_t; |
|
|
|
// from linux/ieee80211.h |
|
|
|
struct ieee80211_hdr_3addr { |
|
u16 frame_control; |
|
u16 duration_id; |
|
u8 addr1[6]; |
|
u8 addr2[6]; |
|
u8 addr3[6]; |
|
u16 seq_ctrl; |
|
|
|
} __attribute__((packed)); |
|
|
|
struct ieee80211_qos_hdr { |
|
u16 frame_control; |
|
u16 duration_id; |
|
u8 addr1[6]; |
|
u8 addr2[6]; |
|
u8 addr3[6]; |
|
u16 seq_ctrl; |
|
u16 qos_ctrl; |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct ieee80211_hdr_3addr ieee80211_hdr_3addr_t; |
|
typedef struct ieee80211_qos_hdr ieee80211_qos_hdr_t; |
|
|
|
struct ieee80211_llc_snap_header |
|
{ |
|
/* LLC part: */ |
|
u8 dsap; /**< Destination SAP ID */ |
|
u8 ssap; /**< Source SAP ID */ |
|
u8 ctrl; /**< Control information */ |
|
|
|
/* SNAP part: */ |
|
u8 oui[3]; /**< Organization code, usually 0 */ |
|
u16 ethertype; /**< Ethernet Type field */ |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct ieee80211_llc_snap_header ieee80211_llc_snap_header_t; |
|
|
|
#define IEEE80211_FCTL_FTYPE 0x000c |
|
#define IEEE80211_FCTL_STYPE 0x00f0 |
|
#define IEEE80211_FCTL_TODS 0x0100 |
|
#define IEEE80211_FCTL_FROMDS 0x0200 |
|
|
|
#define IEEE80211_FTYPE_MGMT 0x0000 |
|
#define IEEE80211_FTYPE_DATA 0x0008 |
|
|
|
#define IEEE80211_STYPE_ASSOC_REQ 0x0000 |
|
#define IEEE80211_STYPE_ASSOC_RESP 0x0010 |
|
#define IEEE80211_STYPE_REASSOC_REQ 0x0020 |
|
#define IEEE80211_STYPE_REASSOC_RESP 0x0030 |
|
#define IEEE80211_STYPE_PROBE_REQ 0x0040 |
|
#define IEEE80211_STYPE_PROBE_RESP 0x0050 |
|
#define IEEE80211_STYPE_BEACON 0x0080 |
|
#define IEEE80211_STYPE_QOS_DATA 0x0080 |
|
#define IEEE80211_STYPE_ATIM 0x0090 |
|
#define IEEE80211_STYPE_DISASSOC 0x00A0 |
|
#define IEEE80211_STYPE_AUTH 0x00B0 |
|
#define IEEE80211_STYPE_DEAUTH 0x00C0 |
|
#define IEEE80211_STYPE_ACTION 0x00D0 |
|
|
|
#define IEEE80211_LLC_DSAP 0xAA |
|
#define IEEE80211_LLC_SSAP 0xAA |
|
#define IEEE80211_LLC_CTRL 0x03 |
|
#define IEEE80211_DOT1X_AUTHENTICATION 0x8E88 |
|
|
|
/* Management Frame Information Element Types */ |
|
#define MFIE_TYPE_SSID 0 |
|
#define MFIE_TYPE_RATES 1 |
|
#define MFIE_TYPE_FH_SET 2 |
|
#define MFIE_TYPE_DS_SET 3 |
|
#define MFIE_TYPE_CF_SET 4 |
|
#define MFIE_TYPE_TIM 5 |
|
#define MFIE_TYPE_IBSS_SET 6 |
|
#define MFIE_TYPE_CHALLENGE 16 |
|
#define MFIE_TYPE_ERP 42 |
|
#define MFIE_TYPE_RSN 48 |
|
#define MFIE_TYPE_RATES_EX 50 |
|
#define MFIE_TYPE_GENERIC 221 |
|
|
|
// from ks7010/eap_packet.h |
|
|
|
#define WBIT(n) (1 << (n)) |
|
|
|
#define WPA_KEY_INFO_TYPE_MASK (WBIT(0) | WBIT(1) | WBIT(2)) |
|
#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 WBIT(0) |
|
#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES WBIT(1) |
|
#define WPA_KEY_INFO_KEY_TYPE WBIT(3) /* 1 = Pairwise, 0 = Group key */ |
|
#define WPA_KEY_INFO_KEY_INDEX_MASK (WBIT(4) | WBIT(5)) |
|
#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 |
|
#define WPA_KEY_INFO_INSTALL WBIT(6) /* pairwise */ |
|
#define WPA_KEY_INFO_TXRX WBIT(6) /* group */ |
|
#define WPA_KEY_INFO_ACK WBIT(7) |
|
#define WPA_KEY_INFO_MIC WBIT(8) |
|
#define WPA_KEY_INFO_SECURE WBIT(9) |
|
#define WPA_KEY_INFO_ERROR WBIT(10) |
|
#define WPA_KEY_INFO_REQUEST WBIT(11) |
|
#define WPA_KEY_INFO_ENCR_KEY_DATA WBIT(12) /* IEEE 802.11i/RSN only */ |
|
|
|
// radiotap header from http://www.radiotap.org/ |
|
|
|
struct ieee80211_radiotap_header |
|
{ |
|
u8 it_version; /* set to 0 */ |
|
u8 it_pad; |
|
u16 it_len; /* entire length */ |
|
u32 it_present; /* fields present */ |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct ieee80211_radiotap_header ieee80211_radiotap_header_t; |
|
|
|
// prism header |
|
|
|
#define WLAN_DEVNAMELEN_MAX 16 |
|
|
|
struct prism_item |
|
{ |
|
u32 did; |
|
u16 status; |
|
u16 len; |
|
u32 data; |
|
|
|
} __attribute__((packed)); |
|
|
|
struct prism_header |
|
{ |
|
u32 msgcode; |
|
u32 msglen; |
|
|
|
char devname[WLAN_DEVNAMELEN_MAX]; |
|
|
|
struct prism_item hosttime; |
|
struct prism_item mactime; |
|
struct prism_item channel; |
|
struct prism_item rssi; |
|
struct prism_item sq; |
|
struct prism_item signal; |
|
struct prism_item noise; |
|
struct prism_item rate; |
|
struct prism_item istx; |
|
struct prism_item frmlen; |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct prism_item prism_item_t; |
|
typedef struct prism_header prism_header_t; |
|
|
|
/* CACE PPI headers */ |
|
struct ppi_packet_header |
|
{ |
|
uint8_t pph_version; |
|
uint8_t pph_flags; |
|
uint16_t pph_len; |
|
uint32_t pph_dlt; |
|
} __attribute__((packed)); |
|
|
|
typedef struct ppi_packet_header ppi_packet_header_t; |
|
|
|
struct ppi_field_header |
|
{ |
|
uint16_t pfh_datatype; |
|
uint16_t pfh_datalen; |
|
} __attribute__((__packed__)); |
|
|
|
typedef struct ppi_field_header ppi_field_header_t; |
|
|
|
#define PPI_FIELD_11COMMON 2 |
|
#define PPI_FIELD_11NMAC 3 |
|
#define PPI_FIELD_11NMACPHY 4 |
|
#define PPI_FIELD_SPECMAP 5 |
|
#define PPI_FIELD_PROCINFO 6 |
|
#define PPI_FIELD_CAPINFO 7 |
|
|
|
// own structs |
|
|
|
struct beaconinfo |
|
{ |
|
u64 beacon_timestamp; |
|
u16 beacon_interval; |
|
u16 beacon_capabilities; |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct beaconinfo beacon_t; |
|
|
|
struct associationreqf |
|
{ |
|
u16 client_capabilities; |
|
u16 client_listeninterval; |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct associationreqf assocreq_t; |
|
|
|
struct reassociationreqf |
|
{ |
|
u16 client_capabilities; |
|
u16 client_listeninterval; |
|
u8 addr[6]; |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct reassociationreqf reassocreq_t; |
|
|
|
struct auth_packet |
|
{ |
|
u8 version; |
|
u8 type; |
|
u16 length; |
|
u8 key_descriptor; |
|
u16 key_information; |
|
u16 key_length; |
|
u64 replay_counter; |
|
u8 wpa_key_nonce[32]; |
|
u8 wpa_key_iv[16]; |
|
u8 wpa_key_rsc[8]; |
|
u8 wpa_key_id[8]; |
|
u8 wpa_key_mic[16]; |
|
u16 wpa_key_data_length; |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct auth_packet auth_packet_t; |
|
|
|
#define MAX_ESSID_LEN 32 |
|
|
|
typedef enum |
|
{ |
|
ESSID_SOURCE_USER = 1, |
|
ESSID_SOURCE_REASSOC = 2, |
|
ESSID_SOURCE_ASSOC = 3, |
|
ESSID_SOURCE_PROBE = 4, |
|
ESSID_SOURCE_DIRECTED_PROBE = 5, |
|
ESSID_SOURCE_BEACON = 6, |
|
|
|
} essid_source_t; |
|
|
|
typedef struct |
|
{ |
|
u8 bssid[6]; |
|
char essid[MAX_ESSID_LEN + 4]; |
|
int essid_len; |
|
int essid_source; |
|
|
|
} essid_t; |
|
|
|
#define EAPOL_TTL 1 |
|
#define TEST_REPLAYCOUNT 0 |
|
|
|
typedef enum |
|
{ |
|
EXC_PKT_NUM_1 = 1, |
|
EXC_PKT_NUM_2 = 2, |
|
EXC_PKT_NUM_3 = 3, |
|
EXC_PKT_NUM_4 = 4, |
|
|
|
} exc_pkt_num_t; |
|
|
|
typedef enum |
|
{ |
|
MESSAGE_PAIR_M12E2 = 0, |
|
MESSAGE_PAIR_M14E4 = 1, |
|
MESSAGE_PAIR_M32E2 = 2, |
|
MESSAGE_PAIR_M32E3 = 3, |
|
MESSAGE_PAIR_M34E3 = 4, |
|
MESSAGE_PAIR_M34E4 = 5, |
|
|
|
} message_pair_t; |
|
|
|
#define BROADCAST_MAC "\xff\xff\xff\xff\xff\xff" |
|
|
|
typedef struct |
|
{ |
|
int excpkt_num; |
|
|
|
u32 tv_sec; |
|
u32 tv_usec; |
|
|
|
u64 replay_counter; |
|
|
|
u8 mac_ap[6]; |
|
u8 mac_sta[6]; |
|
|
|
u8 nonce[32]; |
|
|
|
u16 eapol_len; |
|
u8 eapol[256]; |
|
|
|
u8 keyver; |
|
u8 keymic[16]; |
|
|
|
} excpkt_t; |
|
|
|
// databases |
|
|
|
#define DB_ESSID_MAX 50000 |
|
#define DB_EXCPKT_MAX 100000 |
|
|
|
essid_t *essids = NULL; |
|
lsearch_cnt_t essids_cnt = 0; |
|
|
|
excpkt_t *excpkts = NULL; |
|
lsearch_cnt_t excpkts_cnt = 0; |
|
|
|
// output |
|
|
|
#define HCCAPX_VERSION 4 |
|
#define HCCAPX_SIGNATURE 0x58504348 // HCPX |
|
|
|
struct hccapx |
|
{ |
|
u32 signature; |
|
u32 version; |
|
u8 message_pair; |
|
u8 essid_len; |
|
u8 essid[32]; |
|
u8 keyver; |
|
u8 keymic[16]; |
|
u8 mac_ap[6]; |
|
u8 nonce_ap[32]; |
|
u8 mac_sta[6]; |
|
u8 nonce_sta[32]; |
|
u16 eapol_len; |
|
u8 eapol[256]; |
|
|
|
} __attribute__((packed)); |
|
|
|
typedef struct hccapx hccapx_t; |
|
|
|
// functions |
|
|
|
static u8 hex_convert (const u8 c) |
|
{ |
|
return (c & 15) + (c >> 6) * 9; |
|
} |
|
|
|
static u8 hex_to_u8 (const u8 hex[2]) |
|
{ |
|
u8 v = 0; |
|
|
|
v |= ((u8) hex_convert (hex[1]) << 0); |
|
v |= ((u8) hex_convert (hex[0]) << 4); |
|
|
|
return (v); |
|
} |
|
|
|
static u16 byte_swap_16 (const u16 n) |
|
{ |
|
return (n & 0xff00) >> 8 |
|
| (n & 0x00ff) << 8; |
|
} |
|
|
|
static u32 byte_swap_32 (const u32 n) |
|
{ |
|
return (n & 0xff000000) >> 24 |
|
| (n & 0x00ff0000) >> 8 |
|
| (n & 0x0000ff00) << 8 |
|
| (n & 0x000000ff) << 24; |
|
} |
|
|
|
static u64 byte_swap_64 (const u64 n) |
|
{ |
|
return (n & 0xff00000000000000ULL) >> 56 |
|
| (n & 0x00ff000000000000ULL) >> 40 |
|
| (n & 0x0000ff0000000000ULL) >> 24 |
|
| (n & 0x000000ff00000000ULL) >> 8 |
|
| (n & 0x00000000ff000000ULL) << 8 |
|
| (n & 0x0000000000ff0000ULL) << 24 |
|
| (n & 0x000000000000ff00ULL) << 40 |
|
| (n & 0x00000000000000ffULL) << 56; |
|
} |
|
|
|
int comp_excpkt (const void *p1, const void *p2) |
|
{ |
|
excpkt_t *e1 = (excpkt_t *) p1; |
|
excpkt_t *e2 = (excpkt_t *) p2; |
|
|
|
const int excpkt_diff = e1->excpkt_num - e2->excpkt_num; |
|
|
|
if (excpkt_diff != 0) return excpkt_diff; |
|
|
|
const int rc_nonce = memcmp (e1->nonce, e2->nonce, 32); |
|
|
|
if (rc_nonce != 0) return rc_nonce; |
|
|
|
const int rc_mac_ap = memcmp (e1->mac_ap, e2->mac_ap, 6); |
|
|
|
if (rc_mac_ap != 0) return rc_mac_ap; |
|
|
|
const int rc_mac_sta = memcmp (e1->mac_sta, e2->mac_sta, 6); |
|
|
|
if (rc_mac_sta != 0) return rc_mac_sta; |
|
|
|
if (e1->replay_counter < e2->replay_counter) return 1; |
|
if (e1->replay_counter > e2->replay_counter) return -1; |
|
|
|
return 0; |
|
} |
|
|
|
int comp_bssid (const void *p1, const void *p2) |
|
{ |
|
essid_t *e1 = (essid_t *) p1; |
|
essid_t *e2 = (essid_t *) p2; |
|
|
|
return memcmp (e1->bssid, e2->bssid, 6); |
|
} |
|
|
|
static void db_excpkt_add (excpkt_t *excpkt, const u32 tv_sec, const u32 tv_usec, const u8 mac_ap[6], const u8 mac_sta[6]) |
|
{ |
|
if (essids_cnt == DB_EXCPKT_MAX) |
|
{ |
|
fprintf (stderr, "Too many excpkt in dumpfile, aborting...\n"); |
|
|
|
exit (-1); |
|
} |
|
|
|
excpkt->tv_sec = tv_sec; |
|
excpkt->tv_usec = tv_usec; |
|
|
|
memcpy (excpkt->mac_ap, mac_ap, 6); |
|
memcpy (excpkt->mac_sta, mac_sta, 6); |
|
|
|
lsearch (excpkt, excpkts, &excpkts_cnt, sizeof (excpkt_t), comp_excpkt); |
|
} |
|
|
|
static void db_essid_add (essid_t *essid, const u8 addr3[6], const int essid_source) |
|
{ |
|
if (essids_cnt == DB_ESSID_MAX) |
|
{ |
|
fprintf (stderr, "Too many essid in dumpfile, aborting...\n"); |
|
|
|
exit (-1); |
|
} |
|
|
|
if (essid->essid_len == 0) return; |
|
|
|
if (essid->essid[0] == 0) return; |
|
|
|
memcpy (essid->bssid, addr3, 6); |
|
|
|
void *ptr = lfind (essid, essids, &essids_cnt, sizeof (essid_t), comp_bssid); |
|
|
|
if (ptr == NULL) |
|
{ |
|
essid->essid_source = essid_source; |
|
|
|
lsearch (essid, essids, &essids_cnt, sizeof (essid_t), comp_bssid); |
|
} |
|
else |
|
{ |
|
essid_t *essid_old = (essid_t *) ptr; |
|
|
|
if (essid_source > essid_old->essid_source) |
|
{ |
|
memcpy (essid_old, essid, sizeof (essid_t)); |
|
|
|
essid_old->essid_source = essid_source; |
|
} |
|
} |
|
} |
|
|
|
static int handle_llc (const ieee80211_llc_snap_header_t *ieee80211_llc_snap_header) |
|
{ |
|
if (ieee80211_llc_snap_header->dsap != IEEE80211_LLC_DSAP) return -1; |
|
if (ieee80211_llc_snap_header->ssap != IEEE80211_LLC_SSAP) return -1; |
|
if (ieee80211_llc_snap_header->ctrl != IEEE80211_LLC_CTRL) return -1; |
|
|
|
if (ieee80211_llc_snap_header->ethertype != IEEE80211_DOT1X_AUTHENTICATION) return -1; |
|
|
|
return 0; |
|
} |
|
|
|
static int handle_auth (const auth_packet_t *auth_packet, const int pkt_offset, const int pkt_size, excpkt_t *excpkt) |
|
{ |
|
const u16 ap_length = byte_swap_16 (auth_packet->length); |
|
const u16 ap_key_information = byte_swap_16 (auth_packet->key_information); |
|
const u64 ap_replay_counter = byte_swap_64 (auth_packet->replay_counter); |
|
const u16 ap_wpa_key_data_length = byte_swap_16 (auth_packet->wpa_key_data_length); |
|
|
|
if (ap_length == 0) return -1; |
|
|
|
// determine handshake exchange number |
|
|
|
int excpkt_num = 0; |
|
|
|
if (ap_key_information & WPA_KEY_INFO_ACK) |
|
{ |
|
if (ap_key_information & WPA_KEY_INFO_INSTALL) |
|
{ |
|
excpkt_num = EXC_PKT_NUM_3; |
|
} |
|
else |
|
{ |
|
excpkt_num = EXC_PKT_NUM_1; |
|
} |
|
} |
|
else |
|
{ |
|
if (ap_key_information & WPA_KEY_INFO_SECURE) |
|
{ |
|
excpkt_num = EXC_PKT_NUM_4; |
|
} |
|
else |
|
{ |
|
excpkt_num = EXC_PKT_NUM_2; |
|
} |
|
} |
|
|
|
// we're only interested in packets carrying a nonce |
|
|
|
char zero[32] = { 0 }; |
|
|
|
if (memcmp (auth_packet->wpa_key_nonce, zero, 32) == 0) return -1; |
|
|
|
// copy data |
|
|
|
memcpy (excpkt->nonce, auth_packet->wpa_key_nonce, 32); |
|
|
|
excpkt->replay_counter = ap_replay_counter; |
|
|
|
excpkt->excpkt_num = excpkt_num; |
|
|
|
excpkt->eapol_len = sizeof (auth_packet_t) + ap_wpa_key_data_length; |
|
|
|
if ((pkt_offset + excpkt->eapol_len) > pkt_size) return -1; |
|
|
|
if ((sizeof (auth_packet_t) + ap_wpa_key_data_length) > sizeof (excpkt->eapol)) return -1; |
|
|
|
// we need to copy the auth_packet_t but have to clear the keymic |
|
auth_packet_t auth_packet_orig; |
|
|
|
memcpy (&auth_packet_orig, auth_packet, sizeof (auth_packet_t)); |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
auth_packet_orig.length = byte_swap_16 (auth_packet_orig.length); |
|
auth_packet_orig.key_information = byte_swap_16 (auth_packet_orig.key_information); |
|
auth_packet_orig.key_length = byte_swap_16 (auth_packet_orig.key_length); |
|
auth_packet_orig.replay_counter = byte_swap_64 (auth_packet_orig.replay_counter); |
|
auth_packet_orig.wpa_key_data_length = byte_swap_16 (auth_packet_orig.wpa_key_data_length); |
|
#endif |
|
|
|
memset (auth_packet_orig.wpa_key_mic, 0, 16); |
|
|
|
memcpy (excpkt->eapol, &auth_packet_orig, sizeof (auth_packet_t)); |
|
memcpy (excpkt->eapol + sizeof (auth_packet_t), auth_packet + 1, ap_wpa_key_data_length); |
|
|
|
memcpy (excpkt->keymic, auth_packet->wpa_key_mic, 16); |
|
|
|
excpkt->keyver = ap_key_information & WPA_KEY_INFO_TYPE_MASK; |
|
|
|
if ((excpkt_num == EXC_PKT_NUM_3) || (excpkt_num == EXC_PKT_NUM_4)) |
|
{ |
|
excpkt->replay_counter--; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int get_essid_from_user (char *s, essid_t *essid) |
|
{ |
|
char *man_essid = s; |
|
char *man_bssid = strchr (man_essid, ':'); |
|
|
|
if (man_bssid == NULL) |
|
{ |
|
fprintf (stderr, "Invalid format (%s), should be: MyESSID:d110391a58ac\n", s); |
|
|
|
return -1; |
|
} |
|
|
|
*man_bssid = 0; |
|
|
|
man_bssid++; |
|
|
|
if (strlen (man_essid) >= 32) |
|
{ |
|
fprintf (stderr, "Invalid format (%s), essid is too long\n", s); |
|
|
|
return -1; |
|
} |
|
|
|
if (strlen (man_bssid) != 12) |
|
{ |
|
fprintf (stderr, "Invalid format (%s), bssid must have length 12\n", s); |
|
|
|
return -1; |
|
} |
|
|
|
strncpy (essid->essid, man_essid, 32); |
|
|
|
essid->essid_len = strlen (essid->essid); |
|
|
|
u8 bssid[6]; |
|
|
|
bssid[0] = hex_to_u8 ((u8 *) man_bssid); man_bssid += 2; |
|
bssid[1] = hex_to_u8 ((u8 *) man_bssid); man_bssid += 2; |
|
bssid[2] = hex_to_u8 ((u8 *) man_bssid); man_bssid += 2; |
|
bssid[3] = hex_to_u8 ((u8 *) man_bssid); man_bssid += 2; |
|
bssid[4] = hex_to_u8 ((u8 *) man_bssid); man_bssid += 2; |
|
bssid[5] = hex_to_u8 ((u8 *) man_bssid); man_bssid += 2; |
|
|
|
db_essid_add (essid, bssid, ESSID_SOURCE_USER); |
|
|
|
return 0; |
|
} |
|
|
|
static int get_essid_from_tag (const u8 *packet, const pcap_pkthdr_t *header, u32 length_skip, essid_t *essid) |
|
{ |
|
if (length_skip > header->caplen) return -1; |
|
|
|
u32 length = header->caplen - length_skip; |
|
|
|
const u8 *beacon = packet + length_skip; |
|
|
|
const u8 *cur = beacon; |
|
const u8 *end = beacon + length; |
|
|
|
while (cur < end) |
|
{ |
|
if ((cur + 2) >= end) break; |
|
|
|
u8 tagtype = *cur++; |
|
u8 taglen = *cur++; |
|
|
|
if ((cur + taglen) >= end) break; |
|
|
|
if (tagtype == MFIE_TYPE_SSID) |
|
{ |
|
if (taglen < MAX_ESSID_LEN) |
|
{ |
|
memcpy (essid->essid, cur, taglen); |
|
|
|
essid->essid_len = taglen; |
|
|
|
return 0; |
|
} |
|
} |
|
|
|
cur += taglen; |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
static void process_packet (const u8 *packet, const pcap_pkthdr_t *header) |
|
{ |
|
if (header->caplen < sizeof (ieee80211_hdr_3addr_t)) return; |
|
|
|
// our first header: ieee80211 |
|
|
|
ieee80211_hdr_3addr_t *ieee80211_hdr_3addr = (ieee80211_hdr_3addr_t *) packet; |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
ieee80211_hdr_3addr->frame_control = byte_swap_16 (ieee80211_hdr_3addr->frame_control); |
|
ieee80211_hdr_3addr->duration_id = byte_swap_16 (ieee80211_hdr_3addr->duration_id); |
|
ieee80211_hdr_3addr->seq_ctrl = byte_swap_16 (ieee80211_hdr_3addr->seq_ctrl); |
|
#endif |
|
|
|
const u16 frame_control = ieee80211_hdr_3addr->frame_control; |
|
|
|
if ((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) |
|
{ |
|
if (memcmp (ieee80211_hdr_3addr->addr3, BROADCAST_MAC, 6) == 0) return; |
|
|
|
essid_t essid; |
|
|
|
memset (&essid, 0, sizeof (essid_t)); |
|
|
|
const int stype = frame_control & IEEE80211_FCTL_STYPE; |
|
|
|
if (stype == IEEE80211_STYPE_BEACON) |
|
{ |
|
const u32 length_skip = sizeof (ieee80211_hdr_3addr_t) + sizeof (beacon_t); |
|
|
|
const int rc_beacon = get_essid_from_tag (packet, header, length_skip, &essid); |
|
|
|
if (rc_beacon == -1) return; |
|
|
|
db_essid_add (&essid, ieee80211_hdr_3addr->addr3, ESSID_SOURCE_BEACON); |
|
} |
|
else if (stype == IEEE80211_STYPE_PROBE_REQ) |
|
{ |
|
const u32 length_skip = sizeof (ieee80211_hdr_3addr_t); |
|
|
|
const int rc_beacon = get_essid_from_tag (packet, header, length_skip, &essid); |
|
|
|
if (rc_beacon == -1) return; |
|
|
|
db_essid_add (&essid, ieee80211_hdr_3addr->addr3, ESSID_SOURCE_PROBE); |
|
} |
|
else if (stype == IEEE80211_STYPE_PROBE_RESP) |
|
{ |
|
const u32 length_skip = sizeof (ieee80211_hdr_3addr_t) + sizeof (beacon_t); |
|
|
|
const int rc_beacon = get_essid_from_tag (packet, header, length_skip, &essid); |
|
|
|
if (rc_beacon == -1) return; |
|
|
|
db_essid_add (&essid, ieee80211_hdr_3addr->addr3, ESSID_SOURCE_PROBE); |
|
} |
|
else if (stype == IEEE80211_STYPE_ASSOC_REQ) |
|
{ |
|
const u32 length_skip = sizeof (ieee80211_hdr_3addr_t) + sizeof (assocreq_t); |
|
|
|
const int rc_beacon = get_essid_from_tag (packet, header, length_skip, &essid); |
|
|
|
if (rc_beacon == -1) return; |
|
|
|
db_essid_add (&essid, ieee80211_hdr_3addr->addr3, ESSID_SOURCE_ASSOC); |
|
} |
|
else if (stype == IEEE80211_STYPE_REASSOC_REQ) |
|
{ |
|
const u32 length_skip = sizeof (ieee80211_hdr_3addr_t) + sizeof (reassocreq_t); |
|
|
|
const int rc_beacon = get_essid_from_tag (packet, header, length_skip, &essid); |
|
|
|
if (rc_beacon == -1) return; |
|
|
|
db_essid_add (&essid, ieee80211_hdr_3addr->addr3, ESSID_SOURCE_REASSOC); |
|
} |
|
} |
|
else if ((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) |
|
{ |
|
// process header: ieee80211 |
|
|
|
int addr4_exist = ((frame_control & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == |
|
(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); |
|
|
|
// find offset to llc/snap header |
|
|
|
int llc_offset; |
|
|
|
if ((frame_control & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA) |
|
{ |
|
llc_offset = sizeof (ieee80211_qos_hdr_t); |
|
} |
|
else |
|
{ |
|
llc_offset = sizeof (ieee80211_hdr_3addr_t); |
|
} |
|
|
|
// process header: the llc/snap header |
|
|
|
if (header->caplen < (llc_offset + sizeof (ieee80211_llc_snap_header_t))) return; |
|
if (addr4_exist) llc_offset += 6; |
|
|
|
ieee80211_llc_snap_header_t *ieee80211_llc_snap_header = (ieee80211_llc_snap_header_t *) &packet[llc_offset]; |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
ieee80211_llc_snap_header->ethertype = byte_swap_16 (ieee80211_llc_snap_header->ethertype); |
|
#endif |
|
|
|
const int rc_llc = handle_llc (ieee80211_llc_snap_header); |
|
|
|
if (rc_llc == -1) return; |
|
|
|
// process header: the auth header |
|
|
|
const int auth_offset = llc_offset + sizeof (ieee80211_llc_snap_header_t); |
|
|
|
if (header->caplen < (auth_offset + sizeof (auth_packet_t))) return; |
|
|
|
auth_packet_t *auth_packet = (auth_packet_t *) &packet[auth_offset]; |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
auth_packet->length = byte_swap_16 (auth_packet->length); |
|
auth_packet->key_information = byte_swap_16 (auth_packet->key_information); |
|
auth_packet->key_length = byte_swap_16 (auth_packet->key_length); |
|
auth_packet->replay_counter = byte_swap_64 (auth_packet->replay_counter); |
|
auth_packet->wpa_key_data_length = byte_swap_16 (auth_packet->wpa_key_data_length); |
|
#endif |
|
|
|
excpkt_t excpkt; |
|
|
|
memset (&excpkt, 0, sizeof (excpkt_t)); |
|
|
|
const int rc_auth = handle_auth (auth_packet, auth_offset, header->caplen, &excpkt); |
|
|
|
if (rc_auth == -1) return; |
|
|
|
if ((excpkt.excpkt_num == EXC_PKT_NUM_1) || (excpkt.excpkt_num == EXC_PKT_NUM_3)) |
|
{ |
|
db_excpkt_add (&excpkt, header->tv_sec, header->tv_usec, ieee80211_hdr_3addr->addr2, ieee80211_hdr_3addr->addr1); |
|
} |
|
else if ((excpkt.excpkt_num == EXC_PKT_NUM_2) || (excpkt.excpkt_num == EXC_PKT_NUM_4)) |
|
{ |
|
db_excpkt_add (&excpkt, header->tv_sec, header->tv_usec, ieee80211_hdr_3addr->addr1, ieee80211_hdr_3addr->addr2); |
|
} |
|
} |
|
} |
|
|
|
int main (int argc, char *argv[]) |
|
{ |
|
if ((argc != 3) && (argc != 4) && (argc != 5)) |
|
{ |
|
fprintf (stderr, "usage: %s input.pcap output.hccapx [filter by essid] [additional network essid:bssid]\n", argv[0]); |
|
|
|
return -1; |
|
} |
|
|
|
char *in = argv[1]; |
|
char *out = argv[2]; |
|
|
|
char *essid_filter = NULL; |
|
|
|
if (argc >= 4) essid_filter = argv[3]; |
|
|
|
// database initializations |
|
|
|
essids = (essid_t *) calloc (DB_ESSID_MAX, sizeof (essid_t)); |
|
essids_cnt = 0; |
|
|
|
excpkts = (excpkt_t *) calloc (DB_EXCPKT_MAX, sizeof (excpkt_t)); |
|
excpkts_cnt = 0; |
|
|
|
// manual beacon |
|
|
|
if (argc >= 5) |
|
{ |
|
essid_t essid; |
|
|
|
memset (&essid, 0, sizeof (essid_t)); |
|
|
|
const int rc = get_essid_from_user (argv[4], &essid); |
|
|
|
if (rc == -1) return -1; |
|
} |
|
|
|
// start with pcap handling |
|
|
|
FILE *pcap = fopen (in, "rb"); |
|
|
|
if (pcap == NULL) |
|
{ |
|
fprintf (stderr, "%s: %s\n", in, strerror (errno)); |
|
|
|
return -1; |
|
} |
|
|
|
// check pcap header |
|
|
|
pcap_file_header_t pcap_file_header; |
|
|
|
const int nread = fread (&pcap_file_header, sizeof (pcap_file_header_t), 1, pcap); |
|
|
|
if (nread != 1) |
|
{ |
|
fprintf (stderr, "%s: Could not read pcap header\n", in); |
|
|
|
return -1; |
|
} |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
pcap_file_header.magic = byte_swap_32 (pcap_file_header.magic); |
|
pcap_file_header.version_major = byte_swap_16 (pcap_file_header.version_major); |
|
pcap_file_header.version_minor = byte_swap_16 (pcap_file_header.version_minor); |
|
pcap_file_header.thiszone = byte_swap_32 (pcap_file_header.thiszone); |
|
pcap_file_header.sigfigs = byte_swap_32 (pcap_file_header.sigfigs); |
|
pcap_file_header.snaplen = byte_swap_32 (pcap_file_header.snaplen); |
|
pcap_file_header.linktype = byte_swap_32 (pcap_file_header.linktype); |
|
#endif |
|
|
|
int bitness = 0; |
|
|
|
if (pcap_file_header.magic == TCPDUMP_MAGIC) |
|
{ |
|
bitness = 0; |
|
} |
|
else if (pcap_file_header.magic == TCPDUMP_CIGAM) |
|
{ |
|
bitness = 1; |
|
} |
|
else |
|
{ |
|
fprintf (stderr, "%s: Invalid pcap header\n", in); |
|
|
|
return 1; |
|
} |
|
|
|
if (bitness == 1) |
|
{ |
|
pcap_file_header.magic = byte_swap_32 (pcap_file_header.magic); |
|
pcap_file_header.version_major = byte_swap_16 (pcap_file_header.version_major); |
|
pcap_file_header.version_minor = byte_swap_16 (pcap_file_header.version_minor); |
|
pcap_file_header.thiszone = byte_swap_32 (pcap_file_header.thiszone); |
|
pcap_file_header.sigfigs = byte_swap_32 (pcap_file_header.sigfigs); |
|
pcap_file_header.snaplen = byte_swap_32 (pcap_file_header.snaplen); |
|
pcap_file_header.linktype = byte_swap_32 (pcap_file_header.linktype); |
|
} |
|
|
|
if ((pcap_file_header.linktype != DLT_IEEE802_11) |
|
&& (pcap_file_header.linktype != DLT_IEEE802_11_PRISM) |
|
&& (pcap_file_header.linktype != DLT_IEEE802_11_RADIO) |
|
&& (pcap_file_header.linktype != DLT_IEEE802_11_PPI_HDR)) |
|
{ |
|
fprintf (stderr, "%s: Unsupported linktype detected\n", in); |
|
|
|
return -1; |
|
} |
|
|
|
// walk the packets |
|
|
|
while (!feof (pcap)) |
|
{ |
|
pcap_pkthdr_t header; |
|
|
|
const int nread1 = fread (&header, sizeof (pcap_pkthdr_t), 1, pcap); |
|
|
|
if (nread1 != 1) continue; |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
header.tv_sec = byte_swap_32 (header.tv_sec); |
|
header.tv_usec = byte_swap_32 (header.tv_usec); |
|
header.caplen = byte_swap_32 (header.caplen); |
|
header.len = byte_swap_32 (header.len); |
|
#endif |
|
|
|
if (bitness == 1) |
|
{ |
|
header.tv_sec = byte_swap_32 (header.tv_sec); |
|
header.tv_usec = byte_swap_32 (header.tv_usec); |
|
header.caplen = byte_swap_32 (header.caplen); |
|
header.len = byte_swap_32 (header.len); |
|
} |
|
|
|
if ((header.tv_sec == 0) && (header.tv_usec == 0)) |
|
{ |
|
fprintf (stderr, "Zero value timestamps detected in file: %s.\n", in); |
|
fprintf (stderr, "This prevents correct EAPOL-Key timeout calculation.\n"); |
|
fprintf (stderr, "Do not use preprocess the capture file with tools such as wpaclean.\n"); |
|
|
|
return -1; |
|
} |
|
|
|
u8 packet[TCPDUMP_DECODE_LEN]; |
|
|
|
if (header.caplen >= TCPDUMP_DECODE_LEN || (signed)header.caplen < 0) |
|
{ |
|
fprintf (stderr, "%s: Oversized packet detected\n", in); |
|
|
|
break; |
|
} |
|
|
|
const u32 nread2 = fread (&packet, sizeof (u8), header.caplen, pcap); |
|
|
|
if (nread2 != header.caplen) |
|
{ |
|
fprintf (stderr, "%s: Could not read pcap packet data\n", in); |
|
|
|
break; |
|
} |
|
|
|
u8 *packet_ptr = packet; |
|
|
|
if (pcap_file_header.linktype == DLT_IEEE802_11_PRISM) |
|
{ |
|
if (header.caplen < sizeof (prism_header_t)) |
|
{ |
|
fprintf (stderr, "%s: Could not read prism header\n", in); |
|
|
|
break; |
|
} |
|
|
|
prism_header_t *prism_header = (prism_header_t *) packet; |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
prism_header->msgcode = byte_swap_32 (prism_header->msgcode); |
|
prism_header->msglen = byte_swap_32 (prism_header->msglen); |
|
#endif |
|
|
|
if ((signed)prism_header->msglen < 0) |
|
{ |
|
fprintf (stderr, "%s: Oversized packet detected\n", in); |
|
|
|
break; |
|
} |
|
|
|
if ((signed)(header.caplen - prism_header->msglen) < 0) |
|
{ |
|
fprintf (stderr, "%s: Oversized packet detected\n", in); |
|
|
|
break; |
|
} |
|
|
|
packet_ptr += prism_header->msglen; |
|
header.caplen -= prism_header->msglen; |
|
header.len -= prism_header->msglen; |
|
} |
|
else if (pcap_file_header.linktype == DLT_IEEE802_11_RADIO) |
|
{ |
|
if (header.caplen < sizeof (ieee80211_radiotap_header_t)) |
|
{ |
|
fprintf (stderr, "%s: Could not read radiotap header\n", in); |
|
|
|
break; |
|
} |
|
|
|
ieee80211_radiotap_header_t *ieee80211_radiotap_header = (ieee80211_radiotap_header_t *) packet; |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
ieee80211_radiotap_header->it_len = byte_swap_16 (ieee80211_radiotap_header->it_len); |
|
ieee80211_radiotap_header->it_present = byte_swap_32 (ieee80211_radiotap_header->it_present); |
|
#endif |
|
|
|
if (ieee80211_radiotap_header->it_version != 0) |
|
{ |
|
fprintf (stderr, "%s: Invalid radiotap header\n", in); |
|
|
|
break; |
|
} |
|
|
|
packet_ptr += ieee80211_radiotap_header->it_len; |
|
header.caplen -= ieee80211_radiotap_header->it_len; |
|
header.len -= ieee80211_radiotap_header->it_len; |
|
} |
|
else if (pcap_file_header.linktype == DLT_IEEE802_11_PPI_HDR) |
|
{ |
|
if (header.caplen < sizeof (ppi_packet_header_t)) |
|
{ |
|
fprintf (stderr, "%s: Could not read ppi header\n", in); |
|
|
|
break; |
|
} |
|
|
|
ppi_packet_header_t *ppi_packet_header = (ppi_packet_header_t *) packet; |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
ppi_packet_header->pph_len = byte_swap_16 (ppi_packet_header->pph_len); |
|
#endif |
|
|
|
packet_ptr += ppi_packet_header->pph_len; |
|
header.caplen -= ppi_packet_header->pph_len; |
|
header.len -= ppi_packet_header->pph_len; |
|
} |
|
|
|
process_packet (packet_ptr, &header); |
|
} |
|
|
|
fclose (pcap); |
|
|
|
// inform the user |
|
|
|
printf ("Networks detected: %d\n", (int) essids_cnt); |
|
printf ("\n"); |
|
|
|
if (essids_cnt == 0) return 0; |
|
|
|
// prepare output files |
|
|
|
FILE *fp = fopen (out, "wb"); |
|
|
|
if (fp == NULL) |
|
{ |
|
fprintf (stderr, "%s: %s\n", out, strerror (errno)); |
|
|
|
return -1; |
|
} |
|
|
|
int written = 0; |
|
|
|
// find matching packets |
|
|
|
for (lsearch_cnt_t essids_pos = 0; essids_pos < essids_cnt; essids_pos++) |
|
{ |
|
const essid_t *essid = essids + essids_pos; |
|
|
|
if (essid_filter) if (strcmp (essid->essid, essid_filter)) continue; |
|
|
|
printf ("[*] BSSID=%02x:%02x:%02x:%02x:%02x:%02x ESSID=%s (Length: %d)\n", |
|
essid->bssid[0], |
|
essid->bssid[1], |
|
essid->bssid[2], |
|
essid->bssid[3], |
|
essid->bssid[4], |
|
essid->bssid[5], |
|
essid->essid, |
|
essid->essid_len); |
|
|
|
for (lsearch_cnt_t excpkt_ap_pos = 0; excpkt_ap_pos < excpkts_cnt; excpkt_ap_pos++) |
|
{ |
|
const excpkt_t *excpkt_ap = excpkts + excpkt_ap_pos; |
|
|
|
if ((excpkt_ap->excpkt_num != EXC_PKT_NUM_1) && (excpkt_ap->excpkt_num != EXC_PKT_NUM_3)) continue; |
|
|
|
if (memcmp (essid->bssid, excpkt_ap->mac_ap, 6) != 0) continue; |
|
|
|
for (lsearch_cnt_t excpkt_sta_pos = 0; excpkt_sta_pos < excpkts_cnt; excpkt_sta_pos++) |
|
{ |
|
const excpkt_t *excpkt_sta = excpkts + excpkt_sta_pos; |
|
|
|
if ((excpkt_sta->excpkt_num != EXC_PKT_NUM_2) && (excpkt_sta->excpkt_num != EXC_PKT_NUM_4)) continue; |
|
|
|
if (memcmp (excpkt_ap->mac_ap, excpkt_sta->mac_ap, 6) != 0) continue; |
|
if (memcmp (excpkt_ap->mac_sta, excpkt_sta->mac_sta, 6) != 0) continue; |
|
|
|
const bool valid_replay_counter = (excpkt_ap->replay_counter == excpkt_sta->replay_counter) ? true : false; |
|
|
|
if (excpkt_ap->excpkt_num < excpkt_sta->excpkt_num) |
|
{ |
|
if (excpkt_ap->tv_sec > excpkt_sta->tv_sec) continue; |
|
|
|
if ((excpkt_ap->tv_sec + EAPOL_TTL) < excpkt_sta->tv_sec) continue; |
|
} |
|
else |
|
{ |
|
if (excpkt_sta->tv_sec > excpkt_ap->tv_sec) continue; |
|
|
|
if ((excpkt_sta->tv_sec + EAPOL_TTL) < excpkt_ap->tv_sec) continue; |
|
} |
|
|
|
u8 message_pair = 255; |
|
|
|
if ((excpkt_ap->excpkt_num == EXC_PKT_NUM_1) && (excpkt_sta->excpkt_num == EXC_PKT_NUM_2)) |
|
{ |
|
if (excpkt_sta->eapol_len > 0) |
|
{ |
|
message_pair = MESSAGE_PAIR_M12E2; |
|
} |
|
else |
|
{ |
|
continue; |
|
} |
|
} |
|
else if ((excpkt_ap->excpkt_num == EXC_PKT_NUM_1) && (excpkt_sta->excpkt_num == EXC_PKT_NUM_4)) |
|
{ |
|
if (excpkt_sta->eapol_len > 0) |
|
{ |
|
message_pair = MESSAGE_PAIR_M14E4; |
|
} |
|
else |
|
{ |
|
continue; |
|
} |
|
} |
|
else if ((excpkt_ap->excpkt_num == EXC_PKT_NUM_3) && (excpkt_sta->excpkt_num == EXC_PKT_NUM_2)) |
|
{ |
|
if (excpkt_sta->eapol_len > 0) |
|
{ |
|
message_pair = MESSAGE_PAIR_M32E2; |
|
} |
|
else if (excpkt_ap->eapol_len > 0) |
|
{ |
|
message_pair = MESSAGE_PAIR_M32E3; |
|
} |
|
else |
|
{ |
|
continue; |
|
} |
|
} |
|
else if ((excpkt_ap->excpkt_num == EXC_PKT_NUM_3) && (excpkt_sta->excpkt_num == EXC_PKT_NUM_4)) |
|
{ |
|
if (excpkt_ap->eapol_len > 0) |
|
{ |
|
message_pair = MESSAGE_PAIR_M34E3; |
|
} |
|
else if (excpkt_sta->eapol_len > 0) |
|
{ |
|
message_pair = MESSAGE_PAIR_M34E4; |
|
} |
|
else |
|
{ |
|
continue; |
|
} |
|
} |
|
else |
|
{ |
|
fprintf (stderr, "BUG!!! AP:%d STA:%d\n", excpkt_ap->excpkt_num, excpkt_sta->excpkt_num); |
|
} |
|
|
|
int export = 1; |
|
|
|
switch (message_pair) |
|
{ |
|
case MESSAGE_PAIR_M32E3: export = 0; break; |
|
case MESSAGE_PAIR_M34E3: export = 0; break; |
|
} |
|
|
|
if (export == 1) |
|
{ |
|
printf (" --> STA=%02x:%02x:%02x:%02x:%02x:%02x, Message Pair=%u, Replay Counter=%" PRIu64 "\n", |
|
excpkt_sta->mac_sta[0], |
|
excpkt_sta->mac_sta[1], |
|
excpkt_sta->mac_sta[2], |
|
excpkt_sta->mac_sta[3], |
|
excpkt_sta->mac_sta[4], |
|
excpkt_sta->mac_sta[5], |
|
message_pair, |
|
excpkt_sta->replay_counter); |
|
} |
|
else |
|
{ |
|
printf (" --> STA=%02x:%02x:%02x:%02x:%02x:%02x, Message Pair=%u [Skipped Export]\n", |
|
excpkt_sta->mac_sta[0], |
|
excpkt_sta->mac_sta[1], |
|
excpkt_sta->mac_sta[2], |
|
excpkt_sta->mac_sta[3], |
|
excpkt_sta->mac_sta[4], |
|
excpkt_sta->mac_sta[5], |
|
message_pair); |
|
|
|
continue; |
|
} |
|
|
|
// finally, write hccapx |
|
|
|
hccapx_t hccapx; |
|
|
|
memset (&hccapx, 0, sizeof (hccapx)); |
|
|
|
hccapx.signature = HCCAPX_SIGNATURE; |
|
hccapx.version = HCCAPX_VERSION; |
|
|
|
hccapx.message_pair = message_pair; |
|
|
|
if (valid_replay_counter == false) |
|
{ |
|
hccapx.message_pair |= 0x80; |
|
} |
|
|
|
hccapx.essid_len = essid->essid_len; |
|
memcpy (&hccapx.essid, essid->essid, 32); |
|
|
|
memcpy (&hccapx.mac_ap, excpkt_ap->mac_ap, 6); |
|
memcpy (&hccapx.nonce_ap, excpkt_ap->nonce, 32); |
|
|
|
memcpy (&hccapx.mac_sta, excpkt_sta->mac_sta, 6); |
|
memcpy (&hccapx.nonce_sta, excpkt_sta->nonce, 32); |
|
|
|
if (excpkt_sta->eapol_len > 0) |
|
{ |
|
hccapx.keyver = excpkt_sta->keyver; |
|
memcpy (&hccapx.keymic, excpkt_sta->keymic, 16); |
|
|
|
hccapx.eapol_len = excpkt_sta->eapol_len; |
|
memcpy (&hccapx.eapol, excpkt_sta->eapol, 256); |
|
} |
|
else |
|
{ |
|
hccapx.keyver = excpkt_ap->keyver; |
|
memcpy (&hccapx.keymic, excpkt_ap->keymic, 16); |
|
|
|
hccapx.eapol_len = excpkt_ap->eapol_len; |
|
memcpy (&hccapx.eapol, excpkt_ap->eapol, 256); |
|
} |
|
|
|
#ifdef BIG_ENDIAN_HOST |
|
hccapx.signature = byte_swap_32 (hccapx.signature); |
|
hccapx.version = byte_swap_32 (hccapx.version); |
|
hccapx.eapol_len = byte_swap_16 (hccapx.eapol_len); |
|
#endif |
|
|
|
fwrite (&hccapx, sizeof (hccapx_t), 1, fp); |
|
|
|
written++; |
|
} |
|
} |
|
} |
|
|
|
printf ("\n"); |
|
printf ("Written %d WPA Handshakes to: %s\n", written, out); |
|
|
|
fclose (fp); |
|
|
|
// clean up |
|
|
|
free (excpkts); |
|
free (essids); |
|
|
|
return 0; |
|
} |