なぜPHPアプリにセキュリティホールが多いのか?

第38回 MOPS:PHPにおけるコード実行(2)

この記事を読むのに必要な時間:およそ 3.5 分

第32回 PHPセキュリティ月間(Month of PHP Sercurity)「PHPセキュリティ月間」MOPS - Month of PHP Securityについて簡単に紹介しました。

前回もArthur Gerkis氏が投稿したPHPにおけるコード実行を解説した文書を紹介しました。今回はその続きです。

MOPS Submission 07: Our Dynamic PHP - Obvious and not so obvious PHP code injection and evaluation
http://www.php-security.org/2010/05/20/mops-submission-07-our-dynamic-php/index.html

動的コード

動的コードでのコード実行には「任意コードの実行」のみでなく「不正なコード実行パス」も含めて議論しています。

動的変数

ブラウザからの入力をグローバル変数として初期化するregister_globals設定がデフォルトでoffになってから久しいですが,レガシーコードの中にはregister_globals=onをエミュレートするプログラムも存在します。register_globals=on時にセキュリティ上問題となるコードは十分に議論されてきました。次のコードはregister_globals=onの場合に発生する典型的な脆弱性の例です。

register_globals=onをエミュレートするコード

<?php
foreach ($_GET as $key => $value) {
   $$key = $value;
}
// ... some code
if (logged_in() || $authenticated) {
   // ... administration area
}
?>

このコードに対して

http://www.example.com/index.php?authenticated=true

とアクセスすると,logged_in()がfalseを返しても$authenticatedがtureであるため,if文のコードが不正に実行されます。

PHP 4.2でregister_globals=offがデフォルトとなってから久しいので,現在ではあまり見かけないPHPアプリケーションの脆弱性ですが,古いコードでは時折上記のようなコードを見かけます。PHP 5.4ではregister_globals設定自体が削除されます。上記のようなコードを持つアプリケーションやregister_globals=onが必要なアプリケーションは早めに改修すべきです。

動的な関数

PHPには変数の中に保存された文字列を関数名として呼び出す,可変関数と呼ばれる機能があります。この機能を利用すると任意コード実行が可能となる場合があります。

可変関数の利用

<?php
$dyn_func = $_GET['dyn_func'];
$argument = $_GET['argument'];
$dyn_func($argument);
?>

このスクリプトに次のURLでアクセスすると,system関数でさまざまなコマンドを実行されてしまいます。

http://www.example.com/index.php?dyn_func=system&argument=uname

次はcreate_funciton関数でのコード実行の例です。

<?php
$foobar = "system('ls')";
$dyn_func = create_function('$foobar', "echo $foobar;");
$dyn_func('');
?>

このコードを実行するとsystem関数でlsコマンドが実行されます。create_function関数がeval関数のラッパーとして実装されているのでこのような動作になります。evel関数で記述した場合,次のような動作になります。

<?php
eval("function lambda_n() { echo system('ls'); }");
lambda_n();
?>

このように動作することはPHPマニュアルのcreate_function関数のページにも記載されています。

例1 create_function() による匿名関数の作成

<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "新しい匿名関数: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
// 出力
// 新しい匿名関数: lambda_1
// ln(2) + ln(2.718281828459) = 1.6931471805599
?>

{}構文

PHPは変数とテキストを分けるための{$var_name}構文があります。通常は

<?php
$var_name = '変数';
echo "これは日本語のテキストに{$var_name}を埋め込んでいます";
?>

日本語のように単語の区切りが無いテキストに変数を埋め込むためには必須の構文です。この構文を利用すると変わったコード実行が可能になります。

<?php
$var = "I was innocent until ${`ls`} appeared here";
?>

このコードを実行すると`ls`をPHPスクリプト中で実行したようにlsコマンドを実行します。PHPがこのような動作するのは${}の中に入っている文字列をPHPのコードとして評価しているからです。${`ls`}はlsを実行した結果を変数名として利用しようとします。

これを利用すると,次のようなphpinfo関数を実行するコードが書けます。

<?php
$foobar = 'phpinfo';
${'foobar'}();
?>

この脆弱性だけではセキュリティ上の脅威となりませんが,フィルタを潜り抜けるpreg_replace関数の攻撃やコードと文字列が混ざっている場所での攻撃利用されます。多くの正規表現に対する攻撃はこのテクニックを利用しています。

著者プロフィール

大垣靖男(おおがきやすお)

University of Denver卒。同校にてコンピュータサイエンスとビジネスを学ぶ。株式会社シーエーシーを経て,エレクトロニック・サービス・イニシアチブ有限会社を設立。
オープンソース製品は比較的古くから利用し,Linuxは0.9xのころから利用している。オープンソースシステム開発への参加はエレクトロニック・サービス・イニシアチブ設立後から。PHPプロジェクトでは,PostgreSQLモジュールのメンテナンスを担当している。

URLhttp://blog.ohgaki.net/

著書

コメント

コメントの記入