Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: REM Cost Reform

Wiki MarkupMany programs and libraries, including the shared library loader on both Unix UNIX and Windows systems, depend on environment variable settings. Because environment variables are inherited from the parent process when a program is executed, an attacker can easily sabotage variables, causing a program to behave in an unexpected and insecure manner \ [[Viega 03|AA. C References#Viega 03]\].

Wiki Markup
Attackers can manipulate environmental variables to trick an executable into running a spoofed version of a shared library or executable.  Most modern systems, for example, uses dynamic libraries and most executables are dynamically linked (that is, use dynamic libraries). If an attacker can run arbitary code with the privileges of a spoofed process by installing a spoofed version of a shared library and influencing the mechanism for dynamic linking by setting the {{LD_PRELOAD}} environmental variable (or another {{LD_*}} environmental variable).  An interesting example of this vulnerability involving the RFC 1408/RFC 1572 _Telnet Environment Option_  is documented in CERT Advisory CA-1995-14, "Telnetd Environment Vulnerability" \[[CA-1995-14|http://www.cert.org/advisories/CA-1995-14.html]\].  The Telnet Environment Option extension to telnet supports the transfer of environment variables from one system to another, allowing an attacker to transfer environment variables that influence the login program called by the telnet daemon and bypass the normal login and authentication scheme to become root on that system.

Certain variables can cause insecure program behavior if they are missing from the environment or improperly set. As a result, the environment cannot be fully purged. Instead, variables that should exist should be set to safe values or treated as untrusted data and examined closely before being used.

For example, the IFS variable (which stands for "internal field separator" is used by the sh and bash shells to determine which characters separate command line arguments. Because the shell is invoked by the C99 system() function and the POSIX popen() function, setting IFS to unusual values can subvert apparently-safe calls.

Environment issues are particularly dangerous with setuid/setgid programs or other elevated priviledges, because an attacker can completely control the environment variables.

Non-Compliant Coding Example (POSIX)

Viega 2003].

All programs, particularly those running with higher privileges than the caller (such as those with setuid/setgid flags), should treat their environment as untrusted user input. Because the environment is inherited by processes spawned by calls to the fork(), system(), or exec() functions, it is important to verify that the environment does not contain any values that can lead to unexpected behavior.

The best practice for such programs is to

This recommendation is a more specific instance of STR02-C. Sanitize data passed to complex subsystems.

Subclause 7.22.4.6 of the C Standard states that "the set of environment names and the method for altering the environment list are implementation-defined." Consequently, it is important to understand which functions are available for clearing, modifying, and looking up default values for environment variables. Because some programs may behave in unexpected ways when certain environment variables are not set, it is important to understand which variables are necessary on your system and what are safe values for them.

Noncompliant Code Example (POSIX, ls)

This noncompliant code example invokes the C This non-compliant code invokes the C99 system() function to execute the /bin/ls program. The C99 system() function passes a string to the command processer processor in the host environment to be executed.

Code Block
bgColor#FFcccc#ffcccc
langc
if (
system("/bin/ls");

Using the default setting of the IFS environmental variable, this string is interpreted as a single token. If an attacker sets the IFS}}environmental variable to "/" the meaning of the system call changes dramatically. In this case, the shell interprets the string as two tokens: {{bin and ls. An attacker could exploit this by creating a program called bin in the path (which could also be manipulated by the attacker).

Compliant Solution (POSIX)

Wiki Markup
Sanitize the environment by setting required variables to safe values and removing extraneous environment variables.  Set {{IFS}} to its default of " \t\n" (the first character is a space character). Set the {{PATH}} environment variable to {{_PATH_STDPATH}} defined in {{paths.h}}.  Preserve the {{TZ}} environment variable (if present) which denotes the time zone (see the Open Group Base Specifications Issue 6 specifies for the  format for this variable \[[Open Group 04|AA. C References#Open Group 04]\].

Wiki Markup
One way to clear the environment is to use the {{clearenv()}} function. The function {{clearenv()}} has an odd history; it was supposed to be defined in POSIX.1, but never made it into the standard. However, it is defined in POSIX.9 (the Fortran 77 bindings to POSIX), so there is a quasi-official status for it \[[Wheeler 03|AA. C References#Wheeler 03]\].

Wiki Markup
The other technique is to directly manipulate the environment through the {{environ}} variable.  According to the Open Group Base Specifications Issue 6 \[[Open Group 04|AA. C References#Open Group 04]\]:

The value of an environment variable is a string of characters. For a C-language program, an array of strings called the environment shall be made available when a process begins. The array is pointed to by the external variable environ, which is defined as:

extern char **environ;

These strings have the form name=value; names shall not contain the character '='.

Note that C99 standard states that "The set of environment names and the method for altering the environment list are implementation-defined."

Non-Compliant Coding Example (POSIX)

This non-compliant code invokes the C99 system() function to remove the .config file in the users home directory.

Code Block
bgColor#FFcccc

system("rm ~/.config");

Given that the vulnerable program has sufficient permissions, an attacker can manipulate the value of HOME so that this program can remove any file named .config anywhere on the system.

Compliant Solution (POSIX)

This compliant solution calls the getuid() to determine who the user is, followed by the getpwuid() to get the user's password file record (which contains the user's home directory).

Code Block

uid_t         uid;
struct passwd *pwd;
   
uid = getuid(  );
if (!(pwd = getpwuid(uid))) {
  endpwent(  );
  return 1;
}
endpwent();

Risk Assessment

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ENV03-A

2 (high)

2 (probable)

2 (medium)

P8

L2

Examples of vulnerabilities resulting from the violation of this recommendation can be found on the CERT website.

References

 dir.`date +%Y%m%d`") == -1) {
  /* Handle error */
}

Although IFS does not affect the command portion of this string, /bin/ls, it does determine how the argument is built after calling date. If the default shell does not ignore the incoming value of the IFS environment value, and an attacker sets IFS to ".", the intended directory will not be found.

Compliant Solution (POSIX, ls)

The nonstandard function clearenv() may be used to clear out the environment where available: otherwise, the environment can be cleared by obtaining the environment variable names from environ and removing each one using unsetenv().

In this compliant solution, the environment is cleared by clearenv(), and then the PATH and IFS variables are set to safe values before system() is invoked. Sanitizing shell commands can be difficult, and doing so can adversely affect the power and flexibility associated with them.

Code Block
bgColor#ccccff
langc
char *pathbuf;
size_t n;

if (clearenv() != 0) {
  /* Handle error */
}

n = confstr(_CS_PATH, NULL, 0);
if (n == 0) {
  /* Handle error */
}

if ((pathbuf = malloc(n)) == NULL) {
  /* Handle error */
}

if (confstr(_CS_PATH, pathbuf, n) == 0) {
  /* Handle error */
}

if (setenv("PATH", pathbuf, 1) == -1) {
  /* Handle error */
}

if (setenv("IFS", " \t\n", 1) == -1) {
  /* Handle error */
}

if (system("ls dir.`date +%Y%m%d`") == -1) {
  /* Handle error */
}

POSIX also specifies the confstr() function, which can be used to look up default values for environment variables [IEEE Std 1003.1:2013]. The _CS_V7_ENV argument to confstr() retrieves a list of environment variable settings required for a default conforming environment [IEEE Std 1003.1:2013]. A space-separated list of variable=value pairs is returned, with variable names guaranteed not to contain equal signs (=), and variable=value pairs guaranteed not to contain spaces. Used together with the _CS_PATH request, this completely describes the minimum environment variable settings required to obtain a clean, conforming environment. On systems conforming to the POSIX.1-2008 standard, this should be used to create a sanitized environment.

On systems that have no clearenv() function, the following implementation can be used:

Code Block
bgColor#ccccff
langc
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) {
      /* Handle empty variable name (corrupted environ[]) */
    }
    if (len > lastlen) {
      namebuf = realloc(namebuf, len+1);
      if (namebuf == NULL) {
        /* Handle error */
      }
      lastlen = len;
    }
    memcpy(namebuf, environ[0], len);
    namebuf[len] = '\0';
    if (unsetenv(namebuf) == -1) {
      /* Handle error */
    }
  }
  return 0;
}

Compliant Solution (Windows)

There is no portable or guaranteed way to clear out the environment under Windows. Following ENV33-C. Do not call system(), care should be taken to use _execle(), _execlpe(), _execve(), or _execvpe() instead of system(), because they allow the environment to be explicitly specified.

If it is explicitly known which environment variables need to be kept, Secure Programming Cookbook for C and C++ [Viega 2003] defines a function, spc_sanitize_environment(), that will remove everything else.

Risk Assessment

Invoking an external program in an attacker-controlled environment is inherently dangerous.

Recommendation

Severity

Likelihood

Detectable

Repairable

Priority

Level

ENV03-C

High

Likely

No

No

P9

L2

Automated Detection

Tool

Version

Checker

Description

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C5017
LDRA tool suite
Include Page
LDRA_V
LDRA_V
588 SPartially implemented

Related Vulnerabilities

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

Related Guidelines

SEI CERT C++ Coding StandardVOID ENV01-CPP. Sanitize the environment when invoking external programs
CERT Oracle Secure Coding Standard for JavaIDS07-J. Sanitize untrusted data passed to the Runtime.exec() method
ISO/IEC TR 24772:2013Executing or Loading Untrusted Code [XYS]
MITRE CWECWE-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-471, Modification of Assumed-Immutable Data (MAID)
CWE-807, Reliance on intrusted inputs in a security decision

Bibliography

[CA-1995-14]"Telnetd Environment Vulnerability"
[Dowd 2006]Chapter 10, "UNIX II: Processes"
[IEEE Std 1003.1:2013]Chapter 8, "Environment Variables"
XSH, System Interfaces, confstr
[ISO/IEC 9899:2011]Subclause 7.22.4, "Communication with the Environment"
[Viega 2003]Section 1.1, "Sanitizing the Environment"
[Wheeler 2003]Section 5.2, "Environment Variables"


...

Image Added Image Added Image Added Wiki Markup\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 10, "UNIX II: Processes" \[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.20.4, "Communication with the environment" \[[Open Group 04|AA. C References#Open Group 04]\] Chapter 8, "Environment Variables" \[[Viega 03|AA. C References#Viega 03]\] Section 1.1, "Sanitizing the Environment" \[[Wheeler 03|AA. C References#Wheeler 03]\] [Section 5.2, "Environment Variables"|http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html]