Command Injection

OS command injection (operating system command injection or simply command injection) is a type of an injection vulnerability. The payload injected by the attacker is executed as operating system commands. OS command injection attacks are possible only if the web application code includes operating system calls and user input is used in the call. They are not language-specific – command injection vulnerabilities may appear in all languages that let you call a system shell command: C, Java, PHP, Perl, Ruby, Python, and more.

The operating system executes the injected arbitrary commands with the privileges of the web server. Therefore, command injection vulnerabilities on their own do not lead to full system compromise. However, attackers may be able to use privilege escalation and other vulnerabilities to gain more access.

Command Injection Example

The developer of the example PHP application wants the user to be able to see the output of the Windows ping command in the web application. The user needs to input the IP address and the application sends ICMP pings to that address. Unfortunately, the developer trusts the user too much and does not perform input validation. The IP address is passed using the GET method and then used in the command line.

<?php
  $address = $_GET["address"];
  $output = shell_exec("ping -n 3 $address");
  echo "<pre>$output</pre>";
?>

The attacker abuses this script by manipulating the GET request with the following payload:

http://example.com/ping.php?address=8.8.8.8%26dir

The shell_exec function executes the following OS command: ping -n 3 8.8.8.8&dir. The & symbol in Windows separates OS commands. As a result, the vulnerable application executes an additional command (dir) and displays the command output (directory listing) on-screen:

Pinging 8.8.8.8 with 32 bytes of data:
Reply from 8.8.8.8: bytes=32 time=30ms TTL=56
Reply from 8.8.8.8: bytes=32 time=35ms TTL=56
Reply from 8.8.8.8: bytes=32 time=35ms TTL=56
Ping statistics for 8.8.8.8:
    Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 30ms, Maximum = 35ms, Average = 33ms
 Volume in drive C is OS
 Volume Serial Number is 1337-8055
 Directory of C:\Users\Noob\www
(...)

Command Injection Special Characters

You can use different special characters to inject an arbitrary command. The simplest and most common one for Linux is the semicolon (;) and for Windows, the ampersand (&). However, the following payloads for the ping.php script will also work:

  • address=8.8.8.8%3Bwhoami (; character, Linux only)
  • address=8.8.8.8&26whoami (& character, Windows only)
  • address=8.8.8.8%7Cwhoami (| character)
  • address=invalid%7C%7Cwhoami (|| characters, the second command is executed only if the first command fails)
  • address=8.8.8.8&26&26whoami (&& characters)
  • %3E(whoami) (> character, Linux only)
  • %60whoami%60 (` character, Linux only, the result will be reported by the ping command as an error)

Command Injection Prevention

There are several methods to guarantee your application security and prevent arbitrary command execution via command injection. The simplest and safest one is never to use calls such as shell_exec in PHP to execute any host operating system commands. Instead, you should use the equivalent commands from the programming language. For example, if a developer wants to send mail using PHP on Linux/UNIX, they may be tempted to use the mail command available in the operating system. Instead, they should use the mail() function in PHP.

This approach may be difficult if there is no equivalent command in the programming language. For example, there is no direct way to send ICMP ping packets from PHP. In such cases, you need to use input sanitization before you pass the value to a shell command. As with all types of injections, the safest way is to use a whitelist. For example, in the ping.php script, you could check if the address variable is an IP address:

$address = filter_var($_GET["address"], FILTER_VALIDATE_IP);

We do not recommend using blacklists because attackers may find a way around them. However, if you absolutely must use a blacklist, you should filter or escape the following special characters:

  • Windows: ( ) < > & * ‘ | = ? ; [ ] ^ ~ ! . ” % @ / \ : + , `
  • Linux: { } ( ) < > & * ‘ | = ? ; [ ] $ – # ~ ! . ” % / \ : + , `
SHARE THIS POST
THE AUTHOR
Tomasz Andrzej Nidecki
Principal Cybersecurity Writer
Tomasz Andrzej Nidecki (also known as tonid) is a Primary Cybersecurity Writer at Invicti, focusing on Acunetix. A journalist, translator, and technical writer with 25 years of IT experience, Tomasz has been the Managing Editor of the hakin9 IT Security magazine in its early years and used to run a major technical blog dedicated to email security.