Broadcom produces Wi-Fi HardMAC SoCs which are used to handle the PHY and MAC layer processing. These chips are present in both mobile devices and Wi-Fi routers, and are capable of handling many Wi-Fi related events without delegating to the host OS.
In order to allow fast roaming between access points in a wireless network, the Broadcom firmware supports the Fast BSS Transition feature (IEEE 802.11r-2008 FT) as well as the Radio Resource Management standard (IEEE 802.11k-2008 RRM). Much of the information related to RRM is transferred by means of Wi-Fi Action Frames, using the RRM category (5).
One such frame which is handled by Broadcom's firmware is the "RRM Neighbor Report Response" frame, which has following general structure:
-----------------------------------------------------------------------
| Category (5) | Action (5) | Dialog Token | Neighbor Report Elements |
-----------------------------------------------------------------------
0 1 2 3 X
(See 802.11-2016, 9.6.7.7, 9.4.2.37 for more information).
On the BCM4355C0 SoC with firmware version 9.44.78.27.0.1.56 the RRM Neighbor Report Response frame is handled by RAM function 0x1B0FE8 (which delegates to ROM function 0xABBBC). This function verifies the dialog token (although that is a single byte field, so it can be easily brute-forced by an attacker if they do not know it in advance). Then, the function copies over the contents of the Neighbor Report Response frame into a heap-allocated buffer and subsequently calls an internal ROM function at 0xAC0A8 to store the number of neighbors for each given "Operating Class" (see 9.4.2.37).
Here is the approximate high-level logic for this function:
int function_AC0A8(..., uint8_t* nrrep_buffer, ...) {
...
//Find and increment neighbor in given channel for given OP-Class
int res = function_AC07C(..., nrrep_buffer, ...);
//If there's no entry for the given OP-Class, create and populate it
if (!res) {
uint8_t* buffer = malloc(456);
if ( !buffer ) {
...
}
else {
buffer[4] = nrrep_buffer[16]; //Operational Class
uint8_t channel_number = nrrep_buffer[17]; //Channel Number
uint16_t* chan_neighbor_count_arr = (uint16_t*)(buffer + 6);
chan_neighbor_count_arr[channel_number]++;
...
}
}
...
}
As shown in the snippet above, the firmware keeps a linked list of buffers, one per "Operational Class". Each buffer is 456 byte long, and keeps the array holding the number of neighbors per channel. The entries have the following structure:
-----------------------------------------------------------------------
| Next Pointer | Operational Channel | Padding | Neighbor Count Array |
-----------------------------------------------------------------------
0 4 5 6 456
However, since the "Channel Number" field is not validated, an attacker can arbitrarily provide a large value. While the maximal allowed channel number is 0xE0, by providing a larger value (such as 0xFF), the function above will increment a 16-bit word beyond the bounds of the heap-allocated buffer, thereby performing an OOB write. Note that the same insufficient validation is also present in the internal function 0xAC07C.
I've been able to verify that this code path exists on various different firmware versions, including those present on the iPhone 7 and Galaxy S7 Edge.
Attaching exploit for this issue. The exploit gains code execution on the Wi-Fi firmware on the iPhone 7. The password for the archive is "rrm_exploit".
The exploit has been tested against the Wi-Fi firmware as present on iOS 10.2 (14C92), but should work on all versions of iOS up to 10.3.3 (included). However, some symbols might need to be adjusted for different versions of iOS, see "exploit/symbols.py" for more information.
Upon successful execution of the exploit, a backdoor is inserted into the firmware, allowing remote read/write commands to be issued to the firmware via crafted action frames (thus allowing easy remote control over the Wi-Fi chip).
The attached archive contains the following directories:
-hostapd-2.6 - A modified version of hostapd utilised in the exploit. This version of hostapd is configured to
support 802.11k RRM, and in particular Neighbor Reports. Moreover, this version of hostapd is
instrumented to add various commands, allowing injection and reception of crafted action frames
used throughout the exploit.
-exploit - The exploit itself.
To run the exploit, you must execute the following steps:
-Connect (and enable) a SoftMAC Wi-Fi dongle to your machine (such as the TL-WN722N)
-Compile the provided version of hostapd
-Modify the "interface" setting under "hostapd-2.6/hostapd/hostapd.conf" to match your interface's name
-Configure the following settings under "exploit/conf.py":
-HOSTAPD_DIR - The directory of the hostapd binary compiled above
-TARGET_MAC - The MAC address of the device being exploited
-AP_MAC - The MAC address of your wireless dongle
-INTERFACE - The name of the wireless dongle's interface
-Assemble the backdoor shellcode by running "exploit/assemble_backdoor.sh"
-Run hostapd with the configuration file provided above, broadcasting a Wi-Fi network ("test80211k")
-Connect the target device to the network
-Run "exploit/attack.py"
Following the steps above should result in installation of a simple backdoor allowing read/write access to the firmware. You can interact with the backdoor to gain R/W access to the firmware by calling the "read_dword" and "write_dword" functions, respectively.
Exploit RRM.zip:
https://bugs.chromium.org/p/project-zero/issues/detail?id=1289#c3