Search code examples
apachemod-rewriteowaspmod-security

Updating Apache Mod Security Core Rule OWASP Rule 950120 to allow URLs in one specific input


There is an input field in my form where users can enter url addresses. I know how to update the target rule to prevent false alarms:

SecRuleRemoveById 950120 !ARGS:urlField

But that won't apply to rule 950120: Possible Remote File Inclusion (RFI) Attack: Off-Domain Reference/Link. The error doesn't point out what argument that violates the rule. It just gives the message:

Message: Access denied with code 403 (phase 2). 
Match of "beginsWith %{request_headers.host}" against "TX:1" required. 
[file "/etc/httpd/crs-tecmint/owasp-modsecurity-crs/base_rules/modsecurity_crs_40_generic_attacks.conf"] 
[line "163"] [id "950120"] [rev "3"] 
[msg "Possible Remote File Inclusion (RFI) Attack: Off-Domain Reference/Link"] 
[data "Matched Data: http://asite.com.hk/live found within TX:1: asite.com.hk/live"] 
[severity "CRITICAL"] [ver "OWASP_CRS/2.2.9"] 
[maturity "9"] [accuracy "9"] 
[tag "OWASP_CRS/WEB_ATTACK/RFI"]
Action: Intercepted (phase 2)

Without the violating argument in the message, does it mean SecRuleRemoveById won't work with this rule? How can I update it without completely removing this rule?


Solution

  • The rule can be seen here: https://raw.githubusercontent.com/SpiderLabs/owasp-modsecurity-crs/master/base_rules/modsecurity_crs_40_generic_attacks.conf and I've also copied it below:

    SecRule ARGS "^(?:ht|f)tps?://(.*)$" \
        "chain,phase:2,rev:'3',ver:'OWASP_CRS/2.2.9',maturity:'9',accuracy:'9',t:none,capture,ctl:auditLogParts=+E,block,msg:'Possible Remote File Inclusion (RFI) Attack: Off-Domain Reference/Link',logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',id:'950120',severity:'2',tag:'OWASP_CRS/WEB_ATTACK/RFI'"
       SecRule TX:1 "!@beginsWith %{request_headers.host}" "setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-OWASP_CRS/WEB_ATTACK/RFI-%{matched_var_name}=%{tx.1}"
    

    So this is a chained rule in two parts. The first rule checks if an argument starts with either http:// or https:// or ftp:// or ftps://. As it uses brackets in the regexpr pattern match it also sets the TX variables. TX:0 is set to either ht or ft, and TX:1 is set to the address after the protocol.

    The next rule in the chain, the checks if TX:1 does not begins with the host given in the request header (which should be the host of this server). If so, it's an offsite URL and it blocks.

    So your fix:

    SecRuleRemoveById 950120 !ARGS:urlField
    

    will not work as 1) if think you are intending to update the rule and not remove it so you have the wrong command and 2) urlField is presumably an ARG_NAME rather than an ARG value. So try the following:

    SecRuleUpdateTargetByID 950120 !ARG_NAMES:urlField
    

    or alternatively you could selectively remove this rule, with another rule, for example to only turn off the rule for your /post/location URL, use the following:

    SecRule REQUEST_URI /post/location/ "id:1000,phase:2,log,ctrl:ruleRemoveByID=950120"
    

    Now, to be honest, I think rule 950120 is a bit restrictive, and overkill for most sites and will potentially cause a lot of false positives, so you could just turn it off completely:

    SecRuleRemoveById 950120