連載
» 2004年11月12日 00時00分 公開

Webアプリケーションに潜むセキュリティホール(13):OSコマンドインジェクションを防ぐルールを作成する (2/3)

[中村隆之,三井物産セキュアディレクション]

WebアプリケーションがOSコマンドを実行する方法

 次に、Webアプリケーション内でOSコマンドがどのように呼び出されるのかについて簡単に説明しておこう。開発言語によって呼び出し方法は多少異なるが、筆者の知る限りでは、OSコマンドの呼び出し方法は以下の3通りである。

(1) 直接指定(シェルスクリプト)

(2) open()関数の使用(Perl)

(3) 引数をシェルに渡す関数の使用(ほとんどの言語)

 まず(1)であるが、これは、シェルスクリプト自体がOSコマンドの集合体なので、呼び出し方法も何もない。特に説明は必要ないだろう。

 次の(2)は、PerlでOSコマンドを利用するときの方法の1つである。open()関数は通常はその名前のとおり、ファイルを読み書きするときにファイルをオープンする関数である。しかし、ファイルとしてOSコマンドを指定すると、それを実行することもできる。

 最後の(3)は、指定した文字列をそのままシェルに渡し、その結果を受け取る、といった動作をする。ほとんどすべての言語に備わっており、使い方もすべて同じと考えてよい。(2)で説明したPerlの場合でも、system()という関数があり、これが(3)に該当する。

 以上が、WebアプリケーションがOSコマンドを実行するための方法である。クロスサイトスクリプティング対策用の設定と同様に、これらのOSコマンド呼び出し方法を利用しているときに攻撃が成功するパターンを明らかにして、それをルールに設定する、という流れで進めていく。

 なお、(1)のシェルスクリプトについては、今回は対象外とさせていただく。多数のユーザーにアクセスさせるようなアプリケーションをシェルスクリプトで開発することなどないだろうから、特に問題ないだろう。

Perlのopen()関数での攻撃パターン

1. ファイルを読み込み用に開く場合

open(IN, "$filename"); 

 このような記述では、本来$filenameを開くだけの動作なのだが、「||/bin/date|」のような文字列を$filenameとして与えると、dateコマンドを実行することができる。

 このパターン以外にもいくつか方法があるのだが、Perlのopen()関数でOSコマンドを実行するために最低限必要なことは、文字列の最後に「|」(パイプ)がなければならない、ということである。つまり、文字列の最後尾に「|」がある場合は、不正な入力である可能性がある。ただ、これだけでは確実に危険とはいえないので、

OSコマンド+コマンドオプション+「|」

という形式のときにマッチさせることにしよう。

 この結果、指定すべきルールはリスト1のようになる。

1: SecFilter "!\|$" skipnext:7
2: SecFilter "/bin/.*\|$"
3: SecFilter "/home/.*\|$"
4: SecFilter "/opt/.*\|$"
5: SecFilter "/usr/.*\|$"
6: SecFilter "/etc/.*\|$"
7: SecFilter "/sbin/.*\|$"
8: SecFilter "/var/.*\|$" 
リスト1

 1行目は、入力文字列の最後に「|」がない場合は、2〜8行目のルールは意味がなくなるため、スキップさせる指定になっている。ちなみに、open()関数の呼び出しが、

open(IN, "<$filename"); 

のようになっていると、OSコマンドは実行できないので安全である。

2. ファイルを書き出し用に開く場合

 ファイルに書き出す処理を行うアプリケーションでは、

open(OUT, "|/bin/date"); 

のような状態にすることができれば、OSコマンドを実行することができる。ポイントは、OSコマンドの先頭にある「|」である。ただ、書き出し用にファイルを開く場合、

open(OUT, ">$filename"); 

のように、リダイレクト記号「>」を使わなければならない。この状態では OSコマンドを実行することはできないので、設定するルールは特にない。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。