exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

WebKit On iOS PAC / JIT Hardening Bypass

WebKit On iOS PAC / JIT Hardening Bypass
Posted Aug 14, 2020
Authored by saelo, Google Security Research

A PAC and JIT hardening bypass exists in WebKit on iOS.

tags | advisory
systems | ios
advisories | CVE-2020-9910
SHA-256 | 7e43df27a79d01df906491c3fa75f5b9b076ed4934270a40b2e9bf12e7d1271c

WebKit On iOS PAC / JIT Hardening Bypass

Change Mirror Download
PAC and JIT Hardening Bypass in WebKit on iOS

As per discussions with product-security@apple.com, Apple would like to treat the PAC bypass described here as a security vulnerability by itself. The bypass was initially reported without a deadline on May 6. After receiving the reply that they will treat it as a separate vulnerability, this issue has been created to start the 90-day deadline (from today).

On macOS, gaining shellcode execution from arbitrary memory read/write in a WebKit renderer only requires finding and writing to the JIT region. However, on iOS a combination of APRR [1] and PAC [2] protect the JIT region from an attacker with arbitrary read/write.

WebKit has support for in-process signal handling. This is for example used by some JIT optimizations in JSC [3]. The main signal handler is `catch_mach_exception_raise_state` in Signals.cpp [4], which will traverse a linked list of handlers and call each one of them. If any of the handlers returns success, the signal is treated as handled and the thread will continue.

This enables the following attack:

1. The linked list of handlers is turned into a cycle, causing `catch_mach_exception_raise_state` to loop infinitely upon catching a signal
2. A crash is triggered in another thread, for example in a WebWorker. A GCD thread is now \"stuck\" in `catch_mach_exception_raise_state`
3. The main thread searches the stacks for the stackframe of `catch_mach_exception_raise_state`. Once found, it has access to the reply mach message of `catch_mach_exception_raise_state` and with that to the context (registers + stack) of the crashed thread. It can modify them arbitrarily except for PC which is protected by PAC. After modifying the state and marking the exception as property handled in the reply message, it fixes the linked list of handlers, causing `catch_mach_exception_raise_state` in the other thread to finish
4. The crashed thread now resumes execution with attacker-controlled registers and/or stack content

It should also be possible to catch multiple signals following each other by first making a copy of the handlers list/cycle, then swapping the \"active\" and \"inactive\" exception hander lists before repairing the now inactive handler list. The current exception handler will then return, but if a new exception is immediately raised, the handling thread will again be stuck in `catch_mach_exception_raise_state` as it uses the other list which is still a cycle. It is also worth noting that it should be possible to modify the global `activeExceptions` variable in Signals.cpp prior to the installation of signal handlers, thus allowing the attacker to control which exceptions are handled.

This \"debugger\" now immediately allows brute-forcing PACs as PAC mostly relies on conventional access violations when failing. Moreover, it allows PAC to be bypassed trivially for some pointers, namely in cases where the authentication and use are two separate instructions, with the second instruction triggering a crash. The PoC demonstrates this by bypassing the PAC protecting a TypedArray's backing storage pointer: first, a TypedArray's backing storage pointer in a worker is corrupted, then accessed. This will cause the AUTDB instruction to fail, leaving the pointer clobbered and causing a crash when the pointer is subsequently accessed. Next, this crash is \"handled\" with the debugger and the register containing the
clobbered pointer is replaced with an arbitrary pointer. The worker then continues and re-executes the access instruction which now succeeds and thus accesses an address of the attacker's choosing.

With this, it should now be possible to achieve arbitrary native code execution (i.e. bypassing the JIT hardening). Possible ideas for that are:
- Corrupt the AssemblerBuffer so arbitrary instructions are copied into the JIT region by the LinkBuffer. This will cause the computed hashes to mismatch and the linker to crash, but that only happens after the instructions have been copied and the crash can then simply be caught
- Crash during one of the writes into the JIT region in LinkBuffer::copyCompactAndLinkCode (by corrupting the destination pointer prior to that) and change the content of the source register so that an arbitrary instruction is written into the JIT region while the original instruction is used for the hash computation
- Crash during LinkBuffer::copyCompactAndLinkCode and resume execution somewhere else. This should leave the JIT region writable (although not executable) for that thread
- Brute-force a PAC code (e.g. by repeatedly accessing, crashing, and then changing a PAC protected pointer), then JOP into one of the functions into which performJITMemcpy is inlined

[1] https://siguza.github.io/APRR/
[2] https://github.com/apple/llvm-project/blob/apple/master/clang/docs/PointerAuthentication.rst
[3] https://github.com/WebKit/webkit/blob/015fb86d51851fc3e13f05898c85d62d0b1bae8f/Source/JavaScriptCore/runtime/OptionsList.h#L466
[4] https://github.com/WebKit/webkit/blob/4ceb36e525b55b9d49aed0b400507d522953e025/Source/WTF/wtf/threads/Signals.cpp#L137

This bug is subject to a 90 day disclosure deadline. After 90 days elapse,
the bug report will become visible to the public. The scheduled disclosure
date is 2020-08-13. Disclosure at an earlier date is possible if
agreed upon by all parties.

Related CVE Numbers: CVE-2020-9910

Found by: saelo@google.com

Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags


packet storm

© 2022 Packet Storm. All rights reserved.

Security Services
Hosting By