The iPhone Wiki is no longer updated. Visit this article on The Apple Wiki for current information. |
Difference between revisions of "0x24000 Segment Overflow"
ChronicDev (talk | contribs) (removed old info) |
m (changed "us" in the first line to "people") |
||
(83 intermediate revisions by 21 users not shown) | |||
Line 1: | Line 1: | ||
− | Also known by |
+ | Also known by its codename, 24Kpwn, this was the first exploit in the [[S5L8720]] that allowed people to bypass the bootrom signature checks on [[LLB]] and create what is known as an [[untethered jailbreak]]. |
+ | |||
+ | As of {{date|2009|10}}, seven months after the exposure of this hole, Apple sold updated [[N88AP|iPhone 3GS]] and [[N72AP|iPod touch (2nd generation)]] units with new bootroms that have this vulnerability patched. |
||
==Credit== |
==Credit== |
||
+ | A "hybrid" dev team, in alphabetical order: [[User:ChronicDev|chronic]], [[CPICH]], [[ius]], [[User:MuscleNerd|MuscleNerd]], [[User:Planetbeing|Planetbeing]], [[User:Pod2g|pod2g]], [[User:Posixninja|posixninja]], et al. (anyone wishing to be unnamed) |
||
− | chronic, CPICH, ius, planetbeing, pod2g, posixninja, and co. |
||
+ | |||
+ | ==Background== |
||
+ | Upon boot-up, the [[S5L8720]] and [[S5L8920]] SoC have a MIU configuration which maps the [[S5L8720|Secure ROM]] to 0x0, providing the newly turned on device with an ARM exception vector and the first code to execute. This MIU configuration also maps a small amount of SRAM to 0x22000000 for the [[S5L8720]], and 0x84000000 for the [[S5L8920]]. Statically allocated variables, heap, and stack must use the SRAM, as "[[S5L8720|Secure ROM]]" is unwritable. A region of memory starting from (SRAM Start)+0x24000 is used for this purpose. The region of memory from the start of SRAM to (SRAM Start)+0x24000 is used as a buffer for loading the [[LLB|next stage bootloader]] code. The [[LLB]] code is stored in [[NOR]], along with code for all other bootloader stages, as well as art resources (boot logos) and the [[DeviceTree|OpenFirmware device tree]] to provide to the XNU [[kernel]]. The first portion (first 0x160 bytes) of memory at (SRAM Start)+0x24000 is used for initialized statically allocated variables. Shortly after boot, values for that region are initialized from [[S5L8720|Secure ROM]]. |
||
+ | |||
+ | ==Vulnerability== |
||
+ | The code that reads the [[LLB]] [[IMG3 File Format|IMG3 file]] from [[NOR]] into memory does not check the size of the [[LLB]] image being loaded, instead taking the size directly from the non-signature checked portion of the IMG3 header on the [[NOR]] (see ROM offset 0x2178). Any image greater than 0x24000 bytes in length will begin overwriting the portion of memory used to store Secure ROM statically allocated variables. Immediately vulnerable data includes USB data structures for [[DFU Mode]], a pointer to the bdev list structure, task list structures for the Secure ROM's scheduler, as well as the addresses of the hardware SHA1 registers. All of the above are potential avenues for exploitation. The method described below uses the SHA1 register addresses. |
||
+ | |||
+ | This vulnerability was discovered independently by pod2g and [[User:MuscleNerd|MuscleNerd]]. |
||
+ | |||
+ | == Exploit== |
||
+ | The goal of the exploit is to gain arbitrary code execution capability. |
||
+ | |||
+ | The exploit, as proposed by [[User:Planetbeing|planetbeing]], uses the overflow to overwrite one of the addresses of the SHA1 registers. The particular register is the only one that directly copies data to be hashed into the hardware (or into an arbitrary memory location, once the destination address has been overwritten). Code execution is achieved by writing data into the stack, specifically by overwriting the LR of the function performing the write to the "SHA1 register" so that instead of returning to the main SHA1 routine, it returns to a chosen location in memory that contains the payload code. The location chosen is within the range of memory that is filled with the [[LLB]]'s [[IMG3 File Format|IMG3]], so that the payload code can be placed within the LLB's IMG3. |
||
+ | |||
+ | The challenge is determining what to put in as the SHA1 register location so that the right portion of stack can be overwritten with the payload LR. This can be challenging without having access to any sort of exception dump (crash register dumps in the [[S5L8720|bootrom]] had been disabled by Apple). [[User:Planetbeing|Planetbeing]] performed a static analysis of a very detailed IDB produced by [[User:ChronicDev|chronic]] and CPICH and determined the theoretical call stack for both of the invocations of the SHA1 hardware within the bootrom code [http://web.archive.org/web/20140410202729/http://pastie.org/414981]. |
||
+ | |||
+ | In-situ verification of the LR location was performed by [[User:Posixninja|posixninja]]. CPICH discovered a way to alter the [[IMG3 File Format|IMG3]] DER so that the second invocation of the SHA-1 hardware was not performed without affecting the first, allowing better confirmation that this step was performed properly. |
||
+ | |||
+ | The final SHA-1 register address was chosen so that the first dword of the DATA tag of the [[LLB]] [[IMG3 File Format|IMG3]] would replace sub_5E54's LR. This is because this is the first dword of the [[IMG3 File Format|IMG3]] that can be altered without substantially changing the [[IMG3 File Format|IMG3]]'s structure (and possibly disrupting earlier parsing code). The LR replacement must be done the first time the exploit is triggered (by the invocation of sub_5E54), or else the [[S5L8720|bootrom]] would crash. Since sub_5E54 takes 0x40 bytes of data at a time, the replacement LR thus must be within the first 0x40 bytes of data to be hashed. Data to be hashed starts at 0xC bytes from the start of the [[IMG3 File Format|IMG3]], and the first dword of the DATA tag is 0x20 bytes from the start of the [[IMG3 File Format|IMG3]]. Thus, the SHA1 register address chosen should be 0x20 - 0xC = 0x14 bytes before sub_5E54's LR. So, it must be 0x2202FE24. Note that the exploit will also trash up to 0x2202FE24 + 0x40 = 0x2202FE64. So a sizeable portion of doComputeSHA1's stack will be trashed as well. |
||
+ | |||
+ | The final exploit [[IMG3 File Format|IMG3]] was verified by [[User:Posixninja|posixninja]] under [[User:Planetbeing|planetbeing]]'s instructions to allow arbitrary code execution. It was a regular [[IMG3 File Format|IMG3]] with padding up to 0x24000 bytes. The next 0x100 bytes were taken from the original initialization values for 0x22024000. However, 0x240FC, the offset of the SHA1 register address, was altered to 0x2202FE24. The first dword of the DATA tag (offset 0x20) was altered to 0x22023000. Payload code was placed at offset 0x23000. |
||
+ | |||
+ | ==Payload== |
||
+ | The goal of the payload is to allow an unsigned [[LLB]] to be loaded. |
||
+ | |||
+ | There are several ways that can be used, including directly calling the JumpToMemory function which is designed to prepare the SoC and invoke the [[LLB]] code. However, it's designed to be used on decrypted, unpacked code, and the [[LLB]] code currently resides in an encrypted from within the [[IMG3 File Format|IMG3]]'s DATA tag. The simplest solution is thus to use the bootrom's own machinery to decrypt and execute the code. |
||
+ | |||
+ | The final payload evolved out of a discussion between '''pod2g''' and '''planetbeing''', based on an IDB documented by '''pod2g''', '''chronic''', '''CPICH''', et al. The lowest impact solution is to apply the pwnage patch to the rsaCheck subroutine of the bootrom, and returning from the payload from computing the SHA1 without crashing the bootrom. However, in this case, since bootrom text is unwritable, this was not a viable solution. |
||
+ | |||
+ | The next lowest impact solution is to return from the entire parseFirmwareFooter function with a successful value, instead of the failure value it would normally return if signature checks fail. This would skip any remaining code in that subroutine. This solution did not work in-situ. Failures checking the epoch tags prevented the firmware from being executed. The cause of this was not investigated. |
||
+ | |||
+ | The final payload was to return past the verification of epoch and other tags in the [[LLB]]'s [[IMG3 File Format|IMG3]] to a spot right before the DATA tag was loaded from memory and decrypted. R5 was set to 0 to ensure decryption would not be skipped. The original value for the first DATA dword (before we had to overwrite it with the exploit LR) is written back to 0x22000020 by the payload, and the original SHA1 register value was written back to 0x2202FE24 to ensure the payload only activates once. |
||
+ | |||
+ | == Deployment == |
||
+ | Although the exploitable [[LLB]] can be manually written to [[NOR]] by bootstrapping from a tethered jailbreak, the easiest way is to use the Apple restore process itself. Apple's restore process will write arbitrary [[IMG3 File Format|IMG3]] files onto the [[NOR]], even if they fail signature checks. However, the "total size" value of the [[IMG3 File Format|IMG3]] is fixed up by the kernel before it is written to [[NOR]]. This would negate the exploit. However, [[User:MuscleNerd|MuscleNerd]] discovered that this could be bypassed by including the padding in another tag, such as CERT. Then, the written exploit [[LLB]] would have the "correct", exploitable total size. |
||
+ | |||
+ | ==Timing Impact== |
||
+ | This exploit would have allowed the [[pwnage]] of the [[N88AP|iPhone 3GS]] without the discovery of an additional code execution vulnerability (required to write the exploit [[LLB]]), provided that the bug still existed in the 3GS's [[S5L8920|bootrom]]. Even though it was too late to patch the bootrom, it was not too late for Apple to change the restore process in the stock IPSW, removing the method used to get the exploitive [[LLB]] onto the device. Before, Apple would have no reason to fix this, since writing arbitrary data to [[NOR]] does not negate their chain of trust. However, now that a way has been found, they were able to prioritize a fix for this oversight thus making the permanent [[pwnage]] of future devices significantly more difficult. |
||
+ | |||
+ | Thanks to irresponsible handling of the exploit by a third-party company known as [[NitroKey]] who was interested in making financial gain from the work of others, this eventuality became a near-certainty and pretty much erased the possibility of a day-of-release jailbreak for the [[N88AP|iPhone 3GS]] and the [[N18AP|iPod touch (3rd generation)]]. In addition, to counteract the exploit, with the early exposure of the exploit, Apple was able to add the [[ECID]] tag to the [[IMG3 File Format]] in the [[N88AP|iPhone 3GS]]. The early leak of the exploit allowed Apple to understand that an [[iBoot]] exploit would be necessary to flash the required oversized [[LLB]] and through doing so, Apple have prevented this exploit from allowing the [[N88AP|iPhone 3GS]] to be permanently jailbroken through this exploit unless new [[iBoot]] exploits (allowing unsigned code to be run) can be found in every firmware release or a signed copy of an (older) vulnerable version of [[iBoot]] is stored. |
||
+ | |||
+ | May the bastards of [[NitroKey]] burn in hell for all eternity. |
||
+ | |||
+ | ==3GS Implementation== |
||
+ | Early-run models of the [[N88AP|iPhone 3GS]] are still affected by this vulnerability. In these models, the exploit remains the same in spirit. |
||
+ | |||
+ | The call tree and stacks analysis is very similar although a few bytes here and there changed it slightly. It was again done manually but afterward, and out of fun, an IDA Python Script was written to automate the process. The new static analysis can be seen [http://pastie.org/551212 here], and the IDA Python Script for it [http://github.com/iZsh/IDA-Python-Scripts/ there]. |
||
+ | The main differences are: |
||
− | ==Exploit== |
||
− | The address that the bootrom loads [[LLB]] into is 0x22000000, and for some reason, it stores it's global variables dangerously close, at 0x22024000. Now, when loading [[LLB]] from [[NOR]], it does not have any sort of maximum size limit, unlike if it was receiving a file via USB. You just can gracefully overwrite, and for some parts, will need to reconstruct, the beginning of the data (_bss) section. There are a few different ways you could exploit this to actually run unsigned code at this level, but so far the easiest one found is based on another fail decision that Apple made. For some reason, they and put the SHA1 hardware address array smack dab in our way, so at this point, you can change anything there that you want. By changing the pointer to SHA1 Data Input Register 1 into a pointer to where the current LR is on the stack, it will put whatever is at 0x20 of the image in LR, which is all that is important. By putting your payload somewhere in the padding (you need padding, since LLB is less than 0x24000 bytes obviously), you can just put the address of it at 0x20 of the image! If you actually don't want to run unsigned code but instead just want to run the LLB, then you will first need to have it put the original bytes back at 0x20 in the file before you do anything else, as well as put the original SHA1 hardware address back in the array. Another important thing to remember is that you must 1. add 0x22000000 to whatever the offset of your payload is in the file, since that is where it loads LLB in memory, and 2. reverse it for endianess. |
||
+ | * the SRAM is at 0x84000000 instead of 0x22000000 |
||
− | ==Prerequisites== |
||
+ | * the Original value of the first DATA dword is written back to 0x84000040 (which was overwritten by the LR address) |
||
− | Because files sent over USB have a size limitation, one thing that is the ability to flash the [[NOR]] unsigned. |
||
+ | * the SHA1 register original value is written back to 0x840241CC |
||
+ | * '''The decrypt flag is not held in R5 anymore''', but in a local variable of the function "my_process_module" (sub_2564). An extra static analysis tells us this variable is held at 0x84033F30, thus that's where you have to store your 0x0 value before returning to this function. |
||
− | [[Category:Exploits]] |
+ | [[Category:Bootrom Exploits]] |
Latest revision as of 17:13, 22 October 2021
Also known by its codename, 24Kpwn, this was the first exploit in the S5L8720 that allowed people to bypass the bootrom signature checks on LLB and create what is known as an untethered jailbreak.
As of October 2009, seven months after the exposure of this hole, Apple sold updated iPhone 3GS and iPod touch (2nd generation) units with new bootroms that have this vulnerability patched.
Contents
Credit
A "hybrid" dev team, in alphabetical order: chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al. (anyone wishing to be unnamed)
Background
Upon boot-up, the S5L8720 and S5L8920 SoC have a MIU configuration which maps the Secure ROM to 0x0, providing the newly turned on device with an ARM exception vector and the first code to execute. This MIU configuration also maps a small amount of SRAM to 0x22000000 for the S5L8720, and 0x84000000 for the S5L8920. Statically allocated variables, heap, and stack must use the SRAM, as "Secure ROM" is unwritable. A region of memory starting from (SRAM Start)+0x24000 is used for this purpose. The region of memory from the start of SRAM to (SRAM Start)+0x24000 is used as a buffer for loading the next stage bootloader code. The LLB code is stored in NOR, along with code for all other bootloader stages, as well as art resources (boot logos) and the OpenFirmware device tree to provide to the XNU kernel. The first portion (first 0x160 bytes) of memory at (SRAM Start)+0x24000 is used for initialized statically allocated variables. Shortly after boot, values for that region are initialized from Secure ROM.
Vulnerability
The code that reads the LLB IMG3 file from NOR into memory does not check the size of the LLB image being loaded, instead taking the size directly from the non-signature checked portion of the IMG3 header on the NOR (see ROM offset 0x2178). Any image greater than 0x24000 bytes in length will begin overwriting the portion of memory used to store Secure ROM statically allocated variables. Immediately vulnerable data includes USB data structures for DFU Mode, a pointer to the bdev list structure, task list structures for the Secure ROM's scheduler, as well as the addresses of the hardware SHA1 registers. All of the above are potential avenues for exploitation. The method described below uses the SHA1 register addresses.
This vulnerability was discovered independently by pod2g and MuscleNerd.
Exploit
The goal of the exploit is to gain arbitrary code execution capability.
The exploit, as proposed by planetbeing, uses the overflow to overwrite one of the addresses of the SHA1 registers. The particular register is the only one that directly copies data to be hashed into the hardware (or into an arbitrary memory location, once the destination address has been overwritten). Code execution is achieved by writing data into the stack, specifically by overwriting the LR of the function performing the write to the "SHA1 register" so that instead of returning to the main SHA1 routine, it returns to a chosen location in memory that contains the payload code. The location chosen is within the range of memory that is filled with the LLB's IMG3, so that the payload code can be placed within the LLB's IMG3.
The challenge is determining what to put in as the SHA1 register location so that the right portion of stack can be overwritten with the payload LR. This can be challenging without having access to any sort of exception dump (crash register dumps in the bootrom had been disabled by Apple). Planetbeing performed a static analysis of a very detailed IDB produced by chronic and CPICH and determined the theoretical call stack for both of the invocations of the SHA1 hardware within the bootrom code [1].
In-situ verification of the LR location was performed by posixninja. CPICH discovered a way to alter the IMG3 DER so that the second invocation of the SHA-1 hardware was not performed without affecting the first, allowing better confirmation that this step was performed properly.
The final SHA-1 register address was chosen so that the first dword of the DATA tag of the LLB IMG3 would replace sub_5E54's LR. This is because this is the first dword of the IMG3 that can be altered without substantially changing the IMG3's structure (and possibly disrupting earlier parsing code). The LR replacement must be done the first time the exploit is triggered (by the invocation of sub_5E54), or else the bootrom would crash. Since sub_5E54 takes 0x40 bytes of data at a time, the replacement LR thus must be within the first 0x40 bytes of data to be hashed. Data to be hashed starts at 0xC bytes from the start of the IMG3, and the first dword of the DATA tag is 0x20 bytes from the start of the IMG3. Thus, the SHA1 register address chosen should be 0x20 - 0xC = 0x14 bytes before sub_5E54's LR. So, it must be 0x2202FE24. Note that the exploit will also trash up to 0x2202FE24 + 0x40 = 0x2202FE64. So a sizeable portion of doComputeSHA1's stack will be trashed as well.
The final exploit IMG3 was verified by posixninja under planetbeing's instructions to allow arbitrary code execution. It was a regular IMG3 with padding up to 0x24000 bytes. The next 0x100 bytes were taken from the original initialization values for 0x22024000. However, 0x240FC, the offset of the SHA1 register address, was altered to 0x2202FE24. The first dword of the DATA tag (offset 0x20) was altered to 0x22023000. Payload code was placed at offset 0x23000.
Payload
The goal of the payload is to allow an unsigned LLB to be loaded.
There are several ways that can be used, including directly calling the JumpToMemory function which is designed to prepare the SoC and invoke the LLB code. However, it's designed to be used on decrypted, unpacked code, and the LLB code currently resides in an encrypted from within the IMG3's DATA tag. The simplest solution is thus to use the bootrom's own machinery to decrypt and execute the code.
The final payload evolved out of a discussion between pod2g and planetbeing, based on an IDB documented by pod2g, chronic, CPICH, et al. The lowest impact solution is to apply the pwnage patch to the rsaCheck subroutine of the bootrom, and returning from the payload from computing the SHA1 without crashing the bootrom. However, in this case, since bootrom text is unwritable, this was not a viable solution.
The next lowest impact solution is to return from the entire parseFirmwareFooter function with a successful value, instead of the failure value it would normally return if signature checks fail. This would skip any remaining code in that subroutine. This solution did not work in-situ. Failures checking the epoch tags prevented the firmware from being executed. The cause of this was not investigated.
The final payload was to return past the verification of epoch and other tags in the LLB's IMG3 to a spot right before the DATA tag was loaded from memory and decrypted. R5 was set to 0 to ensure decryption would not be skipped. The original value for the first DATA dword (before we had to overwrite it with the exploit LR) is written back to 0x22000020 by the payload, and the original SHA1 register value was written back to 0x2202FE24 to ensure the payload only activates once.
Deployment
Although the exploitable LLB can be manually written to NOR by bootstrapping from a tethered jailbreak, the easiest way is to use the Apple restore process itself. Apple's restore process will write arbitrary IMG3 files onto the NOR, even if they fail signature checks. However, the "total size" value of the IMG3 is fixed up by the kernel before it is written to NOR. This would negate the exploit. However, MuscleNerd discovered that this could be bypassed by including the padding in another tag, such as CERT. Then, the written exploit LLB would have the "correct", exploitable total size.
Timing Impact
This exploit would have allowed the pwnage of the iPhone 3GS without the discovery of an additional code execution vulnerability (required to write the exploit LLB), provided that the bug still existed in the 3GS's bootrom. Even though it was too late to patch the bootrom, it was not too late for Apple to change the restore process in the stock IPSW, removing the method used to get the exploitive LLB onto the device. Before, Apple would have no reason to fix this, since writing arbitrary data to NOR does not negate their chain of trust. However, now that a way has been found, they were able to prioritize a fix for this oversight thus making the permanent pwnage of future devices significantly more difficult.
Thanks to irresponsible handling of the exploit by a third-party company known as NitroKey who was interested in making financial gain from the work of others, this eventuality became a near-certainty and pretty much erased the possibility of a day-of-release jailbreak for the iPhone 3GS and the iPod touch (3rd generation). In addition, to counteract the exploit, with the early exposure of the exploit, Apple was able to add the ECID tag to the IMG3 File Format in the iPhone 3GS. The early leak of the exploit allowed Apple to understand that an iBoot exploit would be necessary to flash the required oversized LLB and through doing so, Apple have prevented this exploit from allowing the iPhone 3GS to be permanently jailbroken through this exploit unless new iBoot exploits (allowing unsigned code to be run) can be found in every firmware release or a signed copy of an (older) vulnerable version of iBoot is stored.
May the bastards of NitroKey burn in hell for all eternity.
3GS Implementation
Early-run models of the iPhone 3GS are still affected by this vulnerability. In these models, the exploit remains the same in spirit.
The call tree and stacks analysis is very similar although a few bytes here and there changed it slightly. It was again done manually but afterward, and out of fun, an IDA Python Script was written to automate the process. The new static analysis can be seen here, and the IDA Python Script for it there.
The main differences are:
- the SRAM is at 0x84000000 instead of 0x22000000
- the Original value of the first DATA dword is written back to 0x84000040 (which was overwritten by the LR address)
- the SHA1 register original value is written back to 0x840241CC
- The decrypt flag is not held in R5 anymore, but in a local variable of the function "my_process_module" (sub_2564). An extra static analysis tells us this variable is held at 0x84033F30, thus that's where you have to store your 0x0 value before returning to this function.