OS Command Injection
Web applications often need to interact with the underlying operating system,
such as when a file is created through a file upload mechanism.
Sometimes a web application needs to address a multitude of different cases,
and a set of predefined functions can be too inflexible.
In these cases, web developers often tend to directly accept user input,
then sanitize it.
This means that user input is filtered for any command sequences
that might try to change the application’s behavior for malicious purposes.
For this demonstration, let’s review the “Mountain Vaults” web application,
running on port 8000 on the MOUNTAIN system.
In this version, we’re able to clone git repositories by entering
the git clone command combined with a URL.
The example shows us the same command we would use in the command line.
We can hypothesize that maybe the operating system
will execute this string and, therefore,
we may be able to inject our own commands.
Let’s try to use the form to clone the ExploitDB repository.
After we click on submit,
the cloning process of the repository starts.
The output shows that the repository was successfully cloned.
Furthermore, the actual command is displayed
in the the web application’s output.
Let’s try to inject arbitrary commands with curl.
We’ll switch over to HTTP history in Burp
to understand the correct structure for the POST request.
The request indicates the “Archive” parameter is used for the command.
This means we can use curl to provide our own commands to the parameter.
We’ll do this by using the -X parameter to change the request type to POST.
We’ll also use --data to specify what data is sent in the POST request.
On our first try, the web application shows that it detected
a command injection attempt with the ipconfig command.
Let’s attempt to backtrack from the working input
and find a bypass for the filter.
Next, we’ll try to only provide the git command for the Archive parameter
in the POST request.
The output shows the help page for the git command,
confirming that we are not restricted to only using git clone.
Since we know that only providing “git” works for execution,
we can try to add the version subcommand.
If this is executed, we’ll establish that we can specify any git command
and achieve code execution.
This will also reveal if the web application is running
on Windows or Linux, since the output of git version includes the “Windows” string
in Git for Windows.
If the web application is running on Linux,
it will only show the version for Git.
The output shows that the web application is running on Windows.
Now we can use trial-and-error to poke around the filter
and review what’s allowed.
Since we established that we cannot simply specify another command,
let’s try to combine the git and ipconfig -commands with a URL-encoded semicolon.
Semicolons can be used in a majority of command lines,
such as PowerShell or Bash as a delimiter for multiple commands.
The output shows that both commands were executed.
We can assume that there is a filter in place checking if “git” is executed
or perhaps contained in the “Archive” parameter.
Next, let’s find out more about how our injected commands are executed.
We will first determine if our commands are executed by PowerShell or CMD.
In a situation like this, we can use a handy snippet that displays “CMD”
or “PowerShell” depending on where it is executed.
We’ll use URL encoding once again to send it.
The output contains “PowerShell”, meaning that our injected commands are executed
in a PowerShell environment.
Next, let’s try to leverage command injection to achieve system access.
We’ll use Powercat to create a reverse shell.
Powercat is a PowerShell implementation of Netcat included in Kali.
Let’s start a new terminal, copy Powercat to the home directory for the kali user,
and start a Python web server in the same directory.
Next, we’ll start a third terminal tab to create a Netcat listener on port 4444
to catch the reverse shell.
With our web server serving powercat.ps1 and Netcat listener in place,
we can now use curl in the first terminal to inject our command.
It consists of two parts delimited by a semicolon.
The first part uses a PowerShell download cradle to load the Powercat function
contained in the powercat.ps1 script from our web server.
The second command uses the powercat function to create the reverse shell
with -c to specify where to connect,
-p for the port, and -e for executing a program.
Again, we’ll use URL encoding for the command and send it.
After entering the command, the second terminal should show that we received
a GET request for the powercat.ps1 file.
We’ll also find an incoming reverse shell connection in the third terminal
for our active Netcat listener.
Instead of using Powercat,
we could also inject a PowerShell reverse shell directly.
There are many ways to exploit a command injection vulnerability that depend
heavily on the underlying operating system and the implementation of
the web application, as well as any security mechanisms in place.