what you don't know can hurt you
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:

July 2024

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close