CVE-2019-7286: iOS Use-After-Free in cfprefsd

Posted by Ian Beer, Project Zero (2020-07-27)

Disclosure or Patch Date: 7 February 2019
Product: Apple iOS
Affected Versions: Exploit targeted iOS 12-12.1
First Patched Version: iOS 12.1.4
Issue/Bug Report: N/A
Patch CL: N/A
Bug-Introducing CL: N/A
Proof-of-Concept: N/A
Exploit Sample: N/A
Access to the exploit sample? Yes
Reporter(s): Clement Lecigne of Google's Threat Analysis Group (TAG), Ian Beer & Samuel GroƟ of Google Project Zero, & an anonymous researcher (according to Apple's release notes)

Bug Class: use-after-free (UaF)
Vulnerability Details:
cfprefds hosts the com.apple.cfprefsd.daemon XPC service. This service offers a number of operations, including a "multi-message" operation which allows bundling multiple individual operations into one larger message. The vulnerability is in the implementation of this multi-message handling.

The code allocates an array on the stack and fills it with raw pointers to each of the sub-messages inside the multi-message. It then invokes each message handler, passing a custom reply_handler block which rather than sending the reply, instead overwrites the raw sub-message pointer in the stack buffer with a retained reply message pointer.

The code fails to take into account the fact that not all message handlers invoke the reply_handler block, as not all messages send replies. This can leave some slots in the stack buffer containing raw pointers, and some containing retained pointers. xpc_release will be called on each of the entries, dropping an extra reference on the raw pointers which was never obtained leading to a UaF.

Is the exploit method known? Yes
Exploit method: This vulnerability is a sandbox escape. It runs as shellcode loaded in a sandboxed WebContent renderer process and gets ROP execution in cfprefsd, a more privileged process. They exploit the UaF using an XPC heap spray to fill the target heap with a fake objective C object with a fake selector cache. When a method is invoked on this object, it will trigger a ROP payload. The ROP stack opens an IOKit userclient mach port and sends it back to the renderer, allowing the shellcode to interact with the kernel driver and exploit a kernel bug (CVE-2019-7287).

How do you think you would have found this bug? 
A manual audit of the service should have found this bug; the dual use of the stack buffer is a sufficiently weird primitive that I think it would have stood out. A generic XPC fuzzer might be able to find it, but I don't think it's necessarily trivially fuzzable because you'd need well-formed XPC objects with the right dictionaries.

(Historical/present/future) context of bug: This vulnerability was discovered and reported at the same time as CVE-2019-7287. Google's TAG discovered a cache of iOS exploit chains being used in the wild. CVE-2019-7286 and CVE-2019-7287 were the only two vulnerabilities that were still 0-days at the time of discovery. This vulnerability, CVE-2019-7286, is the sandbox escape that is paired with CVE-2019-7287, the kernel vulnerability.

Areas/approach for variant analysis:
Manual XPC object lifetime management is tricky and there are a few APIs which can be unsafe. Looking for places where xpc_retain/xpc_release are called could be a good start, but they're probably quite common.

Found variants: None

Structural improvements:

Potential detection methods for similar 0-days: A memory sanitizer tool would detect 0-days like this.

Other references: 

No comments:

Post a Comment