回答:
この回答は、Creative Commons Attribution-Share Alike 4.0ライセンスの下でライセンスされているMatthew MillerによるFedora Magazineのオリジナル記事の派生物です。
説明させてください:
env x='() { :;}; echo OOPS' bash -c :
これにより、脆弱なシステムでは「OOPS」が出力されますが、bashにパッチが適用されている場合はサイレントに終了します。
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
これにより、脆弱なシステムでは「OOPS」“this is a test”
が出力されますが、bashにパッチが適用されている場合は出力されます。
そして、おそらく環境変数と関係があると聞いたことがあるでしょう。しかし、なぜ環境変数のコードが実行されるのですか?まあ、それは想定されていません—しかし、私は自分の利益のためにちょっと賢すぎると呼びたがっている機能のために、いくつかの欠陥の余地があります。Bashは端末プロンプトとして表示されますが、スクリプト言語でもあり、関数を定義する機能があります。あなたはこのようにします:
$ Ubuntu() { echo "Ubuntu is awesome."; }
そして、新しいコマンドがあります。echo
ここは実際にはまだ実行されていないことに注意してください。新しいコマンドを実行すると何が起こるかとして保存されています。これはすぐに重要になります!
$ Ubuntu
Ubuntu is awesome.
有用!しかし、何らかの理由で、サブプロセスとしてbashの新しいインスタンスを実行し、その下で素晴らしい新しいコマンドを実行する必要があるとしましょう。このステートメントbash -c somecommand
はまさにこれを行います。新しいシェルで指定されたコマンドを実行します。
$ bash -c Ubuntu
bash: Ubuntu: command not found
ああ 悲しい。子は関数定義を継承しませんでした。しかし、それは環境に固有のものです-シェルからエクスポートされたキーと値のペアのコレクション。(これは完全な「概念」です。これに慣れていない場合は、今のところ私を信頼してください。)そして、bashは関数をエクスポートすることもできます。そう:
$ export -f Ubuntu
$ bash -c Ubuntu
Ubuntu is awesome.
これはすべて順調です。ただし、これを実現するメカニズムはかなり危険です。基本的に、環境変数で関数を実行するためのLinux / Unixマジックはないため、エクスポート関数は実際には関数定義を含む通常の環境変数を作成するだけです。次に、2番目のシェルが「着信」環境を読み取り、関数のように見えるコンテンツを持つ変数に遭遇すると、それを評価します。
理論的には、関数を定義しても実際には実行されないため、これは完全に安全です。ただし、これが私たちがここにいる理由です。関数定義の最後に達したときに評価が停止しないというバグがコードにありました。ただ動き続けた。
環境変数に保存された関数がで合法的に作成された場合、それは決して起こりませんexport -f
。しかし、なぜ合法ですか?攻撃者は古い環境変数を作成することができ、関数のように見える場合、新しいbashシェルはそれを考えます!
したがって、最初の例では:
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
env
コマンドは、指定された変数セットを使用してコマンドを実行します。この場合、x
関数のように見えるものに設定しています。この関数は単一で:
、実際には何もしないと定義されている単純なコマンドです。しかし、その後、semi-colon
関数定義の終わりを示すwhichの後に、echo
コマンドがあります。それはそこにあるはずではありませんが、私たちがそれをするのを止めるものは何もありません。
次に、この新しい環境で実行するために指定されたコマンドは、新しい「bash」シェルであり、再び「echo this is a test
」または「do nothing :
」コマンドを使用します。その後、完全に無害に終了します。
しかし—おっと!その新しいシェルが起動して環境を読み取ると、x
変数に到達し、関数のように見えるため、それを評価します。関数定義は無害にロードされます-そして、悪意のあるペイロードもトリガーされます。したがって、脆弱なシステムで上記を実行すると、“OOPS”
印刷されます。または、攻撃者は単に物事を印刷するよりもはるかに悪いことをする可能性があります。
env
必要ではないことに注意してください。次のコマンドを使用せずに、同じ結果(Bashが更新されたかどうかに応じて合格/不合格)を取得できますx='() { :;}; echo OOPS' bash -c "echo this is a test"
。これは、コマンドの前に変数を割り当てると、その変数とその値がコマンドのbash -c "..."
環境(この場合)に渡されるためです。
env
必要かどうかは、テスト対象のシェルではなく、テストを実行するシェルによって決まります。(これらは同じかもしれません。それでも、bashが独自の環境を処理する方法をテストしています。)BourneスタイルのシェルはNAME=value command
構文を受け入れます。Cスタイルのシェル(例えば、csh
、tcsh
)しないでください。そのため、テストの移植性は少し高くenv
なります(ただし、その動作方法について混乱を招く場合があります)。
パッチが適用されていないバージョンbash
も店舗は環境変数として関数定義をエクスポートします。
関数を次のx
ように保存します。
$ x() { bar; }
$ export -f x
そして、その定義を確認してください、
$ env | grep -A1 x
x=() { bar
}
したがって、独自の環境変数を定義し、それらを関数定義として解釈することにより、これを悪用できます。たとえば、次のenv x='() { :;}'
ように扱われます
x() { :;
}
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
からman env
、
env
-変更された環境でプログラムを実行します。
:
終了ステータスで終了するだけ0
です。もっと見る
パッチを当てていないbashの新しいインスタンスがとして起動するbash -c "echo this is a test"
と、細工された環境変数が関数として扱われ、ロードされます。したがって、出力が得られます
傷つきやすい これはテストです
注:関数定義外のエコーは、bashの起動中に予期せず実行されました。関数定義は、評価とエクスプロイトを実現するための単なるステップであり、関数定義自体と使用される環境変数は任意です。シェルは環境変数を調べ、xを見て、関数定義がどのようなものであるかを知っている制約を満たしているように見え、行を評価します。 。また、参照してください。これを
env test='() { echo "anything"; }' bash -c "echo otherthing"
みると出力に表示されますotherthing
。これはパッチで修正されています。まだわからない場合はお気軽に。
unpatched bash
定義されているとおりに関数を呼び出すことができますが、パッチを適用した場合bash
は定義自体が存在しないことです。
echo vulnerable
)に続くコードが実行されないことです。最新のパッチでは、渡される関数には特定のプレフィックス(env 'BASH_FUNC_x()'='() { :;}; echo vulnerable' bash -c "echo this is a test"
)が必要であることに注意してください。いくつかのより新しいパッチが%%
最初のパッチの代わりに使用するかもしれません()
。