OSコマンドインジェクション

Perlスクリプトは比較的簡単に書く事ができ、かつてはCGIイコールPerlと勘違いする人が大勢いるくらい、ネットはPerlだらけでした。そのため、脆弱性について知識のないユーザーが大量にCGIを作成・設置し、そこら中のサーバーに穴が空いていた時代がありました。最近はPerlが昔ほど使われなくなった事、スクリプトを配布する人に脆弱性の知識がある程度浸透した事で昔のような酷い状態ではなくなりました。しかし、ぼくの見たところ未だにOSコマンドインジェクションを抱えたサイトが多数あります。その殆どが学術機関で学生や職員が自作したCGI、中小企業のスタッフが自作したCGIです。特に企業の場合はちょっとしたスクリプトでも致命的な損害を被る事があるので、十分に注意する必要があります。

スポンサーリンク

脆弱性のあるスクリプト

よく見かける悪いスクリプトに次のようなものがあります。

このスクリプトはOSコマンドインジェクションだけでなく、ディレクトリトラバーサル等の脆弱性もありますが、今回はOSコマンドインジェクションの脆弱性に注目します。

Perlはパイプを付けるとOSコマンドを実行する

Perlの仕様で、ファイル名の前もしくは後ろに|(パイプ)を付けるとOSコマンドを実行します。たとえば次のようにします。

http://example.jp/vul.cgi?file=|id

このようにすると、idコマンドが実行されて、ブラウザには次のような表示がされます。

uid=33(www-data) gid=33(www-data) groups=33(www-data)

攻撃者はこれでwww-data権限でコマンドを実行できる事ができるようになります。FWで適切に保護されていなければ、攻撃者は対話的なシェルアクセスを手に入れる事ができるようになるので、場合によってはルート権限の奪取にまで繋がります。

ダメな対策1:先頭にディレクトリ名を付ける

先頭にディレクトリ名を付加すると一見攻撃が成功しないように見えます。例えばファイル名の先頭にカレントディレクトリ(./)を付加してみます。

24行目でファイル名の先頭に”./”を付加しています。確かに、この方法を使うと次のようにしても攻撃は失敗します。

  • http://example.jp/vul.cgi?file=|id
  • http://example.jp/vul.cgi?file=id|

対策回避方法1:ディレクトリを辿る

UnixやWindowsでコマンドラインを使った事がある方なら判ると思いますが、先頭に相対パスや絶対パスがあったとしても、”../”を付加する事でディレクトリを辿る事ができます。

たとえば、次のようにするとどうでしょうか。

http://example.jp/vul.cgi?file=../../../usr/bin/id|

残念ながら、この方法によって攻撃者はOSコマンドを実行する事ができます。

対策回避方法2:セミコロンを挿入する

UnixやLinuxでコマンドラインを使った事がある方なら判ると思いますが、セミコロン(;)を使うとコマンドを順次実行させる事ができます。たとえば次のようにすると攻撃が成功します。

http://example.jp/vul.cgi?file=%3bid|

%3bはセミコロンの16進数表記です。イメージとしては、”./”を実行した後”id”を実行した事と同じになります。

対策回避方法3:改行コードを挿入する

UnixやLinuxのデフォルト改行コードはLF(ラインフィールド)です。これを16進数表記にすると%0aとなります。改行コードを挿入する、というとイメージが難しいかもしれませんが、次のようにしてもコマンドを実行する事ができます。

http://example.jp/vul.cgi?file=%0aid|

イメージとしては、”./”を実行した後、”id”を実行した事と同じになります。

ダメな対策2:拡張子を付ける

次に、拡張子を追加して特定のファイルタイプのみ開く事を許可する、というスクリプトも時々見かけます。

24行目で拡張子(.txt)を付加しています。この方法はディレクトリを辿っても末尾に”.txt”が付加されてしまうので、OSコマンドが実行できないように見えます。

対策回避方法1:NULL文字を挿入する

C言語など低レベルな処理を行う言語の知識がある方には常識だとは思いますが、文字列はNULL文字で終端します。%00は文字列終端を意味するNULL文字のため、次のようにすると攻撃は成功します。

http://example.jp/vul.cgi?file=|id%00

先述した通り、%00は文字列終端を意味するNULL文字のため、%00以降がスクリプト内で無視されます。そのため”.txt”が無視されて”|id%00.txt”はスクリプト内で”|id”と解釈されてしまいます。

対策回避方法2:セミコロンを挿入する

先頭にディレクトリ名を付加した場合と同じく、拡張子を付加した場合もセミコロンを挿入する事で攻撃が成功します。たとえば、次のようにします。

http://example.jp/vul.cgi?file=|id%3b

対策回避方法3:改行コードを挿入する

先頭にディレクトリ名を付加した場合と同じく、拡張子を付加した場合も改行コードを挿入する事で攻撃が成功します。たとえば、次のようにします。

http://example.jp/vul.cgi?file=|id%0a

対策

これらの対策は、WEBアプリケーションでは基本中の基本である、ユーザーが入力するパラメータのサニタイズを行うことです。また、open()を使わなければならない理由などないので、代わりにsysopen()を使うようにします。

スポンサーリンク