Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Take a Jailbreak -Stunning Guards for iOS Jailbreak- by Kaoru Otsuka


Published on

In this talk, I investigate several exploiting ideas for iOS kernel jailbreak using recently exposed vulnerabilities. Recently, Ian Beer found the following promising vulnerabilities:
CVE-2016-7637: Broken kernel mach port name ‘uref’ handling on iOS/MacOS can lead to privileged port name replacement in other processes,
CVE-2016-7644: XNU kernel UaF due to lack of locking in set_dp_control_port,
CVE-2016-7661: MacOS/iOS arbitrary port replacement in powerd.
However, naive combination of the above vulnerabilities cannot easily break recent mitigations implemented in iOS versions. Recent iOS provides the kernel level mitigations against exploitation such as kernel patch protection, sandboxing, AMFI(Apple Mobile File Integrity), MAC(Mandatory Access Control) policy, KASLR(Kernel ASLR) etc. These mitigations will be briefly explained.

Published in: Devices & Hardware
  • Hey guys! Who wants to chat with me? More photos with me here 👉
    Are you sure you want to  Yes  No
    Your message goes here

Take a Jailbreak -Stunning Guards for iOS Jailbreak- by Kaoru Otsuka

  1. 1. Take a Jailbreak - Stunning Guards for iOS Jailbreak - Kaoru Otsuka
  2. 2. Who am I • An iOS hacking enthusiast • A first-grade high school student at Waseda University High School
  3. 3. Summary • Escalation to root • Escalation to kernel • Disabling mitigations for post exploitations This talk explains the following 3 Methods
  4. 4. The bugs • Those bugs are found by Ian beer who is at googleprojectzero • CVE-2016-7637
 - Broken kernel mach port name uref handling on iOS/MacOS can lead to privileged port name replacement in other processes • CVE-2016-7644
 - XNU kernel UaF due to lack of locking in set_dp_control_port • CVE-2016-7661
 - MacOS/iOS arbitrary port replacement in powerd
  5. 5. Attack vector • CVE-2016-7637 and CVE-2016-7661 to privilege escalation to root • CVE-2016-7644 to gain the kernel task port • Applying patches to disable a bunch of mitigations
  6. 6. CVE-2016-7637 This vulnerability can be applied to MITM attack 
 and leads us to gain a root task port.
  7. 7. CVE-2016-7637 • The bug is basically a mistake of an buffer overflow checking (but not buffer overflow bug in ipc_right_copyout)
  8. 8. CVE-2016-7637 • What’s the meaning of “pegging”? • Suppose it is to prevent a sort of buffer overflow and wrap around to 0 • But the concept of “pegging” is hardly used in xnu • Can we exploit it?
  9. 9. Mach IPC system • The ports targeting on this exploit are related to ipc_entry Source: “Through the mach portal”, ianbeer
  10. 10. CVE-2016-7637 • The point is that
 UREFS count is exceeded at 0xFFFE 
 and send “overflow” message to the target port • The next UREFS count being supposed to be 0xFFFF will result in still retaining the UREFS count being 0xFFFE • So it’s promoted to an out-of-sync vulnerability • Let’s take a look at the inside of this exploit in the next slide
  11. 11. CVE-2016-7637 • The applied technique is sending 0x10000 messages (of the same send right) to the target port • The messages are made to be freed in the process of mach_msg_server (sending invalid messages) • Spraying those malicious messages to target port’s UREFS and they will be freed after they are counted to UREFS • This cause the target port being freed! • Let’s reallocate there and take control of the target port
  12. 12. CVE-2016-7637 • There’s a strategy to mitigate for the reallocation of a port and using it (like Use-After-Free) • “ipc_entry” has an entry of generation number (in “ie_bits”) • Generation number entry consists of 6bits bit field. • Generation number will be checked on the userspace/ kernelspace boundary • Incrementing generation number program is below
  13. 13. CVE-2016-7637 • Generation number is up to 64 (not overlapping) • So we need a primitive that allows us to loop generation number around to match the generation number at 64th reallocating • Exploiting reliably, the target port needs to locate at the approximately middle of the freelist
  14. 14. ipc_entry freelist • It’s a simple LIFO list. • Though the value indicating the next node isn’t an address but an index of “is_table” • Unlinking the entry from freelist, old head becomes our next node
  15. 15. CVE-2016-7637 • This topic is to enhance the reliability for this exploit • Sending N messages (reallocating and freed soon) for the sake of target port to be down the freelist • After that, sending 62 loops of 2N messages to increment target port’s generation number
  16. 16. CVE-2016-7637 • Review this exploit • Carry out the UREFS bug • Sending N messages • Sending 62 loop of 2N messages • Target port’s generation number will have been matched
  17. 17. What’s suitable for the target port? • We need a send right for that port • The kernel ports can’t be consumed since kernel-owned ports are looked up each time (e.g. bad setting for generation number) • launchd is a great service
  18. 18. launchd • can be accessed inside the sandbox and approved to have send right • Thanks to insecurities of Apple, receives the task port from client of it • Man-In-The-Middling the target port to capture the task port gives us root task port
  19. 19. Task port • Task port is assigned per task • Task port can be obtained by task_for_pid though this API is so restricted • If we have the task port, we can do anything on its process.
  20. 20. CVE-2016-7661 • Powerd is a client of • Powerd runs as root • Crashing powerd process (CVE-2016-7661) brings the target port to receive powerd’s task port
  21. 21. This vulnerability leads us to gain kernel task port CVE-2016-7644
  22. 22. ipc_port • ipc_entry has a reference to ipc_port (ie_object) • ipc_entry has only reference for ipc_port object • It’s maintained in zones which allocated by zone allocator
  23. 23. CVE-2016-7644 • This vulnerability is a sort of Use-After-Free • set_dp_control_port is only called from root task port so we can’t use this bug without previous exploiting
  24. 24. CVE-2016-7644 • Threads can race to see the same value for dynamic_pager_control_port and release it • ipc_port_release_send decrements the reference count io_references
  25. 25. How we know the reference count 
 hits 0?
  26. 26. CVE-2016-7644 • MIG has the feature named no-more-senders notification to notify us if there’s no ip_srights by ipc_port_release_send
 • The total count of senders ip_srights is decremented as well as the reference count • So we’ll use the advantage to notice when it reaches to 0
  27. 27. no-more-senders • ipc_port_release_send drops one reference and one send right for that port • ipc_notify_no_senders sends port->nsrequest port when port becomes no-more-senders
  28. 28. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries ie_object portA 1 reference 0 send right
  29. 29. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries portA ie_object portB Making a reference for that port 2 references 1 send right portB has send right to portA though doesn’t receive from portA
  30. 30. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries portA ie_object portB 3 references 2 send right portC PortC will be the receiver of no-more-senders notification
  31. 31. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries portA ie_object portB 3 references 2 send right portC Trigger that bug!
  32. 32. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries portA ie_object portB 2 references 1 send right portC Trigger that bug!
  33. 33. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries portA ie_object portB 1 references 0 send right portC Trigger that bug!
  34. 34. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries portA ie_object portB 1 references 0 send right portC send no-more- We could get the notification so we won the race!
  35. 35. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries portA ie_object portB 1 references 0 send right portC Then, what will happen if the portB will be destroyed?
  36. 36. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries portA ie_object 0 references 0 send right portC Then, what will happen if the portB will be destroyed?
  37. 37. ipc_entry ipc_entry ipc_entry ipc_entry ipc_entry ipc_entries ie_object 0 references 0 send right What’s ie_object pointing to? The ipc_entry->ie_object becomes a dangling pointer!
  38. 38. zalloc • zalloc is a system call that assigns zones corresponding to the size • zalloc have a local freelist per zone • zones are freed by memory pressures or mach_force_zone_gc
  39. 39. CVE-2016-7644 • There are zones for ipc_port as I said before • We allocate a ram_mb*20 number of ports (early ports) • And we alllocate 20 of ports (middle ports) • Finally, we allocate 5000 of ports (late ports) • Not forget to prepare stashed port (corresponding to portB) for all of ports we allocated
  40. 40. CVE-2016-7644 • Causes the bug for each middle ports • Destroy the stashed ports • Eventually we’ve made ipc_entries point into dangling port pointers
  41. 41. CVE-2016-7644 • Make the page be able to reallocate other kind of zones(currently it’s for ipc_ports) to capture the kernel port • We here use another technique to gain kernel task port
  42. 42. Fake ipc_port • Use dangling ipc_ports to retrieve or write ip_context • Overlapping the zone we targeted on using ool_ports • ool_ports will misunderstand ipc_ports members Source: “Through the mach portal”, ianbeer attachment?aid=280146
  43. 43. CVE-2016-7644 • We are aiming to get the kernel task port • The kernel task port are supposed to be allocated at bootstrapping kernel which is probably at the first page of ipc_ports • And we can get/set the ip_context of ipc_ports (with mach_port_{set|get}_context)
  44. 44. CVE-2016-7644 • Rewrite the every ip_context of dangling ipc_ports to the addresses which are around the middle of first ipc_ports’ page
 (This is CORE technique of our Jailbreak) • There is a kernelspace to userspace conversion function 
 which converts “port address” to “port object” • Using this conversion, once our dangling ipc_ports’ ipc_context will be rewritten to the address of kernel task ports, the overlapped ool_ports (whose host_port) becomes kernel_task port with some probability! • As a result, the ool_ports can be used for receiving kernel_task_port from userspace tasks. 
 This enables our userspace task to manipulate kernel memory in any way!
  45. 45. Process handling in xnu • Process handling implementation in xnu is similar to one in BSD • There is a great deal of benefits to compromise a couple of values in the exact structure
  46. 46. Privilege Escalation • Most exploits in various platforms likely use this sort of technique • “proc” structure is provided by per process • “allproc” variable holds a single linked list for every process’s “proc” • Rewriting flags and credentials inside “proc” structure!
  47. 47. “proc” structure struct proc { LIST_ENTRY(proc) p_list; /* List of all processes. */ pid_t p_pid; /* Process identifier. (static)*/ void * task; /* corresponding task (static)*/ struct proc * p_pptr; /* Pointer to parent process.(LL) */ pid_t p_ppid; /* process's parent pid number */ pid_t p_pgrpid; /* process group id of the process (LL)*/ uid_t p_uid; gid_t p_gid; uid_t p_ruid; ..... kauth_cred_t p_ucred; /* Process owner's identity. (PUCL) */ ..... uint32_t p_csflags; /* flags for codesign (PL) */ ..... • At first glance, we just rewrite the values “p_uid” and “p_gid” • But these fields are’t used inside the kernel process maintaining system • The real one is inside the “p_ucred” structure!
  48. 48. “kauth_cred_t” • “typedef struct ucred *kauth_cred_t;” • “ucred” structure is the original credential maintainer • So we should do is to copy a highly privileged credential to our process
  49. 49. p_csflags • Flags for codesign • Just a 32bit bitfield • Attributes are defined in bsd/sys/codesign.h • Editing several values to allow/deny options
  50. 50. p_csflags • flag |= CS_PLATFORM_BINARY|CS_INSTALLER| CS_GET_TASK_ALLOW • This allows us to obtain a task from another process • flag &= ~(CS_RESTRICT|CS_KILL|CS_HARD); • Omitting complicated options
  51. 51. • Until 2 months ago, it was called KPP but now it is called KTRR or AMCC • The most annoying mitigation for jailbreakers • Based on arm’s TrustZone technology • As of xnu-4570.1.46, it became partially open-sourced (there seems no sync_handler implementation) AMCC
  52. 52. AMCC • There are 4 privilege level being established in Trustzone • EL0 - User-space programs are running here • EL1- Kernel and iBoot(Bootloader) • EL2 - Unused in iOS • EL3 - AMCC/KTRR
  53. 53. AMCC • AMCC’s strategy is the kernel regions with read-only or read|exec-only permissions to be guaranteed unmodified • If these regions are determined as an invalid region, AMCC causes kernel panic • Bypass the regions checking loop so that giving us to write anywhere
  54. 54. AMCC • In theory, it is inevitable • Though in practice, it is not inevitable • Let’s get started into arm abyss!
  55. 55. AMCC • AMCC needs to retrieve several system registers to know the kernel space states or user space states • We can set these registers if we have kernel execution
  56. 56. System Registers • TTBR1_EL1
 The TTBR1_EL1 controls the base address of translation table 1
 The CPACR_EL1 controls access to floating-point, and Advanced SIMD functionality from EL0, EL1, and EL3.
 The flag register “CPACR_EL1.FPEN” called “NEON” determines if it traps
  57. 57. The loop EL0 FPU Execution EL3 Executes sync_handler EL0 or EL1 IRQ Execution EL3 Executes Watchtower
  58. 58. sync_handler • It’s the core of AMCC • Supposed it checks KTRR regions integrity and registers integrity • If there’s invalid pages it will trigger kernel panic • It sets CPACR_EL1 to not to trap FPU instruction
  59. 59. Watchtower • It will be called by IRQ instruction • Its source is located at osfmk/arm64/locore.s • Restoring a bunch of register and CPACR_EL1 to trap any instruction in EL0 and EL1
  60. 60. The solution • Referred to @qwertyoruiopz Yalu102 jailbreak • 1st, load dummy Translation Table Base address to TTBR1_EL1 • 2nd, hit CPACR_EL1 not to be trapped by EL3
 (but it triggers check on EL3 now) • 3rd, load fake Translation Table Base address to TTBR1_EL1 • 4th, executes “tlbi vmalle1” to invalidate all stage 1 translations • And patching instruction touching cpacr to nop
  61. 61. The solution • The code is below
  62. 62. Shadowmapping technique • gVirtbase - virtual address of translation table entries • gPhybase - physical address of translation table entries • Both of them is stored in pmap structure • The technique is replacing original Translation Table Entry to our fake Translation Table Entry so that giving us write permission to executable pages
  63. 63. Problem • TTBR_EL1 will be reset to 0 on sleeping • There are 2 kinds of sleeping • Idle sleep 
 sleeping when cpu is idle • Deep sleep
 sleeping when the screen has been black out for more than 30 seconds • The state of them is stored in “struct cpu_data>interrupt_handler”
  64. 64. AMFI • Apple Mobile File Integrity • Exist as a daemon and a kext • The reason why it is targeted by attacker is that its kext audits the binary’s entitlements, code signing and MAC(Mandatory Access Control) policy
  65. 65. PE_i_can_has_debugger • Patching a1 for the function to always return true • If the function always returns true, many of the checks in the kernel will turn off
  66. 66. Disabling sandbox • MAC policies are stored at “mac_policy_conf->mac_ops” • These policies needs to be disable for jailbreaking • Just rewrite those pointers to be null
  67. 67. LwVM • Light-weight Volume Manager • LwVM wraps GPT • _mapForIO traps the root partition writing • Partition object which mark it lock by a flag is held on heap • Removing this flag to write anywhere in the root partition
  68. 68. Remount rootfs • mac_mount prevents mounting root partition as r/w • Bypassing this protection is as the same doing as we did in LwVM • vnode(checked every mounting on) have a flag • Remove that flag and remounting root partition
  69. 69. References • Through the mach portal (by ian beer) • yalu102 (by Luca Todesco) • iOS 10 Kernel Heap Revisited (by Stefan Esser) • Mac OS X and iOS Internals (by Jonathan Levin)
  70. 70. Demo Tested on iOS10.1.1 iPhone5s