Penjelasan perintah untuk memeriksa shellshock

32

Ini adalah perintah yang saya gunakan untuk memeriksa bash shell saya untuk bug Shellshock:

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

Adakah yang bisa menjelaskan perintah secara detail?

heemayl
sumber
4
Lihat juga: unix.stackexchange.com/q/157329/70524 - Jawaban fixee mungkin bisa membantu.
muru

Jawaban:

45

Jawaban ini merupakan turunan dari artikel asli di Majalah Fedora oleh Matthew Miller, dilisensikan di bawah lisensi Creative Commons Attribution-Share Alike 4.0 .

Biarkan saya jelaskan:

env x='() { :;}; echo OOPS' bash -c :

Ini akan mencetak "OOPS" pada sistem yang rentan, tetapi keluar secara diam-diam jika bash telah ditambal.

env x='() { :;}; echo OOPS' bash -c "echo this is a test"

Ini akan mencetak "OOPS" pada sistem yang rentan, tetapi mencetak “this is a test”jika bash telah ditambal.

Dan Anda mungkin pernah mendengar bahwa itu ada hubungannya dengan variabel lingkungan. Tetapi, mengapa kode dalam variabel lingkungan dieksekusi? Yah, itu tidak seharusnya - tetapi, karena fitur yang saya tergoda untuk menelepon terlalu pintar untuk kebaikannya sendiri, ada beberapa ruang untuk kesalahan. Bash adalah apa yang Anda lihat sebagai terminal prompt, tetapi juga merupakan bahasa scripting, dan memiliki kemampuan untuk mendefinisikan fungsi. Anda melakukannya seperti ini:

$ Ubuntu()  { echo "Ubuntu is awesome."; }

dan kemudian Anda memiliki perintah baru. Perlu diingat bahwa di echosini belum benar-benar berjalan; itu hanya disimpan sebagai apa yang akan terjadi ketika kita menjalankan perintah baru kita. Ini akan menjadi penting dalam satu menit!

$ Ubuntu
 Ubuntu is awesome.

Berguna! Tetapi, katakanlah, untuk beberapa alasan, Kita perlu menjalankan instance baru dari bash, sebagai subproses, dan ingin menjalankan perintah baru yang mengagumkan di bawah itu. Pernyataan bash -c somecommandtidak persis seperti ini: menjalankan perintah yang diberikan di shell baru:

$ bash -c Ubuntu
  bash: Ubuntu: command not found

Ooh. Sedih. Anak itu tidak mewarisi definisi fungsi. Tapi, itu memang melekat pada lingkungan - kumpulan pasangan nilai kunci yang telah diekspor dari shell. (Ini adalah konsep 'nuther keseluruhan; jika Anda tidak terbiasa dengan ini, percayalah untuk saat ini.) Dan, ternyata, bash dapat mengekspor fungsi juga. Begitu:

$ export -f Ubuntu
$ bash -c Ubuntu
  Ubuntu is awesome.

Yang semuanya baik dan baik - kecuali bahwa mekanisme yang digunakan untuk menyelesaikan ini agak cerdik . Pada dasarnya, karena tidak ada keajaiban Linux / Unix untuk melakukan fungsi dalam variabel lingkungan, fungsi ekspor sebenarnya hanya membuat variabel lingkungan biasa yang berisi definisi fungsi. Kemudian, ketika shell kedua membaca lingkungan "masuk" dan menemukan variabel dengan konten yang terlihat seperti fungsi, ia mengevaluasinya.

Secara teori, ini sangat aman , karena, ingat, mendefinisikan suatu fungsi tidak benar - benar menjalankannya . Kecuali - dan inilah mengapa kami di sini - ada bug dalam kode di mana evaluasi tidak berhenti ketika akhir definisi fungsi tercapai. Itu hanya kepts pergi.

Itu tidak akan pernah terjadi ketika fungsi yang disimpan dalam variabel lingkungan dibuat secara sah, dengan export -f. Tapi, mengapa harus sah? Seorang penyerang bisa membuat variabel lingkungan lama apa saja, dan jika itu tampak seperti fungsi, shell bash baru akan berpikir itu!

Jadi, dalam contoh pertama kami:

env x='() { :;}; echo OOPS' bash -c "echo this is a test"

The envperintah menjalankan perintah dengan satu set variabel yang diberikan. Dalam hal ini, kami menetapkan xsesuatu yang tampak seperti fungsi. Fungsi ini hanya satu :, yang sebenarnya adalah perintah sederhana yang didefinisikan sebagai tidak melakukan apa-apa. Tapi kemudian, setelah semi-colonyang menandakan akhir dari definisi fungsi, ada echoperintah. Seharusnya tidak ada di sana, tetapi tidak ada yang menghentikan kita dari melakukannya.

Kemudian, perintah yang diberikan untuk menjalankan dengan lingkungan baru ini adalah bash shell baru, sekali lagi dengan perintah " echo this is a test" atau "tidak melakukan apa-apa :", setelah itu ia akan keluar, benar-benar tidak berbahaya.

Tapi - oops! Ketika shell baru itu mulai dan membaca lingkungan, ia sampai ke xvariabel, dan karena itu tampak seperti fungsi, ia mengevaluasinya. Definisi fungsi dimuat tanpa berbahaya - dan kemudian muatan berbahaya kami terpicu juga. Jadi, jika Anda menjalankan hal di atas pada sistem yang rentan, Anda akan “OOPS”dicetak kembali pada Anda. Atau, seorang penyerang bisa melakukan jauh lebih buruk daripada hanya mencetak barang.

αғsнιη
sumber
1
Muchas gracias untuk penjelasan yang bagus tentang mengapa ini berhasil.
Doug R.
2
Catatan itu envtidak perlu. Anda bisa mendapatkan hasil yang sama (lulus / gagal tergantung pada apakah Bash telah diperbarui) dengan menggunakan perintah tanpa itu: x='() { :;}; echo OOPS' bash -c "echo this is a test". Ini karena mendahului perintah dengan penugasan variabel melewati variabel itu dan nilainya ke lingkungan perintah ( bash -c "..."dalam hal ini).
Dijeda sampai pemberitahuan lebih lanjut.
1
... tetapi mungkin diperlukan di beberapa tambalan yang lebih baru. Banyak hal berubah.
Dijeda sampai pemberitahuan lebih lanjut.
4
@ DennisWilliamson Apakah perlu atau tidak envditentukan oleh shell dari mana seseorang menjalankan tes, bukan shell yang diuji. (Ini mungkin sama. Bahkan kemudian, kami sedang menguji bagaimana bash memproses lingkungannya sendiri .) Kerang Bourne-style menerima NAME=value commandsintaksis; Kerang gaya-C (mis. csh, tcsh) Tidak. Jadi tes ini sedikit lebih portabel dengan env(dengan biaya kadang-kadang membuat kebingungan tentang cara kerjanya).
Eliah Kagan
2

Dalam versi yang tidak dititipbash itu menyimpan definisi fungsi yang diekspor sebagai variabel lingkungan.

Simpan fungsi xsebagai,

$ x() { bar; }
$ export -f x

Dan periksa definisinya sebagai,

$ env | grep -A1 x
x=() {  bar
}

Jadi seseorang dapat memanfaatkan ini dengan mendefinisikan variabel lingkungannya sendiri, dan menafsirkannya sebagai definisi fungsi. Sebagai contoh env x='() { :;}'akan diperlakukan sebagai

x() { :;
}

Apa yang dilakukan perintah untuk memeriksa shellshock,

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

Dari man env,

  1. env - Jalankan program dalam lingkungan yang dimodifikasi.

  2. :tidak melakukan apa pun kecuali keluar dengan status keluar 0. lihat lebih lanjut

  3. Saat instance baru dari bash yang belum ditambak diluncurkan sebagai bash -c "echo this is a test", variabel lingkungan buatan diperlakukan sebagai fungsi dan dimuat. Dengan demikian seseorang mendapat output

    rentan
    ini adalah sebuah ujian

Catatan: Gema di luar definisi fungsi telah secara tak terduga dieksekusi selama bash startup. Definisi fungsi hanyalah langkah untuk mendapatkan evaluasi dan mengeksploitasi terjadi, definisi fungsi itu sendiri dan variabel lingkungan yang digunakan sewenang-wenang. Shell melihat variabel lingkungan, melihat x, yang kelihatannya memenuhi batasan yang diketahuinya tentang seperti apa definisi fungsi, dan mengevaluasi baris, tanpa sengaja juga menjalankan gema (yang bisa berupa perintah apa pun, berbahaya atau tidak) . Lihat juga ini

souravc
sumber
Saya masih menemukan bahwa setiap fungsi bash yang ditentukan, jika diekspor sedang dievaluasi dalam shell anak dalam versi bash yang ditambal. Lihat ini: chayan @ chayan: ~ / testr $ test () {echo "anything"; }; ekspor-uji; bash -c test Ouput: anything Jadi jawaban Anda agak tidak diarahkan dengan benar. Penjelasan kasiyA tentang bug sebagai memperluas variabel di luar definisi adalah benar saya pikir.
heemayl
@heemayl perilaku ini alami. Tetapi jika Anda mencoba, env test='() { echo "anything"; }' bash -c "echo otherthing"Anda akan melihat pada output otherthing. Itu diperbaiki di patch. merasa bebas jika saya masih belum jelas.
souravc
Tolong jelaskan saya sekali lagi. Dalam komentar terakhir Anda, pada dasarnya kami mendefinisikan fungsi dan kemudian memberitahu bash untuk mengeksekusi gema. Dalam contoh ini kami tidak memanggil fungsi dalam bash. Bukankah ini memiliki output yang sama di bash ditambal dan tidak ditambal? Saya berpendapat bahwa bug pada dasarnya sebagai bash mengeksekusi perintah yang ditempatkan setelah definisi fungsi sedangkan fungsi tidak pernah dipanggil di mana pun kemudian misalnya jika kita melakukan tes env = '() {echo "anything"; }; echo "foo" 'bash -c "echo otherthing". Tolong jelaskan saya dalam konteks ini.
heemayl
@ heemayl Saya telah mengedit jawaban saya, harap sekarang sudah jelas. Anda benar dalam contoh di komentar terakhir saya, kami belum memanggil fungsi. Tetapi perbedaannya adalah bahwa unpatched bashAnda dapat memanggil fungsi seperti yang didefinisikan, tetapi dalam tambalan bashdefinisi itu sendiri tidak ada.
souravc
@ Heemayl: Tidak, itu tidak benar. Bash yang ditambal masih akan meneruskan definisi fungsi ke lingkungan anak. Perbedaan yang dibuat oleh patch adalah kode yang mengikuti definisi fungsi ( echo vulnerable) tidak dieksekusi. Perhatikan bahwa di tambalan terbaru, fungsi yang diteruskan harus memiliki awalan spesifik ( env 'BASH_FUNC_x()'='() { :;}; echo vulnerable' bash -c "echo this is a test"). Beberapa tambalan yang lebih baru mungkin digunakan %%alih-alih yang pertama ().
Dijeda sampai pemberitahuan lebih lanjut.