Introduction

For example, if the supplied value is:

when typed in a Windows command prompt, the application Calculator is displayed.

However, if the supplied value has been tempered with, and now it is:

When execute, it changes the meaning of the initial intended value.

Now, both the Calculator application and the value test are displayed:

The problem is exacerbated if the compromised process does not follow the principle of least privilege principle and attacker-controlled commands end up running with special system privileges that increases the amount of damage.

Primary Defenses

The primary defense is to avoid calling OS commands directly. Built-in library functions are a very good alternative to OS Commands, and they cannot be manipulated to perform tasks other than those it is intended to do.

For example use mkdir() instead of system("mkdir /dir_name").

If there are available libraries or APIs for the language you used, this is the preferred method.

Defense option 2: Escape values added to OS commands specific to each OS

For examples, see or escapeshellcmd() in PHP.

Defense option 3: Parameterization in conjunction with Input Validation

If it is considered unavoidable the call to a system command incorporated with user-supplied, the following two layers of defense should be used within software in order to prevent attacks

Parameterization: If available, use structured mechanisms that automatically enforce the separation between data and command. These mechanisms can help to provide the relevant quoting, encoding.

Layer 2

Input validation: The values for commands and the relevant arguments should be both validated. There are different degrees of validation for the actual command and its arguments:

  • When it comes to the commands used, these must be validated against a whitelist of allowed commands.
  • In regards to the arguments used for these commands, they should be validated using the following options:
    • Positive or whitelist input validation: Where are the arguments allowed explicitly defined.

Note A:

Additional Defenses

On top of primary defences, parameterizations and input validation, we also recommend adopting all of these additional defenses in order to provide defense in depth.

These additional defenses are:

  • Applications should run using the lowest privileges that are required to accomplish the necessary tasks.
  • If possible, create isolated accounts with limited privileges that are only used for a single task.

Code examples

In Java, use and the command must be separated from its arguments.

Note about the Java's Runtime.exec method behavior:

There are many sites that will tell you that Java's Runtime.exec is exactly the same as C's system function. This is not true. Both allow you to invoke a new program/process.

Runtime.exec does NOT try to invoke the shell at any point and do not support shell metacharacters.

The key difference is that much of the functionality provided by the shell that could be used for mischief (chaining commands using &, &&, |, ||, etc, redirecting input and output) would simply end up as a parameter being passed to the first command, and likely causing a syntax error, or being thrown out as an invalid parameter.

Code to test the note above:

  1. String[] specialChars = new String[]{"&", "&&", "|", "||"};
  2. String cmdTemplate = "java -version %s " + payload;
  3. String cmd;
  4. Process p;
  5. int returnCode;
  6. for (String specialChar : specialChars) {
  7. cmd = String.format(cmdTemplate, specialChar);
  8. System.out.printf("#### TEST CMD: %s\n", cmd);
  9. p = Runtime.getRuntime().exec(cmd);
  10. returnCode = p.waitFor();
  11. System.out.printf("RC : %s\n", returnCode);
  12. System.out.printf("OUT :\n%s\n", IOUtils.toString(p.getInputStream(),
  13. "utf-8"));
  14. System.out.printf("ERROR :\n%s\n", IOUtils.toString(p.getErrorStream(),
  15. "utf-8"));
  16. }
  17. System.out.printf("#### TEST PAYLOAD ONLY: %s\n", payload);
  18. System.out.printf("RC : %s\n", returnCode);
  19. System.out.printf("OUT :\n%s\n", IOUtils.toString(p.getInputStream(),
  20. "utf-8"));
  21. System.out.printf("ERROR :\n%s\n", IOUtils.toString(p.getErrorStream(),
  22. "utf-8"));

Result of the test:

Incorrect usage:

  1. ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");

In this example, the command together with the arguments are passed as a one string, making easy to manipulate that expression and inject malicious strings.

Correct Usage:

Here is an example that starts a process with a modified working directory. The command and each of the arguments are passed separately. This make it easy to validated each term and reduces the risk to insert malicious strings.

.Net

In .Net use to call underlying OS functions.

  1. System.Diagnostics.Process process = new System.Diagnostics.Process();
  2. System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
  3. startInfo.FileName = "validatedCommand";
  4. startInfo.Arguments = "validatedArg1 validatedArg2 validatedArg3";
  5. process.StartInfo = startInfo;
  6. process.Start();

PHP

In PHP use or escapeshellcmd() rather than , system(), .

Related articles

  • OWASP .

How to Avoid Vulnerabilities

  • C Coding: .

How to Review Code

  • OWASP .

External References