XXE基础知识
简介
xml特点
- XML仅仅是纯文本,他不会做任何事情。
- XML可以自己发明标签(允许定义自己的标签和文档结构)
- XML 无所不在。XML 是各种应用程序之间进行数据传输的最常用的工具,并且在信息存储和描述领域变得越来越流行。
- 总结成一句话就是:XML是用来存储数据的
DTD
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。
DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
内部的 DOCTYPE 声明
假如 DTD 被包含在您的 XML 源文件中,它应当通过下面的语法包装在一个 DOCTYPE 声明中:
<!DOCTYPE 根元素 [元素生命]>
外部文档声明
假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中:
<!DOCTYPE 根元素 SYSTEM "文件名">
DTD的作用:
- 通过 DTD,您的每一个 XML 文件均可携带一个有关其自身格式的描述。
- 通过 DTD,独立的团体可一致地使用某个标准的 DTD 来交换数据。
- 您的应用程序也可使用某个标准的 DTD 来验证从外部接收到的数据。
- 您还可以使用 DTD 来验证您自身的数据。
实体
实体可以理解为变量,其必须在DTD中定义申明,可以在文档中的其他位置引用该变量的值。
实体类别
实体按类型主要分为以下四种:
- 内置实体 (Built-in entities)
- 字符实体 (Character entities)
- 通用实体 (General entities)
- 参数实体 (Parameter entities)
实体根据引用方式,还可分为内部实体与外部实体,看看这些实体的申明方式。
完整的实体类别可参考 DTD - Entities
参数实体用%实体名称申明,引用时也用%实体名称;其余实体直接用实体名称申明,引用时用&实体名称。
参数实体只能在DTD中申明,DTD中引用;其余实体只能在DTD中申明,可在xml文档中引用。
内部实体:
<!ENTITY 实体名称 "实体的值">
外部实体:
<!ENTITY 实体名称 SYSTEM "URI">
参数实体:
`
或者`
实例演示:参数实体+外部实体
1 |
扩展
php伪协议实际上就是支持与封装的协议(共十二种)
- file:// — 访问本地文件系统
- http:// — 访问 HTTP(s) 网址
- ftp:// — 访问 FTP(s) URLs
- php:// — 访问各个输入/输出流(I/O streams)
- zlib:// — 压缩流
- data:// — 数据(RFC 2397)
- glob:// — 查找匹配的文件路径模式
- phar:// — PHP 归档
- ssh2:// — Secure Shell 2
- rar:// — RAR
- ogg:// — 音频流
- expect:// — 处理交互式的流
漏洞介绍
原理
XXE漏洞形成大体有4种方式:
simplexml_load_string()函数造成的回显注入
SimpleXMLElement()对象造成的回显注入
DOMDocument()类造成的回显注入
BlindXXE形式==>>也是由simplexml_load_string()函数造成的无回显注入
限制
- libxml库在2.9.0以下
- php8.0以后不存在xxe漏洞
- phpstudy中5.5版本之后采用的libxml已经大于2.9.0
XXE利用及payload
文件读取
1 |
|
SSRF
1 |
|
RCE
在安装了expect扩展的环境中可以实现命令执行
1 |
|
DDOS
支持实体测试
1 |
|
如果解析过程变的非常缓慢,则表明测试成功,即目标解析器配置不安全可能遭受至少一种 DDoS 攻击。
Billion Laughs 攻击
一个经典的Dos攻击payload:
1 |
|
当XML解析器加载该文档时,它会看到它包含一个根元素“lolz”,该元素包含文本“&lol9;”。然而,“&lol9;”是一个已定义的实体,它扩展为包含十个“&lol8;”字符串。每个“&lol8;”字符串都是一个已定义的实体,可以扩展到10个“&lol7;”字符串,以此类推。在处理完所有的实体扩展之后,这个小(小于1 KB)的XML块实际上将包含109 = 10亿个“lol”,占用了将近3 gb的内存。
Blind XXE
Blind XXE,字面意思也就是提交xml的服务器端点不再返回有效的数据,此时我们前面的一些利用方法就要失效了。但是解决方法还是有的。
XXE OOB(外带数据通道)
概念
带外数据(out—of—band data),有时也称为加速数据(expedited data),
是指连接双方中的一方发生重要事情,想要迅速地通知对方。这种通知在已经排队等待发送的任何“普通”(有时称为“带内”)数据之前发送。带外数据设计为比普通数据有更高的优先级。带外数据是映射到现有的连接中的,而不是在客户机和服务器间再用一个连接。
利用
带外数据通道的建立是使用嵌套形式,利用外部实体中的URL发出访问,从而跟攻击者的服务器发生联系。但有些情况下不能在实体定义中引用参数实体,即有些解释器不允许在内层实体中使用外部连接,无论内层是一般实体还是参数实体。
将嵌套的实体声明放入到一个外部文件中,这里一般是放在攻击者的服务器上,这样做可以规避错误。
1 |
|
1.xml
1 |
1.php
1 | "3.txt",$_REQUEST['id'],FILE_APPEND) file_put_contents( |
基于错误的XXE
形同blind xxe,当我们成功地让服务端解析了xml文档,得到的响应却是通用的。比如添加账号的时候只返回“添加成功”这样的响应。此时我们可以让服务器响应报错信息来得到我们要的敏感数据。
有两种报错的来源:
- DTD结构的错误
- XML架构验证时的错误
外部DTD
在本例中,我们将让服务器加载一个恶意DTD,它将在错误消息中显示文件的内容(只有当可以看到错误消息时,这才有效)。
可以使用恶意的外部DTD触发包含/etc/passwd文件内容的XML解析错误消息,如下所示:
1 |
|
这个DTD执行以下步骤:
定义一个名为file的XML参数实体,其中包含/etc/passwd文件的内容。
定义一个名为eval的XML参数实体,包含另一个名为error的XML参数实体的动态声明。错误实体将通过加载一个不存在的文件来评估,该文件的名称包含文件实体的值。
使用eval实体,该实体将导致执行错误实体的动态声明。
使用错误实体,以便通过尝试加载不存在的文件来得到数据,从而导致返回包含不存在文件的名称的错误消息,该名称正是/etc/passwd文件的内容。
实例演示:
请注意,外部DTD允许我们在第二个(eval)中包含一个实体,但在内部DTD中是禁止的。因此,在不允许使用外部DTD的情况下(通常)强制执行错误是行不通的。
内外部DTD混合
那么,当带外交互被阻止(外部连接不可用)时, blind XXE漏洞怎么办?
在这种情况下,由于XML语言规范中的漏洞,仍然有可能触发包含敏感数据的错误消息。如果文档的DTD混合使用内部和外部DTD声明,那么内部DTD可以重新定义在外部DTD中声明的实体。当发生这种情况时,在另一个参数实体的定义中使用XML参数实体的限制就放宽了。
这意味着攻击者可以从内部DTD中使用基于错误的XXE技术,前提是他们使用的XML参数实体是重新定义在外部DTD中声明的实体。当然,如果带外连接被阻塞,那么就不能从远程位置加载外部DTD。相反,它需要是应用服务器本地的外部DTD文件。从本质上说,攻击涉及调用碰巧存在于本地文件系统上的DTD文件,并将其重新用于重定义现有实体,从而触发包含敏感数据的解析错误。
例如,假设服务器文件系统上位于位置/usr/local/app/schema.上有一个DTD文件这个dtd文件定义了一个名为custom_entity的实体。攻击者可以通过提交如下混合DTD来触发包含/etc/passwd文件内容的XML解析错误消息:
1 |
这个DTD执行以下步骤:
定义名为local_dtd的XML参数实体,其中包含存在于服务器文件系统上的外部DTD文件的内容。
重新定义名为custom_entity的XML参数实体,该实体已经在外部DTD文件中定义。实体被重新定义为包含前面描述的基于错误的XXE漏洞,用于触发包含/etc/passwd文件内容的错误消息。
使用local_dtd实体,以便解释外部DTD,包括重新定义的custom_entity实体的值。这将导致所需的错误消息。
现实世界的例子:使用GNOME桌面环境的系统通常有一个DTD在/usr/share/yelp/ DTD /docbookx包含名为ISOamso的实体的dtd。
由于该技术使用内部DTD,所以首先需要找到一个有效的DTD。你可以安装相同的服务器正在使用的操作系统/软件和搜索一些默认dtd,或抓取系统内的默认dtd列表,并检查其中是否存在。
1 |
XInclude攻击
什么是XInclude? 顾名思义,xinclude可以理解为xml include
熟悉编译/脚本语言的一定熟知,像php的include,python和java的import都是可以进行文件包含的。
那么文件包含有什么好处?
当然是可以使代码更整洁,我们可以将定义的功能函数放在function.php中,再在需要使用功能函数的文件中使用include包含function.php,这样就避免了重复冗余的函数定义,同样可以增加代码的可读性。故此,xinclude也不例外,它是xml标记语言中包含其他文件的方式。
一些应用程序接收客户端提交的数据,会将其嵌入到服务器端XML文档中,然后解析文档。当客户端提交的数据被放置到后端SOAP(简单对象访问协议)请求中,然后由后端SOAP服务处理时,就会出现这种情况。
在这种情况下,我们不能执行典型的XXE攻击,因为无法控制整个XML文档,因此不能定义或修改DOCTYPE元素。但是,我们可以使用XInclude代替。XInclude是XML规范的一部分,它允许从子文档构建XML文档。我们可以在XML文档中的任何数据值中放置XInclude攻击,因此可以在只控制放在服务器端XML文档中的单个数据项的情况下执行攻击。
要执行XInclude攻击,需要引用XInclude名称空间并提供希望包含的文件的路径。例如:
1 | productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=1 |
详细的利用请参考: 浅析xml之xinclude & xslt
XSTL攻击
XSLT(扩展样式表转换语言)是一种对 XML 文档进行转化的语言。XML 文档通过 XSLT 转化后可以变成为另一份不同的 XML 文档,或者其他类型的文档,例如 HTML 文档、 CSV 文件、纯文本文件等。
有关具体的转化过程,请参考:sourse
因为同样具有XML文档,那也有XXE的漏洞隐患。关于具体的应用,可参考优秀翻译文章:sourse
XXE Bypass
上传文件绕过
有些应用程序允许用户上传文件,然后在服务器端处理这些文件。一些常见的文件格式使用XML或包含XML子组件。基于xml的格式包括DOCX这样的办公文档格式和SVG这样的图像格式。
例如,应用程序可能允许用户上传图像,并在上传后在服务器上处理或验证这些图像。即使应用程序希望接收PNG或JPEG之类的格式,所使用的图像处理库也可能支持SVG图像。由于SVG格式使用XML,攻击者可以提交恶意的SVG图像,从而达到针对XXE漏洞的隐藏攻击面。
1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" version="1.1" height="200"><image xlink:href="file:///etc/hostname"></image></svg> |
另外,许多常见的文档格式,例如doc,docx,odt等,其实质是一个zip文件,其中包含xml文件。当我们用winrar、7z等工具打开这类文件就能看到:
我们可以利用这些文件来绕过xxe防御。 oxml_xxe就是一个用于向此类文件中嵌入XXE Payload的工具。它支持以下文件格式的创建或修改:
- DOCX/XLSX/PPTX
- ODT/ODG/ODP/ODS
- SVG
- XML
- PDF (experimental)
- JPG (experimental)
- GIF (experimental)
oxml_xxe的工作原理分为两种:
- 一是直接建立一个文件,该模式会自动添加DOCTYPE并将XML实体插入到用户选择的文件中。
- 二是替换文件中的字符串,此模式会遍历查找文档中的符号§。并用XML实体(“&xxe;”)替换此符号的所有实例。注意,你可以在任何地方打开文档并插入§来替换它。常见的用例是web应用程序,它读取xlsx,然后将结果打印到屏幕上。利用XXE我们便可以将内容打印到屏幕上。
编码绕过
base64
1 | <foo/> |
utf-7
直接上样例:
1 |
|
使用两种编码
思路是在同一个文档里同时使用两种编码,从而迷惑 WAF。直接用生成的命令来说明:
1 | echo -n '<?xml version="1.0" encoding="UTF-16BE"?>' > payload.xml |
在实体内编码
是新的XML技术,对内部实体中的任何DTD/XML进行编码(编码格式是字符串16进制+UTF-8形式),达到WAF bypass的效果!
当没有XXE,但XML主体中存在漏洞(例如SQL注入)时起作用。
文档中的额外空格
由于XXE通常在XML文档的开头,所以比较省事儿的WAF可以避免处理整个文档,而只解析它的开头。但是,XML格式允许在格式化标记属性时使用任意数量的空格,因此攻击者可以在或
中插入额外的空格,从而绕过此类WAF。
XXE工具
XXEinjector
XXEinjector是一个使用Ruby编写的自动化xxe漏洞检测工具,可以通过给定一个http请求的包,然后设置好好参数就会自动化的进行fuzz,他会通过内置的规则进行自动化的测试,并且还支持二次注入(通过另一个请求触发漏洞)。
注:抄的,原文