2PAC 2Furious: Envisioning an iOS compromise in 2019 Marco Grassi - @marcograss Liang Chen - @chenliang0817
About Us • Members of Tencent KEEN Security Lab (formerly known as KeenTeam) • Marco (@marcograss): My main focus is iOS/Android/macOS and sandboxes. But recently shifted to hypervisors, basebands, firmwares etc. • • pwn2own 2016 Mac OS X Team Mobile pwn2own 2016 iOS team • pwn2own 2017 VMWare escape team • • Mobile pwn2own 2017 iOS Wifi + baseband team • Liang (@chenliang0817): Lead Pwn2Own team in KeenLab (Co-founder of KeenTeam/KeenLab) • • Browser exploiting, iOS/MacOS sandbox bypassing and privilege escalation • Winner of Mobile Pwn2Own 2013 iOS category Winner of Pwn2Own 2014 OSX category •
About Tencent Keen Security Lab • Previously known as KeenTeam • White Hat Security Researchers • Several times pwn2own winners • We are based in Shanghai, China • Our blog is https://keenlab.tencent.com/en/ • Twitter @keen_lab
Agenda • Introduction of ARMv8.3 pointer authentication • PAC on iOS 12 A12 • Possible attacks on PAC • When PAC is combined with APRR • Baseband • Baseband <=> Application Processor • Conclusions
ARMv8.3 pointer authentication • Principle: in ARM64, the pointer uses less than 64bit, the unused bits can be used as additional information to authenticate the pointer(PAC) 64bit pointer 47 0 PAC part Address part
ARMv8.3 pointer authentication • Three factors to generate PAC: value (address), context , key Key + Algorithm in CPU + = Value(address) Context PAC
ARMv8.3 pointer authentication • Context • A 64bit value used to strengthen PAC • Isolate different types of pointers used with the same key • Avoid pointer replacement attack (If all pointers use 0 context) • Key • 4 keys (combination of instruction/data and A/B keys), plus a G key (general key) for data hash purpose • Stored in system registry, inaccessible at userland • Keys are per process and per exception level (or weakness is introduced) • Algorithm • QARMA
ARMv8.3 pointer authentication • Instructions relating to PAC Instruction set Examples Comment PAC* PACIAZ, PACDB, etc… Generate PAC using specific key + context AUT* AUTIAZ, AUTDB, etc… Authenticate PAC using specific key + context Combined RETAA, BRAA, Authenticate PAC first, and do the LDRAA… original instruction
ARMv8.3 pointer authentication • PAC generation and authentication PAC* Raw pointer PACed pointer instruction Pass Continue exec AUT* PACed pointer Crash/Exit instruction Fail • What if the authentication fails? • Place an error code on specific bits of the address, making address invalid (53 rd and 54 th bit for EL0 address) • Process crash? Or not?
ARMv8.3 pointer authentication • What should be protected? • All pointers? • Of course not! Too expensive • Most important and sensitive content should be protected • Function pointers: using instruction keys • Important data pointers: using data keys • Important contents: using G key • Can be used to implement CFI
ARMv8.3 pointer authentication • How effective at preventing exploitation? • Keys are inaccessible in userland • Keys can not obtained by kernel R/W in EL1 • Algorithms might be public and know • So with arbitrary R/W, cannot compute PAC • To obtain arbitrary code execution you must compute PAC of function pointer first • To compute PAC of function pointer you must obtain arbitrary code execution • Chicken-egg problem!
The design is quite good, any real world phones using PAC?
PAC on iOS 12 A12 • iPhone XS, XS Max, XR are facilitated with A12 chip • First phones adopting ARMv8.3 in the world • The whole iOS kernel, and all system Apps/binaries have PAC enforced
Key initialization in iOS 12 • Kernel A key, B key, G key initialized during boot & cpu start (after idle) • Kernel IA IB DA DB G keys all initialized as constant value.
Key initialization in iOS 12 • iOS doesn’t change A key in any situation • B key is per-process initialized at process creation time, IB is enabled by default • In task_create_internal • Switched during context switch
Key initialization in iOS 12 • A key and DB key are enabled by default for platform binary • Such as Webcontent • But disabled for our own App, why? • According to ARMv8.3 document, system register SCTLR_EL1 responsible for key status control • EnIA, EnIB, EnDA, EnDB
Key initialization in iOS 12 • In exception_return: • For non-arm64e binary, EnIA EnDA and EnDB bit are masked
Key initialization in iOS 12 • How to enable IA DA DB keys for our own App? • Compile the binary as arm64e
What we can conclude so far • We can conclude: • B key is per-process • A key is the same for all processes • Non-arm64e apps have A key and DB key disabled, IB key and G key enabled • Questions? • A key and G key are constant value, same pointer same PAC upon each reboot? • That will cause big issue for sure • A key and G key are same for both EL0 and EL1, can use userland App to compute kernel pointer PAC? • Seems crazy idea
How PAC is used in iOS 12?
Enhanced stack protection • Previously stack is protected by adding a cookie value between return address and local variable data • Cookie value is unique in the same process • Attackers can obtain the value via arbitrary memory read, defeating the stack protection • With PAC, the return address is authenticated(Using B key) with SP as context • The value is unique per pointer + stack frame • And, B key is per-process
CFI in iOS 12 • No BLR and BR any more • Indirect function pointers are authenticated • C++ vptr is authenticated via data A key • Functions in vtable are authenticated via instruction A key plus specific context (entry location + a static value) • GOT function pointers are authenticated via A key plus their address(ASLR) as context
Objective C pointers • Objective-c vptr(isa) is not protected by PAC • But the method function pointer is IB key protected • B key is per-process • But before reaching object-c selector cache, there is chance to reach A key call • E.g __xpc_file_transfer_dispose, pointed out by Ian Beer
Use of G key • Exception, trap, interrupt involve PC register change • Previous state needs to be stored and restored frequently • Hackers can change those states to control the execution flow • LR PC and CPSR are the most critical registers • iOS uses G key to compute the hash of those critical registers, and ensure the values are not modified before restore • Validate the hash during restore, panic the system if validation failed
PAC makes exploitation harder • Modern exploitation aims to achieve arbitrary memory read/write as prerequisite • With PAC, achieving arbitrary memory read/write becomes harder • Especially vptr object involved UAF • Heap-overflow, or non vptr UAF are still likely to achieve R/W • Final goal of exploitation is to achieve arbitrary code execution • Sadly • This is what PAC aims to prevent • R/W -> code execution becomes super hard
R/W -> code execution? How?
Possible attacks • Real chicken-egg problem? • Key is there! Even B key can be read via R/W, other keys are constant value • Any ways to compute PAC without calling CPU PAC instruction? • QARMA � https://github.com/dkales/qarma64- python/blob/master/qarma.py • Result: fail • Apple might redesign/tweak the algorithm , and never publish
Possible attacks • Same key, same address, EL0 and EL1 PAC same? • Constant key, on each reboot, same address same PAC? • Result: all different. Why? • Guess: some customization / randomization set to the CPU during iBoot phase • And, Apple’s design cannot be that weak.
Possible attacks • Brute force guess • Some daemons are user-friendly when crashing • Some function pointers use context as 0 • Can replace between each other • Neither of the above is very practical or enough to achieve code execution
I believe, good design always has not so good implementation, in early version
Possible attacks • A key is the same for all processes • App can compute PAC for other processes • Case of userland privilege escalation or sandbox bypass • A great example was posted by Ian Beer recently: • https://googleprojectzero.blogspot.com/2019/04/splitting-atoms-in-xnu.html
Possible attacks – Signing gadgets • Signing gadgets, e.g ”PACIA x0, x1; ret”: • Without arbitrary code execution, just by calling API + R/W • And of course, obvious signing gadgets do not exist in iOS • But how about indirect signing gadgets?
Possible attacks – Signing gadgets • Found by Azad Brandon: in sysctl_unregister_oid, a converted 0-context pointer is stored and can be read out • X10 can be controlled • But AUTIA will fail as we cannot get PACed function pointer with specific context
Possible attacks – Signing gadgets • Failed != panic, after AUT*, a fixed error bit will be appended to the pointer • So we can always get the correct PACIZAed value of any function pointer • Which means we can control the PC • But how about code execution, ROP? Or JOP? • ROP is hard to achieve, as return address is PACed by B key. JOP should also be hard, but thanks to Apple’s obfuscated kernel extension, quite some non-PAC indirect branching instruction
Recommend
More recommend