Stay in touch

Application security insights and invitations to exclusive events in your inbox


Your data will stay confidential Private and Confidential

Patching Complex Web Vulnerabilities Using ModSecurity WAF

Tuesday, February 9, 2016 By

In this blog post we will demonstrate complicated examples of common web application vulnerabilities, and see how they can be mitigated with ModSecurity WAF.


Table of Content

  1. Introduction: Virtual Patching and ModSecurity WAF
  2. Patching Cross-Site Scripting (XSS) Vulnerabilities
  3. Patching SQL Injection Vulnerabilities
  4. Patching Cross-Site Request Forgery Vulnerabilities
  5. Patching Path Traversal Vulnerabilities
  6. Patching Open Redirect Vulnerabilities
  7. Patching Insufficient Session Expiration Vulnerability
  8. Patching Session Fixation Vulnerability
  9. Patching Improper Access Control Vulnerability
  10. Patching Missing HttpOnly and Secure Flags on Sensitive Cookies
  11. Patching Information Disclosure Vulnerability
  12. Patching Arbitrary File Upload Vulnerability
  13. Conclusion

Introduction: Virtual Patching and ModSecurity WAF

These days, insecure web applications are the open doors for Advanced Persistent Threats (APT), as hackers can still easily get into almost any web application, including the most secure ones.

Once a web application security vulnerability is detected, it’s very important to properly remediate it: either by patching the web application code directly, or via so-called virtual patching using a Web Application Firewall (WAF). Both methodologies have their strength and inconveniences, depending on the web application, the vulnerability, related IT environment, corporate risk management strategy and risk appetite. PCI DSS requirement 6.6 clearly states that payment web applications shall be regularly audited or protected by WAF.

In this blog post, we will try to demonstrate complicated examples of common web application vulnerabilities, and see how they can be remediated by using powerful and flexible open source Web Application Firewall ModSecurity. We will also check if, and how, these vulnerabilities can be mitigated in default configuration of the OWASP ModSecurity CRS (Core Rules Set version 2.2.9).


Patching Cross-Site Scripting (XSS) Vulnerabilities Using WAF

Being a part of OWASP Top Ten vulnerabilities, today Cross-Site Scripting is probably the most frequent vulnerability affecting web applications of all sizes and complexity. Despite that XSSs are considered medium-risk vulnerabilities, as they always require a certain level of interaction with victim, cybercriminals exploit them very actively these days both to compromise the end-users and vulnerable web applications.

ModSecurity CRS blocks the majority of classic XSS exploitation vectors in its default configuration via the anti-XSS “modsecurity_crs_41_xss_attacks.conf” ruleset. However, some specific cases of XSS, such as DOM-Based XSS, or XSS inside JavaScript code, can be pretty easily exploited bypassing the CRS.

Let’s have a look on the following example of vulnerable PHP code:

xss.php
  1. <script>
  2. param=<?=$_GET['param']?>
  3. </script>

The exploitation example below will successfully display JavaScript popup with “ImmuniWeb” string:

http://host/xss.php?param=confirm(/ImmuniWeb/)

Nevertheless, exploitation of almost any XSS vulnerability can be reliably prevented by a custom ModSecurity rule. The following rule restricts all HTTP input parameters passed to the script to unsigned integers, making the vulnerability unexploitable:

mod_security_custom_rules.conf
SecRule REQUEST_FILENAME "/xss.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1001"
    SecRule ARGS_GET:param "!^[0-9]+$" "t:none"

However, this example will reliably work only if we know which values the vulnerable parameter may accept, otherwise we risk to break the web application functionality. Therefore, make sure to talk to web developers prior to creating custom rules.

Also, keep in mind that a Web Application Firewall cannot mitigate some variations of Dom-Based XSS by design, just because the malicious payload doesn’t reach the web server and thus cannot be intercepted and blocked by the WAF mechanism.


Patching SQL Injection Vulnerabilities Using WAF

The number of SQL injections has declined in recent years, however it doesn’t mean they do not exist anymore. SQL injections just become more complicated both to detect and to exploit: good example is our recent RCE and SQL injection via CSRF in Horde Groupware Security advisory. If exploited by experienced hackers, SQL injection usually leads to a total compromise of the vulnerable web application, its database(s), web server and even the related IT environment.

Same as for XSS, default configuration of ModSecurity CRS successfully prevents majority of classic SQL injection exploitation vectors, using the “modsecurity_crs_41_sql_injection_attacks.conf” ruleset.

However, there are situations when CRS doesn’t prevent the SQL injection attack. Let’s have a look on the following example of vulnerable code written in PHP:

login.php
  1. sql(“select userid from users where login='$_REQUEST[login]' and password='$_REQUEST[pass]' and level=$_REQUEST[level])

The vulnerable code has classic SQL injection vulnerability in 3 HTTP parameters. The easiest way to bypass the CRS filter in this case will be to exploit the third parameter (“level”) to bypass the authentication mechanism by the following HTTP request:

http://host/login.php?login=admin&pass=xxx&level=level+or+level=0

However, ModSecurity is quite powerful and flexible WAF (if managed and configured correctly), and if you know vulnerability details - you can easily prevent its exploitation, regardless if CRS is used or not. Below is a custom ruleset that will prevent exploitation of the 3 parameters vulnerable to the SQL injection:

SecRule REQUEST_FILENAME "/login.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1011"
    SecRule ARGS:login|ARGS:pass|REQUEST_COOKIES:login|REQUEST_COOKIES:pass "'" "t:none, t:urlDecodeUni"

SecRule REQUEST_FILENAME "/login.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1012"
    SecRule ARGS:level|REQUEST_COOKIES:level "!^[0-9]+$" "t:none"

The first rule will block single and double quotes in “login” and “pass” HTTP parameters (including cookies, as both authentication variables may also come from cookies). The second rule will block any values, but unsigned integer for “level” HTTP variable.

As you can see it’s not very difficult to create a custom ruleset if you know what exactly you need to patch and where. Moreover, custom rules reduces your dependency on CRS that will quite probably trigger a significant volume of false-positives (by blocking legitimate users) in majority of complicated web applications.


Patching Cross-Site Request Forgery Vulnerabilities Using WAF

In many cases, Cross-Site Request Forgery can lead to a total compromise of a web application. Our recent security advisory RCE and CSRF in osCommerce is a good example when a secure product can get hacked via complicated tiny CSRF. Usually CSRF security flaws occur when new scripts are being added to the existing system in a rush, and developers just forget implementing the existing protection for them.

Some people still tend to think that CSRF protection can only be implemented on the web application side, via sophisticated anti-CRSF mechanism. However, in cases when it’s too complicated or impossible due to a reason (such as inability to alter the vulnerable web application source code), a Web Application Firewall can also help doing so.

ModSecurity CRS implements protection against CSRF attacks via its “modsecurity_crs_43_csrf_protection.conf” ruleset, however it is disabled by default. This ruleset modifies the HTML code of web pages that the web server returns to the user, by appending JavaScript code (modifying DOM structure of the page) adding an anti-CSRF token to all active hyperlinks and web forms of the page. The anti-CSRF token mechanism is completely managed by ModSecurity, and you don’t need to worry about it. However, if applied “as is” without any precaution, in many cases this ruleset may just break the normal functionality of the web application, for this reason this ruleset is deactivated in CRS by default.

In some specific cases, for example in complex AJAX-based web applications, or if the vulnerable script does not accept any HTTP parameters and just performs a specific action (e.g. such deleting all inactive users or cleaning up the cache by calling the script via XML HTTP request) this ruleset will not prevent exploitation of CSRF vulnerability.

Nevertheless, we can easily create a custom anti-CSRF ruleset to prevent exploitation of almost any particular CSRF vulnerability, including the above-mentioned examples. However, we will need profound understanding of the web application design and architecture, as well as a thorough debugging process to make sure that everything works as expected.

This is why for CSRF remediation, with all others equal, it’s always better to patch the application source code directly, instead of implementing WAF remediation. Moreover, if you already have a built-in anti-CSRF mechanism, it will be much faster and less time-consuming to fix the flaw by adding the existing protection to the vulnerable script.

Let’s have a look on a very simple example of web application that has the following PHP script vulnerable to CRSF:

close_publick_access.php
  1. <?
  2.   sql(“update config set value='closed' where name='maintenance_mode');
  3.   echoSystem in maintenance mode now!;
  4.   die();
  5. ?>

ModSecurity CRS will not prevent exploitation of the CRSF in the above-mentioned code, as it’s called directly without any parameters. However, we can create a custom ruleset that will prevent its exploitation using the following anti-CSRF algorithm managed by our WAF:

  1. If “csrf_sessid” cookie is missing, or has a wrong value (different from 40 hex characters), a new “csrf_sessid” cookies is generated for user.
  2. Value of “csrf_sessid_sha” (anti-CSRF token) is generated as a derivate of sha() function of “csrf_sessid” and a secret string (usually located in ModSecurity config).
  3. A new HTTP GET parameter “csrf_sessid_sha” will be appended to all hyperlinks (used in the rule example below), including the link calling the “close_publick_access.php” script.
  4. Each time when accessing “close_publick_access.php”, a value of “csrf_sessid_sha” (from HTTP GET parameter) will be compared to the local value from cookie (sha() of “csrf_sessid” and the secret string). In case of mismatch, the HTTP request will be blocked.

Here is the rule:

mod_security_custom_rules.conf
SecRule &REQUEST_COOKIES:csrf_sessid "@eq 0" "phase:2, t:none, chain, pass, nolog ,id:1041"
    SecRule UNIQUE_ID "^(.*)$" "capture, t:none, t:sha1, t:hexEncode, setvar:TX.csrf_sessid=%{TX.1}, setenv:csrf_sessid=%{TX.1}"

SecRule REQUEST_COOKIES:csrf_sessid "!^([0-9a-f]{40})$" "phase:2, t:none, t:lowercase, chain, pass, nolog ,id:1042"
    SecRule UNIQUE_ID "^(.*)$" "capture, t:none, t:sha1, t:hexEncode, setvar:TX.csrf_sessid=%{TX.1}, setenv:csrf_sessid=%{TX.1}"

SecRule REQUEST_COOKIES:csrf_sessid "^([0-9a-f]{40})$" "phase:2, capture, t:none, t:lowercase, pass, setvar:TX.csrf_sessid=%{TX.1}, id:1043"

SecRule TX:csrf_sessid "^(.*)$" "phase:2, capture, pass, t:none, pass, nolog
,setvar:TX.csrf_sessid_sha=%{TX.1}SecretStringMJ7hi732c, id:1044"
SecRule TX:csrf_sessid_sha "^(.*)$" "phase:2, capture, pass, t:none, t:sha1, t:hexEncode, setvar:TX.csrf_sessid_sha=%{TX.1}, id:1045"

Header set Set-Cookie "csrf_sessid=%{csrf_sessid}e; httponly" env=csrf_sessid

SecContentInjection On

SecRule REQUEST_FILENAME "/admin.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, pass, nolog, id:1046"
    SecRule &TX:csrf_sessid_sha "@eq 1" "t:none, append:'\
        <script>\
            var csrf_sessid_sha = \'%{TX.csrf_sessid_sha}\';\
            var csrf_link=document.getElementById(\'close_publick_access\');\
            if(csrf_link) csrf_link.href+=\'?csrf_sessid_sha=\'+csrf_sessid_sha;\
        </script>'"

SecRule REQUEST_FILENAME "/close_publick_access.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1047"
    SecRule &ARGS_GET:csrf_sessid_sha "!@eq 1" "t:none"

SecRule REQUEST_FILENAME "/close_publick_access.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1048"
    SecRule ARGS_GET:csrf_sessid_sha "!@streq %{TX.csrf_sessid_sha}" "t:none"

As you can see, even complicated CSRF can be blocked by ModSecurity, however it’s far from being simple and easy, and requires a lot of time to implement and test. This is why we strongly recommend using web application side anti-CSRF mechanism to remediate such flows.


Patching Path Traversal Vulnerabilities Using WAF

Being a pretty old type of security vulnerability, Path Traversal still exist and affect numerous modern web applications. Our latest security advisory for a popular e-commerce platform RCE and CSRF in osCmax is good example that such vulnerabilities are still alive.

The Path Traversal family of vulnerabilities includes relative and absolute path traversals, LFI and RFI.

ModSecurity CRS assures pretty good protection against classic path traversal attacks using “modsecurity_crs_40_generic_attacks.conf” and “modsecurity_crs_42_tight_security.conf” rulesets (the second one will only be activated in “paranoid mode”, as it causes too many false-positives by blocking legitimate users).

However, some of the Path Traversal variations, such as Absolute Path Traversal (CWE-36), can successfully bypass ModSecurity CRS.

Let’s have a look on the following example of a vulnerable web script written in PHP:

menu.php
  1. <?
  2. echo file_get_contents(/var/www/document_root/.$_GET['file']);
  3. ?>

If a legitimate usage of the script would expect user to read HTML files from particular directories (such as “/help” or “/docs”) by providing the directory and the file name to the script, the malicious exploitation can be done like this:

http://host/menu.php?file=admin/config.php

ModSecurity CRS will not prevent this exploitation vector, and the attacker will successfully obtain web application configuration file with database credentials and other sensitive information.

Here is a custom rule that will prevent this vulnerability exploitation with a minimum number of false-positives:

mod_security_custom_rules.conf
SecRule REQUEST_FILENAME "/menu.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1051"
    SecRule ARGS_GET:file "!^((help)|(docs))\/[a-z0-9]+\.html$" "t:none, t:lowercase"

The rule will only allow alphanumeric names of “.html” files to be called from “help/” and “docs/” directories.


Patching Open Redirect Vulnerabilities Using WAF

Despite that, Open Redirect is usually considered to be a low-risk vulnerability, in some cases, in pair with Spear Phishing techniques, it can lead to dramatic consequences and total compromise of a web application or its users. ModSecurity CRS is not be able to protect against majority of Open Redirect vulnerabilities in its default configuration.

The easiest way to patch the Open Redirect vulnerability is to fix it directly in the application source code by whitelisting the URLs where users can be redirected as part of legitimate web application’s functionality.

However, if for a reason it is not possible, the vulnerability can be also fixed by a custom WAF rule. For example, if we have the following PHP script vulnerable to Open Redirect vulnerability:

redirect.php
  1. <?
  2. header("Location: http://$_GET[go]");
  3. ?>

ModSecurity CRS will not prevent its exploitation in default configuration. We can setup a proxy website (assuming that we don’t have a possibility to modify or add new scripts on the vulnerable website directly) that will explicitly notify and warn users before redirecting them to the target URL (like Facebook and others do):

mod_security_custom_rules.conf
SecRule REQUEST_FILENAME "/redirect.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, redirect:http://proxysite/go.php?go=%{TX.1}, nolog, id:1051"
    SecRule ARGS_GET:go "^(.*)$" "capture, t:none, t:UrlEncode"

Here is the content of the proxifying script:

http://proxysite/go.php
  1. WARNING! You are going to external, potentially untrusted, URL:
  2. <a href="http://<?=htmlspecialchars($_GET['go']);?>"><?=htmlspecialchars($_GET['go']);?></a>

Like this, our users will be explicitly warned that they leave our website and are redirected elsewhere. But again, if you can do this via the web application modification – it will be much faster and easier.


Patching Insufficient Session Expiration Vulnerability Using WAF

Under certain circumstances, the Insufficient Session Expiration vulnerability can put at risk all web application users by enabling attackers to re-use their identifiers during unlimited period of time. It is a pretty common vulnerability mainly affecting in-house web applications, and very few web developers actually bother fixing it.

ModSecurity CRS doesn’t offer protection against Insufficient Session Expiration vulnerability by default. Moreover, very few people actually know that a Web Application Firewall can be used to prevent exploitation of such vulnerabilities, by maintaining its own database of expired sessions (after user’s logout for example).

Let’s have a look on the example where “sess” cookie is used to store session id, while user logout function just deletes this cookie, instead of properly deleting the session from the web application database:

logout.php
  1. <?
  2. setcookie('sess', '', time() - 3600);
  3. echo “Success logout”;
  4. ?>

In order to prevent exploitation of this vulnerability we will need the following 2 ModSecurity rules and an external script written in Lua programming language:

mod_security_custom_rules.conf
SecRule REQUEST_FILENAME "/logout.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, pass, nolog, id:1061"
    SecRule REQUEST_COOKIES:sess "^[0-9a-f]+$" "t:none,,t:lowercase,exec:/etc/apache2/lua/add_expired_sess.lua"

SecRule REQUEST_COOKIES:sess "@pmFromFile /var/spool/mod_security/sessions_expired.data" "phase:2, t:none, deny, log, id:1062"

/etc/apache2/lua/add_expired_sess.lua
  1. #!/usr/bin/lua
  2. function main()
  3.     local f = io.open("/var/spool/mod_security/sessions_expired.data", "a");
  4.     local sess=m.getvar("REQUEST_COOKIES.sess", "none");
  5.     if (sess ~= nil) then
  6.         io.output(f);
  7.         io.write(sess);
  8.         io.write("\n");
  9.         io.close(f);
  10.     end
  11. end

Here is the algorithm we will use to prevent exploitation of the insufficient session expiration flaw:

  1. Once user accesses the “/logout.php” script, current session ID (that normally shall expire) will be added to “/var/spool/mod_security/sessions_expired.data” file of expired session IDs.
  2. Once any user tries to access any script on the server using the expired session ID, his HTTP request will be blocked by ModSecurity.

However, each new session added to the expired sessions file, requires to reboot the web server (you can make a cron script to reboot the web server every 180 seconds for example). Moreover, such protection significantly charges the web server and consumes quite a lot of server resources. This is why we strongly recommend remediating such security vulnerabilities in web application directly.


Patching Session Fixation Vulnerability Using WAF

Being known since a while already, Session Fixation vulnerability is not very trivial to exploit on practice. Nevertheless, once exploited it can provide attacker unlimited access to victim’s account and personal data.

In simple cases, ModSecurity CRS “modsecurity_crs_40_generic_attacks.conf” ruleset prevents exploitation of Session Fixation vulnerability, however it won’t work for scripts without HTTP parameters, or if mod_rewrite is being used for URL normalization. Moreover, ModSecurity default remediation can simply break complicated AJAX-based web applications.

Nevertheless, almost any custom case of this vulnerability can be remediated by tailored ModSecurity rules. For example, let’s take a vulnerable PHP code where session ID is stored in “secureid” cookie that can be somehow altered by the attacker (e.g. via another vulnerability in web application or via physical access to the victim’s PC).

In order to prevent exploitation of Session Fixation, we will just automatically delete the identification cookie (potentially set or altered by the attacker) each time any user opens the login page of the vulnerable web application:

mod_security_custom_rules.conf
SecRule REQUEST_FILENAME "/login.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, pass, nolog, setenv:reset_cookie=1, id:1081"

Header set Set-Cookie "secureid=;expires=Thu, Jan 01 1970 00:00:00;" env=reset_cookie

However, same as for the Insufficient Session Expiration, we strongly recommend using web application to properly and reliably remediate this type of vulnerability.


Patching Improper Access Control Vulnerability Using WAF

By default, ModSecurity and other Web Application Firewalls cannot prevent exploitation of such complicated vulnerabilities as Improper Access Control, due to complexity of the flaw and necessity to take into consideration the application business logic and design. However, a custom rule can remediate even the most complicated Improper Access Control security flaws.

Let’s image a scenario, when a confidential document “secretreport.pdf” is located on the web server, however access to it shall be restricted only to the authenticated and authorized users of the web application database. Let’s also assume that SQL table ‘users’ has ‘sess’ (session ID) and ‘sessexpire’ (Unix timestamp of automated logout) fields that are normally used to grant or deny access to the confidential document.

To prevent unauthorized access to the confidential document, we will again use Lua scripting and a custom ModSecurity rule to connect to the web application database and verify if current user’s “sess” allows accessing the file:

mod_security_custom_rules.conf
SecRule REQUEST_FILENAME "/secretreport.pdf" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1301"
    SecRuleScript "/etc/apache2/lua/checkaccess.lua"

/etc/apache2/lua/checkaccess.lua
  1. function main()
  2.     luasql = require "luasql.mysql"
  3.     env = assert (luasql.mysql());
  4.     con = assert (env:connect("test","root","", "localhost"));
  5.     local sess=m.getvar("REQUEST_COOKIES.sess", "none");
  6.     if sess == nil then
  7.         return "1 deny";
  8.     end
  9.     if string.len(sess) == 0 then
  10.         return "2 deny";
  11.     end
  12.     cur = assert (con:execute( string.format("select id from users where sess='%s' and sessexpire>=%d", con:escape(sess), os.time())));
  13.     row = cur:fetch ({}, "a");
  14.     if row then
  15.         return nil;
  16.     end
  17.     return "3 deny";
  18. end

You can also use any other scripting language for this purpose, however ModSecurity recommends using Lua for performance reasons. As you can see from the above, in custom configuration your WAF can solve even such complex tasks as user access management.


Patching Missing HttpOnly and Secure Flags on Sensitive Cookies Using WAF

Missing Secure Cookie Flag and HttpOnly Cookie Flag can put your web application users at high risk, if they are using insecure public Wi-Fi or if the application is prone to other vulnerabilities such as XSS enabling attackers stealing their cookies.

For generic and common names of session cookies (e.g. “sessid”, “phpsessid” or “sessionid”) ModSecurity CRS has “modsecurity_crs_55_application_defects.conf” ruleset to set “HttpOnly” and “Secure” flags on these cookies. However, this ruleset is disabled by default.

Moreover, if you have custom names of session, or other sensitive, cookies, the CRS will not protect them. This security weakness can be fixed pretty quickly by following rule that will add “HttpOnly” flag to “MyCustomCookie” cookie:

mod_headers_custom_rules.conf
Header edit Set-Cookie "^((?i:MyCustomCookie=(?i:(?!httponly).)+))$" "$1; HttpOnly"

As you can see from the above, a Web Application Firewall can take care of your cookie management as well, however it’s always better to do this directly in your web application.


Patching Information Disclosure Vulnerability Using WAF

Due to a large number of different variations of Sensitive Information Disclosure vulnerability, it’s almost impossible to prevent it by using a Web Application Firewall, including ModSecurity CRS.

However, if we precisely know where the vulnerability is located and which sensitive data is being disclosed, we can pretty easily mitigate the flaw using a custom rule for ModSecurity.

For example, let’s have a look on the following PHP code, where any error in the script discloses all the environment variables (var_dump($_SERVER)):

functions.php
  1. <?
  2. function doerror()
  3. {
  4.     var_dump($_SERVER);
  5.     die();
  6. }
  7. ?>

The following ModSecurity rule will carefully analyze HTML output that the web server gives to the user, and if inside of the HTML it will detect ["SERVER_SIGNATURE"], ["HTTP_HOST"] or ["DOCUMENT_ROOT"] strings – the HTTP response will be aborted:

mod_security_custom_rules.conf
SecRule RESPONSE_BODY "\[\"SERVER_SIGNATURE\"\]" "phase:4, t:none, chain, block, id:1071"
    SecRule RESPONSE_BODY "\[\"HTTP_HOST\"\]" "t:none, chain"
        SecRule RESPONSE_BODY "\[\"DOCUMENT_ROOT\"\]" "t:none"

Therefore, keep in mind that Web Application Firewall is also capable filtering outgoing requests.


Patching Arbitrary File Upload Vulnerability Using WAF

Arbitrary File Upload vulnerability still exists in many in-house and internal web applications, where web developers create the upload mechanism from scratch and without, or with very basic, security controls. ModSecurity CRS’s protection against malicious file upload is pretty basic, and many variations of the arbitrary file upload vulnerabilities cannot be appropriately blocked using the CRS.

Let’s have a look on the following PHP script vulnerable to arbitrary fie upload:

upload_image.php
  1. <?
  2. if($_FILES['f'] && move_uploaded_file($_FILES['f']['tmp_name'], $_FILES['f']['name']))
  3. {
  4.   echo "Upload success!\r\n<br>";
  5. }
  6. ?>
  7. <form enctype="multipart/form-data" method="POST">
  8.   <input type="hidden" name="MAX_FILE_SIZE" value="10000000">
  9.   <input name="f" type="file">
  10.   <input type="submit">
  11. </form>

Despite simplicity of the vulnerability, ModSecurity CRS will not prevent its exploitation in default configuration. Simple exploitation example below will upload a malicious PHP file bypassing the CRS:

POST /upload_image.php HTTP/1.1
Host: [host]
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/1.0
Accept: text/html
Content-Type: multipart/form-data; boundary=---------------------------248082149912414
Content-Length: 335

-----------------------------248082149912414
Content-Disposition: form-data; name="MAX_FILE_SIZE"

10000000
-----------------------------248082149912414
Content-Disposition: form-data; name="f"; filename="shell.php"
Content-Type: application/x-httpd-php

<? system("id"); ?>
-----------------------------248082149912414--

The file will be successfully uploaded to the server and will execute system “id” command:

http://[host]/shell.php
uid=33(www-data) gid=33(www-data) groups=33(www-data)

The following ModSecurity rule will prevent exploitation of the vulnerability by allowing uploading only gif, jpeg and png images to the server:

mod_security_custom_rules.conf
SecRule REQUEST_FILENAME "/upload_image.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1101"
    SecRule FILES:f "![a-z0-9]\.((jpe?g|png|gif))" "t:none, t:lowercase"

Conclusion

As you can see from the above examples, ModSecurity is very powerful and flexible WAF, however it requires a lot of efforts and time to avoid false-negatives and prevent false-positives.

OWASP ModSecurity Core Rules Set can prevent exploitation of many simple security vulnerabilities, however it does not work in default configuration in case of uncommon or complicated flaws. Moreover, it triggers quite significant amount of false-positives that are unacceptable in production environment, and require thorough debugging.

Therefore, make sure that you don’t entirely rely on your Web Application Firewall, and implement other security controls to protect your web applications.


High-Tech Bridge Security Research Team regularly writes about web and mobile application security, privacy, Machine Learning and AI.

User Comments
Add Comment
1 responses to "Patching Complex Web Vulnerabilities Using ModSecurity WAF"
Jonathan C. 2016-12-01 23:25:55 UTC Comment this
If properly configured and managed, I feel comfortable having my team at
http://www.avantgardepartners.com manage my Imperva WAF as my first
and last line of defense for my web applications. They have a system for
constantly monitor for false positives as well as vulnerabilities to tweak
WAF configurations for optimal performance.
↑ Back to Top

High-Tech Bridge on Facebook High-Tech Bridge on Twitter High-Tech Bridge on LinkedIn High-Tech Bridge RSS Feeds Send by Email
Share