Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: new rule

Campione 1996 suggests:

To maximize portability, never refer to an environment variable when the same value is available in a system property. For example, if the operating system provides a user name, it will always be available in the system property user.name.

In fact, relying on environment variables is more than a simple portability issue. An attacker can essentially control all environment variables that enter a program, using a mechanism such as the java.lang.ProcessBuilder class.

Noncompliant Code Example

This noncompliant code example tries to get the user name, using an environment variable.

Code Block
bgColor#ffcccc

String username = System.getenv("USER");

This certainly is a portability issue. Campione 1996 further suggests:

The way environment variables are used also varies. For example, Windows provides the user name in an environment variable called USERNAME, while UNIX implementations might provide the user name in USER, LOGNAME, or both.

Furthermore, an attacker can execute this program with the USER environment variable set to any value he chooses. The following code example does just that:

Code Block
bgColor#ffcccc

public static void main(String args[]

The getenv() function searches an environment list for a string that matches a specified name and returns a pointer to a string associated with the matched list member.

Wiki Markup
Section 7.20.4.5 of C99 states that \[[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\]

The set of environment names and the method for altering the environment list are implementation-defined.

Depending on the implementation, multiple environment variables with the same name may be allowed and can cause unexpected results if a program cannot consistently choose the same value. The GNU glibc library addresses this issue in getenv() and setenv() by always using the first variable it encounters and ignoring the rest. However, it is unwise to rely on this.

Wiki Markup
One common difference between implementations is whether or not environment variables are case sensitive. While UNIX-like implementations are generally case sensitive, environment variables are "not case sensitive in Windows 98/Me and Windows NT/2000/XP" \[[MSDN|AA. Bibliography#MSDN]\].

Duplicate Environment Variable Detection (POSIX)

The following code defines a function that uses the POSIX environ array to manually search for duplicate key entries. Any duplicate environment variables are considered an attack, so the program immediately terminates if a duplicate is detected.

Code Block
bgColor#ccccff

extern char **environ;

int main(void) {
  if (multiple_vars_with_same_name())args.length != 1) {
    printfSystem.err.println("Someone may be tampering.\nPlease supply a username as the argument");
    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++) String user = args[0];
  ProcessBuilder pb = new ProcessBuilder();
  pb.command("/usr/bin/printenv");
  Map<String,String> environment = pb.environment();
  environment.put("USER", user);
  pb.redirectErrorStream(true);
  try {
    for(size_t j = i; environ[j] != NULL; j++) {
      if (i != j) {
        k = 0Process process = pb.start();
    InputStream in   l = 0;

        len_i = strlen(environ[i]= process.getInputStream();
        len_j = strlen(environ[j]);
int c;
        while (k(c < len_i && l < len_j) {
          if (environ[i][k]= in.read()) != environ[j][l])
            break;

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

          k++;System.out.print((char) c);
    }
    int exitVal     l++= process.waitFor();
        }
 catch (IOException x)   }{
    }
  }
  return 0;
}

Noncompliant Code Example

The following noncompliant code behaves differently when compiled and run on Linux and Microsoft Windows platforms.

Code Block
bgColor#ffcccc

if (putenv("TEST_ENV=foo") != 0) {
  /* Handle error */
}
if (putenv("Test_ENV=bar") != 0x.printStackTrace(System.err);
  } catch (InterruptedException x) {
  /* Handle error */
}

const char *temp = getenv("TEST_ENV" x.printStackTrace(System.err);

if (temp == NULL) {
  /* Handle error */
}

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

On an IA-32 Linux machine with GCC Compiler Version 3.4.4, this code prints

Code Block

foo

whereas, on an IA-32 Windows XP machine with Microsoft Visual C++ 2008 Express, it prints

Code Block

bar

Compliant Solution

 }
}

This program runs the program /usr/bin/printenv which prints out all environment variables and their values. It takes a single argument string, and sets the USER environment variable to that string. The subsequent output of the printenv program will indicate that the USER environment variable is indeed set to the string requested.

Compliant Solution

This compliant solution obtains the user name using the user.name system property. This property always contains the correct user name, even if the USER environment variable has been set to an incorrect value, or does not existPortable code should use environment variables that differ by more than capitalization.

Code Block
bgColor#ccccff
if (putenv("TEST_ENV=foo") != 0) {
  /* Handle error */
}
if (putenv("OTHER_ENV=bar") != 0) {
  /* Handle error */
}

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

if (temp == NULL) {
  /* Handle error */
}

printf("%s\n", tempString username = System.getProperty("user.name");

Risk Assessment

An attacker can create multiple environment variables with (for example, by using the POSIX execve() function). If the program checks one copy but uses another, security checks may be circumventedA program that depends on environment variables may be fed misinformation by an attacker.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

ENV02-J

low

unlikely likely

medium low

P2 P9

L3 L2

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

CERT C Secure Coding Standard

ENV02-C. Beware of multiple environment variables with the same effective name

CERT C++ Secure Coding Standard

ENV02-CPP. Beware of multiple environment variables with the same effective name

ISO/IEC 9899:1999

Section 7.20.4, "Communication with the Environment"

ISO/IEC TR 24772

"XYS Executing or Loading Untrusted Code"

MITRE CWE

CWE-462, "Duplicate Key in Associative List (Alist)"

MITRE CWE

CWE-807, "Reliance on Untrusted Inputs in a Security Decision"

Bibliography

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="729ae115-152a-4fe3-84aa-a7d9a6e0e71c"><ac:plain-text-body><![CDATA[

[[API 2006

AA. Bibliography#API 06]]

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="2296c6709da61747-41490f34-48ef4be3-bfbe82b3-6306427676482f0b5ce79309"><ac:plain-text-body><![CDATA[

[[MSDNCampione 1996

AA. Bibliography#MSDNBibliography#Campione 96]]

[getenv()

http://msdn.microsoft.com/en-us/library/tehxacec(VS.71).aspx]  

]]></ac:plain-text-body></ac:structured-macro>

...