本文主要介绍SSRF漏洞受到各种限制时,常见的绕过姿势。

(图片来自 SSRF漏洞Bypass技巧

0x00    URL scheme

第一部分:协议名(以单个冒号结束)
第二部分:用户信息 也就是账号密码!(登陆ftp时常用)
第三部分:主机名(也就是域名)
第四部分:端口
第五部分:查询内容,包含【path+param】,这里有个bug。应该是?号后的内容才是查询! 
第六部分:Fragment ID(不会发送到服务器!)

1.提取协议名:

他会查找第一个 : 号在哪,如果找到了,那么: 号左边的便是协议名!

如果获得的协议名中出现了不该有的字符,那么认为这可能就是个相对的url ,获得的并不是协议名!

2.去除层级url标记符:

字符串 // 应该算跟在协议名后面的 如果发现有该字符 则会跳过该字符 如果没有找到便不管了!所以 http:baidu.com 也是可以访问的! 浏览器中还可以用反斜杠来代替正斜杆 \\ 代替 // firefox除外!

0x01    浏览器解析特性

1. @

简单来说,正常的web应用处理是这样的:

先使用parse_url对用户传入的URL解析,获取到host,将host传入check_inner_ip,检查是否是内网IP。

如果检查通过,则将URL传给HTTP库发送请求。

所以绕过的核心原理是,parse_url时获取的host是A,实际使用HTTP库(如curl)发包时,他内部获取的host是B,利用这两个差异绕过check_inner_ip

这个差异通常是二者使用的URL解析逻辑不同导致的。比如,PHP使用CURL发送请求,而CURL底层实际上是个第三方库。那么PHP自己的parse_url,和CURL库内部的“parse_url”,就可能存在差异。

http://xss1.com&action=test@www.baidu.com

@External_Domain@12.0.0.1

Chrome不可以!

2. 句号

127001 >>> 127.0.0.1

3. # ?

#.jpg
?.jpg

截断!详见一次实战代码审计


0x02    PunnyCode

因为操作系统的核心都是英文组成,DNS服务器的解析也是由英文代码交换,所以DNS服务器上并不支持直接的中文域名解析,所有中文域名的解析都需要转成punycode码,然后由DNS解析punycode码。其实所说和各种浏览器完美支持中文域名,只是浏览器软件里面主动加入了中文域名自动转码,不需要原来的再次安装中文域名转码控件来完成整个流程。

例如:企鹅.com,用Punycode转换后为:xn–hoq754q. com

中国.cn,用Punycode转换后为:xn–fiqs8s. cn

ⅅʳºℙˢ  -->  drops 
ʷººʸⓊⁿ       —>  wooyun
Ⓞʳℊ         —>  org

ⅅʳºℙˢ.ʷººʸⓊⁿ.ºʳℊ --> drops.wooyun.org

0x03    进制转换

http://664552783 => http://baidu.com

$ ping baidu.com
Pinging baidu.com [39.156.69.79] with 32 bytes of data:

十进制

39.156.69.79 => 664552783(十进制)

八进制

39.156.69.79 => 04747042517 (八进制)

Octal,是一种计数法,采用0,1,2,3,4,5,6,7八个数码,逢八进位,并且开头一定要以数字0开头。

还有一种,IPV6形式

[0:0:0:0:0:ffff:127.0.0.1]
::ffff:7f00:1
0:0::1
0:0:0:0:0:0:0:0

以及特殊形式http://0/

0x04    短网址

实际是基于302跳转的

个人常用的短网址服务

suo.im
tinyurl.com
goo.gl 
...

0x05    xip.io / xip.name

xip.name

类似于一个"转发"的东西,绕过关键词白名单时很好用,如 if "baidu" in URL: {visit(URL);}


xip.io****

127.0.0.1.xip.io 								 	>>>  127.0.0.1
www.baidu.com.127.0.0.1.xip.io		>>>  127.0.0.1
...

类似的服务,还有

lvh.me
*.localtest.me	seereadme.localtest.me 

ping 1.2.3.4.sslip.io
ping 1.1.2.3.nip.io 

0x06    Enclosed alphanumerics

ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> http://example.com
ⓑⒶⒾⒹⓤ。Cm >>> http://baidu.com

①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿

0x07    内网地址

通常我们会将以下三个段设置为内网IP段,所有内网内的机器分配到的IP是在这些段中:

完整列表参考https://datatracker.ietf.org/doc/html/rfc5735

  • RFC 5735😂

192.168.0.0/16 	=> 192.168.0.0 ~ 192.168.255.255
10.0.0.0/8 			=> 10.0.0.0 ~ 10.255.255.255
172.16.0.0/12 	=> 172.16.0.0 ~ 172.31.255.255
127.0.0.0/8

所以通常,我们只需要判断目标IP不在这三个段,另外还包括 127.0.0.0/80.0.0.0/8

  1. 本地地址不但可以用常见的127.0.0.1表示,还可以用127.6.6.6来表示
  2. 在Linux下,127.0.0.10.0.0.0 都指向本地,参考 http://blog.orange.tw/2017/07/how-i-chained-4-vulnerabilities-on.html

Some Practices

一些小练习

第一弹: 欲盖弥彰

①②⑦。⓪。⓪。①

第二弹: 偷天换日

http://qq.com?action=submit&ID=@04747042517

加个高亮就更清楚

http://qq.comaction=submit&ID=@04747042517
注意
- 是中文的问号
- @,才是最关键的后面0开头的字符串是八进制表示的IP地址前面的都是userinfo

DNS rebinding 重绑定

1. DNS请求过程

  1. 查询本地DNS服务器(/etc/resolv.conf)
  2. 如果有缓存,返回缓存的结果,不继续往下执行
  3. 如果没有缓存,请求远程DNS服务器,并返回结果

平时使用的MAC和Windows电脑上,为了加快HTTP访问速度,系统都会进行DNS缓存。但是,在Linux上,默认不会进行DNS缓存(https://stackoverflow.com/questions/11020027/dns-caching-in-linux) ,除非运行nscd等软件。

不过,知道Linux默认不进行DNS缓存即可。这也解释了,我为什么同样的配置,我在MAC上配置不成功,Linux上配置可以。

需要注意的是,IP为8.8.8.8的DNS地址,本地不会进行DNS缓存。

  1. Java默认不存在被DNS Rebinding绕过风险(TTL默认为10)

  2. PHP默认会被DNS Rebinding绕过

  3. Linux默认不会进行DNS缓存

DNS请求过程

  1. 查询本地DNS服务器(/etc/resolv.conf)
  2. 如果有缓存,返回缓存的结果,不继续往下执行
  3. 如果没有缓存,请求远程DNS服务器,并返回结果

2. 重绑定实现过程

其实,知道创宇的ceye.io平台中,也有DNS Rebinding服务

实战时,用r.xxxxx.ceye.io即可

第一次请求,返回127.0.0.1

$ nslookup r.abcdef.ceye.io
Server:        8.8.8.8
Address:    8.8.8.8#53
Non-authoritative answer:
Name:    r.abcdef.ceye.io
Address: 127.0.0.1

第二次请求,返回192.168.0.1

$ nslookup r.abcdef.ceye.io
Server:        8.8.8.8
Address:    8.8.8.8#53
Non-authoritative answer:
Name:    r.abcdef.ceye.io
Address: 192.168.0.1

3. 一个不容忽视的前提

目标使用的DNS服务器,会影响DNS Rebinding攻击的效果。因此如果要成功进行DNS Rebinding攻击,必须目标使用了遵守TTL规则的DNS服务器。

常用的public dns:

- 遵守DNS TTL规则的有:	8.8.8.8
- 未遵守规则的有:1.1.1.1、223.5.5.5、119.29.29.29
- 是否缓存DNS记录比较随性的有:114.114.114.114

可见,大部分DNS为了节省请求数量,都会缓存DNS记录,只有8.8.8.8对TTL实现的比较理想。

4. 利用工具

可以采用[https://github.com/taviso/rbndr](https://github.com/taviso/rbndr)来进行DNS rebinding

# 在255.255.255.255与外网ip之间切换
ffffffff.2FF02E9A.rbndr.us
  
# 在127.0.0.1与外网ip之间切换
7F000001.2FF02E9A.rbndr.us


CTF风格的一些题

WMCTF2020-SimpleAuth

https://github.com/wm-team/WMCTF2020-WriteUp/blob/master/WMCTF%202020%E5%AE%98%E6%96%B9WriteUp.md#SimpleAuth

输入url参数后,提示只支持http协议。

构造url请求自己vps的http端口,可以成功收到http请求。

响应正常http时,页面显示nothing,接着可以【尝试修改http响应包】进行测试,比如返回401认证。

<?php
    header('WWW-Authenticate: Basic realm="test"'); 
    header('HTTP/1.0 401 Unauthorized'); 
?>

当响应401认页面的内容发现了变化,提示不支持该认证类型。通过【查阅资料】得知HTTP支持Basic、Digest、NTLM等认证类型,从网站信息中得知网站为Windows服务器。尝试响应NTLM类型的401认证。

<?php
    header('WWW-Authenticate: NTLM'); 
    header('HTTP/1.0 401 Unauthorized'); 
?>

重新请求发现响应内容发现了变化。 

通过tcpdump抓包可以看到,当http响应头要求NTLM认证时,题目会通过http NTLM认证再次请求url。


后记:SSRF实战与理论

知乎主站一处SSRF漏洞可探测内网

来源

【漏洞学习——SSRF】知乎主站一处SSRF漏洞可探测内网 https://blog.csdn.net/Fly_hps/article/details/84400273

漏洞描述

知乎回答问题的时候,输入网址将自动被转换为标题。比如输入http://wooyun.org/,将会变成:

明显是后台进行了请求。

抓包,发现是请求的http://www.zhihu.com/scraper

低危SSRF提权进内网

来源

R3start 低危SSRF提权进内网

https://mp.weixin.qq.com/s/HjvviHp1EdAmWEUE4fbajQ

漏洞描述

通过SSRF点,进入内网,最终在Redis中反复乱杀

WordPress SSRF(DNS Rebinding)

See:http://redteam.today/2019/11/01/wordpress%20xmlrpc.php%20have%20ssrf%20vuln(use%20dns%20rebinding%20bypass%20limit)/

参考资料