Tampaknya ada kerentanan (CVE-2014-6271) di bash: Bash dibuat khusus untuk serangan kode variabel lingkungan injeksi
Saya mencoba mencari tahu apa yang terjadi, tetapi saya tidak sepenuhnya yakin saya memahaminya. Bagaimana bisa echo
dieksekusi seperti dalam tanda kutip tunggal?
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
EDIT 1 : Sistem yang ditambal terlihat seperti ini:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
this is a test
EDIT 2 : Ada kerentanan / tambalan terkait: CVE-2014-7169 yang menggunakan tes yang sedikit berbeda:
$ env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"
keluaran yang belum ditonton :
vulnerable
bash: BASH_FUNC_x(): line 0: syntax error near unexpected token `)'
bash: BASH_FUNC_x(): line 0: `BASH_FUNC_x() () { :;}; echo vulnerable'
bash: error importing function definition for `BASH_FUNC_x'
test
sebagian keluaran (versi awal) yang ditambal :
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
bash: error importing function definition for `BASH_FUNC_x()'
test
output yang ditambal hingga dan termasuk CVE-2014-7169:
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `BASH_FUNC_x'
test
EDIT 3 : cerita berlanjut dengan:
bash
shellshock
vulnerability
jippie
sumber
sumber
vulnerable
muncul di output. Masalah utama adalah bahwa bash mem-parsing dan mengeksekusi kode setelah definisi fungsi juga. Lihat/bin/id
bagian dari seclists.org/oss-sec/2014/q3/650 untuk contoh lainnya.Jawaban:
bash menyimpan definisi fungsi yang diekspor sebagai variabel lingkungan. Fungsi yang diekspor terlihat seperti ini:
Yaitu, variabel lingkungan
foo
memiliki konten literal:Ketika instance baru dari bash diluncurkan, ia mencari variabel lingkungan yang dibuat khusus ini, dan menafsirkannya sebagai definisi fungsi. Anda bahkan dapat menulisnya sendiri, dan melihat bahwa itu masih berfungsi:
Sayangnya, penguraian definisi fungsi dari string (variabel lingkungan) dapat memiliki efek yang lebih luas daripada yang dimaksudkan. Dalam versi yang tidak ditonton, ia juga mengartikan perintah sewenang-wenang yang terjadi setelah penghentian definisi fungsi. Hal ini disebabkan oleh kurangnya kendala dalam penentuan string seperti fungsi yang dapat diterima di lingkungan. Sebagai contoh:
Perhatikan bahwa 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
foo
, yang sepertinya memenuhi batasan yang diketahui tentang seperti apa definisi fungsi, dan mengevaluasi baris, tanpa sengaja juga menjalankan gema (yang bisa berupa perintah apa pun, berbahaya atau tidak).Ini dianggap tidak aman karena variabel biasanya tidak diizinkan atau diharapkan, sendiri, untuk secara langsung menyebabkan permohonan kode arbitrer yang terkandung di dalamnya. Mungkin program Anda menetapkan variabel lingkungan dari input pengguna yang tidak terpercaya. Akan sangat tak terduga bahwa variabel lingkungan tersebut dapat dimanipulasi sedemikian rupa sehingga pengguna dapat menjalankan perintah sewenang-wenang tanpa maksud eksplisit Anda untuk melakukannya menggunakan variabel lingkungan itu untuk alasan yang dinyatakan dalam kode.
Berikut adalah contoh serangan yang layak. Anda menjalankan server web yang menjalankan shell yang rentan, di suatu tempat, sebagai bagian dari masa pakainya. Server web ini meneruskan variabel lingkungan ke skrip bash, misalnya, jika Anda menggunakan CGI, informasi tentang permintaan HTTP sering dimasukkan sebagai variabel lingkungan dari server web. Misalnya,
HTTP_USER_AGENT
mungkin disetel ke konten agen pengguna Anda. Ini berarti bahwa jika Anda menipu agen pengguna Anda menjadi sesuatu seperti '() {:; }; echo foo ', ketika skrip shell berjalan,echo foo
akan dieksekusi. Sekali lagi,echo foo
bisa berupa apa saja, berbahaya atau tidak.sumber
export bar='() { echo "bar" ; }'; zsh -c bar
dan tampilannyabar
bukanzsh:1: command not found: bar
? Apakah Anda yakin Anda tidak membingungkan shell yang Anda gunakan dengan shell yang Anda gunakan untuk mengatur tes?Ini dapat membantu untuk menunjukkan lebih lanjut apa yang sedang terjadi:
Jika Anda menjalankan shell yang rentan, maka ketika Anda memulai subkulit baru (di sini, cukup dengan menggunakan pernyataan bash), Anda akan melihat bahwa kode arbitrer (
echo "pwned"
) segera dieksekusi sebagai bagian dari inisiasinya. Rupanya, shell melihat bahwa variabel lingkungan (dummy) berisi definisi fungsi, dan mengevaluasi definisi untuk mendefinisikan fungsi itu di lingkungannya (perhatikan bahwa ia tidak menjalankan fungsi: yang akan mencetak 'hi'.)Sayangnya, ini tidak hanya mengevaluasi definisi fungsi, tetapi juga mengevaluasi seluruh teks dari nilai variabel lingkungan, termasuk pernyataan yang mungkin berbahaya yang mengikuti definisi fungsi. Perhatikan bahwa tanpa definisi fungsi awal, variabel lingkungan tidak akan dievaluasi, itu hanya akan ditambahkan ke lingkungan sebagai string teks. Seperti yang ditunjukkan Chris Down, ini adalah mekanisme spesifik untuk mengimplementasikan impor fungsi shell yang diekspor.
Kita dapat melihat fungsi yang telah didefinisikan di shell baru (dan telah ditandai sebagai diekspor ke sana), dan kita dapat menjalankannya. Selain itu, dummy belum diimpor sebagai variabel teks:
Baik penciptaan fungsi ini, maupun apa pun yang akan dilakukannya seandainya dijalankan, adalah bagian dari exploit - itu hanya kendaraan yang dengannya exploit dieksekusi. Intinya adalah bahwa jika penyerang dapat menyediakan kode berbahaya, didahului oleh definisi fungsi minimal dan tidak penting, dalam string teks yang dimasukkan ke dalam variabel lingkungan yang diekspor, maka itu akan dieksekusi ketika subkulit dimulai, yang merupakan peristiwa umum dalam banyak skrip. Selanjutnya, itu akan dieksekusi dengan hak istimewa skrip.
sumber
export
perintah sedangkan yang lain punyaenv
? Saya berpikirenv
sedang digunakan untuk mendefinisikan variabel lingkungan yang akan dipanggil ketika bash shell lain diluncurkan. lalu bagaimana ini bekerja denganexport
env
danexport
lingkungan sehingga tersedia dalam subkulit. Masalahnya sebenarnya adalah bagaimana definisi yang diekspor ini diimpor ke lingkungan subkulit, dan khususnya dalam mekanisme yang mengimpor definisi fungsi.env
menjalankan perintah dengan beberapa opsi dan variabel lingkungan yang ditetapkan. Perhatikan bahwa dalam contoh pertanyaan asli,env
setx
ke string, dan panggilanbash -c
dengan perintah untuk dijalankan. Jika Anda melakukannyaenv x='foo' vim
, Vim akan diluncurkan, dan di sana Anda dapat memanggil shell / environment yang berisi dengannya!echo $x
, dan ia akan mencetakfoo
, tetapi jika Anda keluar danecho $x
, itu tidak akan ditentukan, karena hanya ada saat vim sedang berjalan melaluienv
perintah. Theexport
perintah bukan menetapkan nilai-nilai yang terus-menerus dalam lingkungan saat ini sehingga subkulit menjalankan kemudian akan menggunakannya.Saya menulis ini sebagai penyusunan ulang gaya tutorial dari jawaban yang sangat baik oleh Chris Down di atas.
Dalam bash, Anda dapat memiliki variabel shell seperti ini
Secara default, variabel-variabel ini tidak diwarisi oleh proses anak.
Tetapi jika Anda menandai mereka untuk ekspor, bash akan menetapkan bendera yang berarti mereka akan masuk ke lingkungan subproses (meskipun
envp
parameternya tidak banyak terlihat,main
program C Anda memiliki tiga parameter: dimain(int argc, char *argv[], char *envp[])
mana array pointer terakhir adalah array variabel shell dengan definisi mereka).Jadi mari kita ekspor
t
sebagai berikut:Sedangkan di atas
t
tidak ditentukan dalam subkulit, sekarang muncul setelah kami mengekspornya (gunakanexport -n t
jika Anda ingin berhenti mengekspornya).Tetapi fungsi dalam bash adalah binatang yang berbeda. Anda mendeklarasikannya seperti ini:
Dan sekarang Anda bisa menjalankan fungsi dengan memanggilnya seolah-olah itu adalah perintah shell lain:
Sekali lagi, jika Anda menelurkan subkulit, fungsi kami tidak diekspor:
Kami dapat mengekspor fungsi dengan
export -f
:Inilah bagian yang sulit: fungsi yang diekspor seperti
fn
dikonversi menjadi variabel lingkungan seperti ekspor variabel shellt
kami di atas. Ini tidak terjadi ketikafn
merupakan variabel lokal, tetapi setelah ekspor kita dapat melihatnya sebagai variabel shell. Namun, Anda juga dapat memiliki variabel shell reguler (yaitu, tidak berfungsi) dengan nama yang sama. bash membedakan berdasarkan isi variabel:Sekarang kita dapat menggunakan
env
untuk menampilkan semua variabel shell yang ditandai untuk diekspor dan fungsi regulerfn
danfn
muncul:Sub-shell akan mencerna kedua definisi: satu sebagai variabel reguler dan satu sebagai fungsi:
Anda dapat mendefinisikan
fn
seperti yang kami lakukan di atas, atau langsung sebagai tugas variabel biasa:Perhatikan ini adalah hal yang luar biasa tinggi untuk dilakukan! Biasanya kita akan mendefinisikan fungsi
fn
seperti yang kita lakukan di atas denganfn() {...}
sintaks. Tetapi karena bash mengekspornya melalui lingkungan, kita dapat "memotong" langsung ke definisi reguler di atas. Perhatikan bahwa (berlawanan dengan intuisi Anda, mungkin) ini tidak menghasilkan fungsi baru yangfn
tersedia di shell saat ini. Tetapi jika Anda menelurkan shell ** sub **, maka itu akan.Mari kita batalkan ekspor fungsi
fn
dan biarkan reguler barufn
(seperti yang ditunjukkan di atas) tetap utuh.Sekarang fungsinya
fn
tidak lagi diekspor, tetapi variabel regulernyafn
, dan berisi() { echo "direct" ; }
di dalamnya.Sekarang ketika subkulit melihat variabel biasa yang dimulai dengan
()
itu mengartikan sisanya sebagai definisi fungsi. Tapi ini hanya ketika shell baru dimulai. Seperti yang kita lihat di atas, hanya mendefinisikan variabel shell biasa dimulai dengan()
tidak menyebabkannya berperilaku seperti fungsi. Anda harus memulai subkulit.Dan sekarang bug "shellshock":
Seperti yang baru saja kita lihat, ketika shell baru mencerna definisi dari variabel biasa yang dimulai dengan
()
itu menafsirkannya sebagai fungsi. Namun, jika ada lebih banyak diberikan setelah kurung kurawal yang mendefinisikan fungsi, ia mengeksekusi apa pun yang ada di sana.Ini adalah persyaratan, sekali lagi:
Dalam hal ini, bash yang rentan akan menjalankan perintah yang terakhir.
Contoh:
Variabel ekspor reguler
ex
diteruskan ke subshell yang ditafsirkan sebagai fungsiex
tetapi perintah trailing dieksekusi (this is bad
) ketika subshell muncul.Menjelaskan tes satu baris yang apik
Garis satu yang populer untuk menguji kerentanan Shellshock adalah yang dikutip dalam pertanyaan @ jippie:
Berikut ini rinciannya: pertama
:
in bash hanyalah singkatantrue
.true
dan:
keduanya mengevaluasi (Anda dapat menebaknya) benar, dalam bash:Kedua,
env
perintah (juga dibangun ke dalam bash) mencetak variabel lingkungan (seperti yang kita lihat di atas) tetapi juga dapat digunakan untuk menjalankan perintah tunggal dengan variabel yang diekspor (atau variabel) yang diberikan kepada perintah itu, danbash -c
menjalankan satu perintah dari garis komando:Jadi menjahit semua hal ini bersama-sama, kita dapat menjalankan bash sebagai sebuah perintah, memberinya beberapa hal dummy untuk dilakukan (seperti
bash -c echo this is a test
) dan mengekspor variabel yang dimulai dengan()
sehingga subkulit akan menafsirkannya sebagai fungsi. Jika shellshock ada, itu juga akan segera menjalankan perintah trailing di subkulit. Karena fungsi yang kami lewati tidak relevan bagi kami (tetapi harus diuraikan!), Kami menggunakan fungsi valid terpendek yang bisa dibayangkan:Fungsi di
f
sini hanya menjalankan:
perintah, yang mengembalikan true dan keluar. Sekarang tambahkan beberapa perintah "jahat" dan ekspor variabel reguler ke subkulit dan Anda menang. Ini adalah satu-liner lagi:Jadi
x
diekspor sebagai variabel reguler dengan fungsi valid sederhana denganecho vulnerable
ditempel di akhir. Ini diteruskan ke bash, dan bash mengartikanx
sebagai fungsi (yang tidak kita pedulikan) maka mungkin mengeksekusiecho vulnerable
jika shellshock hadir.Kami dapat mempersingkat one-liner sedikit dengan menghapus
this is a test
pesan:Ini tidak mengganggu
this is a test
tetapi menjalankan:
perintah diam lagi. (Jika Anda berhenti-c :
maka Anda duduk di subkulit dan harus keluar secara manual.) Mungkin versi yang paling ramah pengguna adalah yang ini:sumber
{ :;};
sebenarnya dikatakan. Itu akan menjadi tambahan yang bagus untuk jawaban Anda menurut saya. Bisakah menjelaskan bagaimana Anda mendapatkan dari contoh Anda ke perintah asli dalam pertanyaan?Jika Anda dapat memasukkan variabel lingkungan yang berubah-ubah ke program, Anda dapat membuatnya melakukan apa saja dengan meminta memuat pustaka yang Anda pilih. Dalam sebagian besar kasus, ini tidak dianggap sebagai kerentanan dalam program yang menerima variabel lingkungan tersebut, melainkan dalam mekanisme di mana orang luar dapat memberi makan dalam variabel lingkungan yang sewenang-wenang.
Namun CVE-2014-6271 berbeda.
Tidak ada salahnya memiliki data yang tidak dipercaya dalam variabel lingkungan. Kita hanya perlu memastikan itu tidak dimasukkan ke dalam salah satu variabel lingkungan yang dapat mengubah perilaku program. Masukkan sedikit lebih abstrak, untuk permohonan tertentu, Anda dapat membuat daftar putih nama variabel lingkungan, yang diizinkan untuk ditentukan secara langsung oleh orang luar.
Contoh yang telah diajukan dalam konteks CVE-2014-6271 adalah skrip yang digunakan untuk mem-parsing file log. Mereka mungkin memiliki kebutuhan yang sangat sah untuk mengirimkan data yang tidak dipercaya ke dalam variabel lingkungan. Tentu saja nama untuk variabel lingkungan seperti itu dipilih sedemikian rupa sehingga tidak memiliki pengaruh buruk.
Tapi di sini adalah apa yang buruk tentang kerentanan bash khusus ini. Itu dapat dieksploitasi melalui nama variabel apa saja. Jika Anda membuat variabel lingkungan bernama
GET_REQUEST_TO_BE_PROCESSED_BY_MY_SCRIPT
, Anda tidak akan mengharapkan program lain selain skrip Anda sendiri untuk menafsirkan konten variabel lingkungan itu. Tetapi dengan mengeksploitasi bug bash ini, setiap variabel lingkungan tunggal menjadi vektor serangan.Perhatikan bahwa ini tidak berarti nama variabel lingkungan diharapkan dirahasiakan. Mengetahui nama-nama variabel lingkungan yang terlibat tidak membuat serangan lebih mudah.
Jika
program1
panggilanprogram2
yang pada gilirannya panggilanprogram3
, makaprogram1
dapat meneruskan dataprogram3
melalui variabel lingkungan. Setiap program memiliki daftar variabel lingkungan tertentu yang ditetapkannya dan daftar spesifik yang ditindaklanjuti. Jika Anda memilih nama yang tidak dikenaliprogram2
, Anda dapat meneruskan data dariprogram1
keprogram3
tanpa khawatir ini akan berdampak burukprogram2
.Seorang penyerang yang mengetahui nama pasti variabel yang diekspor oleh
program1
dan nama-nama variabel yang ditafsirkan olehprogram2
tidak dapat mengeksploitasi pengetahuan ini untuk mengubah perilaku 'program2` jika tidak ada tumpang tindih antara set nama.Tapi ini rusak jika
program2
itubash
skrip, karena karena bug inibash
akan menafsirkan setiap variabel lingkungan sebagai kode.sumber
Itu dijelaskan dalam artikel yang Anda tautkan ...
Yang berarti bash yang dipanggil dengan
-c "echo this is a test"
mengeksekusi kode dalam tanda kutip tunggal ketika dipanggil.Berarti contoh kode yang Anda poskan mengeksploitasi fakta bahwa bash yang dipanggil tidak berhenti mengevaluasi string ini setelah melakukan penugasan. Tugas fungsi dalam kasus ini.
Hal yang benar-benar spesial tentang potongan kode yang Anda posting, seperti yang saya mengerti, adalah bahwa dengan menggunakan definisi fungsi sebelum kode yang ingin kita jalankan, beberapa mekanisme keamanan dapat dielakkan.
sumber