class: center, middle # checkm8 exploit
&
checkra1n jailbreak #### Student seminar: security protocols and applications #### 03/2020 ##### Louis Merlin (247565) --- # Plan ### 1. What is a jailbreak ? ### 2. History ### 3. Deep Dive ### 4. Conclusion --- # 1. What is a jailbreak ? ??? First, what do I mean by jailbreak ? -- ### - Privilege escalation on Apple's iOS ??? It typically involves some kind of privilege escalation on iOS, making the user root and able to bypass most of Apple's built in limitations. -- ### - Mobile carrier unlocking and device customization ??? A big usage of jailbreaking used to be for mobile carrier unlocking, if you wanted to switch your mobile carrier, say, from Swisscom to Salt or the other way around. It is also used to install apps that are not on the Apple App Store, and tweak your device in different ways. I remember on one of the first versions of iOS, I used jailbreaking to change the background image of my iPod Touch from the only choice, black, to some picture I found cool at the time. -- ### - First jailbreak came out a few days after the first iPhone (2007) ??? Jailbreaks have played a big role in the iPhone from the beginning, as the first jailbreak was published only a few days after the release of the first iPhone. Since then, Apple has upgraded the security of the hardware and the software significantly. Some current versions of iOS and the iPhone have no public jailbreaks. Also, many security researchers that find those jailbreaks end up working on security at Apple. -- ### - Can be tethered, semi-tethered, untethered or semi-untethered ??? A tethered jailbreak means that you get stuck on recovery mode if you reboot your iPhone. A semi-tethered jailbreak means you need to re-jailbreak your iPhone on every boot. An untethered jailbreak means that the jailbreak persists after reboot. A semi-untethered jailbreak means you can re-jailbreak your iPhone by manually launching an app from your iPhone after reboot. Checkra1n is a semi-tethered jailbreak, so you would need to re-jailbreak your iPhone on every reboot. --- # 2. History ### - Late 2019, `ipwndfu` by axi0mX ### - Targets SecureROM (immutable code), so unpatchable ### - Leads to *checkra1n* ??? The exploit was first published in September 2019 by axi0mX in his pwn tool ipwndfu, although littlelailo claimed to have discovered it in March and published it in a text file. It targets SecureROM, the first part of the iOS cold boot process, which is hard-coded in silicon, so unpatchable. Over the months it was used to create a full jailbreak for iPhones 5s to X, named checkra1n. --- # 3. Deep Dive --- ### SecureROM .center[![SecureROM](./SecureROM.png)] ##### .right[https://habr.com/en/company/dsec/blog/472762/] --- ## 3.1 - Normal use of DFU - Start USB DFU protocol: - Input output buffer is allocated by the device in the ram - Address is given to usb stack via global variable - Image is transfered to the device - Image is copied to the memory location from where the boot will happen - Image is verified - On DFU exit: - i/o buffer is freed - If parsing the image fails, the USB stack is activated again ??? DFU stands for Device Firmware Upgrade. SecureROM DFU image upload is used by Apple to bypass iBoot, the next part of the boot process, as an emergency recovery mecanism. The image and its signature will be verified before it is used. The signature is one of Apple's public keys, which are 2048-bit long RSA public keys. --- ## 3.2 - checkm8 - Start USB DFU protocol: - Input output buffer is allocated by the device in the ram - Address is given to usb stack via global variable - Image is transfered to the device
INTERRUPT
-
Image is copied to the memory location from where the boot will happen
-
Image is verified
- On DFU exit: - i/o buffer is freed
=> use-after-free
- If parsing the image fails, the USB stack is activated again ??? Now let's talk about the actual checkm8 exploit. When we interrupt the USB transfer midway, the code jumps to the "On DFU exit" part. The i/o buffer is freed, but the global pointer is never NULLed out. After the USB stack is activated again, if we send the device data instead of a setup packet, the device will copy data on the dangling pointer. This is a typical use-after-free vulnerability. --- ## 3.3 - A8 and A9 processors ### - iPhone 6, 6+, 6s and 6s+ ### - Use-after-free overwrites USB stack ### - USB tasks are a linked list of tasks ### - Overwrite the current task's **next** value, and create that next task ### - 🙌 ??? In the case of two processors, the A8 and the A9, we can directy overwrite the USB stack, and thus we have direct code execution. We cannot target the current task's values, as they are already loaded onto the registers. We can use the `next` pointer though ! Easy Peasy ! --- ## 3.4 - The rest... ### - The ROM is deterministic, an the USB stack is not where we need it to be. ??? For the rest of the vulnerable processors, we can allocate and free data, but we do not get determinism on where the data is. -- ### - Heap Feng Shui to the rescue ! ??? For this, we use Heap Feng Shui. The way the buffers are allocated is actually deterministic, as the process will allocate the smallest hole in memory that fits the data. --- ### Heap Feng Shui ``` def stall(device): libusb1_async_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 'A' * 0xC0, 0.00001) def leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC0, 1) def no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC1, 1) ``` ``` stall(device) leak(device) for i in range(6): no_leak(device) dfu.usb_reset(device) dfu.release_device(device) ``` Requests that are not a multiple of 64 bytes do not trigger the leak ! ??? So we launch multiple USB transfers at the same time, until the stars align and we can insert a gadget. Once the stall and leak transfers are finished, because of their size, the device will add "send zero-length-packets" tasks to the queue. Because of a bug, they will not be freed when DFU shuts off. --- .center[![Heap](./heap.png)] ##### .right[https://habr.com/en/company/dsec/blog/472762/] ??? ZLP = Zero-Length-Packet We will have create a nice little hole in the ram. --- .center[![Alloc](./alloc.png)] ##### .right[https://habr.com/en/company/dsec/blog/472762/] ??? We now restart DFU, and wait for it to do its allocations again. The hole will become the prefered place to put some crucial data because the heap is full. We can now overflow to `usb_device_io_request`, and gain direct code execution. --- ### We want this .center[![DFU](./DFU.png)] ##### .right[https://habr.com/en/company/dsec/blog/472762/] --- ### Payload ``` 0x1800B0000: t8010_shellcode # initializing shell-code ... 0x1800B0180: t8010_handler # new usb request handler ... 0x1800B0400: 0x1000006a5 # fake translation table descriptor # matches the value in the original translation table ... 0x1800B0600: 0x60000180000625 # fake translation table descriptor # matches the value in the original translation table 0x1800B0608: 0x1800006a5 # fake translation table descriptor # plus, in this descriptor,there are rights for code execution 0x1800B0610: disabe_wxn_arm64 # code for disabling WXN 0x1800B0800: usb_rop_callbacks # callback-chain ``` ??? As you can see, the payload defines a few fake address translation tables, to take over the system. WXN (Write permission implies Execute-never) is disabled which enables the code execution in RW memory. The modified translation table makes WXN disabling code execution possible. --- ### Final steps of exploit - Restore USB configuration - USB Serial Number = "PWND:[checkm8]" - Replace USB request handler pointer ??? We now restore the USB configuration to regain access to the device from the outside. The shellcode then overwrites a few values to tell the hacker that the execution was successful. Namely, the USB serial number is replaced with "PWND:[checkm8]" Finaly, we initiate a new USB transfer for the bootkit to load and execute. --- ## 3.5 - The Bootkit - Boot normally and compromise the stages one after the other -- - **But** iBoot will reset all registers and wipe memory ("trampoline") -- - We can hook bzero to avoid that ??? The bzero method (changes all data to \0 in specific memory space) is hooked into so that it never reaches our bootloader (transformed into a NOP in that case). This is a "hacky" way to do it according to the people who wrote it, but at least it has the advantage to work on all devices, and to be independent of future code changes. We now have read-write access to the kernel in the ram, but not to the iPhone's memory. -- - Embed tiny ramdisk in kernel with hijack code ??? In order to retain code execution in usermode, we can embed a tiny (fakeish) ramdisk in the shellcode, in order to hijack root code execution once the phone is booted. -- - We now have a fork(2) during system boot ??? The system will now fork(2) off right as it is booting iOS. In this fork we can launch an SSH daemon to get remote access to the system, and we can also load custom .app files to be installed on the system. --- # 4. Conclusion - latest full jailbreak was on iOS 8 (2014) - enables researchers to do security research - [dual booting](https://twitter.com/Basti564/status/1235316256024285184) - Linux on iPhone ? #### Illustrations and content - https://habr.com/en/company/dsec/blog/472762 - https://media.ccc.de/v/36c3-11238-the_one_weird_trick_securerom_hates