Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False positive on interactions with GoToSocial #3497

Open
kvibber opened this issue Jan 19, 2024 · 10 comments
Open

False positive on interactions with GoToSocial #3497

kvibber opened this issue Jan 19, 2024 · 10 comments

Comments

@kvibber
Copy link

kvibber commented Jan 19, 2024

Description

GoToSocial is an ActivityPub-based social networking server similar to Mastodon, but designed for smaller use cases (ex. just a few people per server).

Today I found that I could not reply from a GoToSocial account to a WordPress post on a blog using the ActivityPub plugin if the blog is protected by mod_security with the core rules. Instead it triggered rules 920600, 920470 and 920420 in REQUEST-920-PROTOCOL-ENFORCEMENT.conf, enough to block the request.

Disabling mod_security allowed the reply to go through. I reported it as GoToSocial Issue #2453.

@mirabilos pointed out that two of the rules do not allow a profile parameter in the Content-Type or Accept headers. GoToSocial uses this parameter for content negotiation.

Additionally, the third rule rejected the media type application/ld+json.

It looks like adding application/ld+json to tx.allowed_request_content_type and updating the relevant regexes to allow ; profile="____" should resolve the false positive.

Logs

[Thu Jan 18 10:14:45.408052 2024] [:error] [pid 206460:tid 140077923862272] [client __IPADDRESS__:56886] [client __IPADDRESS__] ModSecurity: Warning. Match of "rx ^(?:(?:\\\\*|[^\\"(),\\\\/:;<=>?![\\\\x5c\\\\]{}]+)\\\\/(?:\\\\*|[^\\"(),\\\\/:;<=>?![\\\\x5c\\\\]{}]+))(?:\\\\s*+;\\\\s*+(?:(?:charset\\\\s*+=\\\\s*+(?:\\"?(?:iso-8859-15?|windows-1252|utf-8)\\\\b\\"?))|(?:(?:c(?:h(?:a(?:r(?:s(?:e[^t\\"(),\\\\/:;<=>?![\\\\x5c\\\\]{}]|[^e\\"(),/:;<=>?![\\\\x5c ..." against "REQUEST_HEADERS:Accept" required. [file "/etc/modsecurity/mod_sec3_CRS/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "1162"] [id "920600"] [msg "Illegal Accept header: charset parameter"] [data "application/ld+json; profile=\\x22https://www.w3.org/ns/activitystreams\\x22,application/activity+json"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.4"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [hostname "__hostname__"] [uri "__PATH_TO_POST_"] [unique_id "ZalqlTOpiqLEOI9mTEbMkAAAAAE"]

[Thu Jan 18 10:14:45.408233 2024] [:error] [pid 206460:tid 140077848327936] [client __IPADDRESS__:56886] [client __IPADDRESS__] ModSecurity: Warning. Match of "rx ^[\\\\w/.+-]+(?:\\\\s?;\\\\s?(?:action|boundary|charset|type|start(?:-info)?)\\\\s?=\\\\s?['\\"\\\\w.()+,/:=?<>@-]+)*$" against "REQUEST_HEADERS:Content-Type" required. [file "/etc/modsecurity/mod_sec3_CRS/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "933"] [id "920470"] [msg "Illegal Content-Type header"] [data "application/ld+json; profile=\\x22https://www.w3.org/ns/activitystreams\\x22"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.4"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153"] [tag "PCI/12.1"] [hostname "__hostname__"] [uri "__PATH_TO_USER_INBOX_"] [unique_id "ZalqlTOpiqLEOI9mTEbMkQAAAAM"]

[Thu Jan 18 10:14:45.415276 2024] [:error] [pid 206460:tid 140077848327936] [client __IPADDRESS__:56886] [client __IPADDRESS__] ModSecurity: Warning. Match of "within %{tx.allowed_request_content_type}" against "TX:content_type" required. [file "/etc/modsecurity/mod_sec3_CRS/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "957"] [id "920420"] [msg "Request content type is not allowed by policy"] [data "|application/ld+json|"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.4"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153"] [tag "PCI/12.1"] [hostname "__hostname__"] [uri "__PATH_TO_USER_INBOX_"] [unique_id "ZalqlTOpiqLEOI9mTEbMkQAAAAM"]

[Thu Jan 18 10:14:45.417433 2024] [:error] [pid 206460:tid 140077848327936] [client __IPADDRESS__:56886] [client __IPADDRESS__] ModSecurity: Access denied with code 418 (phase 2). Operator GE matched 7 at TX:anomaly_score. [file "/etc/modsecurity/mod_sec3_CRS/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "93"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.2"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "__hostname__"] [uri "__PATH_TO_USER_INBOX_"] [unique_id "ZalqlTOpiqLEOI9mTEbMkQAAAAM"]

Your Environment

  • CRS version: 3.2.0-1
  • Paranoia level 1
  • ModSecurity 2.9.3-1
  • Apache httpd 2.4.41-4ubuntu3.13
  • Ubuntu 20.04.5 LTS

Confirmation

[ ] I have removed any personal data (email addresses, IP addresses,
passwords, domain names) from any logs posted.

@theseion
Copy link
Contributor

Thanks for the report @kvibber. For platforms like WordPress, running CRS pretty much requires the use of the WordPress exclusion rules (a separate plugin in the upcoming v4 release). That being said, there are too many plugins for WordPress out there and we simply cannot accommodate all of them. My advice is to add manual exclusions for those issues, i.e., based on the request URL you can use ctl:ruleRemoveById (https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-%28v2.x%29#ctl) to disable those rules dynamically (for those specific requests only). The documentation on exclusion rules is here: https://coreruleset.org/docs/concepts/false_positives_tuning/#rule-exclusions.

@azurit do you agree, or would you add these to the plugin?

@azurit
Copy link
Member

azurit commented Jan 19, 2024

@theseion I agree. On the top, these are not false positives but simply a misusage of HTTP headers.

@tsmethurst
Copy link

these are not false positives but simply a misusage of HTTP headers

A misusage in what sense? The profile parameter is an established part of json-ld: https://www.w3.org/TR/json-ld/#application-ld-json

@dune73
Copy link
Member

dune73 commented Jan 19, 2024

Thanks for reporting @kvibber and bonus points for returning status code 418.

Thanks for the link to w3.org, @tsmethurst.

@kvibber, you seem to be using CRS 3.2.x. Would you mind reporting on an updated CRS version. 3.3.x or honestly 4.0-dev (we're very close to release this milestone release).

The Content-Type header is the single most dangerous entry points for complete WAF bypasses. We have been bitten time after time by being not strict enough. Bug bounty payments, CVEs, the whole enchillada.

That's why we are doing very strict format checking on the CT header. This leads to a situation where new additions to the header automatically lead to false positives. The IETF branch working on HTTP call this "protocol ossification due to WAF usage".

We try to avoid it generally, but CT is an area where there is hardly a way around it and it takes somebody like you reporting it (-> we're a volunteer driven project and we are not pro-actively monitoring evolving standards).

If you can show us how the problem persists on v4-dev, we will definitely try to work around this.

@tsmethurst
Copy link

No problem, thanks for taking a look!

@kvibber
Copy link
Author

kvibber commented Jan 19, 2024

Unfortunately, I don't have control over the rulesets used on this server. It's managed by my webhost, and all I can do is turn mod_security off and on.

I can set up a test server on another host, though, just probably not before work today.

I do want to stress that this isn't a WordPress issue so much as it's an ActivityPub issue. Most ActivityPub servers I've looked at tend to be self-contained, but they'd probably have the same issues if they were put behind an Apache+mod_security reverse proxy.

@dune73
Copy link
Member

dune73 commented Jan 19, 2024

Thanks for the update.

A lot of modules have problems, we are sure. But little reports and even fewer contributions to help with maintaining a rule exclusion plugin for CRS.

But anyways, here is what you can do with regards to CRS v4: CRS Sandbox: https://coreruleset.org/docs/development/sandbox/

Just recreate the request, send it against the sandbox and report the full request (so we can reproduce) and the rules triggered here.

@theseion
Copy link
Contributor

Thanks for the clarification @kvibber, @tsmethurst. I wasn't aware of that standard. My initial thought is to create a rule exclusion plugin for ActivityPub, I don't think this should be part of core.

@dune73
Copy link
Member

dune73 commented Jan 20, 2024

My initial thought is to create a rule exclusion plugin for ActivityPub, I don't think this should be part of core.

Why? If it's a new standard headed for IANA registration. So it's only a question of time until the next victim shows up. The question is if we can cover this in a useful way before 4.0 ships. Namely 920470 as the format of the additional parameter is somewhat challenging, I think (profile="https://www.w3.org/ns/activitystreams").

@theseion
Copy link
Contributor

theseion commented Jan 20, 2024

Well, I think that ActivityPub servers will represent a minority of all web servers behind CRS and I can also imagine some CRS users not wanting to open up the WAF to those requests at all, if they don't host any ActivityPub servers. To me that means that we would either have to make the rules for ActivityPub configurable (e.g. a switch in the init configuration) or we make it a plugin.

But that's just me trying to think of a way forward. I honestly don't care either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants