1 poin oleh GN⁺ 2024-08-10 | 1 komentar | Bagikan ke WhatsApp
  • 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_struct untuk 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
  • Setelah itu, pointer pada stack eBPF dicemari dengan fungsi helper bpf_skb_load_bytes_relative
    • Verifier menilai len bernilai 8, tetapi pada runtime sebenarnya len menjadi 9 karena nilai r6
    • Akibatnya, bukan 8 byte melainkan 9 byte yang ditulis, sehingga byte pertama nilai pada offset stack -32 tercemar
  • 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
  • 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_ns secara 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 comm yang 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_struct di-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
  • 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

 
GN⁺ 2024-08-10
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

    • PoC menulis map eBPF dengan pointer di luar rentang, tetapi jika ini sekadar kesalahan pelacakan rentang nilai skalar, tampaknya juga bisa dieksploitasi lewat program BPF non-ekstensi yang dapat dimuat melalui seccomp
      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
    • Jangan lupa bahwa container dapat diberi CAP_BPF
      Seiring alat seperti Cilium makin besar, jalur serangan untuk masuk ke lingkungan container yang memiliki cap_bpf menjadi semakin realistis
    • Memperbaiki bug verifier penting karena merupakan prasyarat untuk membuat penggunaan eBPF tanpa privilese menjadi aman
  • “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

    • Untuk kegunaan seperti ini ada juga teknologi lain seperti DTrace
      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
    • Bukankah driver mode kernel tradisional yang dapat dimuat lebih baik daripada patch atau eBPF?
      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

    • Dengan bertambahnya pengalaman, kita akan tahu bahwa meskipun sudah dilakukan dengan aman dan hati-hati, kesalahan tetap bisa terjadi