メソッド/関数呼び出しによるコード実行問題とその対策

(更新日: 2015/07/15)

言語の機能としてシリアライズされた”データ”からオブジェクトを生成(PHPの場合、unserialize関数)したり、呼び出すメソッド/関数を指定できる機能(PHPの場合、call_user_func*関数/call_method*関数など)を使ったりすると意図しないメソッド/関数が呼ばれるケースを想定しなければなりません。

 

unserialize関数の問題点

unserialize関数は”シリアライズされたデータ”をアンシリアライズ処理する際に、オブジェクトが規程の状態に初期化されるよう特殊メソッドの__wakeupを自動的に呼び出します。

http://php.net/manual/ja/function.unserialize.php

多くのオブジェクトはそもそも__wakeupメソッドを定義していなかったり、定義していても害を与えないことが多いです。

しかし、”シリアライズされたデータ”がユーザー入力である場合、ロード済み(定義済み)のクラスならどのクラスの__wakeupメソッドも呼び出せます。__autoloadが有効な場合、__autoloadのためのコード、自動的に読み込めるクラスのどの__wakeupメソッドも呼び出せます。

任意コードが実行できる訳ではありませんが、__autoload、__wakeupメソッドの実装によっては好ましくない動作になる場合があります。

例えば、サーバー内で保存しているユーザーのデータを初期化するようなコード

があった場合、攻撃者が$_GETなどに攻撃用のシリアライズされたデータを埋め込んでfoo::__wakeup()を読み込ませてサービス妨害をする、といった攻撃の可能性があります。

攻撃の影響は__wakeupメソッドの中身次第です。

unserialize問題の対策

unserializeマニュアルに記載されているように、ユーザーへ渡すデータはメソッド呼び出しが発生しないjson_encode/decodeを利用します。

警告

ユーザーからの入力をそのまま unserialize() に渡してはいけません。 アンシリアライズの時には、オブジェクトのインスタンス生成やオートローディングなどで コードが実行されることがあり、悪意のあるユーザーがこれを悪用するかもしれないからです。 シリアル化したデータをユーザーに渡す必要がある場合は、安全で標準的なデータ交換フォーマットである JSON などを使うようにしましょう。json_decode() および json_encode() を利用します。

※ うかつにHTMLコンテクストにJSONを入れると問題の原因です。詳しくはJSONのエスケープをどうぞ。

call_user_func*関数/call_method*関数の問題

これらの関数は任意の関数やメソッドが呼び出せます。あまり使用したことがない方の為に、PHPマニュアルのcall_user_func_array()ページのサンプルコードを掲載します。

関数やオブジェクトのメソッドが呼び出せることが分かります。パラメータがユーザー入力の場合、ユーザーが任意の関数/メソッドを呼び出せることになります。

例えば、以下のようなコードとパラメータは危険性が高いことが分かります。

 

 

 

call_user_func*関数/call_method*関数問題の対策

call_user_method*関数はPHP 4.1.0以降、非推奨なので使用しないようにしましょう。

call_user_func*関数で任意のメソッド/関数を呼び出されると意図しない動作が可能になります。これらの関数にユーザー入力を利用する場合、許可されたメソッド/関数のみ利用できるようにする(ホワイトリスト)と安全性が担保できます。

オブジェクトを指定できるcall_user_func_array関数のオブジェクト変数パラメーターがユーザー入力によって操作できる場合もあります。この場合、メソッドのみが呼び出せるよりも自由度が高く、有効な攻撃が行えるリスクが高くなります。オブジェクト変数のクラスをバリデーションして許可したクラスのオブジェクト変数のみ実行(ホワイトリスト)するようにします。

プラグインなどの場合、以下のようなコードを書いて不正なオブジェクト、不正なメソッドが呼び出されないようにします。

 

まとめ

リスクは通常のインジェクション攻撃ほど高い訳ではありませんが、開発者が意図しないコード(命令、データ)が部外者によって実行されること自体が問題です。

一般に攻撃できるリスクが高くないとはいえ、ここで紹介した問題を利用して攻撃可能になるコードは十分ありえます。そもそも意図しないコードは一切実行できないようにコーディングしておきましょう。

メソッド/関数の不正呼び出しは通常のインジェクション攻撃とは多少異るように見えますが、

  • オブジェクトパラメーター : 識別子
  • メソッド/関数名パラメーター : 命令
  • 引数パラメーター: データ

と考えることができます。

参考

 

Comments

comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です