当前位置:   article > 正文

XEE漏洞基础以及进阶

xee漏洞

XML编程基础

XML 指可扩展标记语言(EXtensible Markup Language)
XML 是一种标记语言,很类似 HTML
XML 的设计宗旨是传输数据,而非显示数据
XML 标签没有被预定义。您需要自行定义标签。
XML 被设计为具有自我描述性。
XML 是 W3C 的推荐标准
###XML标签根据自己主观定义,不像HTML是被预定义好的

<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上例中的标签没有在任何 XML 标准中定义过(比如 和 )。这些标签是由文档的创作者发明的。

这是因为 XML 没有预定义的标签。

在 HTML 中使用的标签(以及 HTML 的结构)是预定义的。HTML 文档只使用在 HTML 标准中定义过的标签(比如

等等)。

XML 允许创作者定义自己的标签和自己的文档结构。

DTD

DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。

它使用一系列的合法元素来定义文档结构。可被成行地声明于 XML 文档中,也可作为一个外部引用。

1.假如 DTD 被包含在您的 XML 源文件中,它应当通过下面的语法包装在一个 DOCTYPE 声明中:

如:

<?xml version="1.0"  encoding="utd-8"?> ##version声明版本号,encoding声明编码方式一定要写
<!DOCTYPE note [
  <!ELEMENT note (to,from,heading,body)>
  <!ELEMENT to      (#PCDATA)>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>
]>
<note>
  <to>黑娃</to>
  <from>铁蛋</from>
  <heading>语录</heading>
  <body>加油!奥利给!</body>
</note>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2.假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中:

//文件名是指上面面中元素声明保存的在哪个文件的文件名,类似于首先将元素声明写在该文件中然后通过SYSTEM调用该文件,在下方的代码中则不需要再写元素申明
注意外部实体引用时的关键字“SYSTEM”,同时也可以使用“PUBLIC”这个关键字,这两者的区别在于,SYSTEM表示私有的DTD,PUBLIC表示共有的DTD。

3.在 DTD 中,XML 元素通过元素声明来进行声明。
1.元素声明使用下面的语法:

<!ELEMENT 元素名称 类别>

例:<!ELEMENT to CDATA>

或者是:<!ELEMENT 元素名称 (元素内容)>
例:<!ELEMENT note (to,from,heading,body)>

2.对于空元素则通过类别关键词EMPTY进行声明:

<!ELEMENT 元素名称 EMPTY>

例:<!ELEMENT note EMPTY>

XML中5个预定义好的符号

< < 小于号
> > 大于号
& & 和
’ ’ 单引号
" " 双引号
尤其是<和&符,在我们编写时不能自定义使用,倘若我们非要使用这些符号,某些文本,比如 JavaScript 代码,包含大量 “<” 或 “&” 字符。为了避免错误,可以将脚本代码定义为 CDATA。怎可以通过CDATA编码。
##在CDATA编码,被CDATA框住的部分,XML编译器会直接忽略,在这其中我们可以包含XML中禁止自定义的5中标识符
CDATA 部分由 “<![CDATA[" 开始,由 "]]>” 结束:

<script>
<![CDATA[
function matchwo(a,b)
{
if (a < b && a < 0) then
  {
  return 1;
  }
else
  {
  return 0;
  }
}
]]>
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

CDATA 部分不能包含字符串 “]]>”。也不允许嵌套的 CDATA 部分。

标记 CDATA 部分结尾的 “]]>” 不能包含空格或折行。

DTD外部实体及内部实体

1)内部实体声明:
声明语法:

<!ENTITY 实体名称 "实体的值">
  一个实体的引用,由三部分构成:&符号, 实体名称, 分号。
  内部实体引用示例:
  • 1
  • 2
<?xml version="1.0" encoding="UTF-8"?>

]>
&test;
使用浏览器进行访问,并将xml代码作为参数传入,可以不复制xml声明,记得要将引用实体时的“&”手动编码为“&”(因为我们这里使用的是GET传参的方式,所以传入的内容会被进行URL编码,但是&在URL中被认为是两个参数的分隔符,所以如果我们不对其进行URL编码转换,浏览器会把它当作参数的分隔符来处理)
2)外部实体声明:
声明语法:

<!ENTITY 实体名称 SYSTEM "URI/URL" >

外部实体引用示例:

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

]>

&xxe;
声明一个外部实体的关键在于“SYSTEM”这个关键字。SYSTEM在此意图让xml解析器知道,现在声明的是一个外部实体,需要从后面的外部资源中获取内容并存储在内部实体,如果后面的外部资源的语法,存在特殊符号,那么xml解析器会报错。
外部实体引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,比如http、file、ftp等,具体内容如下所示:
参数实体应注意以下几点:
在这里插入图片描述在这里插入图片描述

DTD参数实体

参数实体声明:

内部:<!ENTITY % 实体名称 "实体值">
外部:<!ENTITY % 实体名称 SYSTEM "URI">
(1)使用 % 实体名(这里面空格不能少) 在 DTD 中定义,并且只能在 DTD 中使用 “%实体名;” 引用
(2)只有在 DTD 文件中,参数实体的声明才能引用其他实体
(3)和通用实体一样,参数实体也可以外部引用

简单理解呢,就是参数实体不能像普通实体那样在xml文档内容中进行引用,它的引用范围只在当前xml文件的DTD声明中,或者是当前的DTD文件中。

参数实体引用示例:

<?xml version="1.0" encoding="UTF-8"?>
**%xxe;**
  • 1

]>

在这里插入图片描述
在这里插入图片描述xml文档内容中使用“&hello”来引用定义的普通实体hello。所以这个时候,我们直接使用浏览器查看的时候,会是上面的显示。

XXE漏洞

XXE就是XML外部实体注入。当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。

利用场景:有回显和无回显

有回显的情况可以直接在页面中看到Payload的执行结果或现象(带内XML外部实体(XXE),即攻击者可以发送带有XXE有效负载的请求并从包含某些数据的Web应用程序获取响应)
抓包后构造外部实体引用,一般填写本地系统中一定纯在的文档如图中所示,发送包后可以发现文件内 内容被显示了出来
在这里插入图片描述这样我们就读取到了windows系统的system.ini的文件内容。
但是这样也不代表这个payload的就适用于任何情况,比如我们更换一个读取的文件xmltest2.txt,内容是:
在这里插入图片描述
发送数据包后就会发现产生报错,原因是xml对于5种预定义符是会产生报错提示的
在这里插入图片描述
在这里插入图片描述
解决办法:XML CDATA
在这里插入图片描述在这里插入图片描述我们也大概知道了CDATA的使用方式,但是其还需要注意几点:
a. CDATA 部分不能包含字符串 “]]>”。也不允许嵌套的 CDATA 部分,这样会导致异常的闭合,从而使解析器报错。
b. 标记 CDATA 部分结尾的 “]]>” 不能包含空格或换行。
那么了解了这些,我们就可以尝试使用CDATA再次去读取目标文件的内容,我们首先需要把要读取的到的内容放在CDATA中,但是CDATA并没有提供拼接的方法,所以我们暂且使用普通实体进行拼接尝试(注意是尝试):
我们尝试直接使用实体来进行拼接,但是测试失败:
在这里插入图片描述这说明我们的拼接方式不可行,我们现在使用的是一般实体,我们在前面的xml基础知识中介绍过了,一般实体的引用是在xml文档内容中,既然在xml文档内容中拼接不可行,那再dtd中拼接可行吗?我们再次进行尝试,既然再dtd中拼接,那就需要用到参数实体了。
我们再次尝试构造payload:
理论上,我们完美地将这几个参数实体拼接了起来,并将值赋给了一般实体all,但是遗憾的是,我们的payload还是报错了:

在这里插入图片描述那么这又是为什么呢?根据XML规范所描述:“在DTD内部子集中的参数实体调用,不能混掺到标记语言中”,这是什么意思呢?就是不能在实际的标记语言中来调用参数实体,像我们这样,就是在标记语言中进行调用:
在这里插入图片描述
但可以在同级别中被当作标记语言调用,就像是参数实体的引用,就是将调用当成了一个标记语言,像这样:

在这里插入图片描述
也就是我们所构造的payload这种使用方式,不能在内部DTD中被这样使用,但是幸运的是,XML规范还声明了一点:“外部参数实体不受此限制”,这就告诉我们可以使用外部的DTD来构造payload,将我们的CDATA内容拼接起来:

在这里插入图片描述DTD文件的内容:
在这里插入图片描述
我们再次进行攻击尝试,成功读取到文件内容:
在这里插入图片描述Ps:
由于环境资源的关系,我们在进行攻击时,所使用的外部dtd文件,是本地环境的。但是在实际的攻击情况下,这个DTD文件应该是我们自己所掌握的主机的DTD文件,文件的内容是受我们所控的。

无回显的情况又称为Blind XXE,可以使用外带数据通道提取数据即带外XML外部实体(00B-XXE)。
但是,在实际情况中,大多数情况下服务器上的 XML 并不是输出用的,所以就少了输出这一环节,这样的话,即使漏洞存在,我们的payload的也被解析了,但是由于没有输出,我们也不知道解析得到的内容是什么,因此我们想要现实中利用这个漏洞就必须找到一个不依靠其回显的方法——外带数据
相较于前面有回显的漏洞代码,我们去掉了内容输出的一部分。这样,用之前的payload就没有作用了:
在这里插入图片描述Payload的构造:
有了前面使用外部DTD文件来拼接内部DTD的参数实体的经验,我们可以知道,通过外部DTD的方式可以将内部参数实体的内容与外部DTD声明的实体的内容拼接起来,那么我们就可以有这样的设想:
我们可以在本地做一个端口监听,然后利用payload来从目标主机读取到文件内容后,将文件内容作为url的一部分来请求我们本地监听的端口,这样,我们只需要查看请求的url就可以知道读取到的内容是什么。
首先,我们使用ncat监听一个端口:
在这里插入图片描述
然后,我们构造payload:
我们选择使用外部DTD,在我们自己所能掌控(或是自己搭建)的主机上编写一个dtd文件:
在这里插入图片描述
我们注意到,第一个参数实体的声明中使用到了php的base64编码,这样是为了尽量避免由于文件内容的特殊性,产生xml解析器错误。
Payload如下:
在这里插入图片描述
如图,我们先声明一个外部的DTD引用,然后再xml文档内容中引用外部DTD中的一般实体。
开始攻击:
在这里插入图片描述然后查看我们的端口监听情况,会发现我们收到了一个连接请求,问号后面的内容就是我们读取到的文件内容经过编码后的字符串:
在这里插入图片描述
Ps:
有时候也会出现报错的情况(这是我们在漏洞的代码中没有屏蔽错误和警告),比如我们这里的payload没有选用php的base64编码,这里报错了,但是同时也将所读取的内容爆了出来,只是特殊字符经过了HTML实体编码。
在这里插入图片描述

漏洞发现

a.首先寻找接受XML作为输入内容的端点。
(可以通过修改HTTP的请求方法,修改Content-Type头部字段等等方法,然后看看应用程序的响应,然后看看程序是否解析了发送的内容,如果解析了,那么则可能有XXE攻击漏洞。)
还可以尝试注入xml预定义的一些实体,看其是否报错,通过报错信息判断
b…如果站点解析xml,就可以尝试引用实体和DTD c.如果可以。引用外部实体,则存在xxe漏洞

XXE其他攻击方式

1.通过XXE漏洞进行内网探测
当然进行内网探测我们还需要做一些准备工作,就是获取目标主机在内网中的IP地址,或是内网的网络划分信息,我们可以先利用 file 协议读取我们作为支点服务器的网络配置文件,看一下有没有内网,以及网段大概是什么样子(我以linux 为例),我们可以尝试读取 /etc/network/interfaces 或者 /proc/net/arp 或者 /etc/host 等跟内网配置有关的文件,我们可以通过这些文件的内容来获取更多有关内网的信息。如果实在没有办法获取目标主机的内网配置相关信息,那就花费时间爆破吧。
内网存活主机探测:
如下,其实payload就是简单的一个外部实体的注入payload:
在这里插入图片描述
只不过是将http://后面的部分替换为目标主机:
在这里插入图片描述就像这样,如果目标主机对应的端口开启了http服务,或是其他服务,如ftp,也是可以通过http协议来访问,这样根据目标主机的响应内容或者状态码,就可以判断主机的存活与否,根据这个原理,我们在网上找到了相应的py脚本:
在这里插入图片描述运行该脚本就能够找出相应网段是否存在开启http服务的主机。
2.内网主机端口探测:
同样的,根据内网存活主机的扫描方式,我们也可以针对某个主机进行端口的扫描:
构造payload:
在这里插入图片描述
扫描的大概原理是这样的:
比如你扫描一个关闭的端口,在等待了一段时间后,返回协议连接失败且超过了最长时间限制30秒:
在这里插入图片描述 而你扫描开放的端口,也可能是内容错误等其他的警告信息:
在这里插入图片描述Ps:
有时候,端口扫描时判断端口的开放和关闭并不是虚拟机中这个样子,由于环境的不同,版本的不同,你可能会遇到的状况是:关闭的端口在超时之后,返回的是500状态码。
在这里插入图片描述而开放的端口,返回的是200的状态码,以及一些xml警告信息,有时候还会附带上我们payload中期望输出的字符串。
在这里插入图片描述在这里插入图片描述 所以,在进行内网探测时,探测结果判定的依据,还需要你自己来判断。你可以是根据返回状态码,也可以是根据返回的警告信息的内容,又或者你也可以尝试根据返回信息的时间长短。
3.通过XXE漏洞进行DOS攻击(不要轻易尝试!!!!!!!!)。
Payload如下:
在这里插入图片描述 上面的payload就是著名的“billionlaughs”攻击,该代码可以在目标主机的内存中生成十亿个“lol”字符串,从而导致 Dos攻击。它也被称为指数实体扩展攻击,是一种名副其实的XML炸弹。原理为:通过创建一项递归的 XML 定义,构造恶意的XML实体文件耗尽可用内存,如以上代码所示,在XMl中定义了一个实体lol9,它的值包含了十个实体lol8的值,而每个lol8又包含了十个lol7的值…最后产生10亿个“lol”字符串,占用内存约高达3GB。因为许多XML解析器在解析XML文档时倾向于将它的整个结构保留在内存中,解析非常慢,这样,就会占用大量的内存资源,造成了拒绝服务器攻击。

本文参考某大佬博客以及合天安全公司实验所完成

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/590010
推荐阅读
相关标签
  

闽ICP备14008679号