hnwの日記

PHP 5.3.4以降ではヌルバイト攻撃が成立しにくくなった

今回はWebセキュリティの話題です。実はid:t_komuraさんの記事で既報なんですが、案外知られていない気がしたので改めて紹介します。


PHPアプリケーションに特化した攻撃手法として、ヌルバイト攻撃というものがあります。PHPの大半の関数がヌル文字\0(0x00)を文字として認識する一方、Cの関数を直接呼び出すような一部関数では文字列の終端文字として機能することがあり、このねじれを利用する攻撃のことを言います。


特に、これまではディレクトリトラバーサル脆弱性やLFI(Local File Inclusion)脆弱性との組み合せでヌルバイト攻撃が言及される印象がありました。例えば次のような状況です。

<?php
function __autoload($class_name) {
    require 'lib/' . $class_name . '.php';
}
$obj = new $_GET['class_name'];


やや非現実的ですが、「foo.php?class_name=Bar」などとアクセスすることで、lib/Bar.phpファイルをrequireするというコードです。


このコードにはLFI脆弱性があります。つまり、「foo.php?class_name=../upload/Baz」などとアクセスされてしまうと、upload/Baz.phpファイルがPHPコードとして解釈されてしまいます。万一、ユーザーが自由にファイルを設置できるようなアプリケーションであれば、任意のコードが実行されてしまうわけです。


それだけでなく、PHP 5.3.3までは「foo.php?class_name=../../../../../../../../etc/passwd%00」としてアクセスすれば/etc/passwdの中身を表示させることもできました。これは、PHP 5.3.3以前はrequireやその他ファイルアクセス系の関数が\0をファイル名文字列の終端だと判断していたためです。これは典型的なヌルバイト攻撃といえます。


しかし「一部の言語構造と関数で引数の値に NULL バイトが含まれていた場合の挙動修正 - t_komuraの日記」で紹介されているように、PHP 5.3.4以降ではファイル名に\0を含んでいるとrequireやfile_get_contentsの処理が失敗するようになりました。つまり、上の例であれば「.php」で終わるファイルにしかアクセスできないため、被害が限定されるはずです。


また、PHP 5.4.0以降では引数としてファイル名を受け取る関数にヌル文字を含んだ文字列を渡すと次のような警告が出るようになりました。

PHP Warning:  file_get_contents() expects parameter 1 to be a valid path, string given in /tmp/foo.php on line 7


これはid:t_komuraさんも言われているように「保険的対策」でしかないとはいえ、一定のインパクトがある改善のように思います。というのも、これまではヌルバイト攻撃の存在によりLFI脆弱性ディレクトリトラバーサル脆弱性の脅威が大きかった部分もあるように思うので、実害が出る可能性が減るのであれば良いことではないでしょうか。


もちろん、脆弱性を作りこまないことが一番大切なことです。ファイルアクセスなどは特に気をつけたい箇所ですよね。言うまでもないとは思いますが、念のため。