{
	"id": "67c51797-dc36-4f79-aaba-15ce45a3c3e4",
	"created_at": "2026-04-06T00:08:40.135226Z",
	"updated_at": "2026-04-10T03:22:06.259282Z",
	"deleted_at": null,
	"sha1_hash": "a30b04f8d160e9bc09c4326f533a797869b32d3a",
	"title": "Over The Air: Exploiting Broadcom’s Wi-Fi Stack (Part 1)",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 151647,
	"plain_text": "Over The Air: Exploiting Broadcom’s Wi-Fi Stack (Part 1)\r\nArchived: 2026-04-05 20:38:13 UTC\r\nPosted by Gal Beniamini, Project Zero\r\nIt’s a well understood fact that platform security is an integral part of the security of complex systems. For mobile\r\ndevices, this statement rings even truer; modern mobile platforms include multiple processing units, all\r\nelaborately communicating with one another. While the code running on the application processor (AP) has been\r\nthe subject of much research, other components have seldom received the same scrutiny.\r\nOver the years, as a result of the focused attention by security folk, the defenses of code running on the application\r\nprocessor have been reinforced. Taking Android as a case study, this includes hardening the operating system,\r\nimproving the security of applications, and introducing incremental security enhancements affecting the entire\r\nsystem. All positive improvements, no doubt. However, attackers tend to follow the path of least resistance.\r\nImproving the security of one component will inevitably cause some attackers to start looking elsewhere for an\r\neasier point of entry.\r\nIn this two-part blog series, we’ll explore the exposed attack surface introduced by Broadcom’s Wi-Fi SoC on\r\nmobile devices. Specifically, we’ll focus our attention on devices running Android, although a vast amount of this\r\nresearch applies to other systems including the same Wi-Fi SoCs. The first blog post will focus on exploring the\r\nWi-Fi SoC itself; we’ll discover and exploit vulnerabilities which will allow us to remotely gain code execution on\r\nthe chip. In the second blog post, we’ll further elevate our privileges from the SoC into the the operating system’s\r\nkernel. Chaining the two together, we’ll demonstrate full device takeover by Wi-Fi proximity alone, requiring no\r\nuser interaction.\r\nWe’ll focus on Broadcom’s Wi-Fi SoCs since they are the most common Wi-Fi chipset used on mobile devices. A\r\npartial list of devices which make use of this platform includes the Nexus 5, 6 and 6P, most Samsung flagship\r\ndevices, and all iPhones since the iPhone 4. For the purpose of this blog post, we’ll demonstrate a Wi-Fi remote\r\ncode execution exploit on a fully updated (at the time, now fixed) Nexus 6P, running Android 7.1.1 version\r\nNUF26K.\r\nAll the vulnerabilities in the post have been disclosed to Broadcom. Broadcom has been incredibly responsive and\r\nhelpful, both in fixing the vulnerabilities and making the fixes available to affected vendors. For a complete\r\ntimeline, see the bug tracker entries. They’ve also been very open to discussions relating to the security of the Wi-Fi SoC.\r\nI would like to thank Thomas Dullien (@halvarflake) for helping boot up the research, for the productive\r\nbrainstorming, and for helping search the literature for any relevant clues. I’d also like to thank my colleagues in\r\nthe London office for helping make sense of the exploitation constraints, and for listening to my ramblings.\r\nWhy-Fi?\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 1 of 19\n\nIn the past decade, the use of Wi-Fi has become commonplace on mobile devices. Gradually, Wi-Fi has evolved\r\ninto a formidable set of specifications—some detailing the physical layer, others focusing on the MAC layer. In\r\norder to deal with this increased complexity, vendors have started producing “FullMAC” Wi-Fi SoCs.\r\nIn essence, these are small SoCs that perform all the PHY, MAC and MAC SubLayer Management Entity\r\n(MLME) processing on their own, allowing the operating system to abstract itself away from the complex (and\r\nsometimes chip-specific) features related to Wi-Fi. The introduction of Wi-Fi FullMAC chips has also improved\r\nthe power consumption of mobile devices, since much of the processing is done on a low-power SoC instead of\r\nthe power-hungry application processor. Perhaps most importantly, FullMAC chips are much easier to integrate,\r\nas they implement the MLME within their firmware, reducing the complexity on the host’s side.\r\nAll that said and done, the introduction of Wi-Fi FullMAC chips does not come without a cost. Introducing these\r\nnew pieces of hardware, running proprietary and complex code bases, may weaken the overall security of the\r\ndevices and introduce vulnerabilities which could compromise the entire system.\r\nExploring the Platform\r\nTo start off our research, we’ll need to find some way to explore the Wi-Fi chip. Luckily, Cypress has recently\r\nacquired Broadcom’s Wireless IOT business, and have published many of the datasheets related to Broadcom’s\r\nWi-Fi chipsets (albeit for a slightly older SoC, the BCM4339). Reading through the datasheet, we gain some\r\ninsight into the hardware architecture behind the Wi-Fi chipset.\r\nSpecifically, we can see that there’s an ARM Cortex R4 core, which runs all the logic for handling and processing\r\nframes. Moreover, the datasheet reveals that the ARM core has 640KB of ROM used to hold the firmware’s code,\r\nand 768KB of RAM which is used for data processing (e.g., heap) and to store patches to firmware code.\r\nTo start analysing the code running on the ARM core, we’ll need to extract the contents of the ROM, and to locate\r\nthe data that is loaded into RAM.\r\nLet’s start by tackling the second problem first - where is the data that’s loaded into the ARM core’s RAM? Since\r\nthis data is not present in ROM, it must be loaded externally when the chip first powers on. Therefore, by reading\r\nthrough the initialisation code in the host’s driver, we should be able to locate the file containing the RAM’s\r\ncontents. Indeed, going over the driver’s code, we find the BCMDHD_FW_PATH config, which is used to denote\r\nthe location of the file whose contents are uploaded to RAM by the driver.\r\nSo what about the ROM’s contents? One way to extract the ROM would be to use the host driver’s chip memory\r\naccess capabilities (via PIO over SDIO or PCIe) to read the ROM’s contents directly. However, doing so would\r\nrequire modifying the driver to enable us to issue the commands needed to dump the ROM. Another way to\r\nretrieve the ROM would be to load our own modified firmware file into RAM, into which we’ll insert a small stub\r\nthat can be used to dump the ROM’s memory range. Luckily, none of these approaches is actually needed in this\r\ncase; Broadcom provides an extremely powerful command-line utility called dhdutil, which can be used to\r\ninteract with the chip via the bcmdhd driver.\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 2 of 19\n\nAmong the various capabilities this utility supports, it also allows us to directly read and write memory on the\r\ndongle by issuing a special command - “membytes”. Since we already know the size of the ROM (from the\r\ndatasheet), we can just use the membytes command to read the ROM’s contents directly. However, there’s one last\r\nquestion we need to answer first - where is the ROM located? According to the great research done by the folks\r\nbehind NexMon, the ROM is loaded at address 0x0, and the RAM is loaded at address 0x180000 (while NexMon\r\nfocused on BCM4339, this fact remains true for newer chips as well, such as the BCM4358).\r\nFinally, putting all this together, we can acquire the RAM’s contents from the firmware file, dump the ROM using\r\ndhdutil, and combine the two into a single file which we can then start analysing in IDA.\r\nAnalysing the Firmware\r\nDue to the relatively small size of the available memory (both ROM and RAM), Broadcom went to extreme\r\nefforts in order to conserve memory. For starters, they’ve stripped the symbols and most of the strings from the\r\nbinary. This has the added bonus of making it slightly more cumbersome to reverse-engineer the firmware’s code.\r\nThey’ve also opted for using the Thumb-2 instruction set exclusively, which allows for better code density. As a\r\nresult, the ROM image on the BCM4358 is so tightly packed that it contains less than 300 unused bytes.\r\nHowever, this is still not quite enough... Remember that the RAM has to accommodate the heap, stack and global\r\ndata structures, as well as all the patches or modifications to ROM functions. Quite a tall order for a measly\r\n768KB. To get around this, Broadcom has decided to place all the functions that are only used during the\r\nfirmware’s initialisation in two special regions. Once the initialisation is completed, these regions are “reclaimed”,\r\nand are thereafter converted into heap chunks.\r\nWhat’s more, heap chunks are interspersed between code and data structures in RAM - since the latter sometimes\r\nhave alignment requirements (or are referenced directly from ROM, so they cannot be moved). The end result is\r\nthat RAM is a jumbled mess of heap chunks, code and data structures.\r\nAfter spending some time analysing the firmware, we can begin identifying at least a few strings containing\r\nfunction names and other hints, helping us get a grasp of the code base. Additionally, the NexMon researchers\r\nhave released their gathered symbols corresponding to firmware on the BCM4339. We can apply the same\r\nsymbols to the BCM4339’s firmware, and then use bindiff to correlate the symbol names in newer firmware\r\nversions for more recent chips.\r\nLastly, there’s one more trick in our hat - Broadcom produces SoftMAC chips in addition to the FullMAC SoCs\r\nwe’re analysing. Since these SoftMAC chips don’t handle the MLME layer, their corresponding driver must\r\nperform that processing. As a result, much of Broadcom’s MLME processing code is included in the open-source\r\nSoftMAC driver - brcmsmac. While this won’t help us out with any of the chip-specific features or the more\r\ninternal processing code, it does seem to share many utility functions with the firmware’s code.\r\nHunting for Bugs\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 3 of 19\n\nNow that we have a grasp of the firmware’s structure and have the means to analyse it, we can finally start hunting\r\nfor bugs. But… Where should we start?\r\nEven with all the tricks mentioned before, this is a relatively large and opaque binary, and strings or symbols are\r\nfew and far between. One possibility would be to instrument the firmware in order to trace the code paths taken\r\nwhile a packet is received and processed. The Cortex R4 does, indeed, have debug registers which can be used to\r\nplace breakpoints and inspect the code flow at various locations. Alternately, we could manually locate a set of\r\nfunctions which are used to parse and retrieve information from a received frame, and work our way backwards\r\nfrom there.\r\nThis is where familiarity with Wi-Fi comes in handy; Wi-Fi management frames encode most of their information\r\nin small “tagged” chunks of data, called Information Elements (IEs). These tagged chunks of data are structured as\r\nTLVs, where the tag and length fields are a single byte long.\r\nSince a large portion of the information transferred in Wi-Fi frames (other than the data itself) is encoded using\r\nIEs, they make for good candidates from which we can work our way backwards. Moreover, as “tag” values are\r\nunique and standardised, we can use their values to help familiarise ourselves with the currently handled code\r\nflow.\r\nLooking at the brcmsmac driver, we can see that there’s a single function which Broadcom uses in order to extract\r\nIEs from a frame - bcm_parse_tlvs. After a brief search (by correlating hints from nearby strings), we find the\r\nsame function in the firmware’s ROM. Great.\r\nNow we can start cross-referencing locations which call this function, and reverse each of these call-sites. While\r\nsubstantially easier than reversing every part of the firmware, this still takes a considerable amount of time (as the\r\nfunction has more than 110 cross-references, some to other wrapper functions which themselves are called from\r\nmultiple locations).\r\nAfter reverse engineering all of the call sites, I’ve found a few vulnerabilities related to the handling of\r\ninformation elements embedded in management frames.\r\nTwo of the vulnerabilities can be triggered when connecting to networks supporting wireless roaming features;\r\n802.11r Fast BSS Transition (FT), or Cisco’s CCKM roaming. On the one side, these vulnerabilities should be\r\nrelatively straightforward to exploit - they are simple stack overflows. Moreover, the operating system running on\r\nthe firmware (HNDRTE) does not use stack cookies, so there’s no additional information leak or bypass required.\r\nHowever, while these vulnerabilities may be comfortable to exploit, they require some set-up to get working.\r\nFirst, we’d need to broadcast Wi-Fi networks that support these features. 802.11r FT is an open(-ish) standard, and\r\nis implemented by hostapd. In contrast, CCKM is a proprietary standard (although some information can be found\r\nonline). Figuring out how to emulate a CCKM network (or buying a CCKM-capable WLC from Cisco) would be\r\ncumbersome (or costly).\r\nAdditionally, we’d need to figure out which devices actually support the aforementioned features. Broadcom\r\nprovides many features which can be licensed by customers -- not all features are present on all devices (in fact,\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 4 of 19\n\ntheir corresponding patches probably wouldn’t even fit in RAM).\r\nLuckily, Broadcom makes it easy to distinguish which features are actually present in each firmware image. The\r\nlast few bytes in the RAM contents downloaded to the chip contain the firmware’s “version string”. This string\r\ncontains the date at which the firmware was compiled, the chip’s revision, the firmware’s version and a list of\r\ndash-delimited “tags”. Each tag represents a feature that is supported by the firmware image. For example, here’s\r\nthe version string from the Nexus 6P:\r\n4358a3-roml/pcie-ag-p2p-pno-aoe-pktfilter-keepalive-sr-mchan-pktctx-hostpp-lpc-pwropt-txbf-wl11u-mfp-betdls-amsdutx5g-txpwr-rcc-wepso-sarctrl-btcdyn-xorcsum-proxd-gscan-linkstat-ndoe-hs20sta-oobrev-hchk-logtrace-rmon-apf-d11status Version: 7.112.201.1 (r659325) CRC: 8c7aa795 Date: Tue 2016-09-13 15:05:58 PDT Ucode\r\nVer: 963.317 FWID: 01-ba83502b\r\nThe presence of the 802.11r FT feature is indicated by the “fbt” tag. Similarly, support for CCKM is indicated by\r\nthe “ccx” tag. Unfortunately, it seems that the Nexus 6P supports neither of these features. In fact, running a quick\r\nsearch for the “ccx” feature (CCKM support) on my own repository of Android firmware images revealed that this\r\nfeature is not supported on any Nexus device, but is supported on a wide variety of Samsung flagship devices, a\r\nvery partial list of which includes the Galaxy S7 (G930F, G930V), the Galaxy S7 Edge (G935F, G9350), the\r\nGalaxy S6 Edge (G925V) and many more.\r\nSo what about the other two vulnerabilities? Both of them relate to the implementation of Tunneled Direct Link\r\nSetup (TDLS). TDLS connections allow peers on a Wi-Fi network to exchange data between one another without\r\npassing it through the Access Point (AP), thus preventing congestion at the AP.\r\nSupport for TDLS in the firmware is indicated by the “betdls” and “tdls” tags. Searching through my firmware\r\nrepository I can see that the vast majority of devices do, indeed, support TDLS. This includes all recent Nexus\r\ndevices (Nexus 5, 6, 6P) and most Samsung flagships.\r\nWhat’s more, TDLS is specified as part of the 802.11z standard (requires IEEE subscription). Since all the\r\ninformation regarding TDLS is available, we could read the standard in order to gain familiarity with the relevant\r\ncode paths in Broadcom’s implementation. As an open standard, it is also supported by open-source supplicants,\r\nsuch as wpa_supplicant. As a result, we can inspect the implementation of the TDLS features in wpa_supplicant in\r\norder to further improve our understanding of the relevant code in the firmware.\r\nLastly, as we’ll see later on, triggering these two vulnerabilities can be done by any peer on the Wi-Fi network,\r\nwithout requiring any action on the part of the device being attacked (and with no indication that such an attack is\r\ntaking place). This makes these vulnerabilities all the more interesting to explore.\r\nIn any case, it seems like we’ve made our mind up! We’re going to exploit the TDLS vulnerabilities. Before we do\r\nso, however, let’s take a second to learn a little bit about TDLS, and the vulnerabilities discovered (skip this part it\r\nyou’re already familiar with TDLS).\r\n802.11z TDLS 101\r\nThere are many use cases where two peers on the same Wi-Fi network wish to transfer large swaths of data\r\nbetween one another. For example, casting a video from your mobile device to your Chromecast would require\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 5 of 19\n\nlarge amounts of data to be transmitted. In most cases, the Chromecast would be relatively nearby to the caster\r\n(after all, you’d probably be watching the screen to which you’re casting). Therefore, it would seem wasteful to\r\npass the entire data stream from the device to the AP, only to then pass it on to the Chromecast.\r\nIt’s not just the increased latency of adding an additional hop (the AP) that will degrade the connection’s quality.\r\nPassing such large amounts of data to the AP would also put a strain on the AP itself, cause congestion, and would\r\ndegrade the Wi-Fi connectivity for all peers on the network.\r\nThis is where TDLS comes into play. TDLS is meant to provide a means of peer-to-peer communication on a Wi-Fi network that is AP-independant.\r\nOver The Air\r\nLet’s start by familiarising ourselves with the structure of TDLS frames. As you may know, 802.11 frames use the\r\n“flags” field in order to indicate the “direction” in which a frame is travelling (from the client to the AP, AP to\r\nclient, etc.). TDLS traffic co-opts the use of the flag values indicating traffic in an Ad-Hoc (IBSS) network (To-DS=0, From-DS=0).\r\nNext, TDLS frames are identified by a special ethertype value - 0x890D. TDLS frames transmitted over Wi-Fi use\r\na constant value in the “payload type” field, indicating that the payload has the following structure:\r\nThe category for TDLS frames is also set to a constant value. This leaves us with only one field which\r\ndistinguishes between different TDLS frame types - the “action code”. This 1-byte field indicates the kind of\r\nTDLS frame we’re transmitting. This, in turn, controls the way in which the “payload” in interpreted by the\r\nreceiving end.\r\nHigh-Level Flow\r\nBefore two peers can establish a connection, they must first know about the existence of one another. This is\r\ncalled the “discovery” phase. A Wi-Fi client that wishes to discover TDLS-capable peers on the network, can do\r\nso by sending a “TDLS Discovery Request” frame to a peer. A TDLS-capable peer that receives this frame,\r\nresponds by sending a “TDLS Discovery Response” frame. The request and response are correlated to one another\r\nusing a 1-byte “dialog token”.\r\nNext, the peers may wish to set up a connection. To do so, they must perform a 3-way handshake. This handshake\r\nserves a dual purpose; first, it indicates that a connection is successfully established between the two peers.\r\nSecond, it’s used to derive the TDLS Peer Key (TPK), which secures the TDLS traffic between the peers.\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 6 of 19\n\nFinally, once the connection is created, the two peers can exchange peer traffic between one another. When one of\r\nthe peers wishes to tear-down the connection, they may do so by sending a “TDLS Teardown” frame. Upon\r\nreception of such a frame, the TDLS-peer will remove the connection and free up all the related resources.\r\nNow that we know enough about TDLS, let’s take a closer look at the vulnerabilities at hand!\r\nThe Primitives\r\nIn order to ensure the integrity of messages transferred during the setup and teardown phases, the corresponding\r\nTDLS frames include Message Integrity Codes (MIC). For the setup phase, once the second handshake message\r\n(M2) is received, the TPK can be derived by both parties. Using the TPK, the TDLS-initiator can calculate a MIC\r\nover the contents of the third handshake frame, which can then be verified by the TDLS-responder.\r\nSo how can we find these calculations in the firmware’s code? Well, as luck would have it, some strings referring\r\nto TDLS were left-over in the firmware’s ROM, allowing us to quickly home in on the relevant functions.\r\nAfter reverse-engineering much of the flow leading up to the processing of handling TDLS action frames, we\r\nfinally reach the function responsible for handling TDLS Setup Confirm (PMK M3) frames. The function first\r\nperforms some validations to ensure that the request is legitimate. It queries the internal data structures to ensure\r\nthat a TDLS connection is indeed being set up with the requesting peer. Then, it verifies the Link-ID IE (by\r\nchecking that its encoded BSSID matches that of the current network), and also verifies the 32-byte initiator nonce\r\n(“Snonce”) value (by comparing it to the stored initial nonce).\r\nOnce a certain degree of confidence is established that the request may indeed be legitimate, the function moves\r\non to call an internal helper function, tasked with calculating the MIC and ensuring that it matches the one\r\nencoded in the frame. Quite helpfully, the firmware also includes the name for this function\r\n(“wlc_tdls_cal_mic_chk”).\r\nAfter reverse-engineering the function, we arrive at the following approximate high-level logic:\r\n1.  uint8_t* buffer = malloc(256);\r\n2.  uint8_t* pos = buffer;\r\n3.  \r\n4.  //Copying the initial (static) information\r\n5.  uint8_t* linkid_ie = bcm_parse_tlvs(..., 101);\r\n6.  memcpy(pos, linkid_ie + 0x8, 0x6);  pos += 0x6;              //Initiator MAC\r\n7.  memcpy(pos, linkid_ie + 0xE, 0x6);  pos += 0x6;              //Responder MAC\r\n8.  *pos = transaction_seq;             pos++;                   //TransactionSeq\r\n9.  memcpy(pos, linkid_ie, 0x14);       pos += 0x14;             //LinkID-IE\r\n10.\r\n11. //Copying the RSN IE\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 7 of 19\n\n12. uint8_t* rsn_ie = bcm_parse_tlvs(..., 48);\r\n13. if (rsn_ie[1] + 2 + (pos - buffer) \u003e 0xFF) {\r\n14.     ... //Handle overflow\r\n15. }\r\n16. memcpy(pos, rsn_ie, rsn_ie[1] + 2); pos += rsn_ie[1] + 2;    //RSN-IE\r\n17.\r\n18. //Copying the remaining IEs\r\n19. uint8_t* timeout_ie = bcm_parse_tlvs(..., 56);\r\n20. uint8_t* ft_ie      = bcm_parse_tlvs(..., 55);\r\n21. memcpy(pos, timeout_ie, 0x7);       pos += 0x7;              //Timeout Interval IE\r\n22. memcpy(pos, ft_ie, 0x54);           pos += 0x54;             //Fast-Transition IE\r\nAs can be seen above, although the function verifies that the RSN IE’s length does not exceed the allocated\r\nbuffer’s length (line 13), it fails to verify that the subsequent IEs also do not overflow the buffer. As such, setting\r\nthe RSN IE’s length to a large value (e.g., such that rsn_ie[1] + 2 + (pos - buffer) == 0xFF) will cause the Timeout\r\nInterval and Fast Transition IEs to be copied out-of-bounds, overflowing the buffer.\r\n For example, assuming we set the length of the RSN IE (x) to its maximal possible value, 224, we arrive at the\r\nfollowing placements of elements:\r\nIn this diagram, orange fields are those which are “irrelevant” for the overflow, since they are positioned within\r\nthe buffer’s bounds. Red fields indicate values that cannot be fully controlled by us, and green fields indicate\r\nvalues which are fully controllable.\r\nFor example, the Timeout Interval IE is verified prior to the MIC’s calculation and only has a constrained set of\r\nallowed values, making it uncontrollable. Similarly, the FTIE’s tag and length fields are constant, and therefore\r\nnot controllable. Lastly, the 32-byte “Anonce” value is randomly chosen by the TDLS responder, placing it firmly\r\nout of our field of influence.\r\nBut the situation isn’t that grim. In fact, several of the fields in the FTIE itself can be arbitrarily chosen - for\r\nexample, the “Snonce” value is chosen by the TLDS-initiator during the first message in the handshake.\r\nMoreover, the “MIC Control” field in the FTIE can be freely chosen, since it is not verified prior to the execution\r\nof this function.\r\nIn any case, now that we’ve audited the MIC verification for the setup stage, let’s turn our sights towards the MIC\r\nverification during the teardown stage. Perhaps the code is similarly broken there? Taking a look at the MIC\r\ncalculation in the teardown stage (“wlc_tdls_cal_mic_chk”), we arrive at the following high-level logic:\r\n1.  uint8_t* buffer = malloc(256);\r\n2.  ...\r\n3.  uint8_t* linkid_ie = bcm_parse_tlvs(..., 101); //Link ID\r\n4.  memcpy(buffer, linkid_ie, 0x14);\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 8 of 19\n\n5.  ...\r\n6.  uint8_t* ft_ie = bcm_parse_tlvs(..., 55);\r\n7.  memcpy(buffer + 0x18, ft_ie, ft_ie[1] + 2);    //Fast-Transition IE\r\nAh-ha, so once again a straightforward overflow; the FT-IE’s length field is not verified to ensure that it doesn’t\r\nexceed the length of the allocated buffer. This means that simply by providing a crafted FT-IE, we can trigger the\r\noverflow. Nevertheless, once again there are several verifications prior to triggering the vulnerable code path\r\nwhich limit our control on the overflowing elements. Let’s try and plot the placement of elements during the\r\noverflow:\r\nThis seems much simpler - we don’t need to worry ourselves about the values stored in the FTIE that are verified\r\nprior to the overflow, since they’re all placed neatly within the buffer’s range. Instead, the attacker controlled\r\nportion is simply spare data that is not subject to any verification, and can therefore be freely chosen by us. That\r\nsaid, the overflow’s extent is quite limited - we can only overwrite at most 25 bytes beyond the range of the buffer.\r\nWriting an Exploit\r\nInvestigating the Heap State\r\nAt long last we have a grasp of the primitives at hand. Now, it’s time to test out whether our hypotheses match\r\nreality. To do so, we’ll need a testbed that’ll enable us to send crafted frames, triggering the overflows. Recall that\r\nwpa_supplicant is an open-source portable supplicant that fully supports TDLS. This makes it a prime candidate\r\nfor our research platform. We could use wpa_supplicant as a base on top of which we’ll craft our frames. That\r\nwould save us the need to re-implement all the logic entailed in setting up and maintaining a TDLS connection.\r\nTo test out the vulnerabilities, we’ll modify wpa_supplicant to allow us to send TDLS Teardown frames\r\ncontaining an overly-large FTIE. Going over wpa_supplicant’s code, we can quickly identify the function in\r\ncharge of generating and sending the teardown frame - wpa_tdls_send_teardown. By adding a few small changes\r\nto this function (in green) we should be able to trigger the overflow upon reception the teardown frame, causing\r\n25 bytes of 0xAB to be written OOB:\r\nstatic int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)\r\n{\r\n...\r\nftie = (struct wpa_tdls_ftie *) pos;\r\nftie-\u003eie_type = WLAN_EID_FAST_BSS_TRANSITION;\r\nftie-\u003eie_len = 255;\r\nos_memset(pos + 2, 0x00, ftie-\u003eie_len);\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 9 of 19\n\nos_memset(pos + ftie-\u003eie_len + 2 - 0x19, 0xAB, 0x19); //Overflowing with 0xAB\r\nos_memcpy(ftie-\u003eAnonce, peer-\u003ernonce, WPA_NONCE_LEN);\r\nos_memcpy(ftie-\u003eSnonce, peer-\u003einonce, WPA_NONCE_LEN);\r\npos += ftie-\u003eie_len + 2;\r\n...\r\n}\r\nNow we just need to interact with wpa_supplicant in order to setup and teardown a TDLS connection to our target\r\ndevice. Conveniently, wpa_supplicant supports many command interfaces, including a command-line utility called\r\nwpa_cli. This command line interface also supports several commands exposing TDLS functionality:\r\nTDLS_DISCOVER - Sends a “TDLS Discovery Request” frame and lists the response\r\nTDLS_SETUP - Creates a TDLS connection to the peer with the given MAC address\r\nTDLS_TEARDOWN - Tears down the TDLS connection to the peer with the given MAC\r\nIndeed, after compiling wpa_supplicant with TDLS support (CONFIG_TDLS), setting up a network, and\r\nconnecting our target device and our research platform to the network, we can see that issuing the\r\nTDLS_DISCOVER command works - we can indeed identify our peer.\r\nMoving on, we can now send a TDLS_SETUP command, followed by our crafted TDLS_TEARDOWN. If\r\neverything adds up correctly, this should trigger the overflow. However, this raises a slightly more subtle question\r\n- how will we know when the overflow occurs? It may just so happen that the data we’re overflowing is unused.\r\nAlternately, it may be the case that when the firmware crashes, it just silently starts up again, leaving us none the\r\nwiser.\r\nTo answer this fully, we’ll need to understand the logic behind Broadcom’s heap implementation. Digging into the\r\nallocator’s logic, we find that it is extremely straightforward; it is a simple “best-fit” allocator, which performs\r\nforward and backward coalescing, and keeps a singly linked list of free chunks. When chunks are allocated, they\r\nare carved from the end (highest address) of the best-fitting free chunk (smallest chunk that is large enough). Heap\r\nchunks have the following structure:\r\n(recall that the Cortex R4 is a 32-bit ARM processor, so all fields are stored in little-endian)\r\nBy reverse-engineering the allocator’s implementation, we can also find the location of the pointer to the head of\r\nthe first free-chunk in RAM. Combining these two facts together, we can create a utility which, given a dump of\r\nthe firmware’s RAM, can plot the current state of the heap’s freelist. Acquiring a snapshot of the firmware’s RAM\r\ncan be easily achieved by using dhdutil’s “upload” command.\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 10 of 19\n\nAfter writing a small visualiser script which walks over the heap’s freelist and exports the its contents into dot, we\r\ncan plot the state of the freelist using graphviz, like so:\r\nNow, we can send out crafted TDLS_TEARDOWN frame, immediately take a snapshot of the firmware’s RAM,\r\nand check the freelist for any signs of corruption:\r\nAh-ha! Indeed one of the chunks in the freelist suddenly has an exceptionally large size after tearing down the\r\nconnection. Recall that since the allocator uses “best-fit”, this means that subsequent allocations won’t be placed\r\nin this block as long as other large enough free chunks exist. This also means that the firmware did not crash, and\r\nin fact continued to function correctly. Had we not visualised the state of the heap, we wouldn’t have been able to\r\ndetermine anything had happened at all.\r\nIn any case, now that we’ve confirmed that the overflow does in fact occur, it’s time to move to the next stage of\r\nexploitation. We need less crude tools in order to allow us to monitor the state of the heap during the setup and\r\nteardown processes. To this end, it would be advantageous to hook the malloc and free functions in the firmware,\r\nand to trace their arguments and return values.\r\nFirst, we’ll need to write a “patcher”, which will allow us to insert hooks on given RAM-resident functions. It’s\r\nimportant to note that both the malloc and free functions are both present in RAM (they are among the first\r\nfunctions in the RAM’s code chunk). This allows us to freely re-write their prologues in order to introduce a\r\nbranch to our own code. I’ve written a patcher which performs insertion of such hooks, allowing execution of\r\nsmall assembly stubs before and after the invocation of the hooked function.\r\nIn short, the patcher is fairly standard - it writes the patch’s code to an unused region in RAM (the head of the\r\nlargest free chunk in the heap), and then inserts a Thumb-2 wide branch (which is, coincidentally, perhaps the\r\nugliest encoding for an opcode I’ve ever seen - see 4.6.12 T4) from the prologue of the hooked function to the\r\nhook itself.\r\nUsing our new patcher, we can now instrument the malloc and free functions in order to add traces allowing us to\r\nfollow every operation occurring on the heap. These traces can then be read from the firmware’s console buffer,\r\nby issuing dhdutil’s “consoledump” command. Note that on some newer chips, like the BCM4358 on the Nexus\r\n6P, this command fails. This is because Broadcom forgot to add the offset to the magic pointer in the firmware\r\npointing to the console’s data structure. You can fix this either by adding the correct offset to the driver (see\r\ndebug_info_ptrs), or by writing the magic value and pointer to one of the probed memory addresses in the list.\r\nIn any case, you can find both the malloc and free hooks, and the associated scripts needed to parse the traces\r\nfrom the firmware, here.\r\nUsing the newly acquired traces, we can write a better visualiser, allowing us to trace the state of the heap\r\nthroughout the setup and teardown phases. This visualiser will have visibility into every operation occurring on\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 11 of 19\n\nthe heap, offering far more granular data. I’ve written such a visualiser, which you can find here.\r\nWithout further ado, let’s take a look at heap activity while establishing a TDLS connection:\r\nThe vertical axis denotes time - each line is a new heap state after a malloc or free operation. The horizontal axis\r\ndenotes space - lower addresses are on the left, while higher addresses are on the right. Red blocks indicate chunks\r\nthat are in-use, grey blocks indicate free chunks.\r\nAs we can clearly see above, establishing a TDLS connection is a messy operation. There are many allocations\r\nand deallocations, for regions both large and small. This abundance of noise doesn’t bode well for us. Recall that\r\nthe overflow during the setup stage is highly constrained, both in terms of the data being written, and in terms of\r\nthe extent of the overflowing data. Moreover, the overflow occurs during one of the many allocations in the setup\r\nphase. This doesn’t allow us much control over the state of the heap prior to triggering the overflow.\r\nTaking a step back, however, we can observe a fairly surprising fact. Apart from the heap activity during the\r\nTDLS connection establishment, it seems like there is little to no activity on the heap whatsoever. In fact, it turns\r\nout that transmitted and received frames are drawn from a shared pool, instead of the heap. Not only that, but their\r\nprocessing doesn’t incur a single heap operation - everything is done “in-place”. Even when trying to intentionally\r\ncause allocations by sending random frames containing exotic bit combinations, the firmware’s heap remains\r\nlargely unaffected.\r\nThis is both a blessing and a curse. On the one hand, it means that the heap’s structure is highly consistent. In the\r\nseldom events that data structures are allocated, they are immediately freed thereafter, restoring the heap to its\r\noriginal state. On the other hand, it means that our degree of control over the heap’s structure is fairly limited. For\r\nthe most part, whatever structure the heap has after the firmware’s initialisation, is what we’re going to have to\r\nwork with (unless, of course, we find some primitive that will allow us to better shape the heap).\r\nPerhaps we should take a look at the teardown stage instead? Indeed, activating the traces during the TDLS\r\nteardown stage reveals that there are very few allocations prior to triggering the overflow, so it seems like a much\r\nmore convenient environment to explore.\r\nWhile these in-depth traces are useful for getting a high-level view of the heap’s state, they are rather difficult to\r\ndecipher. In fact, in most cases it’s sufficient to take a single snapshot of the heap and just visualise it, as we did\r\nearlier with the graphviz visualiser. In that case, let’s improve our previous heap visualiser by allowing it to\r\nproduce detailed graphical output, based on a single snapshot of the heap.\r\nAs we’ve seen earlier, we can “walk” over the freelist to extract the location and size of each free chunk.\r\nMoreover, we can deduce the location of in-use chunks by walking over the gaps between free chunks and reading\r\nthe “size” field from each in-use chunk. I’ve written yet another visualiser that does just that - it simply produces a\r\nvisualisation of the heap’s state from a series of “snapshot” images.\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 12 of 19\n\nUsing this visualiser, we can now take a look at the state of the heap after setting up a TDLS connection. This will\r\nbe the state of the heap we need to work with when we trigger the overflow during the teardown stage.\r\n(Upper Layer: initial heap state, Bottom Layer: heap state after creating a TDLS connection)\r\nWe can see that after setting up the TDLS connection, most of the heap’s used chunks are consecutive, but also\r\ntwo holes are formed; one of size 0x11C, and another of size 0x124. Activating the traces for the teardown stage,\r\nwe can see that the following allocations occur:\r\n(29) malloc - size: 284, caller: 1828bb, res: 1f0404\r\n(30) free - ptr: 1f0404\r\n(31) malloc - size: 20, caller: 18c811, res: 1f1654\r\n(32) malloc - size: 160, caller: 18c811, res: 1f0480\r\n(33) malloc - size: 8, caller: 80eb, res: 1f2a44\r\n(34) free - ptr: 1f2a44\r\n(35) free - ptr: 1f1654\r\n(36) free - ptr: 1f0480\r\n(37) malloc - size: 256, caller: 7aa15, res: 1f0420\r\n(38) malloc - size: 16, caller: 7aa23, res: 1f1658\r\nThe highlighted line denotes the allocation of the 256-byte buffer for the teardown frame’s MIC calculation, that\r\nsame one we can overflow using our vulnerability. Moreover, it seems as though the heap activity is quite low\r\nprior to sending the overflow frame. Combining the heap snapshot above with the trace file, we can deduce that\r\nthe best-fitting chunk for the 256-byte buffer is in the 0x11C-byte hole. This means that using our 25-byte\r\noverflow we’ll be able to overwrite:\r\n1. The header of the next in-use chunk\r\n2. A few bytes from the contents of the next in-use chunk\r\nLet’s take a closer look at the next in-use chunk and see whether there’s any interesting information that we’d like\r\nto overwrite there:\r\nAh, so the next chunk is mostly empty, save for a couple of pointers near its head. Are these pointers of any use to\r\nus? Perhaps they are written to? Or freed at a later stage? We can find out by manually corrupting these pointers\r\n(pointing them at invalid memory addresses, such as 0xCDCDCDCD), and instrumenting the firmware’s\r\nexception vector to see whether it crashes. Unfortunately, after many such attempts, it seems as though none of\r\nthese pointers are in fact used.\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 13 of 19\n\nThis leaves us, therefore, with a single possibility - corrupting the “size” field of the in-use chunk. Recall that\r\nonce the TDLS connection is torn down, the data structures relating to it are freed. Freeing an in-use chunk whose\r\nsize we’ve corrupted could have many interesting consequences. For starters, if we reduce the size of the chunk,\r\nwe can intentionally “leak” the tail end of the buffer, causing it to remain forever un-allocatable. Much more\r\ninterestingly, however, we could set the chunk’s size to a larger value, thereby causing the next free operation to\r\ncreate a free chunk whose tail end overlaps another heap chunk.\r\nOnce a free chunk overlaps another heap chunk, subsequent allocations for which the overlapping free chunk is\r\nthe best-fit will be carved from the end of the free chunk, thereby corrupting whatever fields reside at its tail.\r\nBefore we start scheming, however, we need to confirm that we can create such a state (i.e., an overlapping\r\nchunk), after the teardown operation completes.\r\nCreating an Overlapping Chunk\r\nRecall that the MIC check is just one of many operations that take place when a TDLS connection is torn down. It\r\nmay just so happen that by overwriting the next chunk’s size, once it is freed during the collection of the TDLS\r\nsession’s data structures, it may become the best-fit for subsequent allocations during the teardown process. These\r\nallocations may then cause additional unintended corruptions, which will either leave the heap in a non-consistent\r\nstate or even crash the firmware.\r\nHowever, the search space for possible sizes isn’t that large - assuming we’re only interested in chunk sizes that\r\nare not larger than the RAM itself (for obvious reasons), we can simply enumerate each of the heap states\r\nproduced by overwriting the “size” field of the next chunk with a given value and tearing down the connection.\r\nThis can be automated by using a script on the sending (to perform the enumeration), while concurrently acquiring\r\n“snapshots” of RAM on the device, and observing their state (whether or not they are consistent, and whether the\r\nfirmware managed to resume operation after the teardown).\r\nSpecifically, it would be highly advantageous if we were able to create a heap state whereby two free chunks\r\noverlap one another. In such a condition, allocations taken from one chunk, can be used to corrupt the “next”\r\npointer of the other free chunk. This could be used, perhaps, to control the location of subsequent allocations - an\r\ninteresting primitive in it’s own right.\r\nIn any case, after running through a few chunk sizes, tearing down the TDLS connection and observing the heap\r\nstate, we come across quite an interesting resulting state! By overwriting the “size” field with the value 72 and\r\ntearing down the connection, we achieve the following heap state:\r\nGreat! So after tearing down the connection, we are left with a zero-sized free chunk, overlapping a different\r\n(larger) free chunk! This means that once an allocation is carved from the large chunk, it will corrupt the “size”\r\nand “next” fields of the smaller chunk. This could prove very useful - we could try and point the next free chunk\r\nat a memory address whose contents we’d like to modify. As long as the data in that address conforms with the\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 14 of 19\n\nformat of a free chunk, we might be able to persuade the heap to overwrite the memory at that address with\r\nsubsequent allocations.\r\nFinding a Controlled Allocation\r\nTo start exploring these possibilities, we’ll first need to create a controlled allocation primitive, meaning we either\r\ncontrol the size of the allocation, or it’s contents, or (ideally) both. Recall that, as we’ve seen previously, it is in\r\nfact very hard to trigger allocations during the normal processing of the firmware - nearly all the processing is\r\ndone in-place. Moreover, even for cases where data is allocated, its lifespan is very short; memory is immediately\r\nreclaimed once it’s no longer used.\r\nBe that as it may, we’ve already seen at least one set of data structures whose lifetime is controllable, and which\r\ncontains multiple different pieces of information - the TDLS connection itself. The firmware must keep all the\r\ninformation pertaining to the TDLS connection as long as its active. Perhaps we could find some data structure\r\nrelating to TDLS which could act as a good candidate for a controlled allocation?\r\nTo search for one, let’s start by looking at the function handling each of the TDLS action frames -\r\nwlc_tdls_rcv_action_frame. The function starts by reading out the TDLS category and action code. Then, it routes\r\nthe frame to the appropriate handler function, according to the received action code:\r\nWe can see that apart from the regular, specification-defined action codes, the firmware also supports an out-of-spec frame with an action code of 127. Anything out-of-spec is automatically suspect, so that might be as good a\r\nplace as any to look for our primitive.\r\nIndeed, digging into this function, we find out that it performs a rather curious task. First, it verifies that the first 3\r\nbytes in the frame’s contents match the Wi-Fi alliance OUI (50:6F:9A). Then, it retrieves the fourth byte of the\r\nframe, and uses it as a “command code”. Currently, only two vendor-specific commands are implemented,\r\ncommands #4 and #5. On a high-level; command #4 is used to send a tunneled probe request over the TDLS\r\nconnection, and command #5 is used to send an “event” notification to the host, signalling that a “special” frame\r\nhas arrived.\r\nHowever, much more interestingly, we see that the implementation for command #4 seems relevant to our current\r\npursuit. First, it does not require the existence of a TDLS connection in order to be processed! This allows us to\r\nsend the frame even after tearing down the connection. Second, by activating heap traces during this function’s\r\nexecution and reverse-engineering its logic, we find that the function triggers the following high-level sequence of\r\nevents:\r\n1. if (A) { free(A); }\r\n2. A = malloc(received_frame_size);\r\n3. memcpy(A, received_frame, received_frame_size);\r\n4. B = malloc(788);\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 15 of 19\n\n5. free(B)\r\n6. C = malloc(284);\r\n7. free(C);\r\nGreat! So we get an allocation (A) with a controlled lifetime, a controlled size and controlled contents! What more\r\ncould we possibly ask for?\r\nThere is one tiny snag, however. Modifying wpa_supplicant to send this crafted TDLS frame results in a\r\nresounding failure. While wpa_supplicant allows us to fully control many of the fields in the TDLS frames, it is\r\nonly a supplicant, not an MLME implementation. This means that the corresponding MLME layer is responsible\r\nfor composing and sending the actual TDLS frames.\r\nOn the setup I’m using for the attack platform, I have a laptop running Ubuntu 16.04, and a TP-Link TL-WN722N\r\ndongle. The dongle is a SoftMAC configuration, so the MLME layer in play is the one present in the Linux kernel,\r\nnamely, the “cfg80211” configuration layer.\r\nWhen wpa_supplicant wishes to create and send TDLS frames, it does so by sending special requests over\r\nNetlink, which are then handled by the cfg80211 framework, and subsequently passed to the SoftMAC layer,\r\n“mac80211”. Regrettably, however, mac80211 is unable to process the special vendor frames, and simply rejects\r\nthem. Nonetheless, this is just a minor inconvenience - I’ve written a few patches to mac80211 which add support\r\nfor these special vendor frames. After applying these patches, re-compiling and booting the kernel, we are now\r\nable to send our crafted frames.\r\nTo allow for easier control over the vendor frames, I’ve also added support for a new command within\r\nwpa_supplicant’s CLI - “TDLS_VNDR”. This command allows us to send a crafted TDLS vendor frame with\r\narbitrary data to any MAC address (regardless of whether a TDLS connection is established to that peer).\r\nPutting It All Together\r\nAfter creating two overlapping chunks, we can now use our controlled allocation primitive to allocate memory\r\nfrom the tail of the larger chunk, thereby pointing the smaller free chunk at a location of our choosing. Whichever\r\nlocation we choose, however, must have valid values for both the  “size” and “next” fields, otherwise later calls to\r\nmalloc and free may fail, possibly crashing the firmware. As a matter of fact, we’ve already seen perfect\r\ncandidates to stand-in for free chunks - in-use chunks!\r\nRecall that in-use chunks specify their size field at the same location free chunks do theirs. As for the “next”\r\npointer, it is unused in free chunks, but is set to zero during the allocation of the chunk. This means that by\r\ncorrupting the free list to point at an in-use chunk, we can trick the heap into thinking it’s just another free chunk,\r\nwhich is coincidentally also the last chunk in the freelist. That’s comfortable.\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 16 of 19\n\nNow all we need to do is find an in-use chunk containing information that we’d like to overwrite. If we make that\r\nchunk the best-fitting chunk in the free list for a subsequent controlled allocation, we’ll get our own data to be\r\nallocated there instead of the in-use chunk’s data, effectively replacing the chunk’s contents. This means we’re\r\nable to arbitrarily replace the contents of any in-use chunk.\r\nAs we’re interested in achieving full code execution, it would be advantageous to locate and overwrite a function\r\npointer in the heap. But… Where can we expect to find such values on the heap? Well, for starters, there are some\r\nevents in the Wi-Fi standards that must be handled periodically, such as performing scans for adjacent networks. It\r\nwould probably be a safe bet to assume that the firmware supports handling such periodic timers by using a\r\ncommon API.\r\nSince timers may be created during the firmware’s operation, their data structures (e.g., which function to execute\r\nand when) must be stored on the heap. To locate these timers, we can reverse-engineer the IRQ vector table entry,\r\nand search for the logic corresponding to handling a timer interrupt. After doing so, we find a linked list of entries\r\nwhose contents seem to conform to that of brcms_timer structure, used in the brcmsmac (SoftMAC) driver. After\r\nwriting a short script, we can dump the list of timers given a RAM snapshot:\r\nWe can see that the timer list is ordered by the timeout value, and most of the timers have a relatively short\r\ntimeout. Moreover, all the timers are allocated during the firmware’s initialisation, and are therefore stored at\r\nconstant addresses. This is important since, if we’d like to target our free chunk at a timer, we’d need to know it’s\r\nexact location in memory.\r\nSo all that’s left is to use our two primitives to replace the contents of one of the timers above with our own data,\r\nconsequently pointing the timer’s function at an address of our choosing.\r\nHere’s the game plan. First, we’ll use the techniques described above to create two overlapping free chunks. Now,\r\nwe can use the controlled allocation primitive to point the smaller free chunk at one of the timers in the list above.\r\nNext, we create another controlled allocation (freeing the old one). This one will be of size 0x3C, for which the\r\ntimer chunk is the best-fitting. Therefore, at this point, we’ll overwrite the timer’s contents.\r\nBut which function do we point our timer to? Well, we can use the same trick to commandeer another in-use\r\nchunk on the heap, and overwrite its contents with our own shellcode. After briefly searching the heap, we come\r\nacross a large chunk which simply contains console data during the chip’s boot sequence, and is then left allocated\r\nbut unused. Not only is the allocation is fairly large (0x400 bytes), but it is also placed at a constant address (since\r\nit is allocated during the firmware’s initialisation sequence) - perfect for our exploit.\r\nLastly, how can we be sure that the contents of the heap is even executable? After all, the ARM Cortex R4 has a\r\nMemory Protection Unit (MPU). Unlike an MMU, it does not allow for the facilitation of a virtual address space,\r\nbut it does allow control over the access permissions of different memory ranges in RAM. Using the MPU, the\r\nheap could (and should) be marked as RW and non-executable.\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 17 of 19\n\nBy reversing the firmware’s initialisation routines in the binary, we can see that the MPU is indeed being activated\r\nduring boot. But what are the contents with which it’s configured? We can find out by writing a small assembly\r\nstub to dump out the contents of the MPU:\r\n0x00000000 - 0x10000000\r\nAP: 3 - Full access\r\nXN: 0\r\n0x10000000 - 0x20000000\r\nAP: 3 - Full access\r\nXN: 0\r\n0x20000000 - 0x40000000\r\nAP: 3 - Full access\r\nXN: 0\r\n0x40000000 - 0x80000000\r\nAP: 3 - Full access\r\nXN: 0\r\n0x80000000 - 0x100000000\r\nAP: 3 - Full access\r\nXN: 0\r\nAh-ha - while the MPU is initialised, it is effectively set to mark all of memory as RWX, making it useless. This\r\nsaves us some hassle… We can conveniently execute our code directly from the heap.\r\nSo, at long last, we have an exploit ready! Putting it all together we can now hijack a code chunk to store our\r\nshellcode, then hijack a timer to point it at our stored shellcode. Once the timer expires, our code will be executed\r\non the firmware!\r\nAt long last, we’ve gone through the entire process of researching the platform, discovering a vulnerability and\r\nwriting a full-fledged exploit. Although this post is relatively long, there are many smaller details that I left out in\r\nfavour of brevity. If you have any specific questions, please let me know. You can find the full exploit, including\r\ninstructions, here. The exploit includes a relatively benign shellcode, which simply writes a magic value to\r\naddress 0x200000 in the firmware’s RAM, signalling successful execution.\r\nWrapping Up\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 18 of 19\n\nWe’ve seen that while the firmware implementation on the Wi-Fi SoC is incredibly complex, it still lags behind in\r\nterms of security. Specifically, it lacks all basic exploit mitigations - including stack cookies, safe unlinking and\r\naccess permission protection (by means of an MPU).\r\nBroadcom have informed me that newer versions of the SoC utilise the MPU, along with several additional\r\nhardware security mechanisms. This is an interesting development and a step in the right direction. They are also\r\nconsidering implementing exploit mitigations in future firmware versions.\r\nIn the next blog post, we’ll see how we can use our assumed control of the Wi-Fi SoC in order to further escalate\r\nour privileges into the application processor, taking over the host’s operating system!\r\nSource: https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nhttps://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html\r\nPage 19 of 19",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html"
	],
	"report_names": [
		"over-air-exploiting-broadcoms-wi-fi_4.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775434120,
	"ts_updated_at": 1775791326,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/a30b04f8d160e9bc09c4326f533a797869b32d3a.pdf",
		"text": "https://archive.orkl.eu/a30b04f8d160e9bc09c4326f533a797869b32d3a.txt",
		"img": "https://archive.orkl.eu/a30b04f8d160e9bc09c4326f533a797869b32d3a.jpg"
	}
}