Tuesday, April 11, 2017

Over The Air: Exploiting Broadcom’s Wi-Fi Stack (Part 2)

Posted by Gal Beniamini, Project Zero

In this blog post we'll continue our journey into gaining remote kernel code execution, by means of Wi-Fi communication alone. Having previously developed a remote code execution exploit giving us control over Broadcom’s Wi-Fi SoC, we are now left with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task of exploiting this vantage point in order to furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r elevate our privileges into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel.

progress (2).png

In this post, we’ll explore two distinct avenues for attacking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host operating system. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first part, we’ll discover and exploit vulnerabilities in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 communication protocols between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi firmware and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host, resulting in code execution within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. Along cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way, we’ll also observe a curious vulnerability which persisted until quite recently, using which attackers were able to directly attack cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internal communication protocols without having to exploit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first place! In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second part, we’ll explore hardware design choices allowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC in its current configuration to fully control cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host without requiring a vulnerability in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first place.

While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerabilities discussed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first part have been disclosed to Broadcom and are now fixed, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 utilisation of hardware components remains as it is, and is currently not mitigated against. We hope that by publishing this research, mobile SoC manufacturers and driver vendors will be encouraged to create more secure designs, allowing a better degree of separation between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 application processor.

Part 1 - The “Hard” Way

The Communication Channel


As we’ve established in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous blog post, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi firmware produced by Broadcom is a FullMAC implementation. As such, it’s responsible for handling much of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 complexity required for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation of 802.11 standards (including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 majority of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MLME layer).

Yet, while many of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operations are encapsulated within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip’s firmware, some degree of control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi state machine is required within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s operating system. Certain events cannot be handled solely by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC, and must cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore be communicated to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s operating system. For example, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host must be notified of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 results of a Wi-Fi scan in order to be able to present this information to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user.

In order to facilitate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se cases where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC wish to communicate with one anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, a special communication channel is required.

However, recall that Broadcom produces a wide range of Wi-Fi SoCs, which may be connected to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host via many different interfaces (including USB, SDIO or even PCIe). This means that relying on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying communication interface might require re-implementing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shared communication protocol for each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 supported channels -- quite a tedious task.

interfaces.png

Perhaps cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s an easier way? Well, one thing we can always be certain of is that regardless of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 communication channel used, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip must be able to transmit received frames back to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. Indeed, perhaps for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very same reason, Broadcom chose to piggyback on top of this channel in order to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 communication channel between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SoC and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host.

When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware wishes to notify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host of an event, it does so by simply encoding a “special” frame and transmitting it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. These frames are marked by a “unique” Ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rType value of 0x886C. They do not contain actual received data, but racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r encapsulate information about firmware events which must be handled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s driver.

ethertype (1).png

Securing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Channel


Now, let’s switch over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s side. On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver can logically be divided into several layers. The lower layers deal with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 communication interface itself (such as SDIO, PCIe, etc.) and whatever transmission protocol may be tied to it. The higher layers cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n deal with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reception of frames, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir subsequent processing (if necessary).
driver layers.png

First, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 upper layers perform some initial processing on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 received frames, such as removing encapsulated data which may have been added on-top of it (for example, transmission power indicators added by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PHY module). Then, an important distinction must be made - is this a regular frame that should be simply forwarded to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relevant network interface, or is it in fact an encoded event that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host must handle?

As we’ve just seen, this distinction is easily made! Just take a look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype and check whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r it has cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “special” value of 0x886C. If so, handle cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encapsulated event and discard cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 frame.

Or is it?

In fact, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is no guarantee that this ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype is unused in every single network and by every single device. Incidentally, it seems that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very same ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype is used for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 LARQ protocol used in HPNA chips (initially developed by Epigram, and subsequently purchased by Broadcom).

Regardless of this little oddity - this brings us to our first question: how can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC and host driver distinguish between externally received frames with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 0x886C ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype (which should be forwarded to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 network interface), and internally generated event frames (which should not be received from external sources)?

This is a crucial question; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internal event channel, as we’ll see shortly, is extremely powerful and provides a huge, mostly unaudited, attack surface. If attackers are able to inject frames over-cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365-air that can subsequently be processed as event frames by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y may very well be able to achieve code execution within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s operating system.

Well… Until several months prior to this research (mid 2016), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware made no effort to filter cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se frames. Any frame received as part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data RX-path, regardless of its ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype, was simply forwarded blindly to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. As a result, attackers were able to remotely send frames containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special 0x886C ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype, which were cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n processed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver as if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y were event frames created by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware itself!

So how was this issue addressed? After all, we’ve already established that just filtering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype itself is not sufficient. Observing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 differences between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pre- and post- patched versions of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware reveals cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 answer: Broadcom went for a combined patch, targeting both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC’s firmware and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s driver.

The patch adds a validation method (is_wlc_event_frame) both to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware’s RX path, and to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver. On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip’s  side, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 validation method is called immediately before transmitting a received frame to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 validation method deems cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 frame to be an event frame, it is discarded. Ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 frame is forwarded to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver. Then, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exact same verification method on received frames with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 0x886C ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype, and processes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m only if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y pass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same validation method. Here is a short schematic detailing this flow:

rxflow (2).png

As long as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 validation methods in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware remain identical, externally received frames cannot be processed as events by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver. So far so good.

However… Since we already have code-execution on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC, we can simply “revert” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch. All it takes is for us to “patch out” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 validation method in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365reby causing any received frame to once again be forwarded blindly to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. This, in turn, allows us to inject arbitrary messages into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 communication protocol between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip. Moreover, since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 validation method is stored in RAM, and all of RAM is marked as RWX, this is as simple as writing “MOV R0, #0; BX LR” to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function’s prologue.

patchrxflow.png

The Attack Surface


As we mentioned earlier, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack surface exposed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internal communication channel is huge. Tracing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 control flow from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entry point for handling event frames (dhd_wl_host_event), we can see that several events receive “special treatment”, and are processed independently (see wl_host_event and wl_show_host_event). Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial treatment is done, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 frames are inserted into a queue. Events are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n dequeued by a kernel thread whose sole purpose is to read events from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 queue and dispatch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir corresponding handler function. This correlation is done by using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event’s internal “event-type” field as an index into an array of handler functions, called evt_handler.

handler_queue (1).png

While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are up to 144 different supported event codes, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host driver for Android, bcmdhd, only supports a much smaller subset of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se. Nonecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365less, about 35 events are supported within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver, each including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own elaborate handlers.

Now that we’re convinced that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack surface is large enough, we can start hunting for bugs! Unfortunately, it seems like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip is considered as “trusted”; as a result, some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 validations in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s driver are insufficient… Indeed, auditing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relevant handler functions and auxiliary protocol handlers outlined above, we find a substantial number of vulnerabilities.

The Vulnerability


Taking a closer look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerabilities we’ve found, we can see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y all differ from one anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r slightly. Some allow for relatively strong primitives, some weaker. However, most importantly, many of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m have various preconditions which must be fulfilled to successfully trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m; some are limited to certain physical interfaces, while ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs work only in certain configurations of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver. Nonecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365less, one vulnerability seems to be present in all versions of bcmdhd and in all configurations - if we can successfully exploit it, we should be set.

Let’s take a closer look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event frame in question. Events of type "WLC_E_PFN_SWC" are used to indicate that a “Significant Wi-Fi Change” (SWC) has occurred within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware and must be handled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. Instead of directly handling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se events, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s driver simply gacá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transferred data from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware, and broadcasts a “vendor event” packet via Netlink to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cfg80211 layer.

More concretely, each SWC event frame transmitted by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware contains an array of events (of type wl_pfn_significant_net_t), a total count (total_count), and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number of events in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 array (pkt_count). Since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 total number of events can be quite large, it might not fit in a single frame (i.e., it might be larger than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 maximal MSDU). In this case, multiple SWC event frames can be sent consecutively - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir internal data will be accumulated by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver until cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 total count is reached, at which point cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver will process cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire list of events.
swc.png

Reading through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver’s code, we can see that when this event code is received, an initial handler is triggered in order to deal with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event. The handler cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n internally calls into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 "dhd_handle_swc_evt" function in order to process cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event's data. Let’s take a closer look:

1.  void* dhd_handle_swc_evt(dhd_pub_t *dhd,const void *event_data,int *send_evt_bytes)
2.  {
3.   ...
4.   wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data;
5.   ...
6.   gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
7.   params = &(gscan_params->param_significant);
8.   ...
9.   if (!params->results_rxed_so_far) {
10.      if (!params->change_array) {
11.          params->change_array = (wl_pfn_significant_net_t *)
12.                                  kmalloc(sizeof(wl_pfn_significant_net_t) *
13.                                          results->total_count, GFP_KERNEL);
14.          ...
15.      }
16.  }
17.  ...
18.  change_array = &params->change_array[params->results_rxed_so_far];
19.  memcpy(change_array,
20.         results->list,
21.         sizeof(wl_pfn_significant_net_t) * results->pkt_count);
22.  params->results_rxed_so_far += results->pkt_count;
23.  ...
24. }

(where "event_data" is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arbitrary data encapsulated in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event passed in from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware)

As we can see above, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function first allocates an array to hold cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 total count of events (if one hasn’t been allocated before) and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n proceeds to concatenate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 encapsulated data starting from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 appropriate index (results_rxed_so_far) in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer.

However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handler fails to verify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relation between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 total_count and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pkt_count! It simply “trusts” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 assertion that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 total_count is sufficiently large to store all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 subsequent events passed in. As a result, an attacker with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to inject arbitrary event frames can specify a small total_count and a larger pkt_count, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365reby triggering a simple kernel heap overflow.

Remote Kernel Heap Shaping


This is all well and good, but how can we leverage this primitive from a remote vantage point? As we’re not locally present on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device, we’re unable to gacá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r any data about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current state of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap, nor do we have address-space related information (unless, of course, we’re able to somehow leak this information). Many classic exploits targeting kernel heap overflows rely on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to shape cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s heap, ensuring a certain state prior to triggering an overflow - an ability we also lack at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 moment.

What do we know about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocator itself? There are a few possible underlying implementations for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kmalloc allocator (SLAB, SLUB, SLOB), configurable when building cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. However, on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vast majority of devices, kmalloc uses “SLUB” - an unqueued “slab allocator” with per-CPU caches.

Each “slab” is simply a small region from which identically-sized allocations are carved. The first chunk in each slab contains its metadata (such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slab’s freelist), and subsequent blocks contain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocations cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365mselves, with no inline metadata. There are a number of predefined slab size-classes which are used by kmalloc, typically spanning from as little as 64 bytes, to around 8KB. Unsurprisingly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocator uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best-fitting slab (smallest slab that is large enough) for each allocation. Lastly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slabs’ freelists are consumed linearly - consecutive allocations occupy consecutive memory addresses. However, if objects are freed within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slab, it may become fragmented - causing subsequent allocations to fill-in “holes” within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slab instead of proceeding linearly.
slub.png
With this in mind, let’s take a step back and analyse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitives at hand. First, since we are able to arbitrarily specify any value in total_count, we can choose cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflown buffer’s size to be any multiple of sizeof(wl_pfn_significant_net). This means we can inhabit any slab cache size of our choosing. As such, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no limitation on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 objects we can target with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow. However, this is not quite enough… For starters, we still don’t know anything about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current state of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slabs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365mselves, nor can we trigger remote allocations in slabs of our choosing.

It seems that first and foremost, we need to find a way to remotely shape slabs. Recall, however, that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are a few obstacles we need to overcome. As SLUB maintains per-CPU caches, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 affinity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel thread in which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation is performed must be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 one from which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflown buffer is allocated. Gaining a heap shaping primitive on a different CPU core will cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocations to be taken from different slabs. The most straightforward way to tackle this issue is to confine ourselves to heap shaping primitives which can be triggered from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same kernel thread on which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow occurs. This is quite a substantial constraint… In essence, it forces us to disregard allocations that occur as a result of processes that are external to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event handling itself.

Regardless, with a concrete goal in mind, we can start looking for heap shaping primitives in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registered handlers for each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event frames. As luck would have it, after going through every handler, we come across a (single) perfect fit!

Events frames of type “WLC_E_PFN_BSSID_NET_FOUND” are handled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handler function dhd_handle_hotlist_scan_evt. This function accumulates a linked list of scan results. Every time an event is received, its data is appended to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list. Finally, when an event arrives with a flag indicating it is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last event in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chain, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function passes on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 collected list of events to be processed. Let’s take a closer look:

1. void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data,
2.                                   int *send_evt_bytes, hotlist_type_t type)
3. {
4.    struct dhd_pno_gscan_params *gscan_params;
5.    wl_pfn_scanresults_t *results = (wl_pfn_scanresults_t *)event_data;
6.    gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
7.    ...
8.    malloc_size = sizeof(gscan_results_cache_t) +
9.                      ((results->count - 1) * sizeof(wifi_gscan_result_t));
10.   gscan_hotlist_cache = (gscan_results_cache_t *) kmalloc(malloc_size, GFP_KERNEL);
11.   ...
12.   gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found;
13.   gscan_params->gscan_hotlist_found = gscan_hotlist_cache;
14.   ...
15.   gscan_hotlist_cache->tot_count = results->count;
16.   gscan_hotlist_cache->tot_consumed = 0;
17.   plnetinfo = results->netinfo;
18.   for (i = 0; i < results->count; i++, plnetinfo++) {
19      hotlist_found_array = &gscan_hotlist_cache->results[i];
20.     ... //Populate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entry with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sanitised network information
21.   }
22.  if (results->status == PFN_COMPLETE) {
23.    ... //Process cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire chain
24.  }
25.  ...
26.}

Awesome - looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function above, it seems that we’re able to repeatedly cause allocations of size { sizeof(gscan_results_cache_t) + (N-1) * sizeof(wifi_gscan_result_t) | N > 0 } (where N denotes results->count). What’s more, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se allocations are performed in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same kernel thread, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir lifetime is completely controlled by us! As long as we don’t send an event with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PFN_COMPLETE status, none of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocations will be freed.

Before we move on, we’ll need to choose a target slab size. Ideally, we’re looking for a slab that’s relatively inactive. If ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r threads on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same CPU choose to allocate (or free) data from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same slab, this would add uncertainty to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slab’s state and may prevent us from successfully shaping it. After looking at /proc/slabinfo and tracing kmalloc allocations for every slab with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same affinity as our target kernel thread, it seems that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kmalloc-1024 slab is mostly inactive. As such, we’ll choose to target this slab size in our exploit.

By using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap shaping primitive above we can start filling slabs of any given size with  “gscan” objects. Each “gscan” object has a short header containing some metadata relating to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 scan and a pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next element in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 linked list. The rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n populated by an inline array of “scan results”, carrying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual data for this node.
gscan.png

Going back to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue at hand - how can we use this primitive to craft a predictable layout?

Well, by combining cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap shaping primitive with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow primitive, we should be able to properly shape slabs of any size-class prior to triggering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow. Recall cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initially any given slab may be fragmented, like so:
heap1 (1).png
However, after triggering enough allocations (e.g. (SLAB_TOTAL_SIZE / SLAB_OBJECT_SIZE) - 1) with our heap shaping primitive, all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 holes (if present) in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current slab should get populated, causing subsequent allocations of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same size-class to be placed consecutively.
heap2 (2).png

Now, we can send a single crafted SWC event frame, indicating a total_count resulting in an allocation from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same target slab. However, we don’t want to trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow yet! We still have to shape cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current slab before we do so. To prevent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow from occurring, we’ll provide a small pkt_count, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365reby only partially filling in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer.

heap3.png
Finally, using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap shaping primitive once again, we can fill cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slab with more of our “gscan” objects, bringing us to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following heap state:

heap4.png

Okay… We’re getting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re! As we can see above, if we choose to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow primitive at this point, we could overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “gscan” objects with our own arbitrary data. However, we’ve yet to determine exactly what kind of result that would yield…

Analysing The Constraints


In order to determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 effect of overwriting a “gscan” object, let’s take a closer look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flow that processes a chain of “gscan” objects (that is, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operations performed after an event with a “completion” flag is received). This processing is handled by wl_cfgvendor_send_hotlist_event. The function goes over each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 events in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list, packs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event’s data into an SKB, and subsequently broadcasts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SKB over Netlink to any potential listeners.

However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function does have a certain obstacle it needs to overcome; any given “gscan” node may be larger than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 maximal size of an SKB. Therefore, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 node would need to be split into several SKBs. To keep track of this information, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “tot_count” and “tot_consumed” fields in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “gscan” structure are utilised. The “tot_count” field indicates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 total number of embedded scan result entries in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 node’s inline array, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “tot_consumed” field indicates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number of entries consumed (transmitted) so far.

As a result, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function slightly modifies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list while processing it. Essentially, it enforces cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 invariant that each processed node’s “total_consumed” field will be modified to match its “tot_count” field. As for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data being transmitted and how it’s packed, we’ll skip those details for brevity’s sake. However, it’s important to note that ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 aforementioned side effect, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function above appears to be quite harmless (that is, no furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r primitives can be “mined” from it). Lastly, after all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 events are packed into SKBs and transmitted to any listeners, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can finally be reclaimed. This is achieved by simply walking over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list, and calling “kfree” on each entry.

Putting it all togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, where does this leave us with regards to exploitation? Assuming we choose to overwrite one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “gscan” entries using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow primitive, we can modify its “next” field (or racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, must, as it is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first field in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure) and point it at any arbitrary address. This would cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processing function to use this arbitrary pointer as if it were an element in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list.
arbitrary_address.png

Due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 invariant of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processing function - after processing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crafted entry, its 7th byte (“tot_consumed”) will be modified to match its 6th byte (“tot_count”). In addition, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be kfree-d after processing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chain. What’s more, recall that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processing function iterates over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire list of entries. This means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first four bytes in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crafted entry (its “next” field) must eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r point to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r memory location containing a “valid” list node (which must cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n satisfy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same constraints), or must ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise hold cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value 0 (NULL), indicating that this is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last element in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list.

This doesn’t look easy… There’s quite a large number of constraints we need to consider. If we willfully choose cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ignore cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kfree for a moment, we could try and search for memory locations where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first four bytes are zero, and where it would be beneficial to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 7th byte to match cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 6th. Of course, this is just cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tip of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iceberg; we could repeatedly trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same primitive in order to repeatedly copy bytes one position to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 left. Perhaps, if we were able to locate a memory address where enough zero bytes and enough bytes of our choosing are present, we could craft a target value by consecutively using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two primitives.

In order to gage cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 feasibility of this approach, I’ve encoded cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constraints above in a small SMT instance (using Z3), and supplied cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual heap data from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, along with various target values and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir corresponding locations. Additionally, since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s translation table is stored at a constant address in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s VAS and even slight modifications to it can result in exploitable conditions, its contents (along with corresponding target values) was added to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SMT instance as well. The instance was constructed to be satisfiable if and only if any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target values could occupy any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target locations within no more than ten “steps” (where each step is an invocation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitive). Unfortunately, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 results were quite grim… It seemed like this approach just wasn’t powerful enough.

Moreover, while this idea might be nice in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory, it doesn’t quite work in practice. You see, calling kfree on an arbitrary address is not without side-effects of its own. For starters, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory address must be marked as eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a “slab” page, or as “compound”. This only holds true (in general) for pages actually used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slab allocator. Trying to call kfree on an address in a page that isn’t marked as such, triggers a kernel panic (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365reby crashing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device).

Perhaps, instead, we can choose to ignore cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r constraints and focus on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kfree? Indeed, if we are able to consistently locate an allocation whose data can be used for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 purpose of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit, we could attempt to free that memory address, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n “re-capture” it by using our heap shaping primitive. However, this raises several additional questions. First, will we be able to consistently locate a slab-resident address? Second, even if we were to find such an address, surely it will be associated with a per-CPU cache, meaning that freeing it will not necessarily allow us to reclaim it later on. Lastly, whichever allocation we do choose to target, will have to satisfy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constraints above - that is, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first four bytes must be zero, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 7th byte will be modified to match cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 6th.

However, this is where some slight trickery comes in handy! Recall that kmalloc holds a number of fixed-size caches. Yet what should happen when a larger allocation is requested? In turn out that in that case, kmalloc simply returns a number of consecutive free pages (using __get_free_pages) and returns cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller. This is done without any per-CPU caching. As such, if we are able to free a large allocation, we should cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be able to reclaim it without having to consider which CPU allocated it in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first place.

This may solve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem of affinity, but it still doesn’t help us locate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se allocations. Unfortunately, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slab caches are allocated quite late in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s boot process, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir contents are very “noisy”. This means that even guessing a single address within a slab is quite difficult, even more so for remote attackers. However, early allocations which use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 large allocation flow (that is, which are created using __get_free_pages) do consistently inhabit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same memory addresses! This is as long as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y occur early enough during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s initialisation so that no non-deterministic events happen concurrently.

Combining cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two facts, we can search for a large early allocation. After tracing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 large allocation path and rebooting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, it seems that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are indeed quite a few such allocations. To help navigate this large trace, we can also compile cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel with a special GCC plugin that outputs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size of each structure used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. Using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two traces, we can quickly navigate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 early large allocations, and try and search for a potential match.

After going over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 list, we come across one seemingly interesting entry:

Screenshot from 2017-03-27 16:26:30.png

Putting It All Togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r


During cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bcmdhd driver’s initialisation, it calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wiphy_new function in order to allocate an instance of wl_priv. This instance is used to hold much of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 metadata related to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver’s operation. But cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s one more sneaky little piece of data hiding within this structure - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event handler function pointer array used to handle incoming event frames! Indeed, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very same table we were discussing earlier on (evt_handler), is stored within this object. This leads us to a direct path for exploitation - simply kfree this object, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n send an SWC event frame to reclaim it, and fill it with our own arbitrary data.

Before we can do so, however, we’ll need to make sure that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object satisfies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constraints mandated by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processing function. Namely, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first four bytes must be zero, and we must be able to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 7th byte to match cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 6th byte. While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second constraint poses no issue at all, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first constraint turns out to be quite problematic! As it happens, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first four bytes are not zero, but in fact point to a block of function pointers related to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver. Does this mean we can’t use this object after all?

No - as luck would have it, we can still use one more trick! It turns out that when kfree-ing a large allocation, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code path for kfree doesn’t require cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 passed in pointer to point to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 beginning of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation. Instead, it simply fetches cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pages corresponding to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation, and frees cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m instead. This means that by specifying an address located within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure that does match cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constraints, we’ll be able to both satisfy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requirements imposed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processing function and free cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying object. Great.
evt_handler_ptr.png

Putting this all togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, we can now simply send along a SWC event frame in order to reclaim cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 evt_handler function pointer array, and populate it with our own contents. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is no KASLR, we can search for a stack pivot gadget in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel image that will allow us to gain code execution. For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 purpose of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit, I’ve chosen to replace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event handler for WLC_E_SET_SSID with a stack pivot into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event frame itself (which is stored in R2 when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event handler is executed). Lastly, by placing a ROP stack in a crafted event frame of type WLC_E_SET_SSID, we can now gain control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel thread’s execution, thus completing our exploit.

rop.png

You can find a sample exploit for this vulnerability here. It includes a short ROP chain that simply calls printk. The exploit was built against a Nexus 5 with a custom kernel version. In order to modify it to work against different kernel versions, you’ll need to fill in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 appropriate symbols (under symbols.py). Moreover, while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitives are still present in 64-bit devices, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re might be additional work required in order to adjust cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit for those platforms.

With that, let’s move on to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 blog post!

Part 2 - The “Easy” Way

How Low Can You Go?


Although we’ve seen that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 high-level communication protocols between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi firmware and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host may be compromised, we’ve also seen how tedious it might be to write a fully-functional exploit. Indeed, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit detailed above required sufficient information about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device being targeted (such as symbols). Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, any mistake during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploitation might cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel to crash; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365reby rebooting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device and requiring us to start all over again. This fact, coupled with our transient control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC, makes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se types of exploit chains harder to exploit reliably.

That said, up until now we’ve only considered cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 high-level attack surface exposed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware. In effect, we were thinking of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 application processor as two distinct entities which are completely isolated from one anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r. In reality, we know that nothing can be furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 truth. Not only are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host physically proximate to one anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y also share a physical communication interface.

As we’ve seen before, Broadcom manufactures SoCs that support various interfaces, including SDIO, USB and even PCIe. While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SDIO interface used to be quite popular, in recent years it has fallen out of favour in mobile devices. The main reason for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “disappearance” of SDIO is due to its limited transfer speeds. As an example, Broadcom’s BCM4339 SoC supports SDIO 3.0, a fairly advanced version of SDIO. Nonecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365less, it is still limited to a cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365oretical maximal bus speed of 104 MB/s. On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r hand, 802.11ac has a cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365oretical maximal speed of 166 MB/s - much more than SDIO can cope with.  
pcie_sdio.png
                                              BCM4339 Block Diagram

The increased transfer rates caused PCIe to become cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most prevalent interface used to connect Wi-Fi SoCs in modern mobile devices. PCIe, unlike PCI, is based on a point-to-point topology. Every device has it’s own serial link connecting it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. Due to this design, PCIe enjoys much higher transfer rates per lane than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 equivalent rates on PCI (since bus access doesn’t need to be arbitrated); PCIe 1.0 has a throughput of 250 MB/s on a single lane (scaling linearly with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number of lanes).

More concretely, let’s take a look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 adoption rate of PCIe in modern mobile devices. Taking Nexus phones as a case study, it seems that since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Nexus 6, all devices use a PCIe interface instead of SDIO. Much in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same way, all iPhones since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 iPhone 6 use PCIe (whereas old iPhones used USB to connect to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC). Lastly, all Samsung flagships since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Galaxy S6 use PCIe.

Interface Isolation


So why is this information relevant to our pursuits? Well, PCIe is significantly different to SDIO and USB in terms of isolation. Without going into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internals of each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interfaces, SDIO simply allows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 serial transfer of small command “packets” (on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CMD pin), potentially accompanied by data (on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DATA pins). The SDIO controller cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n decodes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command and responds appropriately. While SDIO may support DMA (for example, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host can set up a DMA engine to continually read data from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SD bus and transfer it to memory), this feature is not used on mobile devices, and is not an inherent part of SDIO. Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 low-level SDIO communication on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 BCM SoC is handled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “SDIOD” core. In order to craft special SDIO commands, we would most likely need to gain access to this controller first.

Likewise, USB (up to version 3.1) does not include support for DMA. The USB protocol is handled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s USB controller, which performs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 necessary memory access required. Of course, it might be possible to compromise cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 USB controller itself, and use its interface to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory system in order to gain memory access. For example, on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Intel Hub Architecture, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 USB controller connects to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PCH via PCI, which is capable of DMA. But once again, this kind of attack is racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r complex, and is limited to specific architectures and USB controllers.

In contrast to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two interfaces, PCIe allows for DMA by design. This allows PCIe to operate at great speeds without incurring a performance hit on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. Once data is transferred to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s memory, an interrupt is fired to indicate that work needs to be done.

On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transaction layer, PCIe operates by sending small bundles of data, appropriately named “Transaction Layer Packets” (TLPs). Each TLP may be routed by a network of switches, until it reaches cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 destined peripheral. There, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 peripheral decodes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 packet and performs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requested memory operation. The TLP’s header encodes whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r this is a requested read or write operation, and its body contains any accompanying data related to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 request.

Screenshot from 2017-03-24 12:08:51.png
                       Structure of a Transaction Layer Packet (TLP)

IOU an MMU


While PCIe enables DMA by design, that still doesn’t imply that any PCIe connected peripheral should be able to freely access any memory address on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host. Indeed, modern architectures defend cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365mselves against DMA-capable peripherals by including additional memory mapping units (IOMMUs) on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IO buses connecting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 peripherals to main memory.

ARM specifies its own version of an IOMMU, called cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “System Memory Mapping Unit” (SMMU). Among ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r roles, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SMMU is used in order to manage cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory view exposed to different SoC components. In short, each stream of memory transactions is associated with a “Stream ID”. The SMMU cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n performs a step called “context determination” in order to translate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Stream ID to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding memory context.

Using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory context, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SMMU is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n able to associate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory operations with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation table containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mappings for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requesting device. Much like a regular ARM MMU, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation tables are queried in order to translate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input address (eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a virtual address or an intermediate physical address) to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding physical address. Of course, along cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SMMU also ensures that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requested memory operation is, in fact, allowed. If any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se steps fails, a fault is generated.

Screenshot from 2017-03-24 12:30:28.png

While this is all well and good in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory, it still doesn’t mean that an SMMU is, in fact, used in practice. Unfortunately, mobile SoCs are proprietary, so it would be hard to determine how and where SMMUs are actually in place. That said, we can still glean some insight from publically available information. For example, by going over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOMMU bindings in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux Kernel, we can see that apparently both Qualcomm and Samsung have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own proprietary implementations of an SMMU (!), with it’s own unique device-tree bindings. However, suspiciously, it seems that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device tree entries for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Broadcom Wi-Fi chip are missing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se IOMMU bindings…

Perhaps, instead, Broadcom’s host driver (bcmdhd) manually configures cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SMMUs before each peripheral memory access? In order to answer this question, we’ll need to take a closer look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver’s implementation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 communication protocol used over PCIe. Broadcom implements cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own proprietary protocol called “MSGBUF” in order to communicate with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip over PCIe. The host’s implementation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 protocol and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code for handling PCIe can be found under dhd_msgbuf.c and dhd_pcie.c, respectively.

After going through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code, we gain a few key insights into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 communication protocol’s inner workings. First, as expected, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver scans cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PCIe interface, accesses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PCI configuration space, and maps all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shared resources into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s memory. Next, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host allocates a set of “rings”. Each ring is backed by a DMA-coherent memory region. The MSGBUF protocol uses four rings for data flow, and one ring for control. Each data path (eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r RX or TX), has two corresponding rings - one to signal cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 submission of a request, and anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r to indicate its completion. Yet, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re still doesn’t seem to be any reference to an SMMU in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver so far. Perhaps we have to dig deeper...

So how does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip learn about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se rings? After all, so far cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re just a bunch of physically contiguous buffers allocated in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver. Going over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver’s code, it appears that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip hold a shared structure, pciedev_shared_t, containing all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PCIe-related metadata, including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ring buffers. The host holds its own copy of this structure, but where does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC keep its copy? According to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dhdpcie_readshared function, it appears that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip stores a pointer to this structure in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last four bytes of its RAM.

rings.png

Let’s go ahead and take a look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure’s contents. To make this process slightly easier, I’ve written a small script that takes a firmware RAM snapshot (produced using dhdutil), reads cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PCIe shared structure from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of RAM, and dumps out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 relevant information:

Screenshot from 2017-03-24 14:44:17.png

Following cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rings_info_ptr field, we can also dump cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information about each of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rings - including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir size, current index, and physical memory address:

rings.png


For starters, we can see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory addresses specified in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se buffers seem to be, in fact, physical memory addresses from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s memory. This is slightly suspicious… In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 presence of an SMMU, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip could have used an entirely different address range (which would have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n been translated by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SMMU into a physical addresses). However, merely being suspicious is not enough... To check whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r or not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 an SMMU is present (or active), we’ll need to set up a small experiment!

Recall that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MSGBUF protocol uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 aforementioned ring buffers to indicate submission and completion of events, for both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RX and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TX paths. In essence, during transmission of a frame, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host writes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TX submission ring. Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip transmits cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 frame, it writes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TX completion ring to indicate as such. Similarly, when a frame is received, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware writes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RX submission ring, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host subsequently writes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RX completion ring upon reception of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 frame.

If so, what if we were to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ring address corresponding to TX completion ring in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware’s PCIe metadata structure, and point it at an arbitrary memory address? If an SMMU is in place and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chosen memory address is not mapped-in for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SMMU will generate a fault and no modification will take place. However, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is no SMMU in place, we should be able to observe this modification by simple dumping cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding physical memory range from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host (for example, by using /dev/mem). This small experiment also allows us to avoid reverse-engineering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi firmware’s implementation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MSGBUF protocol for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time being, which would no doubt be quite tedious.

To make things more interesting, let’s modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TX completion ring’s address to point at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 beginning of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux Kernel’s code segment (0x80000 on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Nexus 6P : see /proc/iomem). After generating some Wi-Fi traffic and inspecting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of physical memory, we are presented with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following result:

dma_tx_complt.png


Aha! The Wi-Fi chip managed to DMA into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 physical address range containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s kernel, without any interference! This finally confirms our suspicion; eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is no SMMU present, or it isn’t configured to prevent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip from accessing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s RAM.

Not only does this kind of access not require a single vulnerability, but it is also much more reliable to exploit. There’s no need for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exact kernel symbols, or any ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r preliminary information. The Wi-Fi SoC can simply use its DMA access to scan cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 physical address ranges in order to locate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. Then, it can identify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s symbol table in RAM, analyse it to locate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 any kernel function it wishes, and proceed to hijack cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function by overwriting its code (one such example can be seen in this similar DMA-like attack). All in all, this style of attack is completely portable and 100% reliable -- a significant step-up from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous exploit we saw.

Although we could stop here, let’s make one additional small effort in order to get slightly better control over this primitive. While we are able to DMA into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s memory, we are doing so racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r “blindly” at this point. We do not control cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data being written, but instead rely on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi firmware’s implementation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MSGBUF protocol to corrupt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s memory. By delving slightly furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, we should be able to figure out how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA engine on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip works, and manually utilise it to access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s memory (instead of relying on side-effects, as shown above).

So where do we start? Searching for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “MSGBUF” string, we can see some initialisation routines related to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 protocol, which are part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special “reclaim” region (and are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore only used during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip’s initialisation). Nevercá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365less, reverse-engineering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se functions reveals that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y reference a set of functions in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip’s RAM. Luckily, some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se functions’ names are present in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ROM! Their names seem quite relevant: “dma64_txfast”, “dma64_txreset” - it seems like we’re on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right track.

Once again, we are spared some reverse-engineering effort. Broadcom’s SoftMAC driver, brcmsmac, contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se exact functions. Although we can expect some differences, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 general idea should remain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same.

Combing through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code, it appears that for every DMA-capable source or sink, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re exists a corresponding DMA metadata structure, called “dma_info”. This structure contains pointers to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA RX and TX registers, as well as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA descriptor rings into which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA source or destination addresses are inserted. Additionally, each structure is assigned an 8-byte name which can be used to identify it. What’s more, every dma_info structure begins with a pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RAM function block containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA functions - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same block we identified earlier. Therefore, we can locate all instances of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se DMA metadata structures by simply searching for this pointer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC’s RAM.
dma_info (3).png

Now that we know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 format of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se metadata structures and have a means to locate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m, we can try and search for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 instance corresponding to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA TX path from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host.

Unfortunately, this is easier said than done. After all, we can expect to find multiple instances of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se structures, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip performs DMA to and from many sources and sinks. For example, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware likely uses SoC-internal DMA engines to perform access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internal RX and TX FIFOs. So how can we identify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct DMA descriptor?

Recall that each descriptor has an associated “name” field. Let’s search for all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA descriptors in RAM (by searching for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA function block pointer), and output cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding name for each instance:

Found dma_info - Address: 0x00220288, Name: "wl0"
Found dma_info - Address: 0x00220478, Name: "wl0"
Found dma_info - Address: 0x00220A78, Name: "wl0"
Found dma_info - Address: 0x00221078, Name: "wl0"
Found dma_info - Address: 0x00221BF8, Name: "wl0"
Found dma_info - Address: 0x0022360C, Name: "wl0"
Found dma_info - Address: 0x00236268, Name: "D2H"
Found dma_info - Address: 0x00238B7C, Name: "H2D"

Great! While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are a few nondescript dma_info instances which are probably used internally (as suspected), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are also two instances which seem to correspond to host-to-device (H2D) and device-to-host (D2H) DMA accesses. Since we’re interested in DMA-ing into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s memory, let’s take a closer look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 D2H structure:

Screenshot from 2017-03-24 17:56:08.png

Note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RX and TX registers point to an area outside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi firmware’s ROM and RAM. In fact, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y point to backplane addresses corresponding to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA engine’s registers. In contrast, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RX and TX descriptor ring pointers do, indeed, point to memory locations within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SoC’s RAM.

By going over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA code in brcmsmac and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MSGBUF protocol implementation in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host’s driver, we are able to finally piece togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 details. First, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host posts physical addresses (corresponding to SKBs) to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip, using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MSGBUF protocol. These addresses are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n inserted into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA descriptor rings by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware’s MSGBUF implementation. Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rings are populated, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip simply writes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 backplane registers in order to “kick off” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA engine. The DMA engine will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n go over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 descriptor list, and consume cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 descriptor at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current ring index for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA access. Once a DMA descriptor is consumed, its value is set to a special “magic” value (0xDEADBEEF).

Therefore, all we need to do in order to manipulate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA engine into writing into our own arbitrary physical address is to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA descriptor ring. Since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MSGBUF protocol is constantly operating as frames are being sent back and forth, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 descriptor rings change rapidly. It would be useful if we could “hook” one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 functions called during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA TX flow, allowing us to quickly replace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current descriptors with our own crafted values.

As luck would have it, while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dmx64_txfast function is located in ROM, its prologue starts with a branch into RAM. This allows us to use our patcher from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous blog post in order to hook cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function, and execute our own shellcode stub. Let’s write a small stub that simply goes over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 D2H DMA descriptors, and changes every non-consumed descriptor to our own pointer. By doing so, subsequent calls to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA engine should write cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 received frame’s contents into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 aforementioned address. After applying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch and generating Wi-Fi traffic, we are greeted with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following result:

dma_frame.png

Ah-ha! We managed to DMA arbitrary data into an address of our choosing. Using this primitive, we can finally hijack any kernel function with our own crafted data.

Lastly - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 experiment described above was performed on a Nexus 6P, which is based on Qualcomm’s Snapdragon 810 SoC. This raises cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 question: perhaps different SoCs exhibit different behaviour? To test out this cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory, let’s repeat cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same experiment on a Galaxy S7 Edge, which is based on Samsung’s Exynos 8890 SoC.

Using a previously disclosed privilege escalation to inject code into system_server, we can directly issue cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ioctls required to interact with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bcmdhd driver, thus replacing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip memory access capabilities provided by dhdutil in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 above experiment. Similarly, using a previously disclosed kernel exploit, we are able to execute code within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, allowing us to observe changes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code segments.

Putting this togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, we can extract cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi chip’s (BCM43596) ROM, inspect it, and locate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA function as described above. Then, we can insert cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same hook; pointing any non-consumed DMA RX descriptors at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel code’s physical address. After installing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hook and generating some Wi-Fi traffic, we observe cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following result:

dma_exynos8890.png

Once again we are able to DMA freely into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel (bypassing RKP’s protection along cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way)! It seems that both Samsung’s Exynos 8890 SoC and Qualcomm’s Snapdragon 810 eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r lack SMMUs or fail to utilise cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m.

Afterword


In conclusion, we’ve seen that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 isolation between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC can, and should, be improved. While flaws exist in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 communication protocols between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chip, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se can eventually be solved over time. However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current lack of protection against a rogue Wi-Fi chip leaves much to be desired.

Since mobile SoCs are proprietary, it remains unknown whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r current-gen SoCs are capable of facilitating such isolation. We hope that SoCs that do, indeed, have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 capability to enable memory protection (for example, by means of an SMMU), choose to do so soon. For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SoCs that are incapable of doing so, perhaps this research will serve as a motivator when designing next-gen hardware.

The current lack of isolation can also have some surprising side effects. For example, Android contexts which are able to interact with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi firmware, can leverage cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Wi-Fi SoC’s DMA capability in order to directly hijack cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. Therefore, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se contexts should be thought of being “as privileged as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel”, an assumption which I believe is not currently made by Android’s security architecture.  

The combination of an increasingly complex firmware and Wi-Fi’s incessant onwards march, hint that firmware bugs will probably be around for quite some time. This hypocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sis is supported by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fact that even a relatively shallow inspection of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware revealed a number of bugs, all of which were exploitable by remote attackers.

While memory isolation on its own will help defend against a rogue Wi-Fi SoC, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware’s defenses can also be bolstered against attacks. Currently, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 firmware lacks exploit mitigations (such as stack cookies), and doesn’t make full use of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing security mechanisms (such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MPU). Hopefully, future versions are able to better defend against such attacks by implementing modern exploit mitigations and utilising SoC security mechanisms.

17 comments:

  1. Is brcmfmac vulnerable to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same or similar exploit?

    ReplyDelete
  2. Is brcmfmac vulnerable to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same or similar attack?

    ReplyDelete
  3. Would this also apply to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wifi routers that use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 broadcom chips and drivers?

    ReplyDelete
    Replies
    1. The firmware bugs we found were only relevant to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client-related logic, so I don't believe cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y apply to routers. As for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver bugs - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y were in Android's driver, so I'm pretty sure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don't apply to routers eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r.

      Delete
  4. Great fun! Like writing bootstrap code...

    If I was 50 years younger, this would be my hobby!

    ReplyDelete
  5. Incredible and I mean incredible article! Really enjoyed and did require some repeptive paragraph reading on my part.

    Lots of very intersting take aways but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overloading of ecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rtype was one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most fascinating. Not to be too conspiracy minded but what an easy backdoor to leave. Would be so easy to use later and not obvious. Easy deniability.

    ReplyDelete
  6. Hmm... trying to understand this piece of greatness but my System.Map doesn't contain any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbols used in rdev.py and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore throws an error when trying to run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 poc.

    ReplyDelete
    Replies
    1. The System.map needs to correspond to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hammerhead on which you're running cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit. You can also dump /proc/kallsyms and rename it to System.map. Note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r symbols you'll need to extract on your own (see symbols.py).

      Delete
  7. hmm... trying to understand this piece of greatness but my System.Map doesn't contain any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbols used in rdev.py and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore crashes when trying to run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 poc.

    ReplyDelete
  8. Given cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365me of this blog, it might be reasonable to provide an email addy to "pitch something over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 transom" racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than appear as an open comment.

    ReplyDelete
  9. This comment has been removed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 author.

    ReplyDelete
  10. And yet, Google will not patch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability on Nexus 5 devices.

    ReplyDelete
  11. Hi! For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 'dhd_handle_swc_evt' Heap Overflow, should we also need cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patches you mentioned in your first part? ("Regrettably, however, mac80211 is unable to process cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special vendor frames, and simply rejects cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. Nonecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365less, this is just a minor inconvenience - I’ve written a few patches to mac80211 which add support for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se special vendor frames. After applying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se patches, re-compiling and booting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, we are now able to send our crafted frames.")

    If so, what patches do we need here to realize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 'dhd_handle_swc_evt' Heap Overflow? Thanks!!!

    ReplyDelete
    Replies
    1. No. The patches for mac80211 were only needed on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker's side in order to allow mac80211 to send cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crafted vendor frames used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TDLS exploit.

      Delete