owasp-modsecurity / ModSecurity

ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx. It has a robust event-based programming language which provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring, logging and real-time analysis.
https://www.modsecurity.org
Apache License 2.0
7.7k stars 1.54k forks source link

libmodsecurity3: SecAction can't be disabled via ctl action #3053

Open EsadCetiner opened 3 months ago

EsadCetiner commented 3 months ago

Describe the bug

In libmodsecurity3, SecAction can't be disabled via a ctl action like with SecRules. This issue isn't present in ModSecurity2.

Logs and dumps

N/A

To Reproduce

Steps to reproduce the behavior:

  1. Have a fresh Ubuntu 22.04 server setup, this bug was a bit tricky to reproduce when I was opening this issue.
  2. ModSecurity was tested and installed using digitalwave's ModSecurity repository and apt install nginx-extras libnginx-mod-http-modsecurity
  3. I installed this version of CRSv4 RC-2 and ModSecurity.conf with the SecRuleEngine directive set to on, but it shouldn't matter what rulesets are used.
  4. Create this test conf file, but make sure to load it before any blocking rules (i.e Include /etc/nginx/modsecurity/coreruleset/rules/*.conf)
    
    SecRule REQUEST_HEADERS:Host "!@streq example.com" "id:1,phase:1,pass,t:none,nolog,ctl:ruleRemoveById=2"

SecAction \ "id:2,phase:1,pass,t:none,nolog,ctl:ruleRemoveByTag=OWASP_CRS"

5. restart nginx then try to send an attack payload, rule 2 should be disabled yet it still disables OWASP_CRS ``curl 127.0.0.1?exec/bin/bash``
6. If you modify the test file to this, then rule 2 is disabled and everything works as expected:

SecRule REQUEST_HEADERS:Host "!@streq example.com" "id:1,phase:1,pass,t:none,nolog,ctl:ruleRemoveById=2"

SecRule REQUEST_FILENAME "@unconditionalMatch" \ "id:2,phase:1,pass,t:none,nolog,ctl:ruleRemoveByTag=OWASP_CRS"


**Expected behavior**

SecActions rules should be disableable via a ctl action, just like SecRules.

**Server:**
 - ModSecurity version (and connector): libmodsecurity 3.0.12 and ModSec-Nginx 1.0.3
 - WebServer: Nginx 1.18.0
 - OS: Ubuntu 22.04

**Rule Set:**
 - [CRSv4 RC-2](https://github.com/coreruleset/coreruleset/commit/f987e297113545b53d2479a58553e520a3145947)

**Additional context**

This issue currently affects some CRS plugins such as Nextcloud or WordPress, if you wish to use them in a reverse proxy and want to selectively enable/disable the plugins for certain domains.
airween commented 3 months ago

Hi @EsadCetiner,

many thanks for your detailed answer here too. I'm sorry that I didn't see the original report, now I wrote an answer under that issue.

I keep this issue open while it won't be clear that this behavior is really a bug or your config has some mistake. Or feel free to close it if you think that's not a ModSecurity issue.

Thanks again.

EsadCetiner commented 3 months ago

Thank you for the reply @airween, I wasn't able to respond earlier but I have time now.

I didn't use the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf file for the rules I provided, I completely forgot it's a thing. I re-tested by placing my rules in there, but I'm still observing the same behavior. Sending curl http://127.0.0.1?exec=/bin/bash gives me these results:

Request is blocked with 403, as expected when using this code

SecRule REQUEST_HEADERS:Host "!@streq example.com" "id:1,phase:1,pass,t:none,nolog,ctl:ruleRemoveById=2"

SecRule REQUEST_FILENAME "@unconditionalMatch" \
  "id:2,phase:1,pass,t:none,nolog,ctl:ruleRemoveByTag=OWASP_CRS"

Request is allowed with 200 when using this code, which is not expected behavior.

SecRule REQUEST_HEADERS:Host "!@streq example.com" "id:1,phase:1,pass,t:none,nolog,ctl:ruleRemoveById=2"

SecAction \
  "id:2,phase:1,pass,t:none,nolog,ctl:ruleRemoveByTag=OWASP_CRS"

This is how I'm including the files into ModSecurity, in case your doing it a bit different to me:

Include /etc/nginx/modsecurity/coreruleset/crs-setup.conf

Include /etc/nginx/modsecurity/coreruleset/plugins/*-config.conf
Include /etc/nginx/modsecurity/coreruleset/plugins/*-before.conf

Include /etc/nginx/modsecurity/modsecurity.conf

Include /etc/nginx/modsecurity/coreruleset/rules/*.conf

Include /etc/nginx/modsecurity/coreruleset/plugins/*-after.conf

SecAuditLog /var/log/modsec_audit.log

nginx.conf:

        modsecurity on;
        modsecurity_rules_file /etc/nginx/modsecurity/main.conf;

And I have SecRuleEngine set to on.

My test environment is minimal, so I'm not sure what kind of a config issue it could be.

This is my debug log (set to 4) when trying to disable a SecAction. all that stood out to me was this, which as I understand it, means that rule 2 wasn't disabled.

[170748352988.757381] [/?exec=/bin/bash] [4] (Rule: 1) Executing operator "StrEq" with param "example.com" against REQUEST_HEADERS:Host.
[170748352988.757381] [/?exec=/bin/bash] [4] Rule returned 1.
[170748352988.757381] [/?exec=/bin/bash] [4] Running (disruptive)     action: pass.
[170748352988.757381] [/?exec=/bin/bash] [4] (Rule: 2) Executing unconditional rule...
[170748352988.757381] [/?exec=/bin/bash] [4] Running (disruptive)     action: pass.

debug-secaction.log

And this is when I'm disabling a SecRule, where everything is working as expected. debug_secrule.log

If your still having trouble reproducing, I can try to give you a test environment for you to download where the issue occurs.

airween commented 3 months ago

Hi @EsadCetiner,

thanks again your detailed report - now I see the problem. Meantime we chatted about this issue and we convinced that it works on Apache (mod_security2).

I created a regression test file, anyone can try this issue.

I think we should change the behavior of the engine that it should disable SecAction items too, not just SecRule's.

Any other opinions are welcome.