Learn Pentesting: Manually Testing for OS Command Injection
OS command injection is a critical vulnerability that can allow an attacker to execute arbitrary commands on the host operating system via a vulnerable web application. In this post, we’ll walk through the process of manually testing for OS command injection during web-application penetration tests. We’ll cover common vulnerable patterns, payload crafting, manual testing techniques, and provide practical code examples to aid in your testing efforts.
Understanding OS Command Injection
OS command injection occurs when an application passes unsafe user-supplied data (such as a form parameter or HTTP header) to a system shell. If the input isn’t properly sanitized or validated, attackers may append additional commands to the intended command, allowing them to execute arbitrary system-level commands.
Key Characteristics:
- Direct OS Access: Unlike SQL injection, which targets databases, command injection allows direct access to the operating system.
- Impact: Successful exploitation can lead to complete system compromise, data exfiltration, or lateral movement.
- Example Scenario: An application takes an IP address as input for a “ping” command. If the input is directly concatenated into a shell command, an attacker might input
127.0.0.1; id
to execute theid
command on the system.
Common Vulnerable Patterns
When reviewing web applications for OS command injection, look for instances where user input is integrated into system commands without proper sanitization or escaping. Common patterns include:
Concatenation in System Calls:
// PHP example $ip = $_GET['ip']; system("ping -c 4 " . $ip);
In the example above, an attacker can append additional commands via the
ip
parameter.Use of Unsafe Functions:
Functions likeexec()
,system()
,shell_exec()
, and even backticks in various languages can be exploited if user input is not properly handled.Lack of Whitelisting/Validation:
A robust input validation routine often restricts input to expected characters (e.g., digits and dots for IP addresses). Its absence is a red flag.
Manual Testing Techniques
Manually testing for OS command injection involves injecting payloads and analyzing the application’s response. Here’s a systematic approach:
1. Identify Injection Points
Review input fields, URL parameters, headers, or cookies that may be used to construct system commands. Common candidates include:
- IP address fields (e.g., in network diagnostic tools)
- Filename parameters (e.g., for backup or logging functions)
- Debug or administrative tools that pass user input to the command line
2. Crafting Payloads
Payloads are designed to break out of the intended command and introduce new commands. Common payloads include:
Command Separators:
Use characters such as;
,&&
, or|
to separate commands.
Example Payload:127.0.0.1; id
Chained Commands:
On Windows, use&
or&&
.
Example Payload:127.0.0.1 & whoami
Whitespace and Encoding Variations:
Sometimes, URL encoding or whitespace manipulation can bypass simple filters.
Example Payload (URL encoded):127.0.0.1%3B+id
3. Observing Responses
A successful injection may result in:
- The output of the injected command appended to the application’s normal response.
- Errors or unusual behavior that indicate the shell interpreted additional commands.
Practical Code Examples
Below are some sample scripts and HTTP request examples that demonstrate how you might test for OS command injection manually.
Example 1: Testing with Python
Using Python’s requests
library, you can craft and send HTTP requests with injection payloads:
import requests
# Target URL of the vulnerable endpoint (replace with the actual target)
url = "http://target-website.com/vulnerable.php"
# Example payload for a Linux-based system
payload_linux = {"ip": "127.0.0.1; id"}
# Send the request and capture the response
response_linux = requests.get(url, params=payload_linux)
print("Linux Injection Test Response:")
print(response_linux.text)
# Example payload for a Windows-based system
payload_windows = {"ip": "127.0.0.1 & whoami"}
response_windows = requests.get(url, params=payload_windows)
print("Windows Injection Test Response:")
print(response_windows.text)
What to Look For:
- Output Indicators: For Linux, look for output similar to
uid=...
from theid
command. For Windows, you might see a username or system info fromwhoami
. - Error Messages: Unexpected error messages may indicate that the payload was partially executed.
Example 2: Manual Testing in a Browser or Proxy
If you’re using an intercepting proxy like Burp Suite, you can manually modify parameters:
Intercept a Request:
Capture a request that sends user-supplied input to the backend.Modify the Parameter:
Change the value from a benign input (e.g.,127.0.0.1
) to an injection payload (e.g.,127.0.0.1; id
).Analyze the Response:
Observe if the output includes unexpected command output or error details.
Tips for Reliable Testing:
- Environment Consideration:
Always test in an environment where you have permission. Command injection testing can be disruptive. - Non-destructive Commands:
Use commands that have no adverse effect on the system (e.g.,id
,whoami
, orecho
statements) to ensure that your tests do not harm production systems. - Automated Tools:
Although manual testing is crucial, tools like OWASP ZAP or custom scripts can help automate initial scans before a deeper manual analysis.
Escalation & Mitigation Considerations
While this post focuses on detection, it’s important to understand how to mitigate these vulnerabilities.
Mitigation Strategies:
- Input Validation and Whitelisting:
Only allow input that strictly matches expected formats. For example, use regex to validate IP addresses. - Use of Safe APIs:
Avoid using system calls that directly incorporate user input. Use safer alternatives or parameterized commands. - Output Escaping:
Ensure that any output from system commands is properly sanitized before being sent back to the user.
Escalation Testing:
- Chaining Commands:
Once a basic injection is confirmed, further testing might involve chaining commands to explore file systems or network configurations. - Privilege Escalation:
If the application runs with elevated privileges, a successful injection can lead to full system compromise.
Conclusion & Further Resources
OS command injection remains a potent threat, and manual testing is a fundamental skill in a penetration tester’s toolkit. By understanding the vulnerable patterns, crafting precise payloads, and carefully analyzing responses, testers can uncover and remediate these vulnerabilities before they are exploited maliciously.
Further Reading:
This post is part of our “Learn Pentesting” series at Numorian, where we dive deep into the techniques and tools that every penetration tester should know. Happy testing!