
تم تخصيص هذه المقالة لاختبار إمكانية استخدام تقنية Intel Processor Trace (Intel PT) لتسجيل المسارات في وضع وضع إدارة النظام (SMM). تم إنجاز هذا العمل كجزء من Summer Of Hack 2019. أرسلت بواسطة sysenter_eip .
تتم كتابة معظم الأدوات المستخدمة من قبل أشخاص آخرين (خاصة @ d_olex ، aionescu ). والنتيجة هي مجرد مزيج من الأدوات المتاحة من أجل الحصول على مسار تنفيذ التعليمات البرمجية في وضع SMM للوحة أم واحدة محددة . ومع ذلك ، قد تكون المادة مثيرة للاهتمام بالنسبة لأولئك الذين يرغبون في تكرار ذلك لمنصتهم أو يهتمون ببساطة بعمل SMM.
وضع إدارة النظام
SMM هو وضع مميز ومميز لمعالج x86 architecture ، وهو متاح أثناء تشغيل نظام التشغيل ، لكنه غير مرئي تمامًا. وهو مصمم للتفاعل على مستوى منخفض مع الأجهزة ، وإدارة الطاقة ، ومحاكاة إرث الجهاز ، والانتقال إلى وضع السكون (S3) ، والوصول إلى TPM وأكثر من ذلك. يعمل معزولة تماما عن نظام التشغيل. لفترة تنفيذ SMM ، توقف نظام التشغيل تمامًا. يتم تخزين رمز البرنامج الذي يتم تشغيله في هذا الوضع في ذاكرة SPI-Flash باللوحة الأم وهو جزء من البرنامج الثابت لنظام BIOS UEFI.
يتم التبديل إلى وضع SMM باستخدام مقاطعة SMI خاصة (مقاطعة إدارة النظام). أحد خيارات هذا المقاطعة متاح للاستخدام في الحلقة الصفرية (أي من OS kernel) - مستوى التطبيق SMI Interrupt (Software SMI). كذلك سوف نركز على هذه الانقطاعات.
نظرًا لامتيازها العالي ، فإن SMM لها أهمية خاصة في مجال البحوث الأمنية. تؤدي تسوية SMM إلى حدوث انتهاكات خطيرة لسلامة النظام بأكمله وسريته ، وفي معظم الحالات تتيح لك حقن تعليمات برمجية ضارة لا يمكن حذفها ولا يمكن اكتشافها بواسطة نظام التشغيل في البرامج الثابتة لنظام UEFI BIOS.
تتبع معالجات Intel
واحدة من المزالق لعملية التصحيح لمختلف التطبيقات المحملة للغاية هو الحمل - تكاليف أدوات تصحيح الأخطاء. يمكن تقليلها باستخدام حل يدعم الأجهزة.
قدم الجيل الخامس من المعالجات من Intel (Broadwell) للعالم تقنية مثل Intel Processor Trace. كيف هي مفيدة؟ يتيح لك Intel PT الحصول على التدفق الكامل للتنفيذ (التحكم في التدفق) للتطبيق الذي تم تصحيحه بأقل مقدار حمل (<5٪). في الوقت نفسه ، يدعم تعدد العمليات ويمكن أن يساعد في إصلاح الأخطاء مثل "حالة السباق" بسبب طوابع الوقت عند تسجيل تتبع التطبيق. مما لا شك فيه ، توفر تقنية Intel PT فرصًا رائعة لكتابة أدوات البحث عن الثغرات في التطبيقات.
اليوم ، يتم استخدام هذه التكنولوجيا في أدوات مختلفة لتتبع وتصحيح وتقييم تغطية الشفرة - سواء في التطبيقات على مستوى المستخدم أو النواة. يمكن العثور على أمثلة للأدوات على موقع Intel على الويب. يتوفر خيار fuzzer AFL الذي يستفيد من Intel PT في مستودع PTfuzzer . من المشاريع الحديثة ، والانتباه إلى iptanalyzer .
ومع ذلك ، لم نر أي عمل على استخدام Intel PT في وضع SMM. نظرًا لعدم وجود شيء يمنعنا من استخدام Intel PT في هذا السياق ، فقد قررنا معرفة ما إذا كان من الممكن تتبع رمز وضع إدارة النظام باستخدامه.
التحضير للعمل
يستنتج من دليل مطور Intel أنه من المستحيل تنشيط تتبع Intel PT في SMM من الخارج باستخدام الوسائل العادية. إذا كان نشطًا في وقت تشغيل SMI ، فسيقوم المعالج بتعطيله قبل نقل التحكم إلى نقطة إدخال معالج SMI. طريقة التنشيط الوحيدة هي التضمين الطوعي لمعالج SMI بواسطة الكود نفسه.
حتى إذا لم يوفر المعالج مثل هذه الفرصة في البداية ، يمكننا اعتراضها وتنشيط Intel PT يدويًا. ومع ذلك ، تحتاج إلى تحديد بطريقة ما أن النظام جاهز لتسجيل التتبع (يتم تعيين عنوان المخزن المؤقت للإخراج) ، وكذلك إيقاف التتبع في نهاية تنفيذ المعالج (تنفيذ تعليمة RSM). خلاف ذلك ، سيقوم المعالج بإغلاق النظام بأكمله.
بادئ ذي بدء ، تحتاج إلى الوصول إلى SMRAM (منطقة RAM التي يوجد بها الكود الذي تم تنفيذه في وضع SMM). نظرًا لأن منطقة RAM هذه محمية ، لا يمكننا الوصول إليها من نظام التشغيل (حتى لا يمكن القيام بذلك باستخدام DMA). هناك عدة سيناريوهات:
- استغلال ثغرة أمنية معروفة في SMM والحصول على R / W البدائية منه. يمكن أن يكون هذا إما خطأ في البرنامج (مشكلة عدم حصانة في معالج SMI نفسه ؛ وكقاعدة عامة ، يوجد في SMM رمزًا كافيًا تمت إضافته بواسطة الشركة المصنّعة للمعدات الأصلية (OEM) ، وبالتالي فإن الثغرات الأمنية ليست غير شائعة) ، فضلاً عن تكوين نظام أساسي غير محتمل (إلغاء تأمين / نقل SMRAM) ؛
- لتصحيح صورة UEFI بطريقة تجعل لدينا واجهة للقراءة والكتابة إلى عناوين عشوائية - مستتر. لتنفيذ هذا الخيار ، تحتاج إلى العثور على لوحة أم تم تعطيل Intel Boot Guard عليها أو أن هناك ثغرات يمكن التحايل عليه.
تضمين التعليمات البرمجية الخاصة بك في البرامج الثابتة
على الرغم من حقيقة أن نقاط الضعف SMM في رمز مختلف الشركات المصنعة وجدت من وقت لآخر ، سيكون من الأفضل إذا كنا لا نعتمد عليها. من الممتع بالنسبة لنا أن نتتبع الشفرة على البرامج الثابتة الجديدة ، وبالتالي نحاول العثور على نقاط الضعف فيها. لدينا بالفعل اللوحة الأم GIGABYTE GA-Q270M-D3H مع تعطيل Intel Boot Guard ، لذلك كل ما كان علينا فعله هو إضافة باب خلفي إلى SMM.

الشكل 1. اختبار مقاعد البدلاء
هناك بالفعل إطار "لتصيب" SMM والعمل مع مستتر . يتكون من ثلاثة مكونات: برنامج التشغيل UEFI في C ، و "infector" ، و البرنامج النصي للعميل في Python. لتشغيله ، تحتاج إلى استخراج برنامج تشغيل DXE اعتباطي (يمكنك القيام بذلك باستخدام UEFITool ) ومعالجته باستخدام أداة إصابة . تم استبدال الوحدة الأصلية بـ "مُحسَّن" ، وتم تحميل البرنامج الثابت على ذاكرة SPI (لتوفير الراحة من إزالة محرك أقراص فلاش SPI من اللوحة).

الشكل 2. رقاقة ذاكرة SPI- فلاش
تم بدء تشغيل النظام بنجاح ، والآن أصبح لدينا وصول كامل إلى SMRAM من Python (يتم تقديم مثال للاستخدام مع الباب الخلفي). نظرًا لأن البرنامج النصي للعميل الخلفي يستند إلى CHIPSEC ، فأنت بحاجة لمنحه حق الوصول إلى وضع kernel (استخدمنا برنامج التشغيل RWEverything ، وسيكون من المناسب لشخص ما استخدام برنامج التشغيل CHIPSEC الخاص به مع إيقاف تشغيل التحقق من التوقيع في النظام).
يمكنك التحقق من الباب الخلفي بطلب تفريغ SMRAM.
$ python SmmBackdoor.py -d
بعد تنفيذ هذا الأمر ، سيتم إنشاء ملف SMRAM_dump_cb000000_cb7fffff.bin يحتوي على حالة SMRAM الحالية. القيمتان cb000000 و cb7fffff هما ، على التوالي ، العناوين الفعلية لبداية ونهاية SMRAM.
العمل مع تفريغ SMRAM
يمكن تحميل ملف تفريغ SMRAM في أداة فك تجميع أو تمريره للتحليل إلى البرنامج النصي smram_parse.py ، والذي سوف يستخلص الكثير من المعلومات المفيدة لنا. الأهم بالنسبة لنا هو عناوين نقاط دخول SMI. هذه هي عناوين الوظائف التي سيتم نقل التحكم إليها عند تشغيل SMI. كل وحدة المعالجة المركزية لديها نقطة دخول خاصة بها.

الشكل 3. إخراج البرنامج النصي smram_parse
دعنا نلقي نظرة على الكود نظرًا لأن SMM يبدأ تنفيذه في الوضع الحقيقي 16 بت (ينعكس أول 4 جيجابايت من ذاكرة الوصول العشوائي في المساحة الافتراضية) ، فإن أول شيء يفعله الكود هو التبديل إلى وضع 64 بت. في الوقت نفسه ، يتوفر SMRAM بالكامل مع حقوق الكتابة والتنفيذ ، حيث تم إنشاء شريحة واحدة فقط (هل هناك أي بائعين يقومون بذلك بشكل مختلف؟).
لن نرغب في كتابة رمز 16 بت أو إعداد كل ما هو ضروري للتبديل إلى وضع 64 بت بمفردنا ، لذلك سنضع المعترض الخاص بنا مباشرة قبل استدعاء وظيفة مدير SMI (تحدد هذه الوظيفة أي وحدة SMM ينبغي نقل التنفيذ وفقًا ما الخدمة كانت تسمى أو ما حدث حدث).

الشكل 4. التنسيب لتثبيت
أسهل طريقة للسيطرة هي استبدال عنوان المرسل بعنواننا. جميع نقاط الدخول لها نفس الكود ، لذلك يجب تكرار التصحيح لكل نقطة.
ملاحظة: فيما يتعلق بموقع رمز الاعتراض. نظرًا لأن بنية SMRAM غير معروفة تمامًا لنا ، فقد اخترنا قطعة عشوائية من الذاكرة الصفرية بالقرب من إحدى نقاط الدخول ، حيث وضعنا رمز الاعتراض. سيكون الخيار الأفضل هو إضافة وحدة SMM الخاصة بك إلى البرامج الثابتة ، والتي يضعها UEFI بشكل قانوني في SMRAM ، حتى لا تقلق من أن هناك شيئًا مهمًا سيتم الكتابة عليه بواسطة الكود الخاص بنا.
تطبيق اعتراض مدير SMI
دعونا نحدد بالضبط ما سنفعله داخل اعتراضنا. أولاً ، نحتاج إلى تحديد ما إذا كان Intel PT قيد التشغيل قبل الانتقال إلى SMM. من المعروف من وثائق Intel أن كل معالج لديه قاعدة SMBASE الخاصة به (MSR 0x9E) ومساحته الخاصة لتخزين حالة المعالج (منطقة SMM Save State) في وقت الانتقال إلى SMM.

الشكل 5. SMBASE تخطيط
نحدد حالة Intel PT
في Save State SMM ، يجب حفظ قيمة تسجيل MSR IA32_RTIT_CTL ، المسؤولة عن إدارة تتبع Intel PT. لسوء الحظ ، لا يشير Intel Manual إلى المكان الذي يحفظ فيه المعالج حالة IA32_RTIT_CTL.TraceEn بت في لحظة الانتقال إلى SMM (ما إذا كان التتبع ممكّنًا ، صفر بت). ومع ذلك ، يمكننا تحديد ذلك بأنفسنا عن طريق التخلص من Save State SMM مرتين: مع وبدون تمكين التتبع.
استخدمنا أداة WinIPT لتنشيط عملية التتبع على عملية مترجم Python (pid 1337 ) ، وتخصيص 2 ^ 12 (4096) بايت إلى المخزن المؤقت للتتبع ، ثم تنفيذ البرنامج النصي SmmBackdoor.py داخل المترجم (الوسيطة 0 هي علامة ، بالنسبة لنا مهم ، لأنه في SMM لا يزال عليك فرض إعدادات التتبع الخاصة بك).
$ ipttool.exe --start 1337 12 0
بمقارنة لقطات SMRAM ، حددنا موقع سجل IA32_RTIT_CTL في بنية SMM Save State. يتم تخزينه في إزاحة SMBASE + 0xFE3C. حالة IA32_RTIT_CTL.TraceEn bit هي الشرط الرئيسي لإعادة تنشيط Intel PT داخل SMM. تم وضع علامة على الحقل في هذا الإزاحة على أنه محجوز في دليل مطوري Intel.

الشكل 6. وضع علامة على أن الحقول محجوزة
كتابة shellcode
لم نرغب في تكوين Intel PT داخل SMM بمفردنا ، لأن هذا من شأنه أن يعقد كود القشرة لدينا (على سبيل المثال ، في SMM ، سيكون من الصعب تخصيص جزء كبير من ذاكرة الوصول العشوائي (RAM) بحيث لا يستخدمه نظام التشغيل نفسه). لذلك ، قررنا استخدام التتبع الذي تم تكوينه بالفعل وببساطة "تخطي" ذلك داخل SMM ، خاصة وأن لديه بالفعل وظيفة حفظ التتبع إلى ملف.
نظرًا لأننا استخدمنا WinIPT لهذا الغرض ، والذي لم يدعم في ذلك الوقت تتبع كود kernel (CPL == 0) ، كان من الواضح أنه حتى عندما تم تضمين التتبع في SMM ، فلن يظهر أي شيء في السجل ، حيث تم تنفيذ رمز SMM في CPL = 0 . نحتاج إلى تعديل بعض المرشحات حتى يتمكن التتبع من العمل طوال الوقت الذي يقضيه في SMM. نحن ندرج كل ما يجب فحصه وتثبيته:
- يجب تمكين التتبع باستخدام CPL = 0.
- يجب تمكين التتبع لـ CPL> 0 (اختياري).
- يجب تعطيل نطاقات IP الصالحة لتسجيل الأحداث.
- يجب إعادة تعيين IA32_RTIT_STATUS.PacketByteCnt.
- يجب تعطيل تصفية CR3.
يجب أن يقال بضع كلمات حول PacketByteCnt. يحدد هذا العداد عند أي نقطة تحتاج إلى إدراج حزم التزامن (تسلسل العديد من أوامر PSB) في التتبع. نحتاج إلى إعادة تعيين هذا العداد ، وإلا ، أثناء معالجة التتبع ، سيتم تفويت لحظة دخول SMM ، وسيبدأ التتبع من مكان عشوائي عندما يتم إنشاء PSB بشكل طبيعي.
يوجد أدناه كود القشرة الذي استخدمناه:
sub rsp, 0x18 ; this will align stack at 16 byte boundary (in case SMM ; code uses align dependent instructions) mov qword ptr ss:[rsp+0x10], rcx ; need to save rcx for SMI_Dispatcher mov ecx, 0x9E ; MSR_IA32_SMBASE rdmsr test byte ptr ds:[rax+0xFE3C], 0x1 ; Save State area contains saved ; IA32_RTIT_CTL.TraceEn je short @NoTrace call @Trace_Enable mov rcx, qword ptr ss:[rsp+0x10] ; SMI_Dispatcher is __fastcall ; (first argument in rcx) mov eax, 0xCB7DDAA4 ; original SMI_Dispatcher !!!!!!!!!!!!!!!!!!!!! call rax call @Trace_Disable add rsp, 0x18 ret @NoTrace: mov rcx, qword ptr ss:[rsp+0x10] ; SMI_Dispatcher is __fastcall mov eax, 0xCB7DDAA4 ; original SMI_Dispatcher !!!!!!!!!!!!!!!!!!!!! call rax add rsp, 0x18 ret @Trace_Disable: mov ecx, 0x570 ; IA32_RTIT_CTL rdmsr mov rax, qword ptr ss:[rsp+0x10] ; restore IA32_RTIT_STATUS wrmsr mov ecx, 0x571 ; IA32_RTIT_STATUS rdmsr mov rax, qword ptr ss:[rsp+0x8] ; restore IA32_RTIT_CTL wrmsr ret @Trace_Enable: mov ecx, 0x571 ; IA32_RTIT_STATUS rdmsr mov qword ptr ss:[rsp+0x8], rax ; save IA32_RTIT_STATUS and edx, 0xFFFF0000 ; IA32_RTIT_STATUS.PacketByteCnt = 0 wrmsr mov ecx, 0x570 ; IA32_RTIT_CTL rdmsr mov qword ptr ss:[rsp+0x10], rax ; save IA32_RTIT_CTL and eax, 0xFFFFFFBF ; IA32_RTIT_CTL.CR3Filter = 0 or eax, 0x5 ; IA32_RTIT_CTL.OS = 1; IA32_RTIT_CTL.User = 1; and edx, 0xFFFF0000 ; IA32_RTIT_CTL.ADDRx_CFG = 0 wrmsr ret
يجب وضع هذا الرمز في SMRAM ، ويجب تصحيح الانتقال إلى مدير SMI للانتقال إلى الرمز الخاص بنا. كل هذا يتم باستخدام SmmBackdoor.
العمل مع المسار
سمح لنا اعتراض مدير SMI بكتابة أول شفرة تتبع من SMM. يمكن أن يطلب الأمر التالي من WinIPT حفظ التتبع إلى ملف:
$ ipttool.exe --trace 1337 trace_file_name
تعطيل التتبع في العملية:
$ ipttool.exe --stop 1337
يمكنك محاولة تفكيك التتبع باستخدام الأداة المساعدة dumppt من libipt .
$ ptdump.exe --no-pad ./examples/trace_smm_handler_33 > ./examples/trace_smm_handler_33_pt_dump.txt
مثال الإخراج:

الشكل 7. أول مسار تعليمات SMM
يمكننا أن نرى بعض العناوين ، ولكن من الصعب للغاية استخدام هذه المعلومات ، لأنها منخفضة المستوى للغاية.
للحصول على مظهر أكثر قابلية للقراءة ، توجد أداة مساعدة ptxed (من libipt) تقوم بتحويل التتبع إلى سجل لتعليمات المجمّع المنفذة. بالطبع ، سيتعين علينا توفير الأداة المساعدة مع تفريغ ذاكرة SMRAM ، لأن سجل IPT لا يحتوي على معلومات حول قيم خلايا الذاكرة أو الإرشادات التي تم تنفيذها ؛ أنه يحتوي على معلومات فقط حول التغييرات التي حدثت في تدفق التحكم.
$ ptxed.exe --pt tracesmm_12 --raw SMRAM_dump_cb000000_cb7fffff.bin:0xcb000000 > tracesmm_12_ptasm

الشكل 8. قائمة المجمّع المقابلة لسجل IPT
يبدو بالفعل أفضل بكثير ، ولكن إذا كان الكود يحتوي على حلقة ، فسيتم انسداد الإخراج بنفس التعليمات.
تحديد تغطية الرمز باستخدام التتبع
للحصول على تغطية مرئية ، اخترنا المكوّن الإضافي Lighthouse لـ IDA Pro ، والذي يستخدم تنسيق drcov.
لم يتم العثور على أدوات جاهزة ، لذلك قمنا بتعديل ptxed بحيث قام أيضًا بإنشاء ملف تغطية في هذه العملية. ptxed مصححة يتوفر في المستودع . ألقِ نظرة على سجل الالتزام لتحديد ما تمت إضافته بالضبط.
بعد اكتمال ptxed ، يظهر ملف SMRAM_dump_cb000000_cb7fffff.bin.log ، والذي سيحتوي على معلومات التغطية بتنسيق drcov.
ملاحظة: هناك مشكلة بسيطة في مزامنة disassembler على PSB الأول. لسبب غير واضح تمامًا ، إذا تم إنشاء PSB قبل PGE (تتم إعادة تعيين العداد إلى صفر قبل تنشيط التتبع مرة أخرى) ، فلا يمكن مزامنة ptxed عليه. للتغلب على هذه المشكلة ، قمنا بعمل تصحيح صغير. ليس من الواضح ما إذا كانت هذه مشكلة بالنسبة إلى ptxed نفسه أو ما إذا كنا نفعل شيئًا خاطئًا من خلال إعادة تعيين IA32_RTIT_STATUS.PacketByteCnt.

الشكل 9. تصحيح يسمح لك باستخدام PSB الموجود مباشرة أمام PGE
يمكن تنزيل ملفات التغطية التي تم إنشاؤها في IDA Pro والحصول على تسليط الضوء الجميل ، وكذلك إحصاءات حول نسبة التغطية لكل وظيفة.

الشكل 10. IDA Pro Lighthouse البرنامج المساعد مع معلومات تغطية الرمز
ملاحظة: يعمل المكون الإضافي Lighthouse بشكل غريب بعض الشيء على قواعد بيانات غير مكتملة التحليل (لم يتم تسمية الكود القابل للتنفيذ ، ولم يتم إنشاء وظائف). لقد تتبعنا هذه "المشكلة" إلى وظيفة get_instructions_slice في ملف \ lighthouse \ metadata.py ، حيث تقوم بإرجاع 0 تعليمات حتى للعنوان الذي تم إنشاء الوظيفة فيه يدويًا. يبدو أن المكوّن الإضافي يستخدم ذاكرة التخزين المؤقت ويتجاهل الكود الجديد المحدد. يمكن التحايل على ذلك عن طريق استدعاء Reanalyze على البرنامج وإعادة فتح IDB. بعد ذلك فقط ، سيتمكن البرنامج المساعد من رؤية الكود الجديد والبدء في النظر فيه. نظرًا لأن هذه المشكلة غير مريحة للغاية في حالة تفريغ SMRAM (والذي يتكون بالكامل تقريبا في التمهيد الأول من رمز غير معرف) ، فقد أجرينا تغييرًا صغيرًا واحدًا على رمز Lighthouse حتى نتمكن من تحديد رمز جديد يدويًا بشكل أسرع.

الشكل 11. أضيفت رسالة السجل للمساعدة في تحديد رمز جديد
دعم لينكس
نظرًا لأن جميع الاختبارات التي أجريناها أجريت على Windows 10 x64 (احتجنا إلى ipt.sys ، والتي ظهرت في Windows October Creators Update 2018) ، دعنا نقول بضع كلمات حول إمكانية تنفيذ ذلك في Linux.
- هناك وحدة Linux kernel perf يمكنها القيام بنفس إجراءات WinIPT (ipt.sys) ، بما في ذلك القدرة على تتبع التعليمات البرمجية في وضع kernel.
- نظرًا لأن واجهة SMM backdoor تستند إلى إطار CHIPSEC عبر الأنظمة الأساسية ، فإن التصحيح الخاص بنا سيعمل على نظام Linux دون أي تعديلات.
استنتاج
لقد تعاملنا بنجاح مع مهمة الحصول على تتبع رمز تم تنفيذه في SMM باستخدام تقنية Intel Processor Trace. يمكن تحقيق نتيجة مماثلة بمساعدة معدات وبرمجيات باهظة الثمن لا تباع للجميع. لقد كان كافياً بالنسبة لنا أن يكون لدينا لوحة أم واحدة ومبرمج SPI. إن سرعة إزالة المسار مثيرة للإعجاب حقًا ، ولا توجد شكاوى حول دقة النتيجة.
نأمل أن تساعد هذه المقالة الآخرين على الاستفادة من تقنية Intel PT للتحقيق والبحث عن الثغرات الأمنية في كود SMM. يجب ألا يتسبب تكييف عملنا مع اللوحات الأم الأخرى في حدوث صعوبات (لا تنس استخدام Intel Boot Guard). الشيء الرئيسي هو أن نفهم تماما كيف يعمل. الجزء الأكثر صعوبة هو تحديد كيفية اعتراض المرسل SMI وكتابة كود shell للمعترض. في الإصدار الخاص بنا ، تم استخدام العناوين "السلكية" ، لذلك يجب عليك بعناية نقل كود القشرة إلى نظام آخر.
تتوفر جميع الأدوات والبرامج النصية المستخدمة في المستودع على جيثب .