補足
この記事は旧徳丸浩の日記からの転載です(元URL、アーカイブ、はてなブックマーク1、はてなブックマーク2)。備忘のため転載いたしますが、この記事は2011年1月4日に公開されたもので、当時の徳丸の考えを示すものを、基本的に内容を変更せずにそのまま転載するものです。
補足終わり
先日の日記PHPのescapeshellcmdの危険性ではPHPのescapeshellcmd関数の危険性について指摘しましたが、脆弱となる実例を挙げていなかったので、「本当に危険なのか」と半信半疑の方もおられると思います。そこで、同関数が危険となる実例を考えたので報告します。
grepを使って、サーバー内を検索するスクリプトを考えます。
このスクリプトは、外部からのキーワードを/var/data/内のファイル群から検索して表示するものです。PHPのshell_execute関数を用いて、実行結果を文字列として返し、htmlspecialcharsでHTMLエスケープしています。検索キーはescapeshellcmdでエスケープした結果をダブルクォートで囲っています。<?php header('Content-Type: text/html; charset=UTF-8'); ?> <html> <body><pre> <?php $key = @$_GET['key']; $out = shell_exec('grep --no-filename "' . escapeshellcmd($key) . '" /var/data/*'); echo htmlspecialchars($out, ENT_COMPAT, 'UTF-8'); ?> </pre></body> </html>
一見、なんの問題もないスクリプトに見えます。まずは正常系の結果です。key=bookで実行してみます。
bookを含む行が表示されました。book:村上春樹 book:芥川龍之介 book:シェークスピア
次に攻撃です。key=:"+"/etc/passwd として実行してみます。以下の結果となります。
/etc/passwdの内容が表示されました。エスケープしているのに、なぜこの結果になるのでしょうか。root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin …略
それは、escapeshellcmdが「' および " は、対になっていない場合にのみエスケープされます。」という仕様のためです。このため、grepの起動文字列は次のようになっています。
/etc/passwdの各行にはコロンが含まれていますから、これで/etc/passwdの全行が表示されます。適当な文字がなければ「$」(行末にマッチ)などを指定してもいいですね。 あるいは、PHPのソースを表示することもできます。key=$"+"/var/www/html/grep.php と指定すると、以下の表示になります。grep --no-filename ":" "/etc/passwd" "/var/data/*"
この検索プログラム自体のソースが表示されました。スクリプトのソースが見えれば、他の脆弱性を探すのも楽ちんですよね。<?php header('Content-Type: text/html; charset=UTF-8'); ?> <html> <body><pre> <?php $key = @$_GET['key'];
escapeshellcmdの「' および " は、対になっていない場合にのみエスケープされます。」という仕様により、1つのパラメータが2つのパラメータに分かれてしまうことが問題です。これはescapeshellcmdの脆弱性というよりは、仕様の不備と言うしかないでしょうね。マニュアルに書いてある通りの動作が問題な訳ですから。というわけで、escapeshellcmdよりはescapeshellargを使えということと、そもそもOSコマンドを呼ばないなどのもっと良い方法を検討しましょう、というお話です。
0 件のコメント:
コメントを投稿