Command Injection vulnerabilities occur when a server running an application can be compromised using arbitrary operating system (OS) commands supplied by an attacker. If successful, these commands can compromise the application itself and all its data. Furthermore, an attacker can exploit OS command injection vulnerabilities to compromise other parts of the hosting infrastructure and potentially attack other applications related to the compromised one.
As a penetration tester, your job is to determine whether an attacker can inject such shell commands via user input. Attackers typically use an input point (like a form field, cookie, or HTTP header) to inject shell commands into the web application. If the target application does not properly sanitize $\text{[clean or filter]}$ or validate this input, it will execute the commands without suspicion, leaving it defenseless against the attack.
OS Command Injection vs. Code Injection
It is important to know the difference between OS command injection and code injection:
- Code Injection allows the attacker to add their own code (e.g., PHP, Python, SQL) which is then executed by the application’s interpreter.
- OS Command Injection does not act the same way. The attacker only extends the default functionality of the application by appending commands to an existing system call. The application then executes these system commands on the host operating system.
As a penetration tester, your job is to find out whether the application passes unsafe user-supplied data (through forms, cookies, or HTTP headers, etc.) directly to a system command. The vulnerable application normally allows the execution of arbitrary commands on its host operating system.
Discovering OS Command Injection
A common technique for discovering errors in coding or security loopholes in software, operating systems, or networks is fuzz testing. The process involves inputting a massive amount of specially crafted data, called fuzzing, in an attempt to make the application crash or reveal unusual behavior.
Whether the application has vulnerabilities can be determined by fuzzing with command separators. These separators are crucial as they allow an attacker to append their own command to the legitimate one being executed by the application.
Common command separators include:
;(Semicolon)&(Ampersand)&&(Double Ampersand)|(Pipe)||(Double Pipe)
These command separators vary from one operating system to another. What works on Linux may not work on Windows, and vice versa.
Initial Test on Mutillidae
To demonstrate, testing is performed on mutillidae, an intentionally vulnerable web application running on OWASP Broken Web Applications. The focus is on the DNS Lookup section.
The test involves issuing commands separated by ; in the DNS Lookup field, which typically executes a ping or nslookup command on the backend. The payload is:
127.0.0.1; ls
The application’s response is observed for errors related to the operating system or any unusual output. The output received confirms the vulnerability, as the whole directory listing is visible:
The output is quite straightforward, and it assures that more OS commands injection are possible in this application.
Server: 10.13.4.1
Address: 10.13.4.1#53
1.0.0.127.in-addr.arpa name = localhost.
add-to-your-blog.php
ajax
arbitrary-file-inclusion.php
authorization-required.php
... [and a full list of directory contents]
Separators in the Terminal
Before continuing with web application exploitation, it is helpful to check the power of those command separators on the local terminal. If a single ping command is issued to the localhost, it responds with some packets. If a malicious command separator is slipped in to perform commands injection, the system executes both.
//monitor scanning
root@kali:~# ping -c 1 127.0.0.1; ls
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.031 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.031/0.031/0.031/0.000 ms
Desktop Downloads Music Public Videos
Documents juice-shop Pictures Templates xml-attacks.txt
As clearly seen, after the ping command finishes its journey, the command separator ; slips in the ls command, resulting in the output of the current directory contents:
Desktop Downloads Music Public Videos
Documents juice-shop Pictures Templates xml-attacks.txt
Although this is a local terminal command and not a web OS command injection attack, it demonstrates a good example of how the system can be exploited with a single separator and an injected command.
Injecting and Exploiting Malicious Commands with Burp Suite
The next step is to systematically inject malicious commands to test whether a web application has vulnerabilities. Since most web server user accounts have permission to execute directory listings by default, commands like ls (Linux) and dir (Windows) are often used. These commands will run in the context of a web server user, which is typically a low-privilege account (e.g., www-data), not a normal user.
The exploitation technique involves comparing two server responses. A typical, simple request will yield a response with a certain content length. When a malicious command is successfully injected and executed, the command’s output is appended to the response, causing the overall content length to become longer.
Setting Up Burp Suite Scope
- Open mutillidae and pass the response flow through Burp Suite.
- To isolate the traffic, the Scope tool of Burp Suite is used. From the Target tab, right-click the mutillidae host and select “Add to scope”.
- In the Target/Sitemap section, select “Show only in-scope terms” in the filter settings. This quarantines the application for focused testing.
The response on the Target and Sitemap section is then sent to the Repeater tool by right-clicking and selecting “Send to Repeater”.
The header part of the response contains valuable information:
2.2.14 OpenSSL/0.9.8k Phusion_Passenger/4.0.38 mod_perl/2.0.4
Perl/v5.10.1
X-Powered-By: PHP/5.3.2-1ubuntu4.30
Set-Cookie: PHPSESSID=m329900gup8bjmo6um5h6vp8v3; path=/
Set-Cookie: showhints=1
Logged-In-User:
Vary: Accept-Encoding
Content-Length: 45622
Connection: close
Content-Type: text/html
This reveals information about the PHP version, the type of server being used, and the initial content length.
Analyzing the Request in Repeater
The Repeater tool captures the original request, which is a POST request to the DNS Lookup function:
//with intercept on, capturing the request
POST /mutillidae/index.php?page=dns-lookup.php HTTP/1.1
Host: 192.168.2.2
... [other headers]
Content-Type: application/x-www-form-urlencoded
Content-Length: 61
... [other headers and cookies]
target_host=127.0.0.1&dns-lookup-php-submit-button=Lookup+DNS
The output is straightforward, showing the request method (POST), the vulnerable URL, and the form data submitted (target_host=127.0.0.1). Clicking the Go button in Repeater shows the initial, unexploited response.
Setting the Payload Position in Intruder
The request is now sent from Repeater to the Intruder tool. The “Clear” button is clicked to remove all special characters (§) automatically attached by Intruder. The objective is to place the command separator and the malicious command strategically. The placeholder for the injection is in the target_host parameter.
The base request is modified to include placeholders for the command separator (cs) and the malicious command (ls), separated by the placeholder for the command separator:
POST /mutillidae/index.php?page=dns-lookup.php HTTP/1.1
... [headers omitted for brevity]
target_host=127.0.0.1 cs ls &dns-lookup-php-submit-button=Lookup+DNS
The next step is to add the fuzzing symbol (§) only around the command separator placeholder (cs) in the last line, ensuring only the separator is fuzzed.
//fuzzing symbol around the cs command
... [headers omitted for brevity]
target_host=127.0.0.1 §cs§ ls &dns-lookup-php-submit-button=Lookup+DNS
The fuzzing symbols are needed because Burp Suite’s Intruder will automate the testing technique by systematically replacing the §cs§ placeholder with a list of payloads.
Configuring Payloads and Launching the Attack
In the Intruder Payloads tab, the following command separators are added as payloads: |, ||, &, and &&.
Each separator has a defined role:
&(Ampersand): Used to separate multiple commands on one command line; runs the commands one after another.&&(Double Ampersand): Used to inject the malicious commands after the first command, only if the first command succeeds.|(Pipe): The pipeline separator is used to give the standard output of one command as the standard input to the next command.||(Double Pipe): Used to inject the malicious command if the first command fails. In Windows, it separates multiple commands on one command line, similar to&and&&in Linux.
The attack is started. The results are analyzed by monitoring the Length of the payloads. The very first request is the simple request without any payload, but the rest are different, and the successful injections will have a longer content length.
Comparing Responses
The results are analyzed using the Comparer tool to watch the difference. By selecting the lowest and highest content length responses and sending them to Comparer, the word count difference becomes evident.
The difference in word count is significant (e.g., the lowest one is 48,665 and the highest one is 50,039). This large increase in length confirms that the injected command (ls) was executed, and its output (the directory listing) was included in the response. As proof of concept, the directory listings are visible in the highest payload response.