exploit the possibilities

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
MD5 | a3ac179138a9ac48c78209344b6266c3

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:

October 2020

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

Top Authors In Last 30 Days

File Tags


packet storm

© 2020 Packet Storm. All rights reserved.

Security Services
Hosting By