The document discusses finding and analyzing iOS kernel bugs through fuzzing techniques. It begins by providing background on the iOS kernel structure based on XNU and OSX. It then summarizes two known iOS kernel bugs from the past that involved integer overflows and type conversions. The document goes on to describe passive and active fuzzing approaches that can be used to find new bugs, including hooking kernel functions to fuzz parameters. It also provides tips on reversing iOS kernel extensions and debugging the kernel. Finally, it analyzes examples of bugs found through fuzzing and how to understand the crash causes and trigger paths through static analysis and debugging.
3. iOS Kernel Basics
OSX is older that iOS
Guess iOS kernel is developed based on OSX kernel
Learn from OSX kernel
OSX kernel concepts
Early derived from FreeBSD kernel
Named as XNU
Open source
3
5. BSD
Implement File System, Socket and ...
Export POSIX API
Basic interface between kernel and user space
sysent[] - store kernel function address
typedef int32_t sy_call_t(struct proc *, void *, int *);
function call number - /usr/include/sys/syscall.h
5
7. IOKit Objects
OSObject
Root object of all IOKit objects
Overwrite new operator to alloc memory
Declare “init” method to initialize object self
OSMetaClass
Run-time object type check
According to object name
OSDynamicCast
7
8. IOKit Objects
IOService
Define an interface for most kernel
extension
Basic methods - init / start / stop /
attach / detach / probe
ioreg - list all attached IOService
Available in Cydia
8
9. Write IOKit
Service - Inherit from IOService
Overwrite basic methods - init / start / stop / probe
Control - Inherit from IOUserClient
Allow user space control
Modify plist file
At least one IOKitPersonalities
CFBundleIdentifier/IOClass/IOProviderClass/IOMatchCategory/
IOUserClientClass/IOResourceMatch
9
10. Kernelcache
Store all kernel modules (XNU / extensions) into one cache file
iBoot will load the whole kernelcache and jump to entry
An encrypted and packed IMG3 file
/System/Library/Caches/com.apple.kernelcaches/kernelcache
For old devices (A4 devices)
Use xpwntool to decrypt original cache with IV + KEY
A5 devices
No IV + KEY available
10
11. Kernelcache
How to get kernelcache for A5 devices
Dump from kernel memory
task_for_pid(0) & vm_read to dump kernel memory
Read size must less then 0x1000 for once
Find all Mach-O header - test magic 0xFEEDFACE
Determine the whole cache size
Open with IDA - fail
Lack of prelink info
11
12. Kernelcache
Dump each kernel extension
Write a kextstat for iOS
Just call CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef)
from IOKit framework
12
13. Reverse Kernel
Kernelcache is combined with lots of Mach-O files
IDA Pro 6.2 could identify each Mach-O file
Reverse the whole kernel together
Open “Segmentation” view
13
14. Reverse IOKit Extension
IOKit constructor
example
First call
OSObject::new to
allocate memory
Then init IOService
At last init
OSMetaClass
14
15. Debug iOS Kernel
KDP code is included in kernel
KDP via UART
SerialKDPProxy to perform proxy between serial and UDP
Need serial communicate between USB and Dock connector
Make a cable by your own
Using redsn0w to set boot-args
-a “-v debug=0x09”
15
16. Debug iOS Kernel
A5 CPU Devices
No limera1n vulnerability - no way to set boot-arg
Need a kernel exploit to cheat kernel with boot-arg &
debug enable
See “iOS5 An Exploitation Nightmare” from Stefan Esser
for details
16
18. Summary of Known Bugs
iOS kernel attack surface
Socket/Syscalls
ioctl
FileSystem drivers
HFS
iOKit
Device drivers (USB/Baseband etc)
18
19. CVE-2010-2973
CVE-2010-2973 - IOSurfaceRoot integer overflow
Used in the jailbreakme 2 as PE exploit
Can be triggered by mobile user apps (MobileSafari)
Malformed IOSurfaceAllocSize/IOSurfaceBytesPerRow/
IOSurfaceHeight/IOSurfaceWidth values in the plist
Create a Surface object using above plist and return a userland ptr
Calling memcpy to overflow the important kernel structure to
disable the security protection
19
21. CVE-2011-0227
CVE-2011-0227 - IOMobileFrameBuffer Type
Conversion Issue
RootCause happens in the IOMobileFrameBuffer are not
properly to check the object when doing conversion
Suppose to call OSDynamicCast() while doing type
casting/conversion
The user able to control the vtable function pointer to get
code execution
21
23. Summary of Known Bugs
Conclusion
They are both PE vulns because it is happens in the IOKit
drivers framework
Closed source and less people pay attention
Good target for bug hunting!
23
25. Passive Fuzz
Passive Fuzz
First idea coming out is fuzzing
Less work with good results
Write a IOKit client to understand how the IOKit works
Fuzzing parameters for IOConnectCallStructMethod/
IOConnectCallScalarMethod
In the low-level both above APIs are calling to the
IOConnectCallMethod
25
26. Passive Fuzz
Why we need passive fuzzing?
They key point is pay less works because we are lazy to audit
code :P
Just like hook DeviceIoControl on the win32 to hunting kernel
bugs
We are going to hook IOConnectCallMethod to do the passive
fuzzing
26
27. Passive Fuzz
The Preparation
Finding a good hook framework for iOS
MobileSubstrate
http://iphonedevwiki.net/index.php/MobileSubstrate
MSHookFunction/MSHookMessage for C/Object Method
hook
Not much documents but enough to make it work
27
28. Passive Fuzz
TheOS/Tweak
Base the mobilesubstrate but more user-friendly
https://github.com/DHowett/theos
28
29. Passive Fuzz
You can also using interpose (dyld function)
Redirect the functions in the import table
No libmobilesubstrate required.
Inject your dylib via DYLD_INSERT_LIBRARIES to
make your fuzzer running!
29
30. Passive Fuzz
Tips
Struct object could be Data/Plist(XML), So pay some work
here.
Scalar object are integer values only, random enough to find
some interesting stuffs.
Results:
NULL pointer deference/Kernel Use-after-free/handled
panic exception
30
32. Active Fuzz
Weakness of passive fuzz
Only cover small amount of IOKit interfaces
Needs interaction - keep using your iPhone
Not so efficient - waste time
Advantage of active fuzz
Cover most of IOKit interfaces
Automatically and efficient
32
33. Rough Idea
Find all IOKit drivers with IOUserClient
Identify all external methods of the driver
Test all those methods
33
34. External Methods
External methods are used by IOKit to provide function to user-
space application
Application call IOConnectCallMethod to control driver
selector - which method should be called
input / output - Array of uint64_t or struct data
34
35. Kernel Dispatch
IOConnectCallMethod -> IOUserClient:: externalMethod
if dispatch != NULL
Check input and output size & call dispatch->function
else call getTargetAndMethodForIndex
Check type and size & call method->func
35
39. Key Point
Know what to fuzz
Get IOExternalMethodDispatch sMethods[]
Get IOExternalMethod methodTemplate[]
39
40. How
For the IOKit drivers without source code
Reverse the KernelCache with symbol problem resolved
IOKit structure you should know
IOExternalMethodDispatch & IOExternalMethod
Filter the IOKit keywords in the IDA name window
sMethods etc.
Will list all the IOKit drivers interface
40
44. Work Todo
Need some IDA Python works here
Add IOKit struct information in the idb file
(IOExternalMethodDispatch & IOExternalMethod)
Find the dispatch table range and mark it to the correct
struct.
44
46. Correct Input
Flags defines
I = input O = output
For example, type 3 means:
Struct input & output
We must pass the correct input/output type and count,
otherwise the request will be rejected
Start coding your own actively fuzzer!
46
47. Extra
You can also add the vtable information if you like to audit code
Before
After
47
49. Are There Bugs?
Definitely YES
Crashes could be easily generated by our fuzzer
Actually kernel code of iOS is not as good as you imagine
However analyzing crash is a hard job
No code or symbols for most IOKit drivers
Kernel debug is kinda of crap
Any exploitable bug?
This is a QUESTION
49
50. IOKit Bug Analysis
Simplify crash code
Code is generated by fuzzer - there are many IOConnectCallMethod calls
Simplify the code could help you a lot when doing static analysis
Look at panic log
fault_type & register values
Static analysis
Understand the bug and trigger path
Debug
Write exploit
50
53. Bug Sample I
Where did it crash
Try to read data at R1(=0) cause the panic
R1 is the second parameter of this function
It is mostly like a NULL ptr reference bug :(
We shall dig deeper anyway
53
54. Bug Sample I
Locate sMethod array
First to find AppleVXD375UserClient::externalMethod, which
should overwrite IOUserClient’s method
IOUserClient has symbols, see vtable for it
externalMethod pointer offset in vtable
54
55. Bug Sample I
Locate sMethod array
Search IOUserClient::registerNotificationPort address in “const”
segment
Find externalMethod pointer in vtable for AppleVXD375UserClient
AppleVXD375UserClient::externalMethod
Get IOExternalMethodDispatch struct from sMethod array
Call IOUserClient::externalMethod to dispatch it
55
57. Bug Sample I
selector = 1 dispatch struct in sMethod
function address = 0x80457534
checkStructureInputSize = 0x4
checkStructureOutputSize = 0x108
Remember the trigger code?
57
58. Bug Sample I
The whole call path
externalMethod -> sub_ 80457534 -> sub_ 804577EC ->
sub_8045779C -> sub_80456768 -> sub_80455C34 -> panic
sub_ 804577EC call OSObject::release first
This method should be used to destroy AppleVXD375UserClient itself
sub_8045779C should be responsible for freeing memory
R1(=0) maybe some class or struct address stored in
AppleVXD375UserClient object
58
59. Bug Sample I
Understand this bug
We manually try to destroy AppleVXD375UserClient
When in procedure, it will manipulate some object without
checking if it is already created
Lacks of basic check code like
if (obj->ptr != NULL)
We are not able to control PC register
59
62. Bug Sample II
Where did it crash
We got useless PC and no call stack
But luckily we had LR - store return address
Looks like calling method of certain object
R4 - object pointer
R0 - vtable
62
64. Bug Sample II
Crash code analysis
Input
R0 - IOAccelUserClient *self
R1 - int index
IOAccel *service = self + 0x78
OSObject *array[] = service + 0x10
Call array[index]->method = NULL
64
65. Bug Sample II
Weird
Why the object’s method pointer is NULL
Guess
Mistake it as a different object without checking
Todo
Figure out what’s at 0x10 offset
65
66. Bug Sample II
Locate external methods
This time it overwrite getTargetAndMethodForIndex
66
68. Bug Sample II
Where is selector 6 function ?
Check reference to IOAccelUserClient::vtable
It has a child object - IOIMGSGXUserClient
Easy to find getTargetAndMethodForIndex again
68
71. Bug Sample II
Object is created, check vtable 0x8090E5B8
0x8090E5B8+0x3C = 0x8090E5F4
71
72. Bug Sample II
Here is the story
selector 6 function call sub_80907A4C to create an object
and put it in object array at 0x10 offset
selector 3 function get object pointer from the array and call
its method without checking its class type
Actually the child has its own create/destroy method. If the
child create an object and make father to destroy it, PANIC !
Apple should call more OSMetaClassBase::safeMetaCast :P
72
74. Conclusion
Apple should audit iOS kernel code, especially code
of IOKit extensions
Since debug is quite hard, static analysis according to
panic log is very helpful
Fuzz your own iOS kernel bug !
74