ModSecurity is an open-source WAF engine maintained by Trustwave. This blog post discusses an input interpretation bug in ModSecurity v3 related to URI fragments that was identified during a recent internal security review. The main consequence of the bug is that some ModSecurity rules could be evaded by a malicious actor. The bug has been addressed with a fix in v3.0.5. ModSecurity v2 is not affected.
An HTTP request line can include an optional URI fragment. Browsers do not send the fragment information to the server and instead use it for client-side processing only. For example, a browser may use the fragment information to jump to some heading within a document. However, if a malicious actor were to send a URI fragment using a tool that allows it (such as BurpSuite), it would be handled incorrectly by ModSecurity 3.0.0-3.0.4 in a possibly security-relevant way.
For example, with a request like the following sent to nginx with ModSecurity v3:
GET /content/mypage.php?abc=def#ghi
Server PHP code like $_GET['abc'] will yield ‘def’ as the value. But ModSecurity will take everything to the right of the ‘=’ and record the value of that query argument as the seven-character string ‘def#ghi’.
This could be used to evade some ModSecurity rules, such as:
SecRule ARGS: '/abc/' "@streq def" ...
Not all ModSecurity rules would be susceptible to bypass due to this problem. Because URI fragments can appear only in the request line, query argument values are what are chiefly affected. In other words, rules that inspect ARGS or ARGS_GET are the main area of concern.
Most types of rules will not be impacted even if they are inspecting ARGS or ARGS_GET. Because inclusion of the URI fragment affects how a query argument value terminates (as perceived by ModSecurity), rules that test exact values (such as @streq) or string endings (such as a regular expression with the end-anchor '$') would be susceptible. Rules that look for string prefixes, substrings, non-anchored regex, etc. would not be susceptible.
Taking advantage of this bypass mechanism would typically require detailed knowledge of the rule against which evasion is being attempted. Without sufficient knowledge – either direct or deduced – it would be difficult to successfully target a susceptible rule. Some generic rule sets are open source and hence available for inspection. Fortunately, these are less likely to have a large proportion of rules testing exact values for query arguments.
While upgrading to an updated version of the software is good advice, some users may find that impractical on short notice. Fortunately, there is an alternative that should be effective in most deployments.
Reject requests containing a URI fragment
Since legitimate clients do not send URI fragments in HTTP Requests, simple mitigation is to inspect for the ‘#’ in each undecoded request line. For example:
SecRule REQUEST_URI_RAW "@contains #" "id:1,phase:1,deny,status:403,msg:'URI Fragment in request line'"
A ‘#’ may be valid in the request line if it is encoded. For that reason, the above rule inspects REQUEST_URI_RAW , and avoids the use of transformations like t:urlDecode or t:urlDecodeUni.