Remote Code Execution — Bypassing WAF and Filters
The injection is always a thing. Existing and settling well in OWASP Top 10 Security vulnerabilities 2007, 2010, 2013, and 2017 version - in which case made it to the first place for the last three versions, make this vulnerability is tempting to play with.
Injection flaws allow attackers to relay malicious code through an application to another system. These attacks include calls to the operating system via system calls, the use of external programs via shell commands, as well as calls to backend databases via SQL (i.e., SQL injection). Whole scripts written in Perl, Python, and other languages can be injected into poorly designed applications and executed. Any time an application uses an interpreter of any type there is a danger of introducing an injection vulnerability.
There are many scenarios on how one's can take advantage of these Injection flaws, but in this post, we will be talking about Remote Code Execution. Nowadays, most websites are equipped with a Web Application Firewall as it is usually preinstalled in most hosting providers. These Web Application Firewalls usually have fixed rules to prevent and detect "Arbitrary code execution." But there are tons of ways to play with it, and it's where all the fun begins!
Welcome to the series
In this first series, I'll talk about bypassing simple rules. I'll be using a simple PHP script to mimic the vulnerabilities found in real life. This vulnerability is very easy to identify because this vulnerability is very limited to functions that pass input to the Operating System, i.e., pass-thru/system/shell in PHP or os. System and subprocess in python. In the real case, the script will be similar to the one below.
If you're new, you might wonder if this script will harm us as we will only supply the host target as an input. We can use || and && to execute command chaining or two or more different commands. The elegant way is to split the command using ;
This is the point of RCE injection; it allows you to execute all commands that exist in the operating system. But the problem is most of the websites are protected by a Web Application Firewall. This attack requires an exact payload because the payload is exactly an operating system command with a supplied argument. This makes the attack is too easy to detect. Don't worry, and there are many ways to flip this around!
Are you bypassing if "Space" is forbidden?
This might be the case if you're here because of CTF competition. In bash, you can use $IFS to replace space. IFS stands for Internal Field Separator, not only space, and this can help you if you're trying to substitute a new line, line separator, etc.
$IFS work just fine, but if it fails, you could try to use {command, var} to get your file. Well, it's a bit tricky because cURL usually takes the payload as "do this cURL request for each value inside{}."
Bypassing WAF template matching or rules
As I mentioned before, Web Application Firewall and Filter have specific rules, and they will block you right away if you're trying to go with an exact payload like "bin/cat" or "etc/passwd." There are many ways we can play with this.
I've been learning a lot and getting ideas from the sec juice post about evasion techniques, and he provides a deep and clear explanation about the payload. You can check his post for a more detailed explanation about the first three-point below :)
Use 'string' to wrap your payload.
You can split your payload, and it will work just fine!
c’at’ /’e’’t’c/passwd == cat /etc/passwd
Use Uninitialized Variable
In bash, uninitialized variables count as null or no values, which might help us bypass the "template matching."
Not only in your payload, uninitialized variable can also help you if || && is forbidden, you can simply do
x=google.com$x|$y|ls$z -la for ls -la
or
x=google.com$x&$y&$x/bin$y/cat $a/etc$b/passwd$h for /bin/cat /etc/passwd
Use Regex Wildcard
This is the most interesting part, you can replace any character with the wild card, either (? . *) will work like a charm! To help you craft this payload, you can use the command -v till you get the command you are looking for. If the wildcard still returns two or more possibilities, it will execute each with the values given. It's okay, but it might result in an error in the curling process. For example, if you're trying to get a file's content, you might need to call /bin/cat. You can start trying with
command -v /b??/c??
After you get a good payload, you can shoot it right away!
Maximizing Bash Features to your benefit
Well, there are too many ways you can bypass this template matching, but if by any chance you can use the "which" command, you can abuse its features to your benefit. I'll do two examples; base64 and xxd.
Base64
You can check if the base64 command exist by using which base64
This is our golden ticket, and you can do anything you want if WAF / Filter does not filter base64. Pipe or | will be our best friend in this method.
First, we need to base64 encode our string
cat /etc/passwd == Y2F0IC9ldGMvcGFzc3dk
echo our sting -> base 64 decode it -> bash it!
Well, if “base64” is filtered, you can try to combine your payload with splitting, uninitialized variable, or even wild card to get it works!
echo+’Y2F0IC9ldGMvcGFzc3dk’|/usr/bin/base64+-d|bash
is equal to
echo+’Y2F0IC9ldGMvcGFzc3dk’$a|$x/’u’sr/b?n%y/bas’e’64+-d$z|bash$c
XXD
Same with base64, first, we need to see if xxd exists in the target machine.
The only different with base64 is, we’re translating from hex here.
cat /etc/passwd == 636174202f6574632f706173737764
echo our sting -> xxd -r -p -> bash it!
Based on my experience, usually, base64 is filtered while XXD is not. Well, it doesn't matter as you can almost bypass this template matching by combining two or more methods :D
Lastly
It's almost impossible for Web Application Firewall to detect more evolving payload with just "Template Matching". Maybe it's time for you to move to Machine Learning Based- Web Application Firewall.