Closed
Description
Describe the bug
I saw following owasp crs rules that checks that parameters are not duplicated
https://github.com/SpiderLabs/owasp-modsecurity-crs/blob/v3.3/dev/rules/REQUEST-921-PROTOCOL-ATTACK.conf#L294.
The problem is that %{MATCHED_VAR_NAME} is replaced with ARGS_NAME only (doesn't contain real name of parameter).
[1638301508] [/?a=2&b=3] [4] (Rule: 921170) Executing operator "Rx" with param "." against ARGS_NAMES.
[1638301508] [/?a=2&b=3] [9] Target value: "a" (Variable: ARGS_NAMES)
[1638301508] [/?a=2&b=3] [9] Matched vars updated.
[1638301508] [/?a=2&b=3] [4] Running [independent] (non-disruptive) action: setvar
[1638301508] [/?a=2&b=3] [8] Saving variable: TX:paramcounter_ARGS_NAMES with value: 1
[1638301508] [/?a=2&b=3] [9] Target value: "b" (Variable: ARGS_NAMES)
[1638301508] [/?a=2&b=3] [9] Matched vars updated.
[1638301508] [/?a=2&b=3] [4] Running [independent] (non-disruptive) action: setvar
[1638301508] [/?a=2&b=3] [8] Saving variable: TX:paramcounter_ARGS_NAMES with value: 2
[1638301508] [/?a=2&b=3] [4] Rule returned 1.
Logs and dumps
Output of:
- DebugLogs (level 9)
[1638301508] [] [4] Starting phase CONNECTION. (SecRules 0)
[1638301508] [] [9] This phase consists of 0 rule(s).
[1638301508] [] [4] Starting phase URI. (SecRules 0 + 1/2)
[1638301508] [/?a=2&b=3] [4] Adding request argument (GET): name "a", value "2"
[1638301508] [/?a=2&b=3] [4] Adding request argument (GET): name "b", value "3"
[1638301508] [/?a=2&b=3] [4] Starting phase REQUEST_HEADERS. (SecRules 1)
[1638301508] [/?a=2&b=3] [9] This phase consists of 0 rule(s).
[1638301508] [/?a=2&b=3] [4] Starting phase REQUEST_BODY. (SecRules 2)
[1638301508] [/?a=2&b=3] [9] This phase consists of 2 rule(s).
[1638301508] [/?a=2&b=3] [4] (Rule: 921170) Executing operator "Rx" with param "." against ARGS_NAMES.
[1638301508] [/?a=2&b=3] [9] Target value: "a" (Variable: ARGS_NAMES)
[1638301508] [/?a=2&b=3] [9] Matched vars updated.
[1638301508] [/?a=2&b=3] [4] Running [independent] (non-disruptive) action: setvar
[1638301508] [/?a=2&b=3] [8] Saving variable: TX:paramcounter_ARGS_NAMES with value: 1
[1638301508] [/?a=2&b=3] [9] Target value: "b" (Variable: ARGS_NAMES)
[1638301508] [/?a=2&b=3] [9] Matched vars updated.
[1638301508] [/?a=2&b=3] [4] Running [independent] (non-disruptive) action: setvar
[1638301508] [/?a=2&b=3] [8] Saving variable: TX:paramcounter_ARGS_NAMES with value: 2
[1638301508] [/?a=2&b=3] [4] Rule returned 1.
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: application-multi
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: language-multi
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: platform-multi
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: attack-protocol
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: paranoia-level/3
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: CAPEC-460
[1638301508] [/?a=2&b=3] [9] Running action: log
[1638301508] [/?a=2&b=3] [9] Saving transaction to logs
[1638301508] [/?a=2&b=3] [4] Running (disruptive) action: pass.
[1638301508] [/?a=2&b=3] [8] Running action pass
[1638301508] [/?a=2&b=3] [4] (Rule: 921180) Executing operator "Gt" with param "1" against TX:regex(paramcounter_.*).
[1638301508] [/?a=2&b=3] [9] Target value: "2" (Variable: TX:paramcounter_ARGS_NAMES)
[1638301508] [/?a=2&b=3] [9] Matched vars updated.
[1638301508] [/?a=2&b=3] [4] Rule returned 1.
[1638301508] [/?a=2&b=3] [4] Executing chained rule.
[1638301508] [/?a=2&b=3] [4] (Rule: 0) Executing operator "Rx" with param "TX:paramcounter_(.*)" against MATCHED_VARS_NAMES.
[1638301508] [/?a=2&b=3] [9] Target value: "ARGS_NAMES" (Variable: MATCHED_VARS_NAMES:ARGS_NAMES)
[1638301508] [/?a=2&b=3] [9] Target value: "ARGS_NAMES" (Variable: MATCHED_VARS_NAMES:ARGS_NAMES)
[1638301508] [/?a=2&b=3] [9] Target value: "TX:paramcounter_ARGS_NAMES" (Variable: MATCHED_VARS_NAMES:TX:paramcounter_ARGS_NAMES)
[1638301508] [/?a=2&b=3] [7] Added regex subexpression TX.0: TX:paramcounter_ARGS_NAMES
[1638301508] [/?a=2&b=3] [7] Added regex subexpression TX.1: ARGS_NAMES
[1638301508] [/?a=2&b=3] [9] Matched vars updated.
[1638301508] [/?a=2&b=3] [4] Running [independent] (non-disruptive) action: setvar
[1638301508] [/?a=2&b=3] [8] Saving variable: TX:http_violation_score with value: 0
[1638301508] [/?a=2&b=3] [4] Running [independent] (non-disruptive) action: setvar
[1638301508] [/?a=2&b=3] [8] Saving variable: TX:anomaly_score_pl3 with value: 0
[1638301508] [/?a=2&b=3] [4] Rule returned 1.
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: application-multi
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: language-multi
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: platform-multi
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: attack-protocol
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: OWASP_CRS
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: OWASP_CRS/WEB_ATTACK/HTTP_PARAMETER_POLLUTION
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: paranoia-level/3
[1638301508] [/?a=2&b=3] [4] Running (non-disruptive) action: tag
[1638301508] [/?a=2&b=3] [9] Rule tag: CAPEC-460
[1638301508] [/?a=2&b=3] [9] This rule severity is: 2 current transaction is: 255
[1638301508] [/?a=2&b=3] [9] Saving msg: HTTP Parameter Pollution (ARGS_NAMES)
[1638301508] [/?a=2&b=3] [4] Running (disruptive) action: pass.
[1638301508] [/?a=2&b=3] [8] Running action pass
[1638301508] [/?a=2&b=3] [4] Starting phase RESPONSE_HEADERS. (SecRules 3)
[1638301508] [/?a=2&b=3] [9] This phase consists of 0 rule(s).
[1638301508] [/?a=2&b=3] [9] Appending response body: 139 bytes. Limit set to: 10000000.000000
[1638301508] [/?a=2&b=3] [9] Appending response body: 139 bytes. Limit set to: 10000000.000000
[1638301508] [/?a=2&b=3] [4] Starting phase RESPONSE_BODY. (SecRules 4)
[1638301508] [/?a=2&b=3] [9] This phase consists of 0 rule(s).
[1638301508] [/?a=2&b=3] [4] Starting phase LOGGING. (SecRules 5)
[1638301508] [/?a=2&b=3] [9] This phase consists of 0 rule(s).
[1638301508] [/?a=2&b=3] [8] Checking if this request is suitable to be saved as an audit log.
[1638301508] [/?a=2&b=3] [8] Checking if this request is relevant to be part of the audit logs.
[1638301508] [/?a=2&b=3] [5] Saving this request as part of the audit logs.
[1638301508] [/?a=2&b=3] [8] Request was relevant to be saved. Parts: 5990
- AuditLogs
---jeVwIAEc---A--
[30/Nov/2021:19:45:08 +0000] 1638301508 127.0.0.1 34660 127.0.0.1 4321
---jeVwIAEc---B--
GET /?a=2&b=3 HTTP/1.1
Host: localhost:4321
User-Agent: curl/7.61.1
Accept: */*
---jeVwIAEc---E--
<!DOCTYPE html>\x0a<html lang="en">\x0a<head>\x0a<meta charset="utf-8">\x0a<title>Error</title>\x0a</head>\x0a<body>\x0a<pre>Cannot GET /</pre>\x0a</body>\x0a</html>\x0a
---jeVwIAEc---F--
HTTP/1.1 404
Server: nginx
Date: Tue, 30 Nov 2021 19:45:08 GMT
Content-Length: 139
Content-Type: text/html; charset=utf-8
X-Content-Type-Options: nosniff
Connection: keep-alive
X-Powered-By: Express
Content-Security-Policy: default-src 'none'
---jeVwIAEc---H--
ModSecurity: Warning. Matched "Operator `Rx' with parameter `.' against variable `ARGS_NAMES' (Value: `b' ) [file "/usr/local/voipnow/admin/conf/modsectestwaf.conf"] [line "16"] [id "921170"] [rev ""] [msg ""] [data ""] [severity "0"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/3"] [tag "CAPEC-460"] [hostname "127.0.0.1"] [uri "/"] [unique_id "1638301508"] [ref "o0,1v6,1o0,1v10,1"]
ModSecurity: Warning. Matched "Operator `Rx' with parameter `TX:paramcounter_(.*)' against variable `MATCHED_VARS_NAMES:TX:paramcounter_ARGS_NAMES' (Value: `TX:paramcounter_ARGS_NAMES' ) [file "/usr/local/voipnow/admin/conf/modsectestwaf.conf"] [line "30"] [id "921180"] [rev ""] [msg "HTTP Parameter Pollution (ARGS_NAMES)"] [data "Matched Data: TX:paramcounter_ARGS_NAMES found within MATCHED_VARS_NAMES:TX:paramcounter_ARGS_NAMES: TX:paramcounter_ARGS_NAMES"] [severity "2"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS"] [tag "OWASP_CRS/WEB_ATTACK/HTTP_PARAMETER_POLLUTION"] [tag "paranoia-level/3"] [tag "CAPEC-460"] [hostname "127.0.0.1"] [uri "/"] [unique_id "1638301508"] [ref "o0,26o16,10v80,26"]
---jeVwIAEc---I--
---jeVwIAEc---J--
---jeVwIAEc---Z--
- Error logs
2021/11/30 19:45:08 [info] 2438231#2438231: *3 ModSecurity: Warning. Matched "Operator `Rx' with parameter `.' against variable `ARGS_NAMES' (Value: `b' ) [file "/usr/local/voipnow/admin/conf/modsectestwaf.conf"] [line "16"] [id "921170"] [rev ""] [msg ""] [data ""] [severity "0"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/3"] [tag "CAPEC-460"] [hostname "127.0.0.1"] [uri "/"] [unique_id "1638301508"] [ref "o0,1v6,1o0,1v10,1"], client: 127.0.0.1, server: localhost, request: "GET /?a=2&b=3 HTTP/1.1", host: "localhost:4321"
2021/11/30 19:45:08 [info] 2438231#2438231: *3 ModSecurity: Warning. Matched "Operator `Rx' with parameter `TX:paramcounter_(.*)' against variable `MATCHED_VARS_NAMES:TX:paramcounter_ARGS_NAMES' (Value: `TX:paramcounter_ARGS_NAMES' ) [file "/usr/local/voipnow/admin/conf/modsectestwaf.conf"] [line "30"] [id "921180"] [rev ""] [msg "HTTP Parameter Pollution (ARGS_NAMES)"] [data "Matched Data: TX:paramcounter_ARGS_NAMES found within MATCHED_VARS_NAMES:TX:paramcounter_ARGS_NAMES: TX:paramcounter_ARGS_NAMES"] [severity "2"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS"] [tag "OWASP_CRS/WEB_ATTACK/HTTP_PARAMETER_POLLUTION"] [tag "paranoia-level/3"] [tag "CAPEC-460"] [hostname "127.0.0.1"] [uri "/"] [unique_id "1638301508"] [ref "o0,26o16,10v80,26"], client: 127.0.0.1, server: localhost, request: "GET /?a=2&b=3 HTTP/1.1", host: "localhost:4321"
To Reproduce
Nginx conf:
server {
server_name localhost;
listen 127.0.0.1:4321;
modsecurity on;
modsecurity_rules_file /etc/nginx/conf/modsectestwaf.conf;
error_page 500 502 503 504 /50x.html;
location / {
proxy_pass http://localhost:3000;
}
}
modsectestwaf.conf:
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 64000
SecResponseBodyAccess On
SecResponseBodyLimit 10000000
SecDebugLog /usr/local/voipnow/admin/log/modsectestwaf_debug.log
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogType Serial
SecAuditLog /usr/local/voipnow/admin/log/modsectestwaf_audit.log
SecAuditLogParts ABEFHIJZ
SecRule ARGS_NAMES "@rx ." \
"id:921170,\
phase:2,\
pass,\
log,\
tag:'application-multi',\
tag:'language-multi',\
tag:'platform-multi',\
tag:'attack-protocol',\
tag:'paranoia-level/3',\
tag:'CAPEC-460',\
ver:'OWASP_CRS/3.2.0',\
setvar:'TX.paramcounter_%{MATCHED_VAR_NAME}=+1'"
SecRule TX:/paramcounter_.*/ "@gt 1" \
"id:921180,\
phase:2,\
pass,\
msg:'HTTP Parameter Pollution (%{TX.1})',\
logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\
tag:'application-multi',\
tag:'language-multi',\
tag:'platform-multi',\
tag:'attack-protocol',\
tag:'OWASP_CRS',\
tag:'OWASP_CRS/WEB_ATTACK/HTTP_PARAMETER_POLLUTION',\
tag:'paranoia-level/3',\
tag:'CAPEC-460',\
ver:'OWASP_CRS/3.2.0',\
severity:'CRITICAL',\
chain"
SecRule MATCHED_VARS_NAMES "@rx TX:paramcounter_(.*)" \
"capture,\
setvar:'tx.http_violation_score=+%{tx.critical_anomaly_score}',\
setvar:'tx.anomaly_score_pl3=+%{tx.critical_anomaly_score}'"
A curl command line that mimics the original request and reproduces the problem. Or a ModSecurity v3 test case.
curl "http://localhost:4321?a=2&b=3"
Expected behavior
MATCHED_VAR_NAME to be replaced with one value for each parameter. In my example: ARG_NAMES:a and ARG_NAMES:b
Server (please complete the following information):
- ModSecurity version (and connector): modsecurity-3.0.6 with modsecurity-nginx-v1.0.2
- WebServer: nginx 1.21.2
- OS (and distro): CentOS Linux release 8.5.2111
Rule Set (please complete the following information):
- Running any public or commercial rule set? Got rule from Owasp CRS
- What is the version number? v3.2.0