/* This file is part of AirSnort. AirSnort 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. AirSnort 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 AirSnort; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* 4/17/02 - Orinoco's now handle beacons properly thanks to monitor mode patch fix by johnp@chem... */ #include #include #include #include #include #include #include #include #include #include #include #include #include "capture.h" #include "crack.h" #include "bssidlist.h" #include #ifndef SIOCIWFIRSTPRIV #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE #endif #define P80211_IFREQ (SIOCIWFIRSTPRIV + 1) #define ADDR1(x) ((x)+4) #define ADDR2(x) ((x)+10) #define ADDR3(x) ((x)+16) //PROTOTYPES void quick_message(char *title, char *message); void initCapRecs(CaptureRec *cr, PacketInfo *pi); void dump(unsigned char *pkt, int len); int do_ioctl(unsigned char *userMsg); void setPointers(CaptureRec *cr, const unsigned char *pkt); void changeChannel(int x); int resetMAC(void); extern int scan; extern int chan; extern int doCapture; extern int logfile; extern int readPcapFile; extern int oldscan; extern int cardType; extern int breadth40; extern int breadth128; extern char cmd[80]; char dev[WLAN_DEVNAMELEN_MAX] = "wlan0"; int count = 0; int lasttime = 0; //initialize pointers according to TO_DS, //FROM_DS flags. This saves time during packet decoding void setPointers(CaptureRec *cr, const unsigned char *pkt) { cr->iv = pkt + 24; switch (pkt[1] & 0x03) { case 0: //STA to STA, or management and control cr->bssid = ADDR3(pkt); cr->sta = ADDR2(pkt); break; case 2: //AP to STA data cr->bssid = ADDR2(pkt); cr->sta = ADDR1(pkt); break; case 3: //AP to AP cr->iv += 6; case 1: //STA to AP data cr->bssid = ADDR1(pkt); cr->sta = ADDR2(pkt); break; } } void dump(unsigned char *pkt, int len) { int i = 0; int j = 0; for (i = 0; i < len; i += 16) { for (j = 0; j < 16; j++) { if (i + j >= len) { fprintf(stdout, " "); } else { fprintf(stdout, "%2.2x ", pkt[i + j]); } } fprintf(stdout, " "); for (j = 0; j < 16; j++) { if (i + j >= len) break; if (isprint(pkt[i + j])) { fprintf(stdout, "%c", pkt[i + j]); } else { fprintf(stdout, "."); } } fprintf(stdout, "\n"); } fprintf(stdout, "\n----------------------------------------------------------------\n\n"); } //the thread function for the packet capture thread. It opens a packet //source and collects packets until instructed to stop. Packets are //parsed for interesting info and placed on the packet queue for consumption //by the cracking thread void *capture(void *arg) { CaptureArg *parms = (CaptureArg*) arg; int namelen, whichType, channelLoc, isData, crclen; PacketInfo pi; CaptureRec cap; BssidList *apNode = NULL; const unsigned char *pkt; unsigned char fc0 = 0, type = 0, subType = 0; struct pcap_pkthdr pktHdr; cap.pInfo = π while (doCapture) { pi.pack = NULL; pi.name = NULL; pi.wep = 0; apNode = NULL; isData = 0; //this method of cycling through the channels is not the greatest //but it gets the job done. I would rather see it cycle at a fixed //interval like 0.1 seconds pkt = pcap_next(parms->pcap, &pktHdr); if (pkt == NULL) { if (parms->dump) break; //reached end of file continue; } if (parms->dump) { pcap_dump((unsigned char*)parms->dump, &pktHdr, pkt); } //test for prism2 appended dummy crc crclen = memcmp(pkt + pktHdr.len - 4, "\0xFF\0xFF\0xFF\0xFF", 4) ? 0 : 4; pi.channel = -1; pkt += parms->offset; pi.raw = pkt; whichType = pkt[1] & 0x03; setPointers(&cap, pkt); fc0 = pkt[0]; type = fc0 & 0x0C; subType = (fc0 >> 4); switch (type) { case 0: //management if ((subType == 5) || (subType == 8)) { //beacon or probe response frame namelen = pkt[37]; apNode = bssidFind(pkt + 16); //ADDR3 if (apNode) { if (apNode->name) { if (subType == 8) { //don't take name more than once from a beacon break; } free(apNode->name); } apNode->name = (char*) malloc(namelen + 1); strncpy(apNode->name, pkt + 38, namelen); (apNode->name)[namelen] = 0; break; } //might want to check elementid at pkt[36] == 0 as well pi.name = (char*) malloc(namelen + 1); strncpy(pi.name, pkt + 38, namelen); pi.name[namelen] = 0; channelLoc = 38 + namelen + 2; channelLoc += pkt[channelLoc - 1]; if (pkt[channelLoc] == 3) { pi.channel = pkt[channelLoc + 2]; } pi.wep = pkt[34] & 0x10; } break; case 0x04: //control //break; continue; case 0x08: if (subType != 0) break; //not a data frame isData = 1; pktHdr.len -= whichType == 3 ? (parms->offset + 30 + crclen) : (parms->offset + 24 + crclen); //adjust len to size of frame body //this is a sloppy way to detect unencrypted packets, but since 0xAA is not //an IV byte of interest anyway, its probably not a big deal if (*((unsigned short *)cap.iv) != 0xAAAA || (pkt[1] & 0x40)) { pi.wep = 1; if (isResolved(cap.iv)) { pi.pack = (Packet*) malloc(sizeof(Packet)); pi.pack->len = pktHdr.len; //i.e. 802.11b "Frame Body" pi.pack->buf = (unsigned char*) malloc(pktHdr.len); memcpy(pi.pack->buf, cap.iv, pktHdr.len); pi.pack->next = NULL; } } } //switch addPacket(apNode, &cap, isData); } resetMAC(); if (parms->dump) { pcap_dump_close(parms->dump); } pcap_close(parms->pcap); free(parms); if (readPcapFile) { readPcapFile = 0; scan = oldscan; } pthread_exit(NULL); } void changeChannel(int x) { if (doCapture && scan) { chan = (chan % 11) + 1; setChannel(chan); } } /* * The setChannel function was lifted from the wlanctl source file: * *src/wlanctl/wlanctl.c * * user utility for the wlan card * * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. * -------------------------------------------------------------------- * * linux-wlan * linux-wlan 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. linux-wlan 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 linux-wlan; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * -------------------------------------------------------------------- * * Inquiries regarding the linux-wlan Open Source project can be * made directly to: * * AbsoluteValue Systems Inc. * info@linux-wlan.com * http://www.linux-wlan.com * * -------------------------------------------------------------------- */ /* * Set the NIC into promiscuous mode on the indicated channel * This code was distilled from wlanctl.c which is part of * the linux-wlan-ng package. This is the only wlanctl functionality * needed in airsnort, so I put it here rather than shelling out * to invoke wlanctl-ng every time I wanted to change channels. CSE. */ #define MAKE_SYS_CALL /* * as opposed to making ioctl calls directly. We can make ioctls * directly if we can tie into the linux-wlan-ng header files */ int setChannel( unsigned char channel ) { int result = 0; int fd; struct iwreq ireq; //for Orinoco int *ptr; if (cardType == ORINOCO) { //assumes patched pcmcia-cs-3.1.31 and using orinoco_cs /* get a socket */ fd = socket(AF_INET, SOCK_STREAM, 0); if ( fd == -1 ) { return -1; } ptr = (int *) ireq.u.name; ptr[0] = 1; ptr[1] = chan; strcpy(ireq.ifr_ifrn.ifrn_name, dev); result = ioctl( fd, SIOCIWFIRSTPRIV + 0x8, &ireq); close(fd); } else if (cardType == PRISM) { #ifndef MAKE_SYS_CALL p80211msg_lnxreq_wlansniff_t sniff; memset(&sniff, 0, sizeof(p80211msg_lnxreq_wlansniff_t)); sniff.msgcode = DIDmsg_lnxreq_wlansniff; sniff.msglen = sizeof(p80211msg_lnxreq_wlansniff_t); strcpy((char*) sniff.devname, dev); sniff.enable.did = DIDmsg_lnxreq_wlansniff_enable; sniff.enable.len = 4; sniff.enable.status = 0; sniff.enable.data = P80211ENUM_truth_true; sniff.channel.did = DIDmsg_lnxreq_wlansniff_channel; sniff.channel.len = 4; sniff.channel.status = 0; sniff.channel.data = channel; sniff.prismheader.did = DIDmsg_lnxreq_wlansniff_prismheader; sniff.prismheader.len = 4; sniff.prismheader.status = 0; sniff.prismheader.data = P80211ENUM_truth_true; sniff.keepwepflags.did = DIDmsg_lnxreq_wlansniff_keepwepflags; sniff.keepwepflags.len = 4; sniff.keepwepflags.status = 0; sniff.keepwepflags.data = P80211ENUM_truth_true; sniff.resultcode.did = DIDmsg_lnxreq_wlansniff_resultcode; sniff.resultcode.status = P80211ENUM_msgitem_status_no_value; sniff.resultcode.len = 4; result = do_ioctl((uint8_t*) &sniff); #else char cmd[128]; static char *parms = "keepwepflags=false prismheader=true"; sprintf(cmd, "wlanctl-ng %s lnxreq_wlansniff enable=true channel=%d %s > /dev/null", dev, channel, parms); result = system(cmd); #endif } return result; } int resetMAC() { int result = 0; int fd; struct iwreq ireq; //for Orinoco int *ptr; if (cardType == ORINOCO) { //assumes patched pcmcia-cs-3.1.31 and using orinoco_cs /* get a socket */ fd = socket(AF_INET, SOCK_STREAM, 0); if ( fd == -1 ) { return -1; } ptr = (int *) ireq.u.name; ptr[0] = 0; ptr[1] = 0; strcpy(ireq.ifr_ifrn.ifrn_name, dev); result = ioctl( fd, SIOCIWFIRSTPRIV + 0x8, &ireq); close(fd); } else if (cardType == PRISM) { #ifndef MAKE_SYS_CALL p80211msg_lnxreq_wlansniff_t sniff; memset(&sniff, 0, sizeof(p80211msg_lnxreq_wlansniff_t)); sniff.msgcode = DIDmsg_lnxreq_wlansniff; sniff.msglen = sizeof(p80211msg_lnxreq_wlansniff_t); strcpy((char*) sniff.devname, dev); sniff.enable.did = DIDmsg_lnxreq_wlansniff_enable; sniff.enable.len = 4; sniff.enable.data = P80211ENUM_truth_false; sniff.channel.did = DIDmsg_lnxreq_wlansniff_channel; sniff.channel.status = P80211ENUM_msgitem_status_no_value; sniff.channel.len = 4; sniff.resultcode.did = DIDmsg_lnxreq_wlansniff_resultcode; sniff.resultcode.status = P80211ENUM_msgitem_status_no_value; sniff.resultcode.len = 4; result = do_ioctl((uint8_t*) &sniff); #else char cmd[80]; sprintf(cmd, "wlanctl-ng %s lnxreq_wlansniff enable=false > /dev/null", dev); result = system(cmd); #endif } return result; } int do_ioctl( unsigned char *userMsg ) { int result = -1; int fd; p80211ioctl_req_t req; p80211msg_t *msg = (p80211msg_t *) userMsg; strcpy(msg->devname, dev); /* set the magic */ req.magic = P80211_IOCTL_MAGIC; /* get a socket */ fd = socket(AF_INET, SOCK_STREAM, 0); if ( fd == -1 ) { return result; } req.len = msg->msglen; req.data = msg; strcpy( req.name, dev); req.result = 0; result = ioctl( fd, P80211_IFREQ, &req); close(fd); return result; } //load user settings from $HOME/.airsnortrc void loadOpts() { char *home = getenv("HOME"); char rcfile[128]; FILE *rc; char *index; int r; if (home) { sprintf(rcfile, "%s/.airsnortrc", home); rc = fopen(rcfile, "r"); if (rc) { while (fgets(rcfile, 128, rc)) { index = strchr(rcfile, '\n'); if (index) *index = 0; index = strchr(rcfile, ':'); if (index) { *index = 0; if (!strcmp(rcfile, "dev")) { strncpy(dev, index + 1, WLAN_DEVNAMELEN_MAX); dev[WLAN_DEVNAMELEN_MAX - 1] = 0; } else if (!strcmp(rcfile, "driver")) { r = atoi(index + 1); cardType = r < 0 || r > 2 ? 0 : r; } else if (!strcmp(rcfile, "breadth128")) { r = atoi(index + 1); breadth128 = r < 1 || r > 20 ? 1 : r; } else if (!strcmp(rcfile, "breadth40")) { r = atoi(index + 1); breadth40 = r < 1 || r > 20 ? 1 : r; } else if (!strcmp(rcfile, "channel")) { r = atoi(index + 1); chan = r < 1 || r > 11 ? 6 : r; } } } fclose(rc); } } } //save user settings to $HOME/.airsnortrc void saveOpts() { char *home = getenv("HOME"); char rcfile[128]; FILE *rc; if (home) { sprintf(rcfile, "%s/.airsnortrc", home); rc = fopen(rcfile, "w"); if (rc) { fprintf(rc, "dev:%s\n", dev); fprintf(rc, "driver:%d\n", cardType); fprintf(rc, "breadth128:%d\n", breadth128); fprintf(rc, "breadth40:%d\n", breadth40); fprintf(rc, "channel:%d\n", chan); fclose(rc); } } }