DEV Community

Vickie Li for ShiftLeft

Posted on • Originally published at blog.shiftleft.io on

Find command injection in source code

Using Ocular to search for command injection in an application by tracing dataflow

When learning how to find, exploit, or prevent different types of security vulnerabilities, you’ll want to understand the vulnerability’s root causes and what happens to an application when it’s exploited.

Today, we’ll talk about remote code execution (RCE), it’s mechanisms, and how you can spot it in source code.

Remote code execution and command injection

Remote code execution vulnerabilities are also called RCE. They are a class of vulnerabilities that happen when attackers can execute their code on your machine.

There are many different types of bugs that can lead to RCE, like insecure deserialization, remote file inclusion, SQL injections, etc. But a very common root cause for RCE is command injection: when an application concatenates user input into executable code or system commands, it cannot tell the difference between the user input and the code it’s supposed to execute. As a result, the application executes user input as code and attackers can execute arbitrary code via the application.

For instance, let’s say that the application creates new files based on user input. The developer implemented this feature by passing user input into a system command:

def make_file( **user\_input** ):
    exec("touch { **user\_input** }")
Enter fullscreen mode Exit fullscreen mode

If users submit regular file names, the application will execute this command and the functionality works correctly:

touch **abc.txt**
Enter fullscreen mode Exit fullscreen mode

But attackers can submit additional system commands in their input and force the application to execute the commands of their choice:

touch **abc.txt; cat passwords.txt**
Enter fullscreen mode Exit fullscreen mode

Sources? Sinks? Dataflow!

Before we go on, there are a few concepts that you should understand: “sources”, “sinks”, and “data flow”. In the world of code analysis, a “source” is the code that allows a vulnerability to happen. Whereas a “sink” is where the vulnerability actually happens.

Take command injection vulnerabilities, for example. A “source” in this case could be a function that takes in user input. Whereas the “sink” would be functions that execute system commands. If the untrusted user input can get from “source” to “sink” without proper sanitization or validation, there is a command injection vulnerability. Many common vulnerabilities can be identified by tracking this “dataflow” from appropriate sources to their corresponding sinks.

Searching for command injections

The vulnerability we will be looking at today is remote code execution (RCE). There are different types of root causes for RCE, but for this tutorial, let’s focus on searching for a simple case of RCE: command injection.

We’re gonna fire up the analysis tool we are using today calledOcular, and import the project that we are analyzing. We can import the Java project we are analyzing Tarpit Java into Ocular. If you want to follow along with the demo, the vulnerable project Tarpit Java is here.

After I import a project, I like to run a command to make sure that I have the project properly loaded. I typically run cpg.method.name.l for this purpose. This command will look for all the methods defined in the project, extract their names, and list them. So this is essentially a command that lists all the method names in the project:

Our code was imported successfully! Let’s start by looking for the sources of the command injection. A good way to look for places that handle user input is to look for identifiers (local variables, globals, and class members) that are of the type HttpServletRequest. We’ll filter the application’s identifiers by its type name:

Here, we are essentially looking for identifiers whose type name contain the string “HttpServletRequest”. You’ll see that this gives us a list of identifiers that contain input from HTTP requests. We’ll define this as our source.

Next up, let’s take a look at sink functions for command injection. We are going to look for dangerous functions that indicate code execution in the program. For this demo, let’s focus on calls to “exec”, which often indicates system command execution.

First, we’ll determine if the program is using exec anywhere. This command tells Ocular to find all calls to exec, display that line of code, the file name the call is in, and its line number. You can see here that there are three calls to exec, all located in the file Insider.java.

We can define the sink as calls to exec. Since we are tracing identifiers being passed in as the arguments of exec, we’ll specify that we are looking at the call’s arguments.

Finally, we can tell Ocular, show me all the places where a source can reach a sink in terms of dataflow, and pretty print the results. You’ll see a list of dataflows where request data are being passed into exec as an argument.

Static analysis is the most efficient way of uncovering most vulnerabilities in your applications. If you’re interested in learning more about ShiftLeft’s static analysis tools ShiftLeft CORE or Ocular, visit us here. And if you are interested in learning more about common vulnerabilities in web applications, check out our free course on the OWASP top ten.

By the way, you can watch the video version of this demo here: https://www.youtube.com/watch?v=DhRDUVcfOKA.


Top comments (0)