• Web渗透:XXE-XML外部实体漏洞


    XML External Entity (XXE) 漏洞是一种注入攻击,利用不安全的XML解析器来执行各种恶意操作,如读取本地文件、执行远程代码、发起拒绝服务攻击等;此漏洞的根本原因在于XML标准允许在文档中定义外部实体,并在解析时进行解析和替换。在正式开始阐述XXE漏洞之前首先来说明一下XML语言。

    什么是XML?

    XML(可扩展标记语言,Extensible Markup Language)是一种标记语言,用于描述数据。XML非常适合数据存储和传输,因为它是纯文本,并且是可读的和可扩展的。XML广泛用于各种应用程序中,包括配置文件、文档格式和数据交换等。

    XML示例

    下面是一个简单的XML示例,描述了一本书的信息:

    1. "1.0" encoding="UTF-8"?>
    2. <bookstore>
    3.  <book category="children">
    4.    <title lang="en">Harry Pottertitle>
    5.    <author>J K. Rowlingauthor>
    6.    <year>2005year>
    7.    <price>29.99price>
    8.  book>
    9.  <book category="web">
    10.    <title lang="en">Learning XMLtitle>
    11.    <author>Erik T. Rayauthor>
    12.    <year>2003year>
    13.    <price>39.95price>
    14.  book>
    15. bookstore>

    在上述示例中:

    • 根元素是

    • bookstore元素包含两个子元素

    • 每个元素包含四个子元素:</code>、<code><author></code>、<code><year></code>和<code><price></code>。</p> </li><li> <p><code>book</code>元素还有一个属性<code>category</code>,用来标识书的类别。</p> </li><li> <p><code>title</code>元素也有一个属性<code>lang</code>,用来标识语言。</p> </li></ul> <h4><a name="t0"></a>XML的结构</h4> <p>XML文档由以下几部分组成:</p> <ol><li> <p><strong>声明(Prolog)</strong>:可选部分,通常包含XML版本和编码声明。</p> <pre data-index="1" class="set-code-show" name="code"><code class="language-XML hljs"><span class="hljs-meta"><?xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"UTF-8"</span>?></span></code><div class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p> </li><li> <p><strong>根元素(Root Element)</strong>:每个XML文档必须且只能有一个根元素,所有其他元素都是该根元素的子元素。</p> <pre data-index="2" class="set-code-show" name="code"><code class="language-XML hljs"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag"><<span class="hljs-name">root</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">   ...</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag"></<span class="hljs-name">root</span>></span></div></div></li></ol></code><div class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>在上述示例中的根元素是<code><bookstore></code>;根元素是整个XML文档的顶级元素。</p> </li><li> <p><strong>元素(Element)</strong>:由开始标签和结束标签包围的内容,可以包含属性、文本、子元素等。</p> <pre data-index="3" class="set-code-show" name="code"><code class="language-XML hljs"><span class="hljs-tag"><<span class="hljs-name">element</span> <span class="hljs-attr">attribute</span>=<span class="hljs-string">"value"</span>></span>Content<span class="hljs-tag"></<span class="hljs-name">element</span>></span></code><div class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> </li><li> <p><strong>属性(Attribute)</strong>:位于元素的开始标签内,提供额外的信息。</p> <pre data-index="4" class="set-code-show" name="code"><code class="language-XML hljs"><span class="hljs-tag"><<span class="hljs-name">element</span> <span class="hljs-attr">attribute</span>=<span class="hljs-string">"value"</span>></span>Content<span class="hljs-tag"></<span class="hljs-name">element</span>></span></code><div class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> </li><li> <p><strong>文本(Text)</strong>:元素内的内容,可以是纯文本或混合内容(文本和子元素的组合)。</p> <pre data-index="5" class="set-code-show" name="code"><code class="language-XML hljs"><span class="hljs-tag"><<span class="hljs-name">element</span>></span>Text content<span class="hljs-tag"></<span class="hljs-name">element</span>></span></code><div class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> </li><li> <p><strong>CDATA(Character Data)</strong>:不需要解析的文本数据,用于包含不需要被解析的字符,如HTML代码。</p> <pre data-index="6" class="set-code-show" name="code"><code class="language-XML hljs"><![CDATA[<div>Some HTML content</div>]]></code><div class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> </li></ol> <h5>XML解析</h5> <p>不同编程语言提供了丰富的库来解析和生成XML文档;此处我们以PHP语言为例子进行演示:</p> <pre data-index="7" class="set-code-show" name="code"><code class="language-php hljs"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-meta"><?php</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-variable">$xml</span> = <span class="hljs-string"><span class="hljs-string"><<<XML</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string"><bookstore></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string">  <book category="children"></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string">    <title lang="en">Harry Potter

  •    J K. Rowling
  •    2005
  •    29.99
  •  
  • XML;
  • $xmlObject = simplexml_load_string($xml);
  • echo $xmlObject->book->title . "\n";     // 输出:Harry Potter
  • ?>
  • XML-DTD文档类型定义

    DTD(Document Type Definition,文档类型定义)是XML的一种语法,用于定义XML文档的结构和规则;DTD可以在XML文档内部(内部DTD)或外部(外部DTD)定义,通过DTD,您可以指定XML文档中允许的元素、属性、嵌套关系、数据类型等,从而确保XML文档的有效性和一致性。

    以下是一个简单的XML文档及其对应的DTD示例:

    xml文档
    1. "1.0" encoding="UTF-8"?>
    2. bookstore SYSTEM "bookstore.dtd">
    3. <bookstore>
    4.  <book category="children">
    5.    <title lang="en">Harry Pottertitle>
    6.    <author>J K. Rowlingauthor>
    7.    <year>2005year>
    8.    <price>29.99price>
    9.  book>
    10.  <book category="web">
    11.    <title lang="en">Learning XMLtitle>
    12.    <author>Erik T. Rayauthor>
    13.    <year>2003year>
    14.    <price>39.95price>
    15.  book>
    16. bookstore>

    重点解析:

    bookstore SYSTEM "bookstore.dtd">

    这行代码是XML文档中的一个声明,指定了该文档所使用的外部DTD(文档类型定义)。

    :这部分声明了XML文档的文档类型定义(DTD);bookstore 是根元素的名称,表示此DTD描述了名为 bookstore 的根元素及其内容结构。

    SYSTEM "bookstore.dtd":SYSTEM关键字表示DTD的位置是一个系统标识符;"bookstore.dtd" 是一个外部DTD文件的路径或URL,这个文件定义了XML文档的结构和规则。

    外部DTD(bookstore.dtd)
    1. bookstore (book+)>
    2. book (title, author, year, price)>
    3. book category CDATA #REQUIRED>
    4. title (#PCDATA)>
    5. title lang CDATA #REQUIRED>
    6. author (#PCDATA)>
    7. year (#PCDATA)>
    8. price (#PCDATA)>
    DTD的组成部分:

    ①元素声明:用于定义元素的名称和内容模型;语法:

    1. bookstore (book+)>
    2. book (title, author, year, price)>

    ②属性声明:用于定义元素可以拥有的属性。语法:,示例:

    1. book category CDATA #REQUIRED>
    2. title lang CDATA #REQUIRED>

    使用 声明和外部DTD文件,可以确保XML文档符合预定义的结构和规则,帮助验证数据的有效性和一致性。这对于交换和处理结构化数据非常有用。

    ③实体声明(Entity Declarations):实体用于定义常用的文本片段,可以在XML文档中重复使用。语法:;示例:

    example "This is an example entity">

    在说完前置内容XML之后,这会儿我们就接着来说XXE漏洞;在此处我们也是拿pikachu靶场中的XXE相关靶场进行阐述说明:

    1.打开页面后发现页面中出现一个输入框,该输入框是用来接收xml数据的一个接口,输入的内容只能是xml数据,若输入的内容为其他数据则此时我们会被质疑hh。

    2.尝试输入一个简单定义义并使用了一个内部实体的XML文档;查看当前页面是否对输入的xml有回显:

    1. "1.0"?>
    2. foo [xxe "This is an example entity">] >
    3. <foo>&xxe;foo>

    :声明文档类型定义(DTD)部分,指定该XML文档的根元素是foo

    :定义了一个名为xxe的内部实体,其值为字符串 "This is an example entity"。

    foo是根元素。

    &xxe;:引用了之前定义的内部实体xxe

    将xml数据输入后查看到页面效果:

    此时可以判断当前页面对内部输入实体xml是有回显的,接着可以尝试输入xml内带外部实体的payload来确定当前页面是否支持外部实体。

    1. "1.0"?>
    2. foo [xxe SYSTEM "file:///C:/Windows/System32/drivers/etc/hosts">] >
    3. <foo>&xxe;foo>

    这个XML示例定义了一个外部实体 xxe,其内容是指向系统文件 C:/Windows/System32/drivers/etc/hosts。该外部实体在XML文档中被引用。如果一个不安全的XML解析器处理这个XML文档,它会尝试读取并插入 hosts 文件的内容。

    :声明文档类型定义(DTD)部分,指定该XML文档的根元素是foo

    :定义了一个名为xxe的外部实体,指向系统文件路径 C:/Windows/System32/drivers/etc/hosts

    foo是根元素。

    &xxe;:引用了之前定义的外部实体xxe

    输入payload后的效果:页面显示服务器中的hosts文件

    攻击成功;接着我们结合源代码进行XXE漏洞原理的剖析:

    1. $html='';
    2. //考虑到目前很多版本里面libxml的版本都>=2.9.0了,所以这里添加了LIBXML_NOENT参数开启了外部实体解析
    3. if(isset($_POST['submit']) and $_POST['xml'] != null){
    4.    $xml =$_POST['xml'];
    5. //   $xml = $test;
    6.    $data = @simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOENT);
    7.    if($data){
    8.        $html.="
      {$data}
      "
      ;
    9.   }else{
    10.        $html.="

      XML声明、DTD文档类型定义、文档元素这些都搞懂了吗?

      "
      ;
    11.   }
    12. }

    这个PHP代码片段的主要功能是处理用户提交的XML数据,并在某些条件下将其显示为HTML。

    ①使用 simplexml_load_string 函数加载用户提交的XML字符串,创建一个 SimpleXMLElement 对象。

    第三个参数 LIBXML_NOENT 启用了外部实体解析。这意味着如果XML包含外部实体引用,解析器将尝试解析和替换它们。

    @符号抑制了任何可能出现的警告或错误。

    ②如果成功加载XML(即 $data 不为空),将XML数据转换为字符串并包裹在

    标签中追加到 $html 中。

    如果加载失败,显示一条提示信息,告知用户可能需要理解XML声明、DTD文档类型定义和文档元素。

            此处,这个代码片段存在一个严重的安全漏洞——XXE(XML External Entity Injection),因为指定了 LIBXML_NOENT 参数,启用了外部实体解析,这个时候攻击者就可以提交包含外部实体的XML数据,从而读取服务器上的敏感文件或执行其他恶意操作。

    LIBXML 是 PHP 中用于处理 XML 数据的库,基于 libxml2 库。LIBXML 解析器提供了多种常量和选项,用于配置和控制 XML 文档的解析行为。但是在 libxml2 版本 2.9.0 之前,外部实体解析是默认启用的,这意味着,如果没有特别禁用外部实体解析,XML 解析器将会解析和处理外部实体,从而产生XXE漏洞。

    XXE漏洞防护
    1. 禁用外部实体解析

    在 PHP 中,可以通过 libxml_disable_entity_loader 函数来禁用外部实体解析,这是防止 XXE 攻击的主要方法之一:

    1. libxml_disable_entity_loader(true);
    2. $xmlObject = simplexml_load_string($xmlString);
    3. libxml_disable_entity_loader(false);
    2. 验证和清理输入

    在处理 XML 输入之前,进行严格的验证和清理,确保输入数据是可信的。例如:

    • 使用白名单验证文件类型和内容。

    • 对文件内容进行正则表达式验证。

    3. 配置 Web 应用防火墙 (WAF)

    配置 WAF 以检测和阻止恶意的 XML 数据。WAF 可以识别和拦截常见的 XXE 攻击模式。

    4. 关闭不必要的功能

    在 XML 解析器中,关闭不必要的功能,如外部实体解析、DTD 验证等,以减少攻击面。

  • 相关阅读:
    cpp浅析STL-set
    跳转微信小程序提示页面不存在或者页面空白的解决办法【图文教程】
    [MyBatis]一级缓存/二级缓存/三方缓存
    vertx hello gradle 打包jar
    电脑出现错误vcomp140.dll是什么情况?vcomp140.dll丢失怎样修复?
    塑造下一代教育的关键力量:AIGC在教育革命中的角色扮演
    Linux 内存管理 概述与深入理解
    java题库——继承和多态
    ssm+vue+elementUI 少儿编程管理系统-#毕业设计
    Hadoop大数据应用:HDFS 集群节点扩容
  • 原文地址:https://blog.csdn.net/WolvenSec/article/details/139934798