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

ENV02-C. 同じ名前の複数の環境変数に注意する

ENV02-C. 同じ名前の複数の環境変数に注意する

getenv() 関数は、環境の並びの中から指定された名前と一致するものを探し、一致する並びの要素に結び付けられた文字列へのポインタを返す。

C 標準 [ISO/IEC 9899:2011] セクション 7.22.4.6 には次のように記載されている。

環境の並びに定義されている名前の集合及び環境の並びを変更する方法は、処理系定義とする。

処理系によっては、複数の環境変数に同じ名前を付けることが可能であり、プログラムが一貫して同じ環境変数を選択できない場合は予期せぬ結果を招くことがある。GNU glibc ライブラリの getenv()setenv() は、最初に見つかった変数を使用し、それ以外は無視することによって、この問題に対処している。しかし、プログラマはこの動作に依存するべきでない。

環境変数が大文字小文字を区別するかどうかは、処理系ごとに異なることが多い。UNIX 系のOSでは通常大文字小文字を区別するが、Windows 98/Me および Windows NT/2000/XP では環境変数は「大文字小文字を区別しない」 [MSDN]。

重複した環境変数の検出 (POSIX)

次のコードは、POSIX の environ 配列を使用して、重複したキーエントリを手動で検索する関数を定義している。重複した環境変数はすべて攻撃と見なされており、重複が検出されるとプログラムは即座に終了する。

extern char **environ;

int main(void) {
  if (multiple_vars_with_same_name()) {
    printf("Someone may be tampering.\n");
    return 1;
  }

  /* ... */

  return 0;
}

int multiple_vars_with_same_name(void) {
  size_t i;
  size_t j;
  size_t k;
  size_t l;
  size_t len_i;
  size_t len_j;

  for(size_t i = 0; environ[i] != NULL; i++) {
    for(size_t j = i; environ[j] != NULL; j++) {
      if (i != j) {
        k = 0;
        l = 0;

        len_i = strlen(environ[i]);
        len_j = strlen(environ[j]);

        while (k < len_i && l < len_j) {
          if (environ[i][k] != environ[j][l])
            break;

          if (environ[i][k] == '=')
            return 1;

          k++;
          l++;
        }
      }
    }
  }
  return 0;
}
違反コード

以下のコード例は、Linux と Microsoft Windows プラットフォームでは異なる動作をする。

if (putenv("TEST_ENV=foo") != 0) {
  /* エラー処理 */
}
if (putenv("Test_ENV=bar") != 0) {
  /* エラー処理 */
}

const char *temp = getenv("TEST_ENV");

if (temp == NULL) {
  /* エラー処理 */
}

printf("%s\n", temp);

IA-32 Linux マシン上の GCC 3.4.4 でコンパイル・実行すると、このコードの出力は次のようになる。

foo

一方、IA-32 Windows XP マシン上の Microsoft Visual C++ 2008 Express Edition でコンパイル・実行すると、このコードの出力は次のようになる。

bar
適合コード

可搬性のあるコードでは、大文字小文字以外でも異なる環境変数を使用するべきである。

if (putenv("TEST_ENV=foo") != 0) {
  /* エラー処理 */
}
if (putenv("OTHER_ENV=bar") != 0) {
  /* エラー処理 */
}

const char *temp = getenv("TEST_ENV");

if (temp == NULL) {
  /* エラー処理 */
}

printf("%s\n", temp);
リスク評価

攻撃者は、POSIX の execve() 関数を使用するなどして、複数の環境変数を作成できる。プログラムが環境変数を検査しても、その後に参照される変数が別のものであると、セキュリティ検査をすりぬけてしまう可能性がある。

レコメンデーション

深刻度

可能性

修正コスト

優先度

レベル

ENV02-C

P2

L3

自動検出(最新の情報はこちら

ツール

バージョン

チェッカー

説明

Compass/ROSE

 

 

 

関連するガイドライン
CERT C++ Secure Coding Standard ENV02-CPP. Beware of multiple environment variables with the same effective name
ISO/IEC TR 24772:2013 Executing or Loading Untrusted Code [XYS]
MITRE CWE CWE-462, Duplicate key in associative list (Alist)
CWE-807, Reliance on untrusted inputs in a security decision
参考資料
[ISO/IEC 9899:2011] Section 7.22.4, "Communication with the Environment"
[MSDN] getenv()
翻訳元

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

ENV02-C. Beware of multiple environment variables with the same effective name (revision 72)

Top へ

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