ここまではPerlに依存した説明であったが、ここからは、ほぼすべての言語で共通の説明となる。例で示す関数は、Perlのsystem()関数を使うことにする。
コマンドラインでOSを操作したことがある方ならお分かりだろうが、コマンドラインの1行には複数のOSコマンドを渡すことができる。本連載の第2回で説明しているOSコマンドインジェクションは、このパターンである。
OSのシェルに文字列を渡す仕組みでは、OSコマンドだけでなく、シェル上の特殊文字もそのまま機能する。このパターンのOSコマンドインジェクションは、シェルの特殊文字をうまく機能させることによってOSコマンドを実行させる。
シェルの特殊文字については、第2回で説明しているので、ここでは、これらの特殊文字をどのようにして使うかについて説明しよう。
複数のOSコマンドを呼び出す方法としては、以下のようなパターンがある。これは、セキュリティというよりは、シェルの基本である。
command1 ; command2 command1 | command2 command1 || command2 command1 && command2 command1 & command2
これらの攻撃にマッチさせるには、以下の3つの記号に注目するとよい。
「;」、「|」、「&」
「||」と「&&」については、それぞれ1文字のパターンで代用できる。また、上記の記号以外として、サーバのルート上にあるディレクトリを指定する。攻撃者は、OSコマンドを絶対パスで指定してくるためである。
では、この攻撃パターンに対するルールを作成してみる。あまり洗練されていないが、リスト2のようなルールができた。
1: SecFilter ";" skipnext:2 2: SecFilter "&" skipnext:1 3: SecFilter "!|" skipnext:7 4: SecFilter "(;|&|\|)[[:space:]]*/bin/.+" 5: SecFilter "(;|&|\|)[[:space:]]*/home/.+" 6: SecFilter "(;|&|\|)[[:space:]]*/opt/.+" 7: SecFilter "(;|&|\|)[[:space:]]*/usr/+" 8: SecFilter "(;|&|\|)[[:space:]]*/etc/+" 9: SecFilter "(;|&|\|)[[:space:]]*/sbin/+" 10: SecFilter "(;|&|\|)[[:space:]]*/var/+"
仕組みを簡単に説明しておこう。
本来はmod_securityが動作しているOSにインストールされているOSコマンドをすべて調べなければならないのだが、今回は1つの例としてfindコマンドについて説明する。findコマンドは、OS上のファイルやディレクトリを検索するためのコマンドであるが、-exec引数を渡すことによって、別のOSコマンドを実行させることができる。
単純な例として、URLパラメータとして渡したファイルを見つけるCGIを使用する。ソースは以下に示すようになっている。
#!/usr/bin/perl use CGI; $form = new CGI; $file = $form->param('file'); print "Content-Type: text/plain", "\r\n\r\n"; system("/usr/bin/find /etc -name \"*${file}*\"");
このCGIに対して、以下のように「;」(%3b)でOSコマンドをつなげようとすると、先ほどのルールにマッチしてしまい失敗する。
http://server/cgi-bin/test.cgi?file=a"%3b/bin/ls%20%23
上記のようなCGIでは、
http://server/cgi-bin/test3.cgi?file=a"%20-exec%20/bin/date%20\%5c%3b%23
というように、「-exec /bin/date \;#」のような-execオプションを使ってやると、OSコマンドが実行できる。この攻撃パターンを防御するには、先ほどのルールを以下のように変更する。
1: SecFilter ";" skipnext:3 2: SecFilter "&" skipnext:2 3: SecFilter "!|" skipnext:1 4: SecFilter "!-exec" skipnext:7 5: SecFilter "(;|&|\||-exec )[[:space:]]*/bin/.+" 6: SecFilter "(;|&|\||-exec )[[:space:]]*/home/.+" 7: SecFilter "(;|&|\||-exec )[[:space:]]*/opt/.+" 8: SecFilter "(;|&|\||-exec )[[:space:]]*/usr/+" 9: SecFilter "(;|&|\||-exec )[[:space:]]*/etc/+" 10: SecFilter "(;|&|\||-exec )[[:space:]]*/sbin/+" 11: SecFilter "(;|&|\||-exec )[[:space:]]*/var/+"
リスト1とリスト3をつなげると、OSコマンドインジェクション用のルールになる。前回と同じように、リスト1、リスト3の内容を別ファイルに記述し、Includeディレクティブで読み込ませるようにするとよい。
今回は、OSコマンドインジェクションの攻撃パターンを基に、それを防ぐためのmod_securityのルールを作成した。本文中でも説明しているように、コマンド引数を書き換えることにより、任意のOSコマンドが実行できるコマンドがほかにもある可能性がある。その場合は、その攻撃が成功しないように、別途ルールを追加する必要がある。
中村隆之(なかむらたかゆき)
三井物産セキュアディレクション勤務。 セキュリティコンサルタントとして主にWebアプリケーションのセキュリティ検査に従事しており、大手ポータルサイト、オンラインバンキングなどの数多くの 検査実績を持つ。また、セキュアネットワーク及び暗号関連の研究に携わり、大手製造、官公庁、金融機関へのセキュリティシステム導入など数多くの実績を持つ。
主に、不正アクセス監視サービス、セキュリティ検査、セキュリティポリシー策定支援などのサービス提供している。また、セキュリティに関する教育サービスも実施中。
Copyright © ITmedia, Inc. All Rights Reserved.