Bug kecil yang bisa: CVE-2024-30089 adalah kerentanan kernel halus yang saya gunakan untuk mengeksploitasi mesin Windows 11 yang diperbarui sepenuhnya (dengan semua Keamanan Berbasis Virtualisasi dan mitigasi keamanan perangkat keras diaktifkan) dan mencetak kemenangan pertama saya di Pwn2Own tahun ini.
Dalam artikel ini, saya menguraikan pendekatan sederhana saya dalam berburu bug: memilih titik awal dan secara intuitif mengikuti suatu jalur hingga sesuatu menarik perhatian saya. Bug ini menarik karena dapat dipicu dengan andal karena kesalahan logika. Kesalahan terjadi pada kondisi tertentu dalam sistem komunikasi antar-proses, yang kemudian menyebabkan bebas-penggunaan. Menemukan bug diperlukan membandingkan jalur kode program di berbagai kemungkinan statusnya, sebuah proses yang saya jelaskan secara rinci. Yang sama menariknya adalah asal bug dan pendekatan Microsoft untuk menambalnya. Topik-topik ini juga dibahas dalam posting ini.
Pertanyaan umum yang saya terima tentang riset kerentanan adalah bagaimana memulai. Bahkan, memilih target dan ber pegang teguh pada itu mungkin merupakan salah satu langkah paling sulit dari proses riset. Kerentanan yang dibahas di sini ada di Microsoft Kernel Streaming Service (mskssrv.sys). Lihat postingan blog ini untuk mendapatkan gambaran umum mengenai subsistem. Dalam posting itu, saya menunjukkan beberapa karakteristik subsistem MSKSSRV yang mungkin menjadikannya permukaan serangan yang baik, khususnya mekanisme komunikasi antar-proses (IPC).
Basis kode MSKSSRV cukup kecil, dan kerentanan terakhir dalam subsistem ini yang saya temukan juga dieksploitasi secara independen di alam liar sebagai 0-hari. Saya juga mendengar tentang upaya tambahan dari peneliti dan perusahaan lain untuk mengaudit driver ini. Karena itu, saya awalnya jatuh ke dalam perangkap umum dengan mengasumsikan tidak ada lagi bug yang tersisa untuk ditemukan di permukaan serangan ini. Tapi, karena saya telah menyarankannya di postingan blog saya sebelumnya, saya memilih untuk mempercayai naluri saya dan terus mencari.
Cara yang bagus untuk mendapatkan ide-ide riset baru adalah dengan tetap mendapat informasi tentang riset saat ini. Saya membaca sebuah postingan blog yang luar biasa dari k0shl yang memicu inspirasi untuk berburu jenis serangga tertentu. Dalam kerentanan yang ditemukan oleh k0shl, jumlah referensi objek diinisialisasi dan ditingkatkan tanpa penguncian yang tepat, menciptakan use after free window. Meskipun bug k0shl adalah bug userland dan bukan di kernel, pengodean perpustakaan yang rentan mengingatkan saya ketika saya sebelumnya mengaudit driver MSKSSRV.
MS KS Server (MSKSSRV) berinteraksi dengan proses userland melaluiFSStreamReg. dan FSContextReg keduanya berasal dari kelas dasarFSRegObject tidak mengimplementasikan fungsi penguncian vtable, dan implementasi kelas dasar () diimplementasikan dengan sebuah instruksi nop. Ini berarti tidak ada mekanisme penguncian yang benar-benar diterapkan untuk objek . Sebaliknya,FSStreamRegMekanisme penguncian digunakan saat mengakses objek untuk pembersihan, dalam fungsi:
Blok Kode 1: FSRendezvousServer::Close, mengunci dan membuka jalur untuk FSRegObjects
Ada dua objek yang berasal dari kelas dasar
Seperti yang saya sebutkan di posting blog terakhir saya, aspek berbagi objek antar-proses dari MSKSSRV adalah jalan yang menarik untuk kerentanan, jadi saya memutuskan untuk fokus lebih lanjut. Mekanisme IPC dari subsistem diilustrasikan dalam diagram berikut:
Diagram 1: Komunikasi Antar Proses di MS KS Server
Membuka handle file ke perangkat MSKSSRV, melalui CreateFile, akan membuat FILE_OBJECT yang sesuai dengan handle tersebut. Dengan menggunakan handle tersebut, sebuah proses dapat menginisialisasi stream baru atau objek konteks dengan mengirimkan IOCTL ke perangkat menggunakan fungsi DeviceIoControl . Proses inisialisasi menentukan proses jarak jauh mana yang dapat mendaftarkan objek dengan menentukan ID proses melalui argumenlpInBufferFSRegObject disimpan di
Irp->CurrentStackLocation->FileObject->FsContext2.
Penunjuk yang sama ke objek FSRegObject disimpan dua kali di FsContext2, sekali di yang digunakan oleh proses inisialisasi dan sekali di digunakan oleh proses pendaftaran. Dengan cara ini, referensi ke objek dapat dibagikan di seluruh proses. Misalnya, menggunakan objek FSStreamReg, beberapa proses dapat memiliki akses ke buffer bingkai aliran, seperti yang ditunjukkan pada Diagram 1. Jumlah referensi pada awalnya diset ke 1 lalu bertambah sekali lagi setelah tahap inisialisasi selesai. Mendaftarkan meningkatkan jumlah referensi lagi, untuk total tiga referensi per objek.
Diagram 2: Menginisialisasi dan Mendaftarkan Objek FSContextReg
Saya memutuskan untuk melihat lagi di mana saya sebelumnya mengaudit mencoba mencari kerentanan penguncian. Saya perhatikan fungsi
Blok Kode 2: Rutinitas DispatchCleanup dan DIPatchCleanup untuk Driver Server MS KS
Sebuah rutinitas dispatch menangani satu atau lebih jenis IRP, yaitu permintaan I/O yang telah dikemas. Di Windows, ketika semua referensi handle ke file telah ditutup, driver sistem file yang sesuai untuk file tersebut menerima
Dalam MSKSSRV,
Blok Kode 3: FSRendezVousServer: :Close, Proses pemeriksaan pada FSRegObjects
Informasi spesifik proses disimpan dalam
Irp->CurrentStackLocation->FileObject->FsContext2
pada saat inisialisasi atau pendaftaran. Driver menentukan mana yang memproses sumber daya tertentu (
objek, objek acara, dan hal-hal lain) perlu dilepaskan dengan memeriksa ID proses pemanggil. Jika prosesnya adalah proses inisialisasi atau pendaftaran, beberapa pembersihan tambahan dilakukan untuk sumber daya spesifik proses tersebut.
Hal ini menarik perhatian saya karena pada umumnya semua rutinitas Dispatch dijalankan dalam konteks proses arbitrary, dengan beberapa pengecualian. Dengan kata lain, sistem memilih utas untuk melakukan pekerjaan Dispatch ; utas apa yang dipilihnya secara acak. Saya menemukan bahwa
Selain itu, sebagai fitur dari OS Windows, handle dapat dibagikan dengan proses lain (dengan pewarisan proses anak atau menggunakan fungsi API DuplicateHandle ). Melalui pegangan file bersama, proses lain juga dapat berinteraksi dengan
Diagram 3: Berbagi Handle Perangkat Server MS KS
Karena ini, mungkin juga konteks proses selama
Diagram 4: Proses Asing Menutup Handle Terakhir ke FILE_OBJECT
Saya perhatikan bahwa fungsi
Blok Kode 4: FSRegObject: :Release dapat dipanggil dua kali dari fsRendezVousServer: :Close
Secara umum, lebih banyak dereferensi daripada referensi pada suatu objek bukanlah satu-satunya cara penggunaan setelah bebas dapat terjadi. Namun dalam hal ini, kita dapat yakin bahwa jika telah dibebaskan, jumlah referensi telah turun menjadi nol. Terakhir kali sebuah yang valid diakses selama Permintaan IRP adalah dalam panggilan ke . Jadi, jika use-after-free dimungkinkan, panggilan ke akan selalu terjadi setelah objek dibebaskan. Selama panggilan, objek akan sekali lagi didereferensikan. Untuk alasan itu, menghitung jumlah dereferensi adalah heuristik yang baik untuk menemukan penggunaan setelah bebas untuk kasus khusus ini.
Satu-satunya hal yang tersisa untuk dilakukan adalah melacak kemungkinan status program, mencatat kapan objek dibebaskan dan diakses. Saya melakukan ini dengan meniru logika program secara mental selama permintaan , masing-masing dimulai dengan fungsi Dispatch yang sesuai (Blok Kode 2), untuk setiap kasus yang mungkin terjadi.
Berikut ini adalah status-status berdasarkan proses mana yang menutup referensi terakhir ke sebuah handle. Setiap entri mewakili jumlah dereferensi objek FSContextReg yang terjadi jika proses yang sesuai menutup handle akhir. Catatan: tidak ada perbedaan fungsional antara HANDLE #1 (inisialisasi pegangan) dan HANDLE #2 (pendaftaran handle), karena bidang menunjuk ke memori yang sama di kedua diwakili ole handle yang sesuai.
Dereferensi FSContextReg untuk masing-masing kenungkinan status IPC MSKSSRV
Berhasil! Keadaan terakhir menghasilkan empat kali dereferensi: dua oleh proses asing dan dua oleh proses yang melakukan inisialisasi (sekaligus registrasi), sementara pada awalnya hanya ada tiga referensi, yang berarti use-after-free dapat terjadi! Saya juga mengulangi latihan yang sama dengan objek
Saat melakukan latihan otak mesin virtual yang diuraikan di atas, saya menemukan masalahnya. Jika prosesnya adalah proses inisialisasi atau proses pendaftaran, pembersihan yang sesuai terjadi, dan pointer toko di
Blok Kode 5: fsRegObject: :CloseInitProcess menyetel penunjuk fsContext ke NULL
Ini berarti
Namun, jika proses panggilan adalah proses asing, tidak ada pembersihan yang terjadi dan
Sekarang, jika handle kedua ditutup oleh proses yang menginisialisasi dan mendaftarkan objek FSContextReg, objek akan membersihkan semua sumber daya yang tersimpan, membuatnya kosong. Hal ini menyebabkan
Hal ini menghasilkan total empat dereferensi pada satu objek
Diagram 5: CVE-2024-30089 digambarkan
Pembaca mungkin bertanya-tanya mengapa proses lain tidak bisa menjadi yang terakhir menutup kedua handle tersebut, karena secara tampak hal itu juga akan menghasilkan empat kali dereferensi. Sebelum objek dihancurkan dan dibebaskan, objek tersebut dilepaskan dari daftar yang disimpan dalam objek globalFSRendezvousServer , penunjuk di dalam diperiksa sebagai anggota yang valid dari daftar. Dalam hal ini, objek dibebaskan dalam panggilan kedua ke pada akhir fungsi. Selama panggilan keempat ke , objek telah dibatalkan tautan dari daftar, menjadikannya objek yang tidak valid, sehingga tidak dapat digunakan. Untuk memicu use-after-free, hal itu harus terjadi setelah objek diambil dan divalidasi di . Cuplikan kode di bawah ini menunjukkan primitif use-after-free yang dapat diperoleh dengan kerentanan:
Blok Kode 6: Jalur primitif UAF
Dalam panduanpembaruan keamanan untuk kerentanan ini, skor CVSS menunjukkan bahwa “Eksploitasi [adalah] Lebih Mungkin“ dan kompleksitas serangan untuk kerentanan ini adalah “Rendah“. Meskipun Microsoft tidak memberikan penjelasan terperinci untuk penilaian mereka, saya telah mencatat beberapa pola saat menambal membedakan kerentanan lainnya. Kerentanan ini kemungkinan mendapat skor tersebut karena berasal dari kesalahan logika, sehingga mudah dipicu. Dengan mengikuti langkah-langkah yang diuraikan dalam Diagram 5, penyerang dapat secara konsisten memicu skenario penggunaan setelah bebas yang digambarkan dalam Blok Kode 6. Namun, ini tidak berarti bahwa mengeksploitasi dalam praktik itu mudah. Panduan terperinci dari langkah-langkah eksploitasi akan dibahas di bagian selanjutnya dari seri ini.
Memahami bagaimana bug terjadi penting untuk mengembangkan pendekatan proaktif untuk mengamankan praktik pengembangan. Untuk mengetahui bagaimana kerentanan itu muncul, saya menganalisis versi driver sebelumnya yang diperoleh dari Winbindex dan mencari perbedaan logika dalam fungsi
Di bagian kerentanan, saya menyebutkan bahwa penyebab utama bug ini bukanlah pengaturan
Irp->CurrentStackLocation->FileObject->FsContext2
ke
jika proses panggilan adalah proses asing. Yang mengejutkan saya, saya melihat baris kode yang tepat ini di versi awal mskssrv.sys:
Blok Kode 7: Versi awal FSRendezVousServer: :Close, fsContext2 disetel ke NULL
Dalam blok kode yang ditunjukkan di atas,
Blok Kode 8: FSContext disetel ke NULL dalam pemeriksaan feature flag
Yang ditunjukkan dalam blok kode di atas adalah pemeriksaan untuk feature flag
Feature_Servicing_TeamsUsingMediaFoundationCrashes
.
Feature flag adalah komponen Windows yang mengaktifkan berbagai fungsi dan eksperimen, meskipun tidak ada banyak informasi publik tentang mereka. Dalam postingan blog sebelumnya, kami membahas bagaimana fitur telah digunakan untuk patch kerentanan. Bendera fitur terkadang digunakan untuk menguji fungsionalitas sebelum diadopsi secara resmi. Dalam hal ini, jika
Feature_Servicing_TeamsUsingMediaFoundationCrashes
diaktifkan, tidak diatur ke NULL, memperkenalkan kerentanan. Fitur ini diamati diaktifkan secara default pada instalasi Windows 10. Di Windows 11 dan seperti yang ditunjukkan pada Blok Kode 1, kondisional feature flag ini tidak ada dan pointer tidak disetel ke sehingga membuatnya rentan juga.
Karena nama fiturnya, saya melihat fungsionalitas Microsoft Teams, perangkat lunak konferensi video. Saya mengonfirmasi bahwa aplikasi dapat menggunakan fungsionalitas MSKSSRV untuk berbagi aliran media lintas proses. Ada kemungkinan bahwa berbagi handle stream menyebabkan Teams mengalami crash. Topik yang menarik untuk riset lanjutan adalah menelaah bagaimana Teams membagikan handle perangkat MSKSSRV antarproses, serta alasan mengapa pembersihan pointer yang dilakukan dengan benar justru dapat menyebabkan aplikasi mengalami crash.
Bagian dari seri ini berfokus pada kerentanan itu sendiri, termasuk cara memperbaikinya. Saya sangat tertarik untuk memeriksa patch untuk bug ini, karena perbaikan yang saya usulkan tampaknya memicu crash di Microsoft Teams. Perlu dicatat bahwa hingga tahap ini saya belum meneliti bagaimana aplikasi nyata menggunakan driver MSKSSRV dalam praktiknya. Ketiadaan konteks tersebut menciptakan blind spot dalam memahami mengapa sebuah sistem memiliki desain seperti sekarang. Patch yang sepenuhnya menyelesaikan bug ini memerlukan restrukturisasi kode dasar dan dapat mengungkap lebih banyak detail mengenai bagaimana sistem IPC seharusnya berfungsi. Saya juga berharap untuk mendapatkan beberapa insight tentang praktik pengodean yang aman dari pengembang Microsoft.
Yang membuat saya kecewa, kesalahan logika yang menyebabkan kerentanan, yang ditambal dalam pembaruan Keamanan Juni 2024, tidak ditangani secara langsung. Sebagai gantinya, pemeriksaan token akses ditambahkan sebelum jalur kode yang rentan. Lihat kode di bawah ini untuk konteks inisialisasi IOCTL, ditangani oleh fungsi
Blok Kode 9: Fungsi IOCTL dimulai dengan pemeriksaan feature flag dan memeriksa apakah proses pemanggilan adalah server bingkai
Fungsi di atas dimulai dengan memeriksa apakah fitur diaktifkan. Ini kemungkinan feature flag yang sesuai dengan patch. Jika fitur ini diaktifkan,
Mari kita lihat
Code Block 10: Fungsi KsIsCurrentProcessFrameServer melakukan SID check terhadap access token milik thread yang memanggil
Fungsi ini memeriksa token thread pemanggil terhadap dua pengenal keamanan tertentu (SID). SID sesuai dengan token di grup . Jika salah satu SID diaktifkan di token akses thread pemanggil, maka kode fungsi rentan dapat dijalankan.
Setelah melihat hal ini, saya menduga kemungkinan masih ada bug Administrator ke Kernel yang belum diperbaiki. Pada akhirnya, masalah korupsi memori tidak diatasi sama sekali. Saya mengonfirmasi hal ini dengan melakukan sedikit modifikasi pada eksploit asli saya: pengguna administrator dapat menjalankan layanan , membuka handle ke layanan tersebut, lalu membuat proses eksploit menggunakan handle itu. Saya dapat memperoleh primitif kernel R/W penuh pada sistem yang sepenuhnya ditambal.
Meskipun Microsoft tidak menganggap jalur Administrator ke Kernel sebagai batas keamanan, bug serupa telah digunakan oleh aktor ancaman untuk memperoleh primitif R/W pada kernel dan memanfaatkannya untuk membutakan EDR serta menjalankan operasi rootkit. Jika Anda tertarik mengetahui apa saja yang dapat dilakukan dengan primitif ini, lihat presentasi BlackHat kami bersama FuzzySec.
Posting ini berfokus pada bagian riset kerentanan dari upaya Pwn2Own saya, yang terdiri dari menemukan kerentanan kernel 0 hari yang dapat dieksploitasi untuk eskalasi hak istimewa. Tulisan ini menguraikan perjalanan tersebut: mulai dari terinspirasi oleh riset lain, gagal menemukan bug, mencoba pendekatan baru, menemukan hal yang mencurigakan, hingga akhirnya menentukan lokasi kerentanannya. Sekarang setelah bug berhasil diidentifikasi dan terdapat primitif use-after-free, sisanya seharusnya berjalan dengan mudah, bukan? Microsoft tampaknya berpendapat demikian; mereka memberi penilaian bug ini sebagai “Exploitation More Likely” dengan tingkat kompleksitas serangan “rendah”. Benarkah demikian? Saya akan membahas itu, strategi eksploitasi, dan mengungkap arti judul seri, di bagian selanjutnya!
Tetap terinformasi tentang tren industri yang paling penting—dan menarik—tentang AI, otomatisasi, data, dan di luarnya dengan buletin Think. Lihat Pernyataan Privasi IBM®.
Andréa Piazza, untuk diagram yang menakjubkan
Emma Kirkpatrick, yang dengan sabar menjelaskan model keamanan Windows kepada saya