Skip to content

Command Injection

What does this mean ?

Command injection is an attack in which the goal is execution of arbitrary commands on the host operating system via a vulnerable application. Command injection attacks are possible when an application passes unsafe user supplied data (forms, cookies, HTTP headers etc.) to a system shell. In this attack, the attacker-supplied operating system commands are usually executed with the privileges of the vulnerable application. Command injection attacks are possible largely due to insufficient input validation.

What can happen ?

This vulnerability allows an attacker to execute arbitrary operating system (OS) commands on the server that is running an application, and typically fully compromise the application and all its data. Very often, an attacker can leverage an OS command injection vulnerability to compromise other parts of the hosting infrastructure, exploiting trust relationships to pivot the attack to other systems within the organization.

Recommendation

By far the most effective way to prevent OS command injection vulnerabilities is to never call out to OS commands from application-layer code. In virtually every case, there are alternate ways of implementing the required functionality using safer platform APIs. If it is considered unavoidable to call out to OS commands with user-supplied input, then strong input validation must be performed. Some examples of effective validation include: Validating against a whitelist of permitted values. Validating that the input is a number. Validating that the input contains only alphanumeric characters, no other syntax or whitespace. Never attempt to sanitize input by escaping shell metacharacters. In practice, this is just too error-prone and vulnerable to being bypassed by a skilled attacker.

Sample Code

Vulnerable :

var p = new Process();
p.StartInfo.FileName = "exportLegacy.exe";
p.StartInfo.Arguments = " -user " + input + " -role user";
p.Start();

Non Vulnerable :

Regex rgx = new Regex(@"^[a-zA-Z0-9]+$");
if(rgx.IsMatch(input))
{
    var p = new Process();
    p.StartInfo.FileName = "exportLegacy.exe";
    p.StartInfo.Arguments = " -user " + input + " -role user";
    p.Start();
}

Vulnerable :

import java.io.IOException;
import javax.servlet.http.HttpServletRequest;

public void runUnsafe(HttpServletRequest request) throws IOException {
  String cmd = request.getParameter("command");
  String arg = request.getParameter("arg");

  Runtime.getRuntime().exec(cmd+" "+arg); // Noncompliant
}

Non Vulnerable :

import java.io.IOException;
import javax.servlet.http.HttpServletRequest;

public void runUnsafe(HttpServletRequest request) throws IOException {
  String cmd = request.getParameter("command");
  String arg = request.getParameter("arg");

  if(cmd.equals("/usr/bin/ls") || cmd.equals("/usr/bin/cat"))
  {
      // only ls or cat command are authorized
      String cmdarray[] =  new String[] { cmd, arg };
      Runtime.getRuntime().exec(cmdarray); // Compliant
  }
}
MySecurityManager sm = new MySecurityManager();
System.setSecurityManager(sm);

Vulnerable :

$binary = $_GET["binary"];

// If the value "/sbin/shutdown" is passed as binary and the web server is running as root,
// then the machine running the web server will be shut down and become unavailable for future requests

exec( $binary ); // Noncompliant

Non Vulnerable :

$binary = $_GET["binary"];

// Restrict to binaries within the current working directory whose name only contains letters
$pattern = "[a-zA-Z]++";
if ( preg_match($pattern, $binary) ) {
  exec( $binary ); // Compliant
}

References