第32回 PHPセキュリティ月間(Month of PHP Sercurity)で「PHPセキュリティ月間」(MOPS - Month of PHP Security)について簡単に紹介しました。
今回は静的にPHPソースコードを分析しセキュリティ脆弱性を検査するツールの紹介です。
- MOPS Submission 09: RIPS - A static source code analyser for vulnerabilities in PHP scripts
- http://www.php-security.org/2010/05/24/mops-submission-09-rips-a-static-source-code-analyser-for-vulnerabilities-in-php-scripts/index.html
昨年発見された脆弱性のおよそ3割がPHPアプリケーション関連の脆弱性とされています。PHPは簡単にWebアプリケーションが作れるため,セキュリティに十分留意したWeb開発フレームワークを利用しなくてもアプリケーションが作れてしまいます。Webアプリケーションが簡単に作れることはよいことですが,これが多くの脆弱性を生む原因になっています。
Johannes Dahse氏はこのような状況を改善するためにRIPSと呼ばれる,オープンソースのPHPソースコード分析ツールを開発しました。
この記事を執筆するにあたり,筆者は執筆時点の最新版rips-0.32.zipを利用しました。MacOS 10.6上のPHP 5.3で実行してみたところ一見動作しているように見えますが正常に動作しませんでした。LinuxのPHP 5.2で動作させると期待通りの正常に動作しました。PHP 5.3では動作しない可能性があるので注意してください。
RIPSの基本設計
RIPSは危険性がある関数をPVF(Potentialy Vulnerable Function 潜在的に危険な関数 ─ system(), pg_query()など)と定義し,$_GET, $_POST, $_COOKIE, $_FILES, $_SERVER, $_ENVのユーザ入力をソースとするデータがPVFに渡されると脆弱性があるとレポートします。
RIPSは構文解析を行いPVFを見つけ,PVFへ渡されたパラメータが危険なパラメータでないか,変数の遷移を確認します。構文解析にはPHPスクリプトを解析しトークンに分解するモジュールであるTokenizerを利用しています。TokenizerはPHPのパーサを利用しているので正確にPVFや変数を識別できます。論文執筆時点で,RIPSはpreg_replace_callback関数やhilight_file関数など危険性がよく知られていない関数を含め139のPVFを識別するそうです。
静的なソースコード脆弱性スキャナと聞くとコマンドラインアプリケーションを想像するかも知れませんが,RIPSはWebアプリケーションとして実装されています。恐らくUIが作りやすいからでしょう。スキャンするファイルをWebサーバ上に置いてスキャンします。
脆弱性スキャン
RIPSが脆弱性を検出する過程を簡単なスクリプトで解説します。
サンプルコード
<?php
$a = $_GET['a'];
$b = $a;
system($b, $ret);
?>
Tokenizerでトークンに分解されたスクリプト情報から,system関数が利用されていることが検出されます。次にsystem関数は危険な関数なのでPVFとして識別されます。同時にパラメータ$bが追跡すべき変数として認識され,その変数ソースが危険なソースでないか追跡されます。変数のソースが危険なソースであれば脆弱性として識別します。
サンプルコードのスキャン結果
4 : system($b ,$ret);
3 : $b = $a;
2 : $a = $_GET['a'];
危険なデータソースである$_GET['a']と危険な関数であるsystem関数が識別され,脆弱性として正しくレポートされています。
今度は危険でないサンプルコードをスキャンしてみます。
サンプルコード2
<?php
$a = $_GET['a'];
$b = 'date';
system($b, $ret);
?>
期待通りに脆弱性はレポートされませんでした。
次にもう少し複雑なサンプルコードをスキャンしてみます。
サンプルコード3
<?php
$a = $_GET['a'];
$b = escapeshellarg($a);
$c = 'cal ' . $b;
system($c, $ret);
?>
脆弱性はないので,対策済みのコードも表示されるレベルに変えると次のような結果となります。
3行目で対策が取られていることがわかります。これはsystem関数の最初のパラメータが危険なパラメータで,安全にするための関数が escapeshellarg関数, escapeshellcmd関数だと登録されているため,このような結果になります。
RIPSに保存されている検出用データのイメージ
"system" => array (
array(1), array("escapeshellarg", "escapeshellcmd")
);
実際にはconfig/PVF.phpファイルでPVFが,config/securing.phpで対策用の関数が定義されています。config/securing.phpを見たところ対応しているデータベースはMySQLのみで,まだPostgreSQLやSQLiteには対応していませんでした。PostgreSQLやSQLiteサポートを追加することは簡単にできそうでした。RIPSはまだまだ開発中のツールだと言えるでしょう(注:RIPS 0.34以降はPostgreSQL,SQLiteもサポートしています)。
include/require文にも対応しており,複数のファイルにまたがるアプリケーションでもスキャンは可能です。しかし,アプリケーションを実際に実行していないので,正確にインクルードするファイルが特定できる訳ではありません。このため,スキャン結果が不正確になる場合もあります。

