ENV03-C. 外部プログラムを呼び出す際は環境を無害化する
プログラムやライブラリの多くは、環境変数の設定に依存する。これには UNIX と Windows の共有ライブラリローダも含まれる。環境変数はプログラムの実行時に親プロセスから継承されるため、攻撃者は簡単に環境変数を改ざんすることができ、結果としてプログラムの予期せぬ、安全でない動作を引き起こす可能性がある [Viega 2003]。
すべてのプログラム、特に呼び出し側よりも高い権限で実行されているプログラム(setuid/setgid フラグ付きのものなど)は、その環境を、信頼できないユーザからの入力と見なすべきである。環境は、fork()、system()、または exec() の呼び出しによって生成されたプロセスに引き継がれるため、予期せぬ動作を引き起こす値が環境に含まれていないか確認することが重要である。
この種のプログラムでは、次の対策をとることが推奨される。
- 不要になったら権限を引き下げる(「POS02-C. 最小権限の原則に従う」を参照)。
system()の呼び出しを避ける(ENV04-C. 「コマンドプロセッサが必要ない場合は system() を呼び出さない」を参照)。- 環境を無害化して、信頼できる値やデフォルト値を設定する。
このルールは「STR02-C. 複雑なサブシステムに渡すデータは無害化する」の具体例である。
C 標準のセクション 7.22.4.6 には、「環境の並びに定義されている名前の集合及び環境の並びを変更する方法は、処理系定義とする。」と記載されている。したがって、環境変数のクリア、変更、デフォルト値の検索にどのような関数が利用できるかを理解することが重要である。プログラムによっては特定の環境変数が設定されていないと予期せぬ動作を引き起こす場合があるため、使用するシステムで必要な変数や、その安全な値について理解しておくことが重要である。
違反コード(POSIX、ls)
以下のコード例は、C の system() 関数を呼び出して /bin/ls プログラムを実行している。system() 関数は、ホスト環境内のコマンドプロセッサへ文字列を渡し、実行させる。
if (system("/bin/ls dir.`date +%Y%m%d`") == -1) {
/* エラー処理 * /
}
IFS はこの文字列のコマンド部分である /bin/ls には影響を及ぼさないが、引数の組み立て方を date の呼び出し後に決定する。デフォルトシェルが IFS 環境変数の値を無視せず、攻撃者が IFS を "." に設定した場合、意図したディレクトリは検出されない。
適合コード (POSIX、ls)
非標準関数 clearenv() を使用すると環境を無害化できる。あるいは、environ から環境変数名を取得して、unsetenv() を使用して 1 つずつ削除することもできる。
この適合コードでは、clearenv() によって環境がクリアされ、system() を呼び出す前に PATH 変数と IFS 変数が安全な値に設定される。シェルコマンドを無害化するのは難しく、無害化によってシェルコマンドの機能や柔軟性を損ねてしまう可能性がある。
char *pathbuf;
size_t n;
if (clearenv() != 0) {
/* エラー処理 */
}
n = confstr(_CS_PATH, NULL, 0);
if (n == 0) {
/* エラー処理 */
}
if ((pathbuf = malloc(n)) == NULL) {
/* エラー処理 */
}
if (confstr(_CS_PATH, pathbuf, n) == 0) {
/* エラー処理 */
}
if (setenv("PATH", pathbuf, 1) == -1) {
/* エラー処理 */
}
if (setenv("IFS", " \t\n", 1) == -1) {
/* エラー処理 */
}
if (system("ls dir.`date +%Y%m%d`") == -1) {
/* エラー処理 */
}
POSIX は、環境変数のデフォルト値を検索できる confstr() 関数も規定している [Open Group 2004]。POSIX.1-2008 に適合する環境では、confstr() に対する新しい _CS_V7_ENV 引数を定義している [Austin Group 2008]。これにより、環境変数の並びを取得することができる。空白文字で区切られた variable=value の並びが返され、変数名には等号(=)が含まれないこと、そして variable=value には空白文字が含まれないことが保証される。_CS_PATH リクエストと併用することで、必要最小限の環境変数だけが設定された、無害化された環境を得ることができる。POSIX.1-2008 規格に適合しているシステムでは、これを使用して無害化した環境を作成するべきである。
clearenv() 関数を利用できないシステムでは、次のように実装できる。
extern char **environ;
int clearenv(void) {
static char *namebuf = NULL;
static size_t lastlen = 0;
while (environ != NULL && environ[0] != NULL) {
size_t len = strcspn(environ[0], "=");
if (len == 0) {
/* 空の変数名を処理 (environ[] が壊れている ) */
}
if (len > lastlen) {
namebuf = realloc(namebuf, len+1);
if (namebuf == NULL) {
/* エラー処理 */
}
lastlen = len;
}
memcpy(namebuf, environ[0], len);
namebuf[len] = '\0';
if (unsetenv(namebuf) == -1) {
/* エラー処理 */
}
}
return 0;
}
適合コード (Windows)
Windows 上では、環境を無害化する可搬性のある方法も、確実に無害化が保証される方法もない。「ENV04-C. コマンドプロセッサを必要としない場合は system() を呼び出さない」に従って system() ではなく _execle()、_execlpe()、_execve()、_execvpe() を使用する場合は、これらの関数は環境を明示的に指定できるため注意が必要である。
どの環境変数を保持する必要があるかが明確にわかっている場合、「Secure Programming Cookbook for C and C++」 [Viega 2003] に他のすべてを削除するための関数 spc_sanitize_environment() を定義する。
リスク評価
攻撃者によって制御されている環境で外部プログラムを呼び出すことは、本質的に危険である。
|
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
|---|---|---|---|---|---|
|
ENV03-C |
高 |
高 |
高 |
P9 |
L2 |
自動検出(最新の情報はこちら)
|
ツール |
バージョン |
チェッカー |
説明 |
|---|---|---|---|
| PRQA QA-C | 8.1 | Warncall -wc system | 部分的に実装済み |
関連するガイドライン
| CERT C++ Secure Coding Standard | ENV03-CPP. Sanitize the environment when invoking external programs |
| CERT Oracle Secure Coding Standard for Java | IDS07-J. Do not pass untrusted, unsanitized data to the Runtime.exec() method |
| ISO/IEC TR 24772:2013 | Executing or Loading Untrusted Code [XYS] |
| MITRE CWE | CWE-78, Failure to sanitize data into an OS command (aka "OS command injection") CWE-88, Argument injection or modification CWE-426, Untrusted search path CWE-807, Reliance on intrusted inputs in a security decision |
参考資料
| [Austin Group 2008] | Vol. 2, System Interfaces, confstr() |
| [CA-1995-14] | "Telnetd Environment Vulnerability" |
| [Dowd 2006] | Chapter 10, "UNIX II: Processes" |
| [ISO/IEC 9899:2011] | Section 7.22.4, "Communication with the Environment" |
| [Open Group 2004] | Chapter 8, "Environment Variables"confstr() |
| [Viega 2003] | Section 1.1, "Sanitizing the Environment" |
| [Wheeler 2003] | Section 5.2, "Environment Variables" |
翻訳元
これは以下のページを翻訳したものです。
ENV03-C. Sanitize the environment when invoking external programs (revision 112)
