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

New rule 942550 (PL1) JSON in SQL #3055

Merged
merged 16 commits into from
Dec 14, 2022

Conversation

theMiddleBlue
Copy link
Contributor

This PR contains a new rule at PL1 that tries to catch SQL in JSON payloads not covered at PL1. For more information about the bypass technique, please refer to https://claroty.com/team82/research/js-on-security-off-abusing-json-based-sql-to-bypass-waf

@theMiddleBlue theMiddleBlue marked this pull request as draft December 12, 2022 22:10
@theMiddleBlue
Copy link
Contributor Author

This is a draft, I'm working to a more stricter version for SQLite and PostgreSQL in order to avoid FPs

@RedXanadu
Copy link
Member

@theMiddleBlue We don't seem to match against this example, which appears to be path-based (original example screenshot):

curl -H 'x-crs-version: nightly' -H 'x-crs-paranoia-level: 4' -H 'x-backend: apache' -H 'x-format-output: txt-matched-rules' "https://sandbox.coreruleset.org/blah/\"\}' and data @> '\{\"a\":\"a\"\}' union select ASCII(s.token) from unnset(string_to_array((select cookie from cookie limit 1 ),NULL)) s(token)--/state?sig=1&timeStamp=50"

We don't catch it when the attack is in the path, but we do catch it when it's in ARGS as a query string parameter:

curl -H 'x-crs-version: nightly' -H 'x-crs-paranoia-level: 4' -H 'x-backend: apache' -H 'x-format-output: txt-matched-rules' "https://sandbox.coreruleset.org/blah?param=\"\}' and data @> '\{\"a\":\"a\"\}' union select ASCII(s.token) from unnset(string_to_array((select cookie from cookie limit 1 ),NULL)) s(token)--/state?sig=1&timeStamp=50"

980170 PL1 Anomaly Scores: (Inbound Scores: blocking=90, detection=90, per_pl=15-56-11-8, threshold=5) - (Outbound Scores: blocking=0, detection=0, per_pl=0-0-0-0, threshold=4) - (SQLI=70, XSS=5, RFI=0, LFI=0, RCE=10, PHPI=0, HTTP=0, SESS=0)

@theMiddleBlue
Copy link
Contributor Author

thanks @RedXanadu !

@theMiddleBlue
Copy link
Contributor Author

I've changed the SQLite regex in order to avoid FPs. This rule could probably be bypassed by using other SQL engine functions to transform the string parameters. But other CRS rules should catch it.

https://regex101.com/r/uAPMQY/1

@theMiddleBlue
Copy link
Contributor Author

HA! the test is failing on 4 and 6 because of / ... apache always returns a 404 if / is in the URL IIRC.
@dune73 @fzipi any idea? the regex matches correctly...

https://regex101.com/r/0J5Zr0/1

@theMiddleBlue
Copy link
Contributor Author

theMiddleBlue commented Dec 13, 2022

I can remove all comment syntaxes on tests, it should fix the test problem...

@fzipi
Copy link
Member

fzipi commented Dec 13, 2022

Probably using the data field in tests is better than using the url?

@theMiddleBlue
Copy link
Contributor Author

ok this should cover all test cases, including the payload from @RedXanadu

@theMiddleBlue theMiddleBlue marked this pull request as ready for review December 13, 2022 13:16
@RedXanadu
Copy link
Member

RedXanadu commented Dec 13, 2022

Yay: tested and confirmed that it now catches the path-based payload from above 😄

Imperva have published some more example payloads. Some of them we catch at PL 1, some of them we don't.

Are these concerning? Do we need to catch all of these variations, or will we be here forever?

Either way, here are the results I got:

1

' or '{"key":"value"}' ? "key" --

curl -v -o/dev/null 'localhost' --data "param=' or '{\"key\":\"value\"}' ? \"key\" --"

Result: per_pl=0-36-11-13

2

' or '{"name":"jack"}' ?| array['a','location']

curl -v -o/dev/null 'localhost' --data "param=' or '{\"name\":\"jack\"}' ?| array['a','location']"

Result: per_pl=0-31-11-13

3

' or '{"name":"jack", "Location":"UK"}' ?& array['name','Location']

curl -v -o/dev/null 'localhost' --data "param=' or '{\"name\":\"jack\", \"Location\":\"UK\"}' ?& array['name','Location']"

Result: per_pl=0-21-19-26

4 ✔️

' or '{"a":"b"}'::JSONB @> '{"a":"b"}'--

curl -v -o/dev/null 'localhost' --data "param=' or '{\"a\":\"b\"}'::JSONB @> '{\"a\":\"b\"}'--"

Result: per_pl=10-36-11-13 (942550 matches)

5

' or '[1,2,3]'::json ->> 2 = '3'

curl -v -o/dev/null 'localhost' --data "param=' or '[1,2,3]'::json ->> 2 = '3'"

Result: per_pl=0-36-16-13

6 ✔️

' or '{"a":{"b":{"c":"foo"}}}'::jsonb#>'{a,b}' @> '{"c":"foo"}'::jsonb --

curl -v -o/dev/null 'localhost' --data "param=' or '{\"a\":{\"b\":{\"c\":\"foo\"}}}'::jsonb#>'{a,b}' @> '{\"c\":\"foo\"}'::jsonb --"

Result: per_pl=10-36-11-13 (942550 matches)

7 ✔️

' or '{"a": {"b":{"c": "foo"}}}'::jsonb#>'{a,b}' ? 'c' --

curl -v -o/dev/null 'localhost' --data "param=' or '{\"a\": {\"b\":{\"c\":        \"foo\"}}}'::jsonb#>'{a,b}' ? 'c' --"

Result: per_pl=10-46-11-13 (942550 matches)

8 ✔️

' or '{"a":{"b":{"c"}}}'::jsonb#>'{a,b}' ? 'c' --

curl -v -o/dev/null 'localhost' --data "param=' or '{\"a\":{\"b\":{\"c\"}}}'::jsonb#>'{a,b}' ? 'c' --"

Result: per_pl=10-41-11-13 (942550 matches)

@theMiddleBlue
Copy link
Contributor Author

oh wow, thanks @RedXanadu this is really useful! I'm going to see if I can integrate all variations

@theMiddleBlue theMiddleBlue marked this pull request as draft December 13, 2022 19:40
@theMiddleBlue theMiddleBlue marked this pull request as ready for review December 13, 2022 19:52
@theMiddleBlue
Copy link
Contributor Author

added new payloads and I removed useless parts from the ra file, so the regex should be less chaotic.
moreover, it should match all payload you listed @RedXanadu (I've added a modified version of that list on the regression test file)

Copy link
Contributor

@theseion theseion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work!

regex-assembly/942550.ra Outdated Show resolved Hide resolved
rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf Outdated Show resolved Hide resolved
regex-assembly/942550.ra Outdated Show resolved Hide resolved
@theMiddleBlue
Copy link
Contributor Author

a possible false positive could be an ARGS value that contains the following string:

are '{' and '}' brackets? yes.

something like:

message=are '{' and '}' brackets? yes.

Copy link
Member

@fzipi fzipi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@theMiddleBlue This is an amazing PR. You nailed it!

Copy link
Member

@RedXanadu RedXanadu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed that all of the Imperva examples are now caught at PL 1 by this new rule.

Seriously cool work @theMiddleBlue! And such a fast turn around! Plus, the regex-assemble file for this new rule is elegant and easy to read: a great example to use 🚀

@fzipi fzipi merged commit 431557d into coreruleset:v4.0/dev Dec 14, 2022
@studersi
Copy link
Contributor

Thanks a lot!

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

Successfully merging this pull request may close these issues.

5 participants