- Google menemukan CVE-2023-2163 pada verifier eBPF dengan Buzzer, dan mengonfirmasi bahwa kerentanan ini dapat dieksploitasi untuk eskalasi hak akses lokal dan pelolosan dari container
- eBPF memperluas fungsi kernel saat runtime, tetapi karena menjalankan bytecode arbitrer dengan hak akses tinggi, verifikasi verifier sebelum pemuatan menjadi pilar utama keamanan
- Masalah terjadi ketika path pruning pada verifier secara keliru menilai jalur eksekusi yang sebenarnya berbeda sebagai setara dengan jalur yang sudah aman
- Eksploit memanfaatkan perbedaan bahwa register yang dilihat verifier sebagai 0 memiliki nilai lain saat runtime, mencemari pointer stack eBPF, lalu berujung pada baca/tulis arbitrer dan bypass KASLR
- Patch menandai sebagai precise hingga imprecise register yang memengaruhi precise register, dan setelah itu tidak ditemukan isu tambahan dengan strategi fuzzing aritmetika pointer yang sama
Permukaan serangan kernel yang diperluas oleh verifier eBPF
- eBPF adalah teknologi yang memungkinkan fungsi kernel Linux diperluas saat runtime tanpa modul kernel yang kompleks
- Program eBPF ditulis dalam bytecode kustom, dan sebelum dijalankan ketika peristiwa tertentu terjadi, program tersebut melewati verifikasi keamanan
- Contoh umumnya adalah program eBPF yang dijalankan saat pemanggilan syscall tertentu
- Karena strukturnya memungkinkan eksekusi kode arbitrer pada tingkat hak akses tinggi, permukaan serangan kernel meningkat secara signifikan
- Sebelum dimuat, program harus melewati verifier, dan verifier memeriksa apakah asumsi keamanan eBPF terpenuhi
- Jika kerentanan verifier dieksploitasi, biasanya hal itu berujung pada eskalasi hak akses lokal atau pelolosan dari container di lingkungan container
Buzzer dan fuzzing aritmetika pointer
- Google membuat Buzzer untuk mengaudit kode verifier eBPF secara otomatis
- Buzzer adalah fuzzer yang menghasilkan program eBPF yang valid secara sintaksis dalam jumlah besar, dan dapat dikonfigurasi dengan strategi untuk memicu bug logika
- Untuk menemukan CVE-2023-2163, digunakan strategi aritmetika pointer
- Membuat header yang menginisialisasi register dengan nilai arbitrer
- Membuat urutan instruksi aritmetika dan jump arbitrer
- Memilih register arbitrer dan melakukan operasi penjumlahan dengan pointer element eBPF map
- Menulis nilai magic ke element tersebut
- Jika nilai yang ditulis tidak teramati dari user space, ada kemungkinan telah terjadi penulisan di luar batas
- CVE-2023-2163 yang ditemukan Buzzer berada pada logika path pruning eBPF, dan berujung pada eksploit yang dapat digunakan baik untuk pelolosan dari container maupun eskalasi hak akses lokal
Bug path pruning dan precise tracking
- Verifier eBPF menyimulasikan jalur eksekusi yang mungkin untuk memastikan program dapat dijalankan dengan aman
- Jika nilai register tidak pasti pada percabangan bersyarat, verifier berusaha mengikuti eksekusi semua state yang mungkin
- Semakin banyak conditional jump, jumlah jalur eksekusi meningkat secara eksponensial, dan hal ini juga berdampak buruk pada performa pemuatan program ke kernel
- Untuk menguranginya, para pengembang eBPF memperkenalkan path pruning
- Jika verifier dapat menjamin bahwa state yang setara dengan state tertentu sudah mencapai instruksi exit dengan aman, jalur tersebut tidak dieksplorasi lebih lanjut
- Untuk pruning yang lebih efisien, konsep precise tracking juga digunakan
- Jika register terlibat dalam operasi aritmetika pointer atau diteruskan sebagai konstanta ke fungsi helper, register tersebut ditandai sebagai precise
- Verifier harus mengeksplorasi semua state yang terkait dengan register tersebut
- Pada CVE-2023-2163, r9 yang memengaruhi presisi r6 tidak ditandai dengan benar
- Verifier mengasumsikan r9 tidak berkontribusi pada preciseness r6
- Setelah menilai bahwa pada jalur sebelumnya r6 dapat mencapai exit dengan aman, verifier menganggap state lain setara dan melakukan pruning
- Saat runtime, jalur 1:2:4:6 dijalankan, dan pada 6, r6 yang dilihat verifier sebagai 0 sebenarnya memiliki nilai lain dan dapat digunakan dalam operasi aritmetika pointer
Baca/tulis arbitrer dan bypass KASLR
- Kode eksploit dipublikasikan di repository Google security research
- Dalam pengembangan eksploit, pekerjaan @chompie dan @_manfp dimanfaatkan secara penting
- Alur keseluruhannya adalah mendapatkan baca/tulis arbitrer terlebih dahulu, lalu menemukan credentials proses dan mem-patch uid serta pointer
fs_structuntuk menaikkan hak akses - Pada tahap pertama, nilai register yang tercemar dibuat menjadi 1
- Dalam analisis manual, nilai r6 saat runtime adalah
0x400, sedangkan verifier melihatnya sebagai 0 - Nilai yang diinginkan, 1, dibuat dengan instruksi
r6 >>= 10
- Dalam analisis manual, nilai r6 saat runtime adalah
- Setelah itu, pointer pada stack eBPF dicemari dengan fungsi helper
bpf_skb_load_bytes_relative- Verifier menilai
lenbernilai 8, tetapi pada runtime sebenarnyalenmenjadi 9 karena nilai r6 - Akibatnya, bukan 8 byte melainkan 9 byte yang ditulis, sehingga byte pertama nilai pada offset stack
-32tercemar
- Verifier menilai
- Dengan memanipulasi pointer stack yang tercemar, eBPF map pointer dapat dibocorkan
- Membaca nilai R2 dan R3 dari user space, lalu memastikan apakah R2 menjadi
0xBACA - Jika kondisi ini terpenuhi, R3 menjadi nilai bocoran map pointer
- Bocoran eBPF map pointer berujung pada kondisi KASLR sudah di-bypass
- Membaca nilai R2 dan R3 dari user space, lalu memastikan apakah R2 menjadi
- Dengan strategi yang sama, jika bukan satu byte melainkan seluruh area stack berurutan ditimpa dengan pointer yang diinginkan, baca/tulis arbitrer menjadi mungkin
- Dari sudut pandang verifier, ini adalah manipulasi stack BPF, tetapi sebenarnya memori kernel dapat dibaca dan ditulis
Dari map leak hingga root shell
- Setelah map pointer bocor, eksploit tidak jauh berbeda dari eksploit Chompie, dan sebagian kodenya dipinjam
- Prosedur kasarnya adalah sebagai berikut
- Mencari string
init_pid_nssecara berulang di kstrtab - Menemukan simbol ksymtab yang mereferensikan string tersebut dan memperoleh alamat struktur init_pid_ns
- Menelusuri radix tree untuk menemukan entry dengan field
commyang cocok dengan nama file executable eksploit yang sedang berjalan- Jika berjalan di dalam container, PID bukan heuristik yang dapat dipercaya, sehingga tidak hanya menggunakan PID
- Mem-patch uid menjadi 0 dan mem-patch pointer
fs_struct - Jika
fs_structdi-patch menjadi nilai yang sama dengan pointer yang direferensikan PID 1, filesystem host dapat diamati saat berjalan di dalam container - Menjalankan
system("/bin/bash")untuk mendapatkan root shell
- Mencari string
- Kode yang dipublikasikan di GitHub berfungsi sebagai pelolosan dari container hanya pada versi Linux tertentu
- Pada Ubuntu dan beberapa distribusi, offset struktur data yang ditimpa berbeda, sehingga hanya berfungsi sebagai eskalasi hak akses lokal
- Agar berfungsi di distribusi Linux mana pun, penyesuaian kode diperlukan
Patch dan verifikasi lanjutan
- Analisis penyebab dan patch CVE-2023-2163 dapat dilihat di kernel mailing list
- Perbaikannya dilakukan dengan menandai imprecise register dari operasi yang memengaruhi precise register sebagai precise
- Belum jelas apakah perbaikan ini memengaruhi performa verifier eBPF
- Strategi fuzzing aritmetika pointer yang sama terus dijalankan, tetapi tidak ditemukan isu tambahan
- Buzzer masih terus dikembangkan, dan menerima kontribusi dari komunitas open-source melalui repo GitHub
1 komentar
Komentar di Hacker News
Pada platform yang paling umum dipakai untuk eBPF, sejak awal kode tanpa privilese tidak bisa memuat program eBPF, sehingga dampak bug verifier sering kali tidak terlalu besar
Bug seperti ini pada akhirnya adalah kerentanan root → ring0; bukan berarti sepele, tetapi untuk beban kerja sisi server umumnya merupakan kompromi yang bisa diterima
Khususnya, riwayat eskalasi privilese lokal kernel pada eBPF cukup baik dibandingkan kernel secara keseluruhan, dan nilai terbesar verifier dalam lingkungan eBPF saat ini adalah membuat kernel sulit mati secara tidak sengaja akibat program eBPF yang salah
Hal ini sama sekali tidak berlaku secara menggelikan pada modul kernel yang dapat dimuat pada umumnya
Dalam kasus ini, pada sebagian besar platform tidak diperlukan privilese
Dan jika ada namespace pengguna tanpa privilese, seseorang bisa menjadikan dirinya “root”, sehingga root → ring0 pun menjadi masalah yang kurang terbatas
Ini adalah pola yang terus terlihat pada PoC bug eBPF yang muncul setelah distro-distro sempat mengaktifkannya lalu sebagian besar mematikannya lagi
Seiring alat seperti Cilium makin besar, jalur serangan untuk masuk ke lingkungan container yang memiliki cap_bpf menjadi semakin realistis
“Uno no es ninguno” secara harfiah berarti “satu bukanlah ketiadaan”, yakni mendekati “One is not none”
Dalam bahasa Spanyol, negasi ganda sering kali sebenarnya bukan negasi ganda
Misalnya “tidak ada apa-apa di sini” dikatakan “no hay nada aquí”, yang jika diterjemahkan kata per kata tampak seperti “bukannya tidak ada apa-apa di sini”
Royal Spanish Academy juga menjelaskannya demikian:
https://www.rae.es/espanol-al-dia/doble-negacion-no-vino-nad...
Yang disebut “negasi ganda” muncul karena keselarasan negasi yang dalam situasi tertentu wajib ada dalam bahasa Spanyol dan bahasa Roman lainnya; akibatnya adverbia no dan unsur lain yang bermakna negatif muncul bersama dalam satu kalimat
Kehadiran dua “negasi” ini sekaligus tidak membatalkan makna negatif kalimat
Saat dulu mencoba memakai eBPF, daya ungkapnya kurang untuk melakukan pekerjaan yang dibutuhkan
Saya mempertanyakan apakah menambah kompleksitas ruang kernel demi fleksibilitas terbatas itu benar-benar dapat dibenarkan
Untuk pemfilteran paket saya bisa mengerti, tetapi pemakaian untuk tujuan lain seperti sandboxing terasa kurang meyakinkan
Pilihan kernel bukan eBPF atau tidak ada apa-apa, melainkan eBPF atau sesuatu yang lain yang mirip dengannya
Anda mungkin tidak banyak memakainya secara langsung, tetapi ada orang-orang yang menggunakannya sepanjang hari
Seingat saya, para engineer FAANG mengatakan mereka selalu menjalankan puluhan, mungkin ratusan, program seperti ini di setiap server, bahkan tanpa menghitung penggunaan sekali pakai
FAANG juga mempekerjakan pengembang kernel khusus, jadi mereka juga ikut mendanai kompleksitas yang mereka gunakan ini
Saya sendiri pernah menyelesaikan masalah dengan eBPF
Tanpa eBPF, masalah-masalah itu pada praktiknya mustahil dipecahkan oleh orang yang bukan pakar kernel, dan meski tidak sering dibutuhkan, saat dibutuhkan tidak ada penggantinya
Dalam beberapa kasus, bahkan bagi pakar kernel pun pilihannya adalah memakai eBPF atau memelihara patch kernel kustom selamanya
Saya tahu itu tidak aman, tetapi orang-orang yang menanganinya tahu bahwa kekuatan besar membawa tanggung jawab besar
“Uno no es ninguno” tampaknya memang benar diterjemahkan sebagai “One is not none”
https://bughunters.google.com/blog/6303226026131456/a-deep-d...
Namun diterjemahkan sebagai “One is none”
Ini adalah negasi ganda yang terkenal menyulitkan penutur bahasa asing, termasuk saya
https://spanish.stackexchange.com/questions/26777/how-does-d...
Kalau diterjemahkan harfiah memang begitu, tetapi dalam bahasa Spanyol, anehnya negasi ganda biasanya dipakai hanya sebagai negasi biasa
Mungkin terjemahan seperti “one ain't nothin'” lebih tepat
Di negara kami ada ungkapan “landak di dalam celana”
Betapapun banyak gunanya, ini tidak tampak ditulis dengan aman dan hati-hati