usb_control_msg(0x21, 2) Exploit

From The iPhone Wiki
Revision as of 11:06, 6 October 2009 by ChronicDev (talk | contribs) (New page: {{DISPLAYTITLE:usb_control_msg(0x21, 2) Exploit}} == Credit (Alphabetical) == * '''vulnerability''': pod2g and westbaer * '''exploitation''': ius, chronic, pod2g, and posixninja * '''payl...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Credit (Alphabetical)

  • vulnerability: pod2g and westbaer
  • exploitation: ius, chronic, pod2g, and posixninja
  • payload (greenpois0n): chronic and posixninja


pod2g and westbaer discovered, via some reversing + fuzzing, you could overwrite the content of 0x0 thanks to Apple not checking the contents of a register they should have, shown in the disassm below. Now, the reason that this is useful is because the MMU maps whatever is running (LLB, iBoot, etc.) to 0x0 so that if an exception vector is triggered, it would jump to the one designed to be used with what is running, versus jumping to what is normally located at 0x0, the S5L8920 (Bootrom).

All you need to do is send the following...

usb_control_msg(iDev, 0x21, 2, 0, 0, 0, 0, 1000);

And thanks to our vulnerability, it will do this:

memcpy(0, LOAD_ADDR, 0x2000);

As you can see, we have full control over the first 0x2000 bytes of iBoot.


// R5: a pointer to a buffer is here if requesttype==0xA1.
//     however, if requesttype==0x21, R5 is undefined.

SRAM:22009ED2                 code_1                                  ; CODE XREF: handle_file_io_control_req+62�j
SRAM:22009ED2 014 36 49                       LDR     R1, =usb_file_loadaddr
SRAM:22009ED4 014 36 4B                       LDR     R3, =usb_file_offset
SRAM:22009ED6 014 28 68                       LDR     R0, [R5]
SRAM:22009ED8 014 09 68                       LDR     R1, [R1]
SRAM:22009EDA 014 1B 68                       LDR     R3, [R3]
SRAM:22009EDC 014 22 1C                       ADDS    R2, R4, #0
SRAM:22009EDE 014 C9 18                       ADDS    R1, R1, R3
SRAM:22009EE0 014 07 F0 94 EF                 BLX     memcpy
SRAM:22009EE4 014 00 2E                       CMP     R6, #0
SRAM:22009EE6 014 53 D0                       BEQ     return
SRAM:22009EE8 014 01 23                       MOVS    R3, #1
SRAM:22009EEA 014 33 60                       STR     R3, [R6]
SRAM:22009EEC 014 50 E0                       B       return


[1] [2] [3]

echo -n "Send a file and then usb_control_msg(0x21, 2, 0, 0, 0, 1000); to copy it to 0x0. To exploit, send a decrypted version of whatever is running (iboot / ibec / ibss / etc.) with whatever you want patched. This relies on a memcpy(); to an unchecked location." | openssl sha1


So, how do you actually run code with this? Well, chronic suggested that since the irq vector was in constant use, we try that, so we were able to simply replace the address of the irq vector handler in the 0x2000 iBoot chunk that we send with 0x41002000, and then just tack our payload to the end of that chunk. Of course, since we are hijacking the irq exception, you must disable interrupts first. Here is the basic procedure:

  • Call enter_critical_task(); disabling interrupts, so that your code can reliably execute.
  • Restore 0x38 with the original irq vector address
  • Call exit_critical_task(); re-enabling interrupts.
  • Call the irq handler so that the interrupt request that you jijacked can execute.


  • If what you send is not 0x2000 bytes, the remainder is filled in with zeroes, which is bad.
  • Due to the above rule, you need the first 0x2000 of a decrypted iBoot by the time your payload is done running.
  • You must disable interrupts to reliably execute your payload. Due to this, this will rule out the possibility of reading the 0x2000 iBoot chunk needed from NOR, since nor_read(); requires interrupts.

The PwnageTool method requires an IPSW to be input in order to create a custom firmware anyway, so the 0x2000 chunk is not an issue. It can just be copied from the iBoot in the IPSW.