Stephen S. Stephen S. - 4 months ago 18
Apache Configuration Question

ModSecurity: Whitelist Arguments By Value

I'm trying to set up a ModSecurity whitelist for arguments with an unknown name, but matching a value. For example, I want to whitelist any parameter that is a timestamp (e.g.

timestamp=2016-01-01 00:00:00
). Currently, this triggers rule
981173 (Restricted SQL Character Anomaly Detection Alert - Total # of special characters exceeded)


The following will work, but will skip checks on all parameters if at least one matches, so it doesn't catch the
badvalue
parameter in
https://www.example.com/?timestamp=2016-01-01+00:00:00&badvalue=2016-01-01+00:00:00:00
.

SecRule ARGS "@rx ^2[0-9]{3}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]$" \
"id:'99001', phase:1, nolog, pass, t:none, \
ctl:ruleRemoveTargetByTag=OWASP_CRS/WEB_ATTACK/SQL_INJECTION;ARGS"


The following works if I hardcode the parameter name.

SecRule ARGS:timestamp "@rx ^2[0-9]{3}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]$" \
"id:'99001', phase:1, nolog, pass, t:none, \
ctl:ruleRemoveTargetByTag=OWASP_CRS/WEB_ATTACK/SQL_INJECTION;ARGS:timestamp"


I've tried the following, but they haven't worked.

SecRule ARGS "@rx ^2[0-9]{3}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]$" \
"id:'99001', phase:1, nolog, pass, t:none, \
ctl:ruleRemoveTargetByTag=OWASP_CRS/WEB_ATTACK/SQL_INJECTION;/%{MATCHED_VAR_NAME}/"

SecRule ARGS "@rx ^2[0-9]{3}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]$" \
"id:'99001', phase:1, nolog, pass, t:none, \
ctl:ruleRemoveTargetByTag=OWASP_CRS/WEB_ATTACK/SQL_INJECTION;MATCHED_VAR_NAME"


Is this possible with ModSecurity? Is there a way to use
MATCHED_VAR_NAME
for this use case? I would rather not have to add a rule for every argument name that might contain a timestamp.

Answer

Unfortunately, it is currently not possible to use Macro Expansion within the ctl action argument.

As evidence consider the following examples:

SecRule ARGS "@contains bob" "id:1,t:none,pass,ctl:ruleRemoveTargetById=2;ARGS:x"
SecRule ARGS "@contains hello" "id:2,deny,status:403"

When providing the following request: 'http://localhost/?x=bobhello' we will see the following in the debug log when evaluating the second rule

[04/Aug/2016:00:44:07 --0400] [localhost/sid#55e47aa583e0][rid#55e47ad7cb10][/][4] Recipe: Invoking rule 55e47ab14638; [file "/etc/httpd/modsecurity.d/includeOWASP.conf"] [line "12"] [id "2"]. [04/Aug/2016:00:44:07 --0400] [localhost/sid#55e47aa583e0][rid#55e47ad7cb10][/][5] Rule 55e47ab14638: SecRule "ARGS" "@contains hello" "phase:2,log,auditlog,id:2,deny,status:403" [04/Aug/2016:00:44:07 --0400] [localhost/sid#55e47aa583e0][rid#55e47ad7cb10][/][4] Transformation completed in 0 usec. [04/Aug/2016:00:44:07 --0400] [localhost/sid#55e47aa583e0][rid#55e47ad7cb10][/][9] fetch_target_exception: Found exception target list [ARGS:x] for rule id 2 [04/Aug/2016:00:44:07 --0400] [localhost/sid#55e47aa583e0][rid#55e47ad7cb10][/][9] fetch_target_exception: Target ARGS:x will not be processed. [04/Aug/2016:00:44:07 --0400] [localhost/sid#55e47aa583e0][rid#55e47ad7cb10][/][4] Executing operator "contains" with param "hello" against ARGS:x skipped. [04/Aug/2016:00:44:07 --0400] [localhost/sid#55e47aa583e0][rid#55e47ad7cb10][/][4] Rule returned 0.

However, When we provide the same request ('http://localhost/?x=bobhello') While have Macro Expansion within our ctl action (as follows):

SecRule ARGS "@contains bob" "id:1,t:none,pass,ctl:ruleRemoveTargetById=2;%{MATCHED_VAR_NAME}"
SecRule ARGS "@contains hello" "id:2,deny,status:403"

Our Debug log will appear as follows:

[04/Aug/2016:00:44:41 --0400] [localhost/sid#559f82a0b3e0][rid#559f82d2fb50][/][5] Rule 559f82ac76e8: SecRule "ARGS" "@contains hello" "phase:2,log,auditlog,id:2,deny,status:403" [04/Aug/2016:00:44:41 --0400] [localhost/sid#559f82a0b3e0][rid#559f82d2fb50][/][4] Transformation completed in 0 usec. [04/Aug/2016:00:44:41 --0400] [localhost/sid#559f82a0b3e0][rid#559f82d2fb50][/][9] fetch_target_exception: Found exception target list [%{MATCHED_VAR_NAME}] for rule id 2 [04/Aug/2016:00:44:41 --0400] [localhost/sid#559f82a0b3e0][rid#559f82d2fb50][/][4] Executing operator "contains" with param "hello" against ARGS:x. [04/Aug/2016:00:44:41 --0400] [localhost/sid#559f82a0b3e0][rid#559f82d2fb50][/][9] Target value: "bobhello" [04/Aug/2016:00:44:41 --0400] [localhost/sid#559f82a0b3e0][rid#559f82d2fb50][/][4] Operator completed in 2 usec. [04/Aug/2016:00:44:41 --0400] [localhost/sid#559f82a0b3e0][rid#559f82d2fb50][/][4] Rule returned 1.

I cannot think of a method of accomplishing this goal without excessive overhead. At this point the best solution would likely be to manually whitelist each offending argument.