1. 项目概述:从“内部请求”到“内网漫游”的SSRF
SSRF,全称Server-Side Request Forgery,翻译过来是“服务器端请求伪造”。这名字听起来有点拗口,但它的本质其实很直接: 一个能让服务器“替”攻击者去发起网络请求的漏洞 。想象一下,你是一个公司的前台,职责是接收访客的请求,然后根据访客的要求,去公司内部(比如财务部、研发部)取一些文件或信息回来交给访客。SSRF漏洞就相当于,一个伪装成访客的攻击者,递给你一张纸条,上面写着“请去总裁办公室的保险柜里,把公司机密文件取出来给我”。如果你不假思索地照做了,那么攻击者就成功利用你这个“前台”,访问到了他本无权触及的核心区域。
在渗透测试的实战中,SSRF是我个人认为“性价比”极高的漏洞之一。它不像SQL注入那样需要复杂的闭合和绕过,也不像XSS那样受限于浏览器环境。一个功能看似正常的“转码”、“预览”、“采集”功能,背后可能就是一条通往内网的秘密通道。随着云原生、微服务架构的普及,内外网边界日益模糊,内网服务的安全性假设往往比外网服务更弱,这使得SSRF的危害被急剧放大。它不再仅仅是读取本地文件,而是成为了攻击者从外网打入内网、进行横向移动的“桥头堡”。无论是新手安全工程师想理解漏洞原理,还是资深红队成员在实战中寻找突破口,深入掌握SSRF都至关重要。
2. SSRF漏洞的核心原理与危害深度剖析
2.1 漏洞产生的根本原因:过度的信任与模糊的边界
SSRF漏洞产生的根源,在于应用程序对用户提供的URL(或可构造为URL的参数)缺乏足够严格的校验和控制。程序的本意是提供一个便利的功能,例如:
- 从指定URL获取数据 :头像设置、文章封面图支持网络URL;内容采集功能。
- 进行服务器端处理 :网页转PDF、生成缩略图、DNS解析查询、端口扫描(一些管理功能)。
- 与内部服务交互 :通过服务器作为代理访问某些受限制的API(如获取天气、汇率)。
问题出在,开发者通常只考虑了“功能正确”,而忽略了“安全边界”。他们潜意识里认为:“用户只会输入一个正常的外网图片地址”。但攻击者的思维是:“我能否让服务器去访问
file:///etc/passwd
、
http://169.254.169.254/latest/meta-data/
(云服务器元数据接口)或者
http://192.168.1.1/admin
?”
从代码层面看,漏洞通常出现在使用了如
curl
、
file_get_contents
、
requests
等网络请求库,且参数完全或部分由用户控制的地方。程序没有对目标地址的协议(如是否允许
file://
、
gopher://
、
dict://
)、域名/IP(如是否指向内网、回环地址
127.0.0.1
)、端口范围进行有效过滤。
注意 :这里有一个常见的误区。很多开发者认为,用正则表达式过滤掉“127.0.0.1”、“localhost”、“192.168.”、“10.”、“172.16.”等字符串就安全了。这恰恰是众多绕过手法的起点。攻击者可以使用进制转换(如2130706433代表127.0.0.1)、域名重定向、DNS解析技巧、URL解析差异等多种方式绕过这些简单的黑名单。
2.2 漏洞带来的实际危害:不止于信息泄露
SSRF的危害远比读取一个本地文件要深远,它像一把钥匙,能打开多扇通往不同风险场景的大门:
- 攻击内网应用与服务 :这是SSRF最经典的危害。互联网公司的内部办公系统(OA)、开发测试环境、未授权访问的Redis/Memcached/MySQL服务、Jenkins/Gitlab等运维系统,通常只监听在内网。通过SSRF,攻击者可以像在内网一样对这些服务发起请求,进行未授权访问、数据窃取甚至命令执行。
-
窃取云服务元数据与凭证
:在AWS、阿里云、腾讯云等云环境中,虚拟机实例可以通过一个特殊的内部地址(如
169.254.169.254)访问元数据服务,其中可能包含临时安全凭证、角色信息等。获取这些凭证可能导致云资源被接管,危害范围从一台ECS扩展到整个云账户。 - 端口扫描与内网探测 :利用服务器作为代理,攻击者可以探测目标服务器所在内网的其他主机和开放端口,绘制内网拓扑,为后续的横向移动做准备。
-
读取本地敏感文件
:利用
file://协议,直接读取服务器本地的配置文件(如/etc/passwd、/proc/self/environ)、源码、日志等,获取数据库密码、加密密钥等敏感信息。 -
与内部协议交互,扩大攻击面
:利用
gopher://、dict://、tftp://等协议,可以与内网的Redis、Memcached、FTP、Telnet等服务进行交互。例如,通过gopher协议向内网Redis发送命令,可能实现未授权写入公钥,进而获取服务器权限。 -
发起拒绝服务攻击
:诱导服务器向自身(
127.0.0.1)或某个特定端口发起大量请求,消耗服务器资源,可能导致服务不可用。
我个人在实际渗透测试中的体会是 :SSRF很少作为一个孤立的漏洞存在。它通常是一个“跳板”,其价值在于将攻击位置从“外网”转移到了“内网”。在内网中,安全防护等级通常较低,你会发现大量默认口令的服务、未修复的旧漏洞、甚至是完全裸奔的测试系统。一个简单的SSRF,配合内网脆弱的Redis未授权访问,就可能演变成一场严重的服务器沦陷事件。
3. SSRF漏洞的探测与识别手法
发现SSRF漏洞,需要一双“挑剔”的眼睛,关注任何可能发起网络请求的功能点。以下是系统性的探测思路:
3.1 功能点枚举与参数定位
首先,你需要梳理应用所有可能涉及“外部资源引用”或“服务器端请求”的功能:
- 图片/视频/音频上传与处理 :支持通过URL上传;头像设置支持网络图片。
- 内容采集/导入 :输入文章链接,自动抓取标题和内容。
- 文件转换/处理 :URL转PDF、网页截图、生成二维码、视频转码。
- 网络工具类功能 :站长工具(如死链检测、DNS查询、端口扫描、网站测速)。
- API代理或Webhook :某些功能需要服务器去调用第三方API,而API地址可能由用户部分控制。
- SSO/Callback回调 :某些回调地址参数可能被滥用。
-
参数中包含完整URL
:如
?url=、?path=、?file=、?src=、?api=、?target=、?redirect=、?image=。
3.2 基础探测与回显判断
找到可疑参数后,第一步是判断请求是否由服务器发出,以及响应是否回显给用户。
-
DNSLOG外带测试(无回显/Blind SSRF首选) : 这是最安全、最有效的初步探测方法。你不需要服务器返回内容,只需要证明它发起了请求。
-
原理
:使用一个你能接收DNS查询记录的临时域名(如
xxx.dnslog.cn或burpcollaborator.net生成的域名)。 -
操作
:将参数值设置为
http://your-unique-subdomain.dnslog.cn。 - 判断 :稍后在DNSLOG平台查看是否有该子域的解析记录。如果有,百分百确认存在SSRF,因为只有服务器发起的请求才会触发DNS解析。
-
原理
:使用一个你能接收DNS查询记录的临时域名(如
-
有回显测试 : 如果响应内容会显示在页面上(如图片预览、采集到的标题正文),则可以尝试访问一个你能控制且会返回特定内容的公网地址。
-
操作
:搭建一个简单的HTTP服务(用Python:
python3 -m http.server 8080),在根目录放一个test.txt,内容为SSRF_TEST_OK。 -
请求
:将参数值设为
http://your-vps-ip:8080/test.txt。 -
判断
:如果应用响应中包含了
SSRF_TEST_OK,则证实漏洞存在且可回显。
-
操作
:搭建一个简单的HTTP服务(用Python:
-
协议探测 : 尝试不同的协议,观察应用行为。
-
file:///etc/passwd:尝试读取本地文件。 -
http://127.0.0.1:8080:尝试访问本地回环地址的不同端口。 -
dict://127.0.0.1:6379/info:尝试与本地Redis服务交互(如果存在)。
-
3.3 进阶探测与内网探测
一旦确认存在SSRF,下一步是探索其能力边界。
-
端口扫描 : 通过Burp Suite的Intruder或自己编写脚本,批量尝试
http://127.0.0.1:PORT。通过响应时间、长度、状态码或错误信息的差异,来判断端口是否开放。例如,连接被拒绝和请求超时的错误信息通常不同。- 技巧 :关注常见服务端口,如 22(SSH), 80/443(Web), 6379(Redis), 27017(MongoDB), 9200(Elasticsearch), 11211(Memcached), 3306(MySQL)等。
-
访问云元数据 : 这是云上渗透的高价值目标。直接尝试访问云厂商的元数据地址。
-
AWS:
http://169.254.169.254/latest/meta-data/ -
阿里云:
http://100.100.100.200/latest/meta-data/ -
腾讯云:
http://metadata.tencentyun.com/latest/meta-data/ -
Google Cloud:
http://metadata.google.internal/computeMetadata/v1/
-
AWS:
-
识别内网段与存活主机 : 结合端口扫描,可以系统地探测常见内网网段。
-
常见内网IP段
:
192.168.0.0/16,10.0.0.0/8,172.16.0.0/12。 -
方法
:使用工具如
ffuf或脚本,对http://192.168.1.1、http://192.168.1.2... 进行快速访问,根据响应差异判断主机存活。
-
常见内网IP段
:
实操心得 :在探测时,务必注意“频率”和“隐蔽性”。盲目的批量端口扫描可能会触发目标服务器的安全告警(如防火墙、IDS)。建议先通过DNSLOG确认,然后有针对性地测试高价值目标(如元数据、常见服务端口),最后再考虑大范围探测。在有回显的场景下,注意观察错误信息,它们常常会泄露路径、服务版本等有价值的信息。
4. 常见的SSRF绕过手法与限制突破
当你的探测请求被拦截时,战斗才真正开始。开发者会设置各种过滤规则,而攻击者则需要找到规则的盲点。以下是一些经典的绕过手法:
4.1 针对黑名单过滤的绕过
如果开发人员只是简单过滤了“localhost”、“127.0.0.1”、“192.168”等关键词。
-
IP地址的多种表示法 :
-
十进制IP
:
127.0.0.1的十进制是2130706433。访问http://2130706433等价于http://127.0.0.1。在线工具可以轻松转换。 -
八进制IP
:
127.0.0.1转换为八进制0177.0.0.1(注意前导0)。在某些上下文解析中可能生效。 -
十六进制IP
:
0x7f000001转换为十进制也是2130706433。或者用0x7f.0x00.0x00.0x01的形式。 -
混合表示
:
127.1、127.0.1在某些解析器里等同于127.0.0.1。
-
十进制IP
:
-
利用URL解析差异 : 这是绕过手法的“富矿”,不同库(
curl、urllib、浏览器)对URL的解析存在差异。-
利用
@符号 :URL格式为protocol://user:pass@host:port/path。你可以构造http://foo@127.0.0.1。一些简单的正则可能只检查://到第一个/之间的内容,而curl实际请求的主机是@后面的部分。 -
利用
#号 :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(IDN域名)。某些过滤逻辑可能只检查ASCII点号。
-
利用
-
域名重定向 : 如果目标只检查第一次请求的域名,你可以控制一个域名,让其返回一个
302或301跳转,跳转到内网地址。服务器会跟随跳转,从而访问到内网资源。
4.2 针对白名单过滤的绕过
如果应用只允许访问特定域名(如
*.example.com
),绕过难度更大,但仍有方法。
-
利用子域名解析
:如果你能控制
attacker.example.com的DNS解析,可以将其A记录指向127.0.0.1或任意内网IP。 -
利用DNS Rebinding攻击
:这是一个高级技巧。你控制一个域名,第一次DNS查询返回一个合法的外网IP(通过白名单检查),但TTL极短。服务器在真正发起HTTP请求时,DNS缓存已过期,第二次查询你返回一个内网IP(如
127.0.0.1),从而成功访问内网。这需要精心设计DNS服务。 -
利用URL中的参数污染
:
http://api.trusted.com/v1/getInfo?url=http://127.0.0.1。如果api.trusted.com存在SSRF,且其内部会请求url参数,就可能形成链式SSRF。 -
利用已知漏洞或特性
:例如,某些URL解析器在处理
http://trusted.com@127.0.0.1时,可能会错误地将trusted.com视为用户名,而将127.0.0.1视为主机。
4.3 协议利用与扩大攻击
-
file://协议 :直接读取本地文件。路径穿越:file:///etc/passwd。 -
gopher://协议 :一个非常强大的协议,可以构造任意格式的TCP数据包。常用于攻击内网的Redis、Memcached、FastCGI等文本协议服务。例如,通过SSRF发送一个精心构造的gopher请求到内网Redis,可以写入计划任务或SSH公钥,从而getshell。 -
dict://协议 :用于访问字典服务,可以用于探测端口和服务信息,如dict://127.0.0.1:6379/info获取Redis信息。 -
tftp://、ldap://、jar://等 :在特定环境下也可能被利用。
踩过的坑
:不是所有语言和库都支持这些协议。
gopher
和
dict
在PHP的
curl
扩展中默认支持,但在Python的
requests
库或Java的某些HTTP客户端中可能不支持。在实际测试前,最好先确认后端使用的技术栈。一个快速测试方法是,先尝试
file:///etc/passwd
,如果成功,再尝试其他协议。
5. 针对SSRF的防御方案与最佳实践
防御SSRF需要从多个层面建立纵深防御体系,核心思想是“统一出口,严格校验”。
5.1 输入校验:建立可靠的白名单
黑名单永远会漏,白名单才是王道。
-
协议白名单
:只允许应用业务必需的协议,通常是
http://和https://。在代码层面,在解析URL后,检查其scheme是否在白名单内。 - 域名/IP白名单 :如果业务只允许从几个特定的第三方获取数据,那么将允许的域名或IP地址列入白名单。这是最严格的方案。
-
使用应用层统一的URL解析库
:不要自己用字符串拼接或简单的正则处理URL。使用语言标准库或经过安全审计的第三方库来解析URL,并从中规范地提取
host、port、scheme等部分进行校验。
5.2 网络层隔离与限制
-
为后端请求设置独立的网络策略 :
-
使用出口防火墙
:在服务器或容器层面,配置严格的出站规则。只允许后端服务访问其业务所必需的外部IP和端口。例如,一个图片处理服务,可能只允许访问80和443端口,并且禁止访问内网RFC 1918地址段(
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16)和回环地址。 -
禁用不需要的协议
:在操作系统或应用容器中,禁用
curl或底层库对file、gopher、dict等危险协议的支持。
-
使用出口防火墙
:在服务器或容器层面,配置严格的出站规则。只允许后端服务访问其业务所必需的外部IP和端口。例如,一个图片处理服务,可能只允许访问80和443端口,并且禁止访问内网RFC 1918地址段(
-
使用网络中间层或代理 :
- 正向代理与过滤 :所有从应用服务器发起的对外请求,必须经过一个统一的正向代理(如Squid)。在该代理上实施严格的白名单策略。即使应用存在漏洞,请求也会被代理拦截。
- 微服务间的服务网格 :在K8s等环境中,使用Istio、Linkerd等服务网格,通过Sidecar代理严格控制服务间的通信,避免Pod被利用后访问非授权服务。
5.3 应用层安全设计
-
避免直接请求用户提供的URL :
- 二次验证 :对于头像URL等场景,可以先下载到服务器临时目录,进行病毒扫描、图片格式校验后,再存储或使用。
- 使用中间服务 :不直接请求用户URL,而是将URL发送给一个受严格控制的、无状态的“下载器”微服务。该服务运行在高度受限的网络环境中,只负责下载并返回内容。
-
认证与权限 :
- 如果必须请求内部服务,确保该请求携带了适当的服务间认证凭证(如JWT、mTLS),并且内部服务会验证这些凭证,而不是简单地信任来自“同网段”的请求。
-
对响应内容进行再处理 :
- 不要将后端请求的原始响应直接返回给前端。对内容进行清洗、转码或只提取需要的部分。
5.4 云环境下的特殊防护
-
保护元数据服务 :
- 使用云厂商提供的元数据服务加固功能。例如,AWS EC2可以通过IMDSv2(需要PUT请求获取token)来替代不安全的IMDSv1。或者直接通过安全组/防火墙策略,禁止非实例本身对元数据端口的访问(但这通常很难,因为元数据服务通常在实例内部)。
- 最根本的方法是,确保应用程序代码和配置中不包含对元数据服务的依赖,或使用IAM角色而非将凭证写入代码。
-
使用VPC端点与私有子网 :
- 将关键内部服务(如数据库、缓存)部署在私有子网,完全无公网IP。
- 使用VPC端点(如AWS PrivateLink)来安全地暴露服务给其他VPC或本地网络,避免通过公网或NAT网关。
防御方案对比表
| 防御层面 | 具体措施 | 优点 | 缺点/注意事项 |
|---|---|---|---|
| 输入校验 | 协议白名单、域名白名单 | 从根本上杜绝非常规请求,效果最好 | 业务灵活性受限,维护白名单有成本 |
| 网络隔离 | 出口防火墙、禁用危险协议 | 系统级防护,与业务逻辑解耦 | 规则配置复杂,可能影响正常业务 |
| 架构设计 | 统一正向代理、下载器微服务 | 集中管控,降低每个应用的开发负担 | 引入额外组件,增加系统复杂度 |
| 云原生 | 使用IMDSv2、服务网格、私有子网 | 贴合云环境,提供精细化的网络控制 | 云平台特定,学习和迁移成本高 |
6. 实战中的问题排查与高级技巧
即使理解了原理,在真实的渗透测试或漏洞挖掘中,你仍会遇到各种“奇怪”的情况。这里记录一些实战中遇到的问题和解决思路。
6.1 盲SSRF的利用与信息外带
当SSRF没有回显(Blind SSRF)时,证明漏洞存在只是第一步,如何利用它获取信息才是关键。
-
时间延迟探测 :
- 原理 :诱导服务器访问一个你控制的、但响应很慢的端点,通过观察应用请求的响应时间差异,来判断目标端口或服务的状态。
-
方法
:在你的VPS上运行一个脚本,当接收到特定路径的请求时,休眠10秒再响应。例如,构造
http://your-vps/sleep10。如果应用请求这个URL花了10秒以上,说明请求成功到达了你的服务器并触发了休眠。你可以用这个方法来“盲测”内网端口:如果请求内网某端口触发了到你的慢速请求,说明该端口开放。 - 工具 :Burp Suite的 Collaborator 客户端就支持生成这种带延迟的交互 payload。
-
错误信息差异 :
- 即使没有正常回显,应用在遇到连接拒绝、连接超时、SSL错误、DNS解析失败时,返回的错误页面或状态码可能不同。仔细对比这些差异,可以推断出后端网络状况。
-
多通道外带 :
-
除了HTTP和DNS,还可以尝试利用其他协议将信息带出。例如,如果服务器支持
gopher协议,可以尝试让服务器向你的VPS的某个TCP端口发送包含窃取数据(如文件内容)的原始TCP包。你需要在你VPS上用nc -lvp 端口监听。
-
除了HTTP和DNS,还可以尝试利用其他协议将信息带出。例如,如果服务器支持
6.2 处理复杂的重定向与跳转
有些应用会对URL进行预处理、重定向或递归请求。
-
识别递归请求
:如果应用的功能是“获取URL的标题”,它可能会先获取URL的内容,然后解析其中的
<title>标签。你可以构造一个页面,其<title>标签里又包含一个指向内网的URL。有些粗心的实现可能会递归处理,从而触发对内网的二次请求。 -
利用开放重定向
:如果目标网站本身存在一个开放重定向漏洞(例如
example.com/redirect?url=http://evil.com),你可以先将SSRF参数指向这个重定向地址,并最终跳转到内网目标。这有时可以绕过一些基于“首次请求目标”的过滤。
6.3 工具链与自动化
手动测试SSRF效率低下,合理的工具能事半功倍。
- Burp Suite - Collaborator :这是盲测神器。它能生成唯一的域名,并自动监听该域名收到的HTTP、DNS、SMTP等请求。在测试时,只需将Collaborator域名插入参数即可,无需自己搭建服务器。
-
ffuf / gobuster
:用于对内网IP和端口进行批量扫描。可以快速探测存活主机和Web服务。
# 示例:扫描 192.168.1.1-254 的80端口 ffuf -u http://192.168.1.FUZZ -w range-1-254.txt -mc 200,403,401 - Gopherus :一个专门用于生成攻击Redis、MySQL、FastCGI等服务的gopher协议payload的工具。它简化了手动构造复杂协议包的难度。
- SSRFmap :一个自动化的SSRF漏洞利用工具,可以自动进行内网探测、端口扫描,并尝试利用gopher等协议攻击常见服务。
最后再分享一个小技巧
:在测试云上应用时,除了标准的元数据地址,别忘了尝试一下历史版本或不同区域的地址。例如,阿里云早期的元数据地址是
http://100.100.100.200/latest/meta-data/
,但有些文档或旧实例可能配置了其他地址。多尝试,总会有意外发现。同时,在编写漏洞报告时,不仅要证明可以访问
127.0.0.1:80
,更要深入演示其危害,比如通过访问元数据拿到了临时凭证,或者通过内网Redis写入了webshell。清晰的危害演示能让开发和安全团队更直观地认识到问题的严重性,从而更快地推动修复。

130

被折叠的 条评论
为什么被折叠?



