
Artikel ini dikhususkan untuk menguji kemungkinan penggunaan teknologi Intel Processor Trace (Intel PT) untuk merekam jejak dalam mode System Management Mode (SMM). Pekerjaan ini dilakukan sebagai bagian dari Summer Of Hack 2019. Diposting oleh @sysenter_eip .
Sebagian besar alat yang digunakan ditulis oleh orang lain (khususnya @d_olex , @aionescu ). Hasilnya hanyalah kombinasi alat yang tersedia untuk mendapatkan jalur eksekusi kode dalam mode SMM untuk satu motherboard tertentu . Namun, materi mungkin menarik bagi mereka yang ingin mengulang ini untuk platform mereka atau hanya tertarik pada pekerjaan SMM.
Mode manajemen sistem
SMM adalah mode khusus dan istimewa dari prosesor arsitektur x86, yang tersedia saat sistem operasi berjalan, tetapi sama sekali tidak terlihat olehnya. Ini dirancang untuk interaksi tingkat rendah dengan perangkat keras, manajemen daya, emulasi warisan perangkat, transisi ke mode tidur (S3), akses ke TPM dan banyak lagi. Ini berfungsi sepenuhnya terisolasi dari OS. Selama durasi eksekusi SMM, OS berhenti sepenuhnya. Kode program yang berjalan dalam mode ini disimpan dalam memori SPI-Flash pada motherboard dan merupakan bagian dari firmware UEFI BIOS.
Beralih ke mode SMM dilakukan menggunakan interupsi SMI khusus (System Management Interrupt). Salah satu opsi untuk interupsi ini tersedia untuk digunakan dalam deringan nol (mis., Dari kernel OS) - Level Aplikasi SMI Interrupt (Software SMI). Selanjutnya kami akan fokus pada gangguan ini.
Karena keistimewaannya yang tinggi, SMM menjadi minat khusus untuk penelitian keamanan. Kompromi SMM mengarah pada pelanggaran serius terhadap integritas dan kerahasiaan seluruh sistem, dan dalam kebanyakan kasus memungkinkan Anda untuk menyuntikkan kode berbahaya yang tidak dapat dihapus dan tidak dapat dideteksi oleh sistem operasi ke dalam firmware UEFI BIOS.
Intel Processor Trace
Salah satu perangkap dari proses debugging untuk berbagai aplikasi yang sangat dimuat adalah biaya overhead - biaya alat debugging. Mereka dapat dikurangi dengan solusi yang mendukung perangkat keras.
Prosesor generasi kelima dari Intel (Broadwell) telah menghadirkan teknologi dengan dunia seperti Intel Processor Trace. Bagaimana ini bermanfaat? Intel PT memungkinkan Anda untuk mendapatkan alur eksekusi penuh (Aliran Kontrol) aplikasi debugged dengan overhead yang minimal (<5%). Pada saat yang sama, ini mendukung multithreading dan dapat membantu memperbaiki kesalahan seperti "kondisi balapan" karena stempel waktu saat merekam jejak aplikasi. Tidak diragukan lagi, teknologi Intel PT menawarkan peluang besar untuk menulis alat pencarian kerentanan dalam aplikasi.
Saat ini, teknologi ini digunakan dalam berbagai alat untuk melacak, debugging, dan mengevaluasi cakupan kode - baik dalam aplikasi tingkat pengguna dan kernel. Contoh alat dapat ditemukan di situs web Intel . Opsi fuzzer AFL yang memanfaatkan Intel PT tersedia di repositori PTfuzzer . Dari proyek-proyek terbaru, perhatikan iptanalyzer .
Namun, kami belum melihat adanya kerja pada penggunaan Intel PT dalam mode SMM. Karena tidak ada yang mencegah kami menggunakan Intel PT dalam konteks ini, kami memutuskan untuk mencari tahu apakah mungkin untuk melacak kode Mode Manajemen Sistem dengannya.
Persiapan untuk bekerja
Ini mengikuti dari Manual Pengembang Intel bahwa tidak mungkin untuk mengaktifkan pelacakan PT Intel di SMM dari luar menggunakan cara biasa. Jika aktif pada saat SMI dipicu, prosesor akan menonaktifkannya sebelum mentransfer kontrol ke titik masuk pengendali SMI. Satu-satunya metode aktivasi adalah inklusi sukarela handler SMI oleh kode itu sendiri.
Bahkan jika prosesor pada awalnya tidak memberikan kesempatan seperti itu, kami dapat mencegatnya dan mengaktifkan Intel PT secara manual. Namun, Anda perlu menentukan bahwa sistem siap merekam jejak (alamat buffer output diatur), dan juga mematikan pelacakan di akhir eksekusi prosesor (eksekusi instruksi RSM). Jika tidak, prosesor akan mematikan seluruh sistem.
Pertama-tama, Anda perlu mengakses SMRAM (area RAM tempat kode dijalankan dalam mode SMM). Karena wilayah RAM ini dilindungi, kami tidak dapat mengaksesnya dari sistem operasi (bahkan ini tidak dapat dilakukan dengan DMA). Ada beberapa skenario:
- mengeksploitasi kelemahan yang diketahui dalam SMM dan dapatkan primitif R / W darinya. Ini bisa berupa kesalahan perangkat lunak (kerentanan pada prosesor SMI itu sendiri; sebagai aturan, di SMM ada cukup kode yang ditambahkan oleh OEM, sehingga kerentanan tidak jarang terjadi), serta konfigurasi platform yang rentan (membuka / memindahkan SMRAM);
- untuk menambal gambar UEFI sedemikian rupa sehingga kami memiliki antarmuka untuk membaca dan menulis ke alamat sewenang-wenang - pintu belakang. Untuk menerapkan opsi ini, Anda perlu menemukan motherboard yang Intel Boot Guard dinonaktifkan atau ada kerentanan yang dapat menghindarinya.
Sematkan kode Anda di firmware
Terlepas dari kenyataan bahwa kerentanan SMM dalam kode berbagai produsen ditemukan dari waktu ke waktu , akan lebih baik jika kita tidak bergantung pada mereka. Lebih menarik bagi kami untuk melacak kode pada firmware baru dan, karenanya, mencoba menemukan kerentanan di dalamnya. Kami sudah memiliki motherboard GIGABYTE GA-Q270M-D3H dengan Intel Boot Guard dinonaktifkan, jadi yang harus kami lakukan adalah menambahkan pintu belakang ke SMM.

Gambar 1. Test bench
Sudah ada kerangka kerja untuk "menginfeksi" SMM dan bekerja dengan backdoor . Ini terdiri dari tiga komponen: driver UEFI di C, "infector", dan skrip klien dengan Python. Untuk operasinya, Anda perlu mengekstrak driver DXE sembarang (Anda dapat melakukan ini menggunakan UEFITool ) dan memprosesnya dengan infector. Modul asli diganti dengan "ditingkatkan", dan firmware diunggah ke memori SPI (untuk kenyamanan menginstal flash drive SPI dihapus dari papan).

Gambar 2. Chip memori SPI-Flash
Sistem dimulai dengan sukses, dan sekarang kami memiliki akses penuh ke SMRAM dari Python (contoh penggunaan disediakan dengan backdoor). Karena skrip klien untuk pintu belakang didasarkan pada CHIPSEC , Anda perlu memberinya akses ke mode kernel (kami menggunakan driver RWEverything; akan lebih mudah bagi seseorang untuk menggunakan driver CHIPSEC mereka sendiri dengan verifikasi tanda tangan dimatikan dalam sistem).
Anda dapat memeriksa pintu belakang dengan meminta dump SMRAM.
$ python SmmBackdoor.py -d
Setelah menjalankan perintah ini, file SMRAM_dump_cb000000_cb7fffff.bin akan dibuat berisi keadaan SMRAM saat ini. Nilai cb000000 dan cb7fffff, masing-masing, adalah alamat fisik awal dan akhir SMRAM.
Bekerja dengan dump SMRAM
Dump SMRAM dapat dimuat ke disassembler atau diteruskan untuk dianalisis ke skrip smram_parse.py , yang akan mengekstrak banyak informasi berguna bagi kami. Yang paling penting bagi kami adalah alamat titik masuk SMI. Ini adalah alamat fungsi yang kontrolnya akan ditransfer ketika SMI dipicu. Setiap CPU memiliki titik masuknya sendiri.

Gambar 3. Output skrip smram_parse
Mari kita lihat kodenya. Sejak SMM memulai eksekusi dalam Mode Real 16-bit (4 GB RAM pertama tercermin dalam ruang virtual), hal pertama yang dilakukan kode adalah beralih ke mode 64-bit. Pada saat yang sama, seluruh SMRAM tersedia dengan hak tulis dan eksekusi, karena hanya satu segmen yang dibuat (apakah ada vendor yang melakukannya secara berbeda?).
Kami tidak ingin menulis kode 16-bit atau menyiapkan segala yang diperlukan untuk beralih ke mode 64-bit sendiri, jadi kami akan menempatkan interceptor kami tepat sebelum memanggil fungsi manajer SMI (fungsi ini menentukan modul SMM mana yang harus ditransfer oleh eksekusi tergantung pada layanan apa yang dipanggil atau peristiwa apa yang terjadi).

Gambar 4. Penempatan untuk pengait
Cara termudah untuk mengambil kendali adalah mengganti alamat pengirim dengan alamat kami. Semua titik masuk memiliki kode yang sama, sehingga tambalan perlu diulang untuk masing-masing.
Catatan: Mengenai lokasi kode interseptor. Karena struktur SMRAM tidak sepenuhnya diketahui oleh kami, kami memilih sepotong memori nol acak di dekat salah satu titik masuk, tempat kami meletakkan kode interseptor. Opsi terbaik adalah menambahkan modul SMM Anda ke firmware, yang UEFI akan tempatkan secara hukum di SMRAM, agar tidak khawatir bahwa sesuatu yang penting akan ditimpa dengan kode kami.
Menerapkan Interceptor Manajer SMI
Mari kita tentukan apa yang akan kita lakukan di dalam pencegat kita. Pertama kita perlu menentukan apakah Intel PT dihidupkan sebelum pindah ke SMM. Diketahui dari dokumentasi Intel bahwa setiap prosesor memiliki basis SMBASE sendiri (MSR 0x9E) dan ruangnya sendiri untuk menyimpan status prosesor (area SMM Save State) pada saat transisi ke SMM.

Gambar 5. Tata letak SMBASE
Kami menentukan status Intel PT
Dalam SMM Save State, nilai register MSR IA32_RTIT_CTL, yang bertanggung jawab untuk mengelola pelacakan PT Intel, harus disimpan. Sayangnya, Intel Manual tidak menunjukkan di mana prosesor menyimpan status IA32_RTIT_CTL.TraceEn pada saat transisi ke SMM (apakah pelacakan diaktifkan, nol bit). Namun, kami dapat menentukan sendiri dengan membuang SMM Simpan Status dua kali: dengan dan tanpa pelacakan diaktifkan.
Kami menggunakan alat WinIPT untuk mengaktifkan pelacakan pada proses interpreter Python (pid 1337 ), mengalokasikan 2 ^ 12 (4096) byte ke buffer jejak, dan kemudian menjalankan skrip SmmBackdoor.py di dalam interpreter (argumen 0 adalah bendera, bagi kami mereka tidak penting, karena di SMM Anda masih harus memaksakan pengaturan jejak Anda).
$ ipttool.exe --start 1337 12 0
Dengan membandingkan snapshot SMRAM, kami menentukan lokasi register IA32_RTIT_CTL dalam struktur SMM Save State. Ini disimpan di offset SMBASE + 0xFE3C. Keadaan bit IA32_RTIT_CTL.TraceEn adalah syarat utama untuk aktivasi ulang Intel PT di dalam SMM. Bidang pada offset ini ditandai sebagai Dicadangkan dalam Manual Pengembang Intel.

Gambar 6. Menandai bahwa bidang disediakan
Menulis shellcode
Kami tidak ingin mengonfigurasi Intel PT di dalam SMM sendiri, karena ini akan menyulitkan shellcode kami (misalnya, berada di SMM, akan sulit untuk mengalokasikan sejumlah besar RAM sehingga tidak digunakan oleh sistem operasi itu sendiri). Oleh karena itu, kami memutuskan untuk menggunakan pelacak yang sudah dikonfigurasi dan cukup "lewati" di dalam SMM, terutama karena sudah memiliki fungsi menyimpan jejak ke file.
Karena kami menggunakan WinIPT untuk tujuan ini, yang pada saat itu tidak mendukung pelacakan kode kernel (CPL == 0), jelas bahwa bahkan ketika penelusuran disertakan dalam SMM, tidak ada yang akan muncul di log, karena kode SMM dieksekusi di CPL = 0 . Kita perlu memodifikasi beberapa filter agar pelacak dapat bekerja sepanjang waktu yang dihabiskan di SMM. Kami mencantumkan semua yang perlu diperiksa dan diinstal:
- Pelacakan dengan CPL = 0 harus diaktifkan.
- Pelacakan untuk CPL> 0 harus diaktifkan (opsional).
- Rentang IP yang valid untuk acara perekaman harus dinonaktifkan.
- IA32_RTIT_STATUS.PacketByteCnt harus diatur ulang.
- Pemfilteran CR3 harus dinonaktifkan.
Beberapa kata harus dikatakan tentang PacketByteCnt. Penghitung ini menentukan pada titik apa Anda perlu memasukkan paket sinkronisasi (urutan beberapa perintah PSB) ke dalam penelusuran. Kita perlu mengatur ulang penghitung ini, jika tidak, selama pemrosesan jejak, saat memasuki SMM akan terlewatkan, dan jejak akan mulai dari tempat acak ketika PSB dihasilkan secara alami.
Di bawah ini adalah shellcode yang kami gunakan:
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
Kode ini harus ditempatkan di SMRAM, dan transisi ke manajer SMI harus ditambal untuk menuju ke kode kami. Semua ini dilakukan dengan menggunakan SmmBackdoor.
Bekerja dengan trek
Pencegat manajer SMI memungkinkan kami untuk menulis jejak kode pertama dari SMM. Perintah berikut dapat meminta WinIPT untuk menyimpan jejak ke file:
$ ipttool.exe --trace 1337 trace_file_name
Menonaktifkan pelacakan pada suatu proses:
$ ipttool.exe --stop 1337
Anda dapat mencoba membongkar jejak menggunakan utilitas dumppt dari libipt .
$ ptdump.exe --no-pad ./examples/trace_smm_handler_33 > ./examples/trace_smm_handler_33_pt_dump.txt
Contoh Keluaran:

Gambar 7. Jalur instruksi SMM pertama
Kita dapat melihat beberapa alamat, namun sangat sulit untuk menggunakan informasi ini, karena sangat rendah.
Untuk mendapatkan tampilan yang lebih mudah dibaca, ada utilitas ptxed (dari libipt) yang mengubah jejak menjadi log instruksi assembler yang dieksekusi. Tentu saja, kita harus menyediakan utilitas dengan dump memori SMRAM, karena log IPT tidak mengandung informasi tentang nilai-nilai sel memori atau instruksi apa yang dijalankan; itu hanya berisi informasi tentang perubahan apa yang terjadi dalam aliran kontrol.
$ ptxed.exe --pt tracesmm_12 --raw SMRAM_dump_cb000000_cb7fffff.bin:0xcb000000 > tracesmm_12_ptasm

Gambar 8. Daftar assembler yang sesuai dengan log IPT
Ini sudah terlihat jauh lebih baik, tetapi jika kode tersebut berisi loop, output akan tersumbat dengan instruksi yang sama.
Tentukan cakupan kode menggunakan jejak
Untuk mendapatkan visualisasi cakupan, kami memilih plugin Lighthouse untuk IDA Pro, yang menggunakan format drcov.
Tidak ada alat siap pakai yang ditemukan, jadi kami memodifikasi ptx sehingga juga menghasilkan file cakupan dalam proses. Patched ptxed tersedia di repositori . Lihatlah histori komit untuk menentukan apa yang sebenarnya ditambahkan.
Setelah ptxed selesai, file SMRAM_dump_cb000000_cb7fffff.bin.log muncul, yang akan berisi informasi cakupan dalam format drcov.
Catatan: Ada sedikit masalah dengan sinkronisasi disassembler pada PSB pertama. Untuk alasan yang tidak sepenuhnya jelas, jika PSB dihasilkan sebelum PGE (penghitung diatur ulang ke nol sebelum jejak diaktifkan kembali), maka ptxed tidak dapat disinkronkan di atasnya. Untuk mengatasi masalah ini, kami membuat tambalan kecil. Tidak jelas apakah ini masalah untuk ptxed itu sendiri, atau apakah kami melakukan sesuatu yang salah dengan mengatur ulang IA32_RTIT_STATUS.PacketByteCnt.

Gambar 9. Patch yang memungkinkan Anda untuk menggunakan PSB yang terletak tepat di depan PGE
File cakupan yang dihasilkan dapat diunduh ke IDA Pro dan mendapatkan sorotan yang indah, serta statistik pada cakupan persen untuk setiap fungsi.

Gambar 10. Plugin IDA Pro Lighthouse dengan informasi cakupan kode
Catatan: Plugin Lighthouse bekerja sedikit aneh pada database yang dianalisis secara tidak lengkap (kode yang dapat dieksekusi tidak diberi label, fungsi belum dibuat). Kami melacak "masalah" ini ke fungsi get_instructions_slice di file \ lighthouse \ metadata.py, di mana ia mengembalikan 0 instruksi bahkan untuk alamat tempat fungsi itu dibuat secara manual. Pengaya tampaknya menggunakan cache dan mengabaikan kode spesifik baru. Ini dapat dielakkan dengan memanggil Reanalyze pada program dan membuka kembali IDB. Hanya setelah itu plugin akan dapat melihat kode baru dan mulai mempertimbangkannya. Karena masalah ini sangat merepotkan dalam kasus dump SMRAM (yang pada boot pertama hampir seluruhnya terdiri dari kode yang tidak ditentukan), kami membuat satu perubahan kecil pada kode Mercusuar sehingga kami dapat secara manual mendefinisikan kode baru lebih cepat.

Gambar 11. Menambahkan pesan log untuk membantu mengidentifikasi kode baru
Dukungan Linux
Karena semua pengujian kami dilakukan pada Windows 10 x64 (kami membutuhkan ipt.sys, yang muncul di Windows October Creators Update 2018), katakanlah beberapa kata tentang kemungkinan penerapan ini di Linux.
- Ada modul perf kernel Linux yang dapat melakukan tindakan WinIPT (ipt.sys) yang sama, termasuk kemampuan untuk melacak kode dalam mode kernel.
- Karena antarmuka SMM backdoor didasarkan pada kerangka CHIPSEC lintas-platform, tambalan kami akan bekerja pada sistem Linux tanpa modifikasi apa pun.
Kesimpulan
Kami berhasil mengatasi tugas mendapatkan jejak kode yang dieksekusi di SMM menggunakan teknologi Intel Processor Trace. Hasil serupa dapat dicapai dengan bantuan peralatan dan perangkat lunak mahal yang tidak dijual kepada semua orang. Sudah cukup bagi kami untuk memiliki satu motherboard dan SPI-programmer. Kecepatan penghapusan trek sangat mengesankan, dan tidak ada keluhan tentang keakuratan hasilnya.
Kami berharap artikel ini membantu orang lain memanfaatkan teknologi Intel PT untuk menyelidiki dan mencari kerentanan dalam kode SMM. Menyesuaikan pekerjaan kami dengan motherboard lain seharusnya tidak menyebabkan kesulitan (jangan lupa tentang Intel Boot Guard). Hal utama adalah untuk sepenuhnya memahami cara kerjanya. Bagian yang paling sulit adalah menentukan cara mencegat dispatcher SMI dan menulis shellcode untuk pencegat. Dalam versi kami, alamat "berkabel" digunakan, jadi Anda harus dengan hati-hati mentransfer shellcode ke sistem lain.
Semua alat dan skrip yang digunakan tersedia di repositori di GitHub .