This bug has been fixed in Mojave Beta, but still present in latest High Sierra (10.13.5). It’s a logical bug that an entitled binary tries to load an insecure external library controllable by environment variable. To exploit it we need to abuse sandbox, which is interesting that sometimes a mitigation could be turned to an exploit.
CoreSymbolication(/System/Library/PrivateFrameworks/CoreSymbolication.framework) has some private api for symbolication. When demangling swift application symbols, it tries to load external library in following order:
The function xcselect_get_developer_dir_path will return environ variable DEVELOPER_DIR if exists. Absolutely controllable.
Actually the first libswiftDemangle.dylib exists. Will it reach the last branch? I’ll talk about it later.
Apple has built-in com.apple.SamplingTools in:
And they are entitled:
➜ ~ jtool --ent `which symbols`
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
With this entitlement, SamplingTools can attach to SIP protected process with
task_for_pid, even without root privilege.
$ vmmap Finder | head -n 8
Process: Finder 
Load Address: 0x10515f000
Version: 10.13.5 (10.13.5)
Build Info: Finder_FE-1054005004000000~3
Code Type: X86–64
Parent Process: ??? 
LLDB fails even it’s rooted:
$ sudo lldb -n Finder
(lldb) process attach --name "Finder"
error: attach failed: cannot attach to process due to System Integrity Protection
So this seems like a “meta” entitlement. With it you can just inject to other entitled process and gain arbitrary entitlement.
Let’s just start an application compiled with swift, then run
symbols [pid] -printDemangling and it will call
CoreSymbolication!demangle, which has potential ability to load insecure code.
But there are two problems. First, the last branch looks impossible to be reached because /System/Library/PrivateFrameworks/Swift/libswiftDemangle.dylib exists.
Actually we can just block them with a sandbox. Yeah, use the security facility to trigger something insecure.
(version 1)(allow default)(deny file-read*
Then, spawn a child process with
symbols [pid] -printDemangling to trigger dylib hijack.
Now we have a second problem. It crashes.
System Integrity Protection: enabledCrashed Thread: 0 Dispatch queue: com.apple.main-threadException Type: EXC_BAD_ACCESS (Code Signature Invalid)
Exception Codes: 0x0000000000000032, 0x000000010d745000
Exception Note: EXC_CORPSE_NOTIFYTermination Reason: Namespace CODESIGNING, Code 0x2kernel messages:External Modification Warnings:
Process used task_for_pid().VM Regions Near 0x10d745000:
MALLOC_LARGE 000000010d70a000-000000010d745000 [ 236K] rw-/rwx SM=PRV
--> mapped file 000000010d745000-000000010d746000 [ 4K] r-x/r-x SM=PRV Object_id=2929ab85
mapped file 000000010d748000-000000010d762000 [ 104K] r--/r-- SM=ALI Object_id=2af85085Application Specific Information:
dyld: in dlopen()
/var/folders/4d/1_vz_55x0mn_w1cyjwr9w42c0000gn/T/tmp.0b5SeUjh/Toolchains/XcodeDefault.xctoolchain/usr/lib/libswiftDemangle.dylib12 libdyld.dylib 0x00007fff66c9fd86 dlopen + 86
13 com.apple.CoreSymbolication 0x00007fff52d15332 invocation function for block in call_external_demangle(char const*) + 348
14 libdispatch.dylib 0x00007fff66c64e08 _dispatch_client_callout + 8
15 libdispatch.dylib 0x00007fff66c64dbb dispatch_once_f + 41
16 com.apple.CoreSymbolication 0x00007fff52cb880f demangle + 298
17 com.apple.CoreSymbolication 0x00007fff52cb85e3 TRawSymbol<Pointer64>::name() + 75
18 com.apple.CoreSymbolication 0x00007fff52cbd88e CSSymbolGetName + 166
com.apple.SamplingTools in latest macOS are code signed with Library Validation flag, so loading unsigned dylib is prohibited.
➜ ~ codesign -dvvv `which symbols`
Format=Mach-O thin (x86_64)
CodeDirectory v=20100 size=1384 flags=0x2000(library-validation) hashes=36+5 location=embedded
I just had an El Capitan vm and I looked into it. Wow, the previous SamplingTools distribution has valid code signature, but no library validation flag. So just copy to High Sierra and it works.
Although we can now invoke
task_for_pid on any restricted process, it still requires same euid, which means we need a local root privilege escalation exploit as part of the chain.
Now inject into
diskmanagementd and you’ll have the
com.apple.rootless.install.heritable entitlement, which means privilege to write to
/System and spawn a shell without rootless restriction.
The bug has been fixed in Mojave Beta, no more external library, finally.
This bug can actually be a root to kernel privilege escalation. Please refer to the slides for my HITB Ams 2019 talk:
And here’s the exploit to load an totally unsigned KEXT on macOS 10.13.x