Exploit-DB #41805
Description: Broadcom Wi-Fi SoC - TDLS Teardown Request Remote Heap Overflow
Type: remote
Platform: hardware
Date: 2017-04-04
Author: Google Security Research

Exploit:
Source:
https://bugs.chromium.org/p/project-zero/issues/detail?id=1046
https://googleprojectzero.blogspot.ca/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html

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.

One of the events handled by the BCM firmware is the processing of TDLS connections (802.11z). TDLS connections allow clients to exchange data between one another without passing it through the AP (thus preventing congestion at the AP).

In order to verify the integrity of TDLS messages, each message exchanged between the TDLS peers includes a message integrity code (MIC). The MIC is calculated using AES-CMAC with a key derived during the setup process (TPK-KCK).

When a TDLS Teardown Request frame is sent by either one of the peers in an established TDLS connection, the receiving client must verify the MIC before processing the request. The MIC for TDLS teardown requests is calculated as follows:

AES-CMAC(TPK-KCK, LinkID-IE || ReasonCode || DialogToken || TransactionSeq || FastTransition-IE)

(see "wpa_tdls_key_mic_teardown" under https://w1.fi/cgit/hostap/plain/src/rsn_supp/tdls.c)

It should be noted that all TDLS connections are accepted automatically from any peer and are handled solely by the BCM firmware (meaning there is no need for user interaction or involvement in any way - once a TDLS Setup Request is received by the firmware, it will proceed with the TDLS handshake and subsequently create a TDLS connection with the requesting peer).

When the BCM firmware receives a TDLS Teardown frame, it first verifies the Link-ID information element in order to make sure it matches the current link information. Then, if the Link ID is valid, it calls the "wlc_tdls_cal_teardown_mic_chk" function in order to verify the MIC of the request. The function starts by extracting the Fast Transition IE information element (FTIE - number 55). Then, if the IE is present, its contents are copied into a heap-allocated buffer of length 256. The copy is performed using the length field present in the IE, and at a fixed offset from the buffer's start address. Since the length of the FTIE is not verified prior to the copy, this allows an attacker to include a large FTIE (e.g., with a length field of 255), causing the memcpy to overflow the heap-allocated buffer.

Here's the high-level logic of the "wlc_tdls_cal_teardown_mic_chk" function:

uint8_t* buffer = malloc(256);
...
uint8_t* linkid_ie = bcm_parse_tlvs(..., 101);
memcpy(buffer, linkid_ie, 0x14);
...
uint8_t* ft_ie = bcm_parse_tlvs(..., 55);
memcpy(buf + 0x18, ft_ie, ft_ie[1] + 2);

(Note that each IE is a TLV; the tag and value fields are each a single byte long. Therefore, ft_ie[1] is the IE's length field).

It should also be noted that the heap implementation used in the BCM firmware does not perform safe unlinking or include heap header cookies, allowing heap overflows such as the one described above to be exploited more reliably.

I'm attaching a patch to wpa_supplicant 2.6 which modifies the TDLS Teardown frame sent by the supplicant in order to trigger the heap overflow. You can reproduce the issue by following these steps:

  1. Download wpa_supplicant 2.6 from https://w1.fi/releases/wpa_supplicant-2.6.tar.gz
  2. Apply the included patch file
  3. Build wpa_supplicant (with TDLS support)
  4. Use wpa_supplicant to connect to a network
  5. Connect to wpa_cli:
    5.1. Setup a TDLS connection to the BCM peer using "TDLS_SETUP <MAC_ADDRESS_OF_PEER>"
    5.2. Teardown the connection using "TDLS_TEARDOWN <MAC_ADDRESS_OF_PEER>"

(Where MAC_ADDRESS_OF_PEER is the MAC address of a peer with a BCM SoC which is associated to the same network).

At this point the heap overflow will be triggered. The code in the patch will corrupt the heap, causing the remote BCM SoC to reset after a while.

I've been able to verify this vulnerability on the BCM4339 chip, running version 6.37.34.40 (as present on the Nexus 5). However, I believe this vulnerability's scope includes a wider range of Broadcom SoCs and versions.

patch 

################################################################################

Attaching exploit - running exploit.py results in arbitrary code-execution on the Wi-Fi dongle.

Here is a high-level overview of the exploit:

  1. Create a TDLS connection to the target device
  2. Teardown the connection using a crafted "TDLS Teardown Request" frame, triggering the overflow
  3. Create a new TDLS connection, using crafted arguments causing a situation where two chunks in
     the freelist overlap one another
  4. Send a TDLS frame with action code 127
    4.1. Craft the size of the TDLS frame s.t. it overlaps the other chunk in the freelist
    4.2. Craft the contents in order to point the free chunk to the location of a periodic timer
         which was created during the firmware's initialization
  5. Send another TDLS frame with action code 127
    5.1. Craft the size of the TDLS frame s.t. it will be placed on top of the timer object
    5.2. Craft the contents in order to replace the timer's data structures, allowing us to point
         the timer's handler function at any arbitrary address. In this case, we point the handler
         function at an address near the heap's end
  6. Send a large TDLS frame with action code 127
    6.1. Craft the frame's contents so that it contains the shellcode we'd like to execute
  7. Since the heap is zero-initialized, and "00 00" is NOP (MOVS R0,R0) in Thumb, this means that
     jumping to a location slightly before our created code chunk is fine, as it won't cause any
     adverse affects until we reach our code blob. Putting all this together, Once the timer
     expires, our code chunk is executed on the firmwar