Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

0
0
【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

2017-08-01 14:51:48

阅读:856次
点赞(0)
收藏
来源: blackhat.com





【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

作者:math1as





【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

译者:math1as

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


并非完全翻译,掺杂了一点自己的私货和见解。


什么是SSRF

[1] 服务器端请求伪造 [2] 穿透防火墙,直达内网 [3] 让如下的内网服务陷入危险当中

Structs2

Redis

Elastic



SSRF中的协议'走私'

[1] 让SSRF的利用更加有效

本质上说,是利用原本的协议夹带信息,攻击到目标的应用

[2] 用来'走私'的协议必须是适合的,比如

基于HTTP的各类协议=>Elastic,CouchDB,Mongodb,Docker

基于Text的各类协议=>FTP,SMTP,Redis,Memcached



一个有趣的例子

像这样的一个协议


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

我们来分析一下,各个不同的python库,分别请求到的是哪个域名呢?


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

可以看到,Python真是个矛盾的语言呢。


另一个有趣的例子

[1] HTTP协议中的CRLF(换行符)注入 [2] 使用HTTP协议'走私'信息来攻击SMTP协议

我们尝试构造CRLF注入,来进行如下的攻击


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

STMP '讨厌' HTTP协议

这似乎是不可利用的,可是,真的如此么?

我们在传统的SSRF利用中都使用gopher协议来进行相关攻击

可是事实上,如果真实的利用场景中不支持gopher协议呢?


利用HTTPS协议:SSL握手中,什么信息不会被加密?

[1] HTTPS协议中的CRLF(换行符)注入 [2] 化腐朽为神奇 - 利用TLS SNI(Server Name Indication),它是用来改善SSL和TLS的一项特性

允许客户端在服务器端向其发送证书之前请求服务器的域名。

https://tools.ietf.org/html/rfc4366RFC文档

简单的说,原本的访问,是将域名解析后,向目标ip直接发送client hello,不包含域名

而现在包含了域名,给我们的CRLF攻击提供了利用空间

我们尝试构造CRLF注入,来进行如下的攻击


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

监听25端口


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

分析发现,127.0.0.1被作为域名信息附加在了client hello之后


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

由此我们成功的向STMP'走私'了信息,实施了一次攻击


URL解析中的问题

[1] 所有的问题,几乎都是由URL解析器和请求函数的不一致造成的。 [2] 为什么验证一个URL的合法性是很困难的?

1.在 RFC2396/RFC3986 中进行了说明,但是也只是停留在说明书的层面。

2.WHATWG(网页超文本应用技术工作小组)定义了一个基于RFC的具体实现

但是不同的编程语言仍然使用他们自己的实现


RFC 3986中定义的URL组成部分

大致用这张图片来说明


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

其中的协议部分,在真实场景中一般都为http或https

而查询字符串和fragment,也就是#号后的部分,我们实际上是不关心的,因为这和我们的利用无关

所以,我们着重看的也就是authority和path部分

那么,在这几个部分中,能不能进行CRLF注入?

各个语言以及他们对应的库的情况如下图所示


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

可以看到支持CRLF注入的部分还是很多的,但是除了在实际的请求中能利用CRLF注入外

还要能通过URL解析器的检查,而这个图也列出来了对应的情况。


关于URL解析器

[1] 让我们思考如下的php代码
【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

在这段代码中,我们最后使用readfile函数来实施我们的SSRF攻击

但是,我们构造出的URL需要经过parse_url的相应检查


误用URL解析器的后果

当我们对上述的php脚本传入这样的一个URL


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

对于我们的请求函数readfile来说,它所请求的端口是11211

而相反的,对于parse_url来说,它则认为这个url的端口号是80,符合规定


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

这就产生了一个差异化的问题,从而造成了SSRF的成功利用

让我们来看看,在RFC3986中,相关的定义


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

那么,按照这个标准,当我们传入如下URL的时候,会发生什么呢


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

对比我们的两个函数


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

可以看到,parse_url最终得到的部分实际上是google.com

而readfile则忠实的执行了RFC的定义,将链接指向了evil.com

进行一下简单的分析

[1] 这样的问题同样影响了如下的编程语言

cURL,Python

[2] RFC3962的进一步分析

在3.2小节中有如下的定义:authority(基础认证)部分应该由//作为开始而由接下来的一个/号,或者问号

以及 #号作为一个结束,当然,如果都没有,这个部分将延续到URL的结尾。


cURL的利用

参照我们刚才所得到的结论


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

对这样的一个URL进行分析和测试


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

可以发现,在cURL作为请求的实施者时,它最终将evil.com:80作为了目标

而其他的几种URL解析器则得到了不一样的结果,产生了不一致。

当他们被一起使用时,可以被利用的有如下的几种组合


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

于是我向cURL团队报告了这个问题,很快的我得到了一个补丁

但是这个补丁又可以被添加一个空格的方式绕过


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

但是,当我再次向cURL报告这个情况的时候,他们认为,cURL并不能100%的验证URL的合法性

它本来就是要让你来传给他正确的URL参数的

并且他们表示,这个漏洞不会修复,但是上一个补丁仍然在7.54.0版本中被使用了


NodeJS的Unicode解析问题

让我们来看如下的一段nodeJS代码


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

可以看到,阻止了我们使用..来读取上层目录的内容

当对其传入如下的URL时,会发生什么呢


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

注意,这里的N是 U+FF2E,也就是拉丁文中的N,其unicode编码为 /xFF/x2E


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

最终,由于nodeJS的处理问题 \xFF 被丢弃了,剩下的\x2E被解析为.

于是我们得到了如下的结论


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

在NodeJS的http模块中, NN/ 可以起到../ 的作用,绕过特定的过滤

那么,nodeJS对于之前我们所研究的CRLF注入,又能不能够加以防御呢?

[1] HTTP模块可以避免直接的CRLF注入 [2] 那么,当我们将换行符编码时,会如何呢?
【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

很明显,这时候它并不会进行自动的解码操作

如何打破这个僵局呢? 使用U+FF0D和U+FF0A


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

我们成功的往请求中注入了新的一行


Glibc中的NSS特性

在Glibc的源代码文件 resolv/ns_name.c中,有一个叫ns_name_pton的函数


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

它遵循RFC1035标准,把一个ascii字符串转化成一个编码后的域名

这有什么可利用的呢?

让我们来看下面的代码


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

通过gethostbyname函数来解析一个域名

在字符串中,\代表转义符号,因此用\\097来代表ascii码为97,也就是字母a

成功的解析到了orange.tw的ip地址

那么我们看看python的gethostbyname


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

更让我们惊奇的是,它忽略了这些\号 而解析到了orange.tw

同样的,一些类似的特性存在于linux的getaddrinfo()函数中,它会自动过滤掉空格后的垃圾信息


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

python socket中的gethostbyname是依赖于getaddrinfo()函数的

因此出现了类似的问题,当传入CRLF时,后面的部分被丢弃了


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

说了这么多,这些特性有什么可以利用的地方呢?

让我们来看如下的几种payload


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

可以想到的是,如果利用Glibc的NSS特性,当检查URL时,gethostbyname将其识别为127.0.0.1

为什么%2509能够生效呢?部分的函数实现可能会解码两次,甚至循环解码到不含URL编码

那么接下来,实际发起访问时,我们就可以使用CRLF注入了


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

由此注入了一条redis语句

同样的,当HTTPS开启了之前我们提到的TLS SNI(Server Name Indication)时

它会把我们传入的域名放到握手包的client hello后面


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

这样我们就成功的注入了一条语句


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

而我们还可以进一步延伸,比如曾经的python CRLF注入漏洞,CVE-2016-5699

可以看到,这里其实允许CRLF后紧跟一个空格


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

由此绕过了_is_illegal_header_value()函数的正则表达式

但是,相应的应用会接受在行开头的空格么?


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

可以看到,redis和memcached都是允许的,也就产生了利用。


利用IDNA标准

IDNA是,Internationalizing Domain Names in Applications的缩写,也就是'让域名变得国际化'


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

上图是IDNA各个版本的标准,这个问题依赖于URL解析器和实际的请求器之间所用的IDNA标准不同

可以说,仍然是差异性的攻击。


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

比如,我们来看这个例子,将这个希腊字母转化为大写时,得到了SS

其实,这个技巧在之前的xss挑战赛 prompt 1 to win当中也有用到

这里我们面对的的是Wordpress

1.它其实很注重保护自己不被SSRF攻击

2.但是仍然被我们发现了3种不同的方法来绕过它的SSRF保护;

3.在2017年2月25日就已经向它报告了这几个漏洞,但是仍然没有被修复

4.为了遵守漏洞披露机制,我选择使用MyBB作为接下来的案例分析

实际上,我们仍然是追寻'差异性'来达到攻击的目的

这次要分析的,是URL解析器,dns检查器,以及URL请求器之间的差异性


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

上表列出了三种不同的web应用分别使用的URL解析器,dns检查器,以及URL请求器

[1] 第一种绕过方法

其实就是之前大家所普遍了解的dns-rebinding攻击


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

在dns解析和最终请求之间有一个时间差,可以通过重新解析dns的方法进行绕过


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

1.gethostbyname()函数得到了ip地址1.2.3.4

2.检查发现,1.2.3.4不在黑名单列表中

3.用curl_init()来获得一个ip地址,这时候cURL会再次发出一次DNS请求

4.最终我们重新解析foo.orange.tw到127.0.0.1 产生了一个dns攻击

[2] 第二种绕过方法

利用DNS解析器和URL请求器之间的差异性攻击


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

对于gethostbynamel()这个DNS解析器所用的函数来说

它没有使用IDNA标准的转换,但是cURL却使用了

于是最终产生的后果是,gethostbynamel()解析不到对应的ip,返回了false

也就绕过了这里的检查。

[3] 第三种绕过方法

利用URL解析器和URL请求器之间的差异性攻击

这个漏洞已经在PHP 7.0.13中得到了修复


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

有趣的是,这里最终请求到的是127.0.0.1:11211

而下一个payload则显示了curl的问题,最终也被解析到本地ip


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

而这个漏洞也在cURL 7.54中被修复

可惜的是,ubuntu 17.04中自带的libcurl的版本仍然是7.52.1

但是,即使是这样进行了修复,参照之前的方法,添加空格仍然继续可以绕过


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

而且cURL明确表示不会修复


协议'走私' 案例分析

这次我们分析的是github企业版

它使用ruby on rails框架编写,而且代码已经被做了混淆处理

关于github企业版的远程代码执行漏洞

是github三周年报告的最好漏洞

它把4个漏洞结合为一个攻击链,实现了远程代码执行的攻击

[1] 第一个漏洞:在webhooks上的SSRF绕过

webhooks是什么?


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

这就很明显了,它含有发送POST数据包的功能

而它是如何实现的呢?

请求器使用了rubygem-faraday是一个HTTP/REST 客户端库

而黑名单则由其内部的faraday-restrict-ip-addresses所定义

它过滤了localhost,127.0.0.1等地址

但是仅仅用一个简单的 0 就可以加以绕过,像这样


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

但是,这个漏洞里有好几个限制,比如

不允许302重定向

不允许http,https之外的协议

不允许CRLF注入

只允许POST方式发送数据包

[2] 第二个漏洞:github企业版使用Graphite来绘制图标,它运行在本地的8000端口
【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

这里也是存在SSRF的

[3] 第三个漏洞 Graphite 中的CRLF注入

Graphite是由python编写的

于是,分析可知,这第二个SSRF的实现是httplib.HTTPConnection

很明显的,httplib是存在CRLF注入问题的

于是,我们可以构造下面的URL,产生一个'走私'漏洞


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器
[4] 第四个漏洞 Memcached gem中不安全的编排问题

Github企业版使用Memcached gem来作为它的缓存客户端

所有缓存的ruby对象都会被编排

最终的攻击链如下:


【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器

这个漏洞最终获得了12500美金的奖励

在github企业版<2.8.7中可以使用


缓解措施

[1] 应用层

使用唯一的ip地址和URL,而不是对输入的URL进行复用

简单的说,拒绝对输入的URL进行二次解析,只使用第一次的结果

[2] 网络层

使用防火墙或者协议来阻断内网的通行

[3] 相关的项目

由 @fin1te 编写的SafeCurl

它也被 @JordanMilne 所提倡


总结

SSRF中的新攻击面

[1] URL解析器的问题 [2] 滥用IDNA标准

协议'走私'中的新攻击向量

[1] 利用linux Glibc中的新特性 [2] 利用NodeJS对Unicode字符的处理问题

以及相关的具体案例分析


未来展望

[1] OAuth中的URL解析器 [2] 现代浏览器中的URL解析器 [3] 代理服务器中的URL解析器

以及.. 更多




【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器
【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf

Viewing all articles
Browse latest Browse all 12749