this time, we encountered cases where due to the brainbending logic
in this code reaver thought we were associated when we weren't -
in fact, we didnt even get an auth reply.
some or all 5 GHz APs do not set tagged data for channel information.
since later on there's a check if channel == get_channel, this caused
wash to not print anything at all.
the code could be improved by getting the channel from the radiotap
header, but parsing that is rather complex, so we leave it for another
opportunity.
loosely based on a patch by @wiire-a
in reaver and plain wash mode, we display a hardcoded OUI vendor string,
while in wash's json mode we print the raw hex value. this makes it
possible for 3rd party scripts to flexibly extend their functionality
without waiting for us to add a new string, ship a new version, etc,
should a new/previously not added OUI show up.
the new field in json mode is called "vendor_oui".
This reverts commit b35ec10ceed45003f29f27eb60c6e7194e302297.
json mode displays raw data, it is the tool processing the data which
may format it (or not).
Tag version (0x104a) is always set to 1.0 (0x10) for backwards
compatibility. Version 2.x is included in subelement Version2 (0x0)
inside the WFA Vendor Extension attribute (0x1049).
the display of those values was missing from the debug output of
the old version of wpa_supplicant code embedded in reaver.
new code taken from the exact same spots in wpa_supplicant 2.5.
usage of -N causes the internal state machine of wpa_supplicant code
to detect irregularities and precludes the processing of those
nonces.
additionally, we need to prevent early exit when the authenticator code
fails.
this is a fixup for the previous commit[0], which was made in a hurry and
actually only prints junk from the stack when it should print E-Snonce2.
[0]: acf77b84c18aa03cdc9cbecf44a6677f7778f71e
i encountered an AP of type
"wps_manufacturer" : "TP-LINK",
"wps_model_name" : "TL-MR3220",
"wps_model_number" : "1.0",
"wps_device_name" : "Wireless N 3G Router TL-MR3220"
which would not respond to probe requests sent by wash, but responded
immediately to "iw wlan0 scan". so i added some tags that most
standard clients usually send, and voila, it works now.
it stands to reason that wash should by default send only broadcast
probe requests, in order to keep a more stealthy profile.
as such, also the WPS tag should be emitted, since it is typically
not sent.
while debugging connectivity issues with RALINK chipset, i was quite
baffled to see that just after we got associated, reaver would,
after it printed "Sending EAPOL START request", deauthenticate,
authenticate, and associate immediately again. according to the
comments in the source, the first association is only made
"to check if the association works at all", whereas the second
reassociation cycle is done from inside the main pin-bruteforce loop,
with a comment saying that by not doing this the AP would rate-limit
us.
after commenting out one of the 2 blocks, i could suddenly send
successul EAP initialization, whereas it failed all the time before.
i think the reason is that because the RALINK drivers duplicates all
packets it sends several times, doing the second iteration of the
reassociation cycle leads to delayed deauthentication packets sent
and being received by the AP just after it received the EAPOL start
packet.
while i am sure that this gratuitous reassociation needs to be fixed,
i am in doubt if the correct fix would not actually be to remove the
reassociation from inside the bruteforce loop, but leave the initial
association intact, although since there's a delay between each
iteration of the bruteforce loop, it shouldn't have the same
disastrous effect of doing the association all over again.
if it turns out to still be problematic, one might even consider
adding a small delay to after the reassocation finished, so any
spurious packet retransmissions get absorbed by the target AP
before the EAPOL start packet is being sent.
when using RALINK adapters, after a successful attack, one got just:
[+] Received M7 message
[+] Sending WSC NACK
[+] Sending WSC NACK
[+] Pin cracked in 51 seconds
[+] WPS PIN: ''
[*] String pin was specified, nothing to save.
but the WPA PSK was always missing.
the cause was that the internal state machine of the wpa supplicant
code denied processing the M7 data due to a mismatching state, which
was revealed by enabling the internal debug output of the wpa code:
WPS: Received M1
WPS: UUID-E - ...
...
WPS: M1 Processed
...
WPS: Building Message M2
...
WPS: Received M1
WPS: Unexpected state (15) for receiving M1
...
WPS: Received M3
WPS: Unexpected state (12) for receiving M3
...
WPS: Received M5
WPS: Unexpected state (12) for receiving M5
WPS: WPS_CONTINUE, Freeing Last Message
WPS: WPS_CONTINUE, Saving Last Message
WPS: returning
[+] Received M5 message
WPS: Processing received message (len=120 op_code=4)
WPS: Received WSC_MSG
WPS: attr type=0x104a len=1
WPS: attr type=0x1022 len=1
WPS: attr type=0x1039 len=16
WPS: attr type=0x1018 len=64
WPS: attr type=0x1049 len=6
WPS: Unsupported attribute type 0x1049 len=6
WPS: attr type=0x1005 len=8
WPS: Parsed WSC_MSG
WPS: Received M5
WPS: Unexpected state (12) for receiving M5
WPS: WPS_CONTINUE, Freeing Last Message
WPS: WPS_CONTINUE, Saving Last Message
WPS: returning
[+] Received M5 message
WPS: Processing received message (len=216 op_code=4)
WPS: Received WSC_MSG
WPS: attr type=0x104a len=1
WPS: attr type=0x1022 len=1
WPS: attr type=0x1039 len=16
WPS: attr type=0x1018 len=160
WPS: attr type=0x1049 len=6
WPS: Unsupported attribute type 0x1049 len=6
WPS: attr type=0x1005 len=8
WPS: Parsed WSC_MSG
WPS: Received M7
WPS: Unexpected state (12) for receiving M7
WPS: WPS_CONTINUE, Freeing Last Message
WPS: WPS_CONTINUE, Saving Last Message
WPS: returning
[+] Received M7 message
WPS: Building Message WSC_NACK
WPS: * Version
WPS: * Message Type (14)
WPS: * Enrollee Nonce
WPS: * Registrar Nonce
WPS: * Configuration Error (0)
[+] Sending WSC NACK
WPS: Building Message WSC_NACK
WPS: * Version
WPS: * Message Type (14)
WPS: * Enrollee Nonce
WPS: * Registrar Nonce
WPS: * Configuration Error (0)
[+] Sending WSC NACK
[+] Pin cracked in 2 seconds
[+] WPS PIN: ''
[+] Nothing done, nothing to save.
WPS: Full PIN information revealed and negotiation failed
WPS: Invalidated PIN for UUID ...
the key point here is:
"Unexpected state (12) for receiving M7".
12 equals SEND_WSC_NACK, while RECV_M7 state (expected) equals 19.
notice that we got a similar message for all M5's too:
WPS: Unexpected state (12) for receiving M5
but for some reason the state machine went forward anyway.
for our purposes, it is sufficient to just comment out all POST-M7
checks, since we only care about getting the WPA-PSK.
in the long term, it would be advisable to find out what's causing
the wrong expected state with ralink drivers though, since it might
lead to suboptimal behaviour elsewhere too (it may be related to
usage of -N switch, without which RALINK is entirely unusable to
begin with).
a router of type TP-LINK TL-WA850RE sent as model number "2.0\x0d"
which had weird effects on the json string printed in the terminal.
any of those strings need to be sanitized, as a malicious AP could
include terminal escape sequences in its strings and so cause remote
code execution on the pentester's terminal.
recent versions of pixiewps don't require the bytes to be separated by colon
anymore. having the command shorter makes it easier to copy/paste it again
into the shell.
with bad connections, it would happen very often that tries was equal
to MAX_AUTH_TRIES when the ASSOC_OK response was received; but due to
the bad comparison the result would be dismissed and association started
all over again.
previously, some spots used pcap_inject(), while others used send_packet().
since send_packet() does slightly more (it starts some timer) then
pcap_inject, i added a boolean switch to indicate whether the use of
this timer is desired. this way the behaviour doesn't change.
if it turns out later that the timer can safely be used from all callsites,
we can remove the additional parameter again.
This reverts commit a543ff7bce87ac738788f2045ab4bca26189e8c0.
the commit was done in a hurry, and the info displayed messes up stdout
in some scenarios.
reaver used to send a hardcoded extended rate list, and some APs
would reject such an association request with the following error
set (from wireshark):
Status code: Association denied due to requesting STA not
supporting all of the data rates in the BSSBasicRateSet
parameter (0x0012)
fix it by saving the extended rate parameters the AP sends in the
beacon.
for compatibility with POSIX getopt, the recently introduced -j
option which doesn't take an argument, should be grouped together
with the other non-option arguments, since on the first occurence
of such an argument, it will consider all following arguments
non-option arguments too. this could be an issue with alternative
libc implementations.
the mode is meant to be piped into a helper program processing the
json data.
just outputting the plain json data has several advantages over the
previous -x (exec a script per line of json) mode.
1) the helper script must be only started once, instead of once
per line.
2) there's no special case code needed to print the header, you
can just naturally print it on the start of the script.
3) can be combined easily with other command line tools like grep.
4) to get to the raw json output with -x you'd have to use a
dedicated script with the old approach.
a script might want to reorder fields in a custom way, so we call
the script once with `--header` as first command line argument,
and it's supposed to detect that and print the header.
example python script, mimicking the default output of wash, while
printing additional WPS info in a second line:
import json, sys
if sys.argv[1] == '--header':
print "BSSID Ch dBm WPS Lck ESSID"
print "==========================================="
sys.exit(0)
fc = json.loads(open(sys.argv[1], 'r').read())
def field(fieldname):
global fc
return fc[fieldname] if fieldname in fc else ''
def lock_string(lv):
ls = {0: 'No ', 1 : 'Yes', 2: 'No '}
return ls[lv] if lv in ls else 'No '
def wpsver(v):
return '' if v is '' else "%d.%d" % (v >> 4, v & 0xf)
s = ''
s += "%s " %field("bssid")
s += "%2d " %field("channel")
s += "%.2d " %field("rssi")
s += "%3s " %wpsver(field("wps_version"))
s += "%3s " %lock_string(field("wps_locked"))
s += "%.32s " %field("essid")
s2 = ''
s2 += "%s " %field("wps_manufacturer")
s2 += "%s " %field("wps_model_name")
s2 += "%s " %field("wps_model_number")
s2 += "%s " %field("wps_device_name")
s2 += "%s" %field("wps_serial")
print s
if s2.strip() != '': print " " + s2
this option allows to call a user-provided script, which gets
passed a filename containing all the WPS information we got from
a probe response.
example scripts to use:
1) output_everything.sh
#!/bin/sh
cat "$1"
2) output a specific field via python: manufacturer.py
#!/usr/bin/env python
import json, sys
fc = json.loads(open(sys.argv[1], 'r').read())
print "manufacturer :" + fc['wps_manufacturer']
in order to use, chmod +x the script and run like:
$ ./wash -f capture.pcap -x ./manufacturer.py