XMLやJSONなどの構造を持つデータを保存や送受信できるように変換することをシリアライズと呼ぶ。
シリアライズは配列データを配列データとして保存できたりなど、配列の要素や構造が動的に変化するデータを扱う際などに使用される。
ここではシリアライズに関する脆弱性の一つであるevalインジェクションについて記載する。
#概要
プログラム言語にはevalと呼ばれる関数・機能があり、これは文字列(各言語のコード)を式として評価したのものである。
evalは使い方によって外部から送り込んだスクリプトが実行されることがある。
それをevalインジェクション攻撃と言い、そのような攻撃を受ける脆弱性をevalインジェクション脆弱性と呼ぶ。
###evalの例
JavaScript(MDN)
eval(string)
PHP(php.net)
eval ( string $code ) : mixed
evalインジェクションによる影響は以下のOSコマンド・インジェクション攻撃と同じ。
- 情報漏洩
- サイト改ざん
- 不正な機能実行
- 他サイトへの攻撃(踏み台)
- 暗号通貨の採掘(マイニング)
evalインジェクション脆弱性の対策は以下の通り
- evalに相当する機能を使わない
- evalの引数には外部からのパラメータを含めない
- evalに与える外部からのパラメータを英数字に限定する
#攻撃手法と影響
シリアライズしてフォーム間を受け渡す場合の脆弱性について。
例としてPHPのvar_export関数を使ってシリアライズした後にbase64にエンコードしデータを受け渡す。受け渡されたデータのbase64をデコードし、evalを用いて元のデータに戻す(デシリアライズする)とする。
参考イメージ
<?php
$a = array(1, 2, 3);
$ex = var_export($a, true);
$b64 = base64_encode($ex);
?>
<body>
<form action="4e-002.php" method="GET">
<input type="hidden" name="data" value="<?php echo htmlspecialchars($b64) ?>">
<input type="submit" value="次へ">
</form>
</body>
<?php
$data = $_GET['data'];
$str = base64_decode($data);
eval('$a = ' . $str . ';');
?>
<body>
<?php var_dump($a); ?>
</body>
##攻撃手法
evalに渡す式に任意の文を追加(スクリプトを注入)する。
$a = 式: 任意の文;
$a = 0: phpinfo();
OWASP ZAPで上記を試すとphpinfoが表示され、外部から注入したスクリプトが実行された状態となる。
これらの事例から情報漏洩やサイト改ざんなどの影響を受ける可能性がある。
#脆弱性が生まれる原因
evalに与えるパラメータをチェックしていないため。
PHPであれば任意のコードを実行できてしまうようにevalはそもそも危険な言語構造であること。
evalインジェクション脆弱性の原因は以下の通り。
- evalを用いることがそもそも危険
- evalに与えるパラメータのチェックがされていない
#対策
evalインジェクション脆弱性の対策は以下の通り。
- eval(同等機能含む)を使わない
- evalの引数に外部からのパラメータを指定しない
- evalの与える外部からのパラメータを英数字に制限する
##evalを使わない
eval(同等機能含む)を使わず、eval以外の選択肢を検討する。
シリアライズが目的であれば以下の選択肢がある。
シリアライズ以外の目的でもevalは極力使わない実装を検討する。
evalを使わずに同等の処理は実装可能。
##evalの引数に外部からのパラメータを指定しな
evalを使った場合でも外部からパラメータを指定しない。
外部からスクリプトを注入できなくすれば安全だが、注入経路がファイルやデータベースの場合この対策は使えない。
##evalに与える外部からのパラメータを英数字に制限する
外部から与えるパラメータを英数字に限定できればスクリプト注入に必要な記号文字を使えなくすることができる。
正規表現による入力値検証などを行う。
#まとめ
evalを使わない実装を行う。
どうしてもevalを使わなければならない場合は外部からのスクリプト注入を防ぐ対策を行う。
#さらに進んだ学習のために
phpMyAdminに存在したpreg_replaceによるコード実行脆弱性の実例