XML注入简介
什么是xml?
XML 指可扩展标记语言(EXtensible Markup Language)
XML 是一种标记语言,很类似 HTML
XML 的设计宗旨是传输数据,而非显示数据
XML 标签没有被预定义。您需要自行定义标签。
XML 被设计为具有自我描述性。
XML 是 W3C 的推荐标准
例如:在tomcat中配置文件的存储格式便是XML文件,server.xml、web.xml
xml特点
XML仅仅是纯文本,他不会做任何事情。
XML可以自己发明标签(允许定义自己的标签和文档结构)
XML 无所不在。XML 是各种应用程序之间进行数据传输的最常用的工具,并且在信息存储和描述领域变得越来越流行。
总结成一句话就是:XML是用来存储数据的
xml的定义
推荐学习文章如下:
https://www.w3school.com.cn/xml/xml_syntax.asp
https://jingyan.baidu.com/article/77b8dc7fb26f366174eab639.html
https://www.cnblogs.com/weiyinfu/p/5374824.html
最终得出一个结构
首先进行XML声明,然后是DTD部分 ==>> <!DOCTYPE 变量名 <元素>>
也就是XML名单定义,最后XML文档元素,如下代码
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY test SYSTEM "file:///etc/passwd">
]>
<a>
<b>&test;</b>
</a>
什么是XML注入?
XML注入又叫XXE攻击
XXE = XML External Entity 即外部实体,从安全角度理解成XML External Entity attack 外部实体注入攻击
有了XML实体,关键字’SYSTEM’会令XML解析器从URI中读取内容,并允许它在XML文档中被替换
因此,攻击者可以通过实体将他自定义的值发送给应用程序,然后让应用程序去呈现
简单来说,攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件)
XXE扩展
<!ENTITY 实体名称 SYSTEM “URI/URL”>
外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,具体内容如下所示:
知识扩展
php伪协议
php伪协议实际上就是支持与封装的协议(共十二种)
a. file:// — 访问本地文件系统
b. http:// — 访问 HTTP(s) 网址
c. ftp:// — 访问 FTP(s) URLs
d. php:// — 访问各个输入/输出流(I/O streams)
e. zlib:// — 压缩流
f. data:// — 数据(RFC 2397)
g. glob:// — 查找匹配的文件路径模式
h. phar:// — PHP 归档
i. ssh2:// — Secure Shell 2
j. rar:// — RAR
k. ogg:// — 音频流
l. expect:// — 处理交互式的流
file://协议
file://协议在双off的情况下也是可以正常使用的
allow_url_fopen :off/on
allow_url_include:off/on
file://用于访问本地文件系统,在CTF中常用来读取本地文件
使用方法:file://文件的绝对路径和文件名
php://协议
php://协议的使用条件:
1. 不需要开启allow_url_fopen
2. php://input、 php://stdin、 php://memory 和 php://temp 需要开启allow_url_include。
php://filter 用于读取源码且在双off的情况下也可以正常使用
allow_url_fopen :off/on (使用条件)
allow_url_include:off/on
Eg: http://127.0.0.1/cmd.php?file=php://filter/read=convert.base64-encode/resource=index.php
php://input 可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。
allow_url_fopen :off/on
allow_url_include:on
Eg:http://127.0.0.1/cmd.php?file=php://input
[POST DATA] <?php phpinfo()?>
漏洞原理
XXE漏洞形成大体有4种方式:
- simplexml_load_string()函数造成的回显注入
- SimpleXMLElement()对象造成的回显注入
- DOMDocument()类造成的回显注入
- BlindXXE形式==>>也是由simplexml_load_string()函数造成的无回显注入
simplexml_load_string()函数
转换形式良好的XML字符串为SimpleXMLElement对象,然后输出对象的键和元素,下面的菜鸟教程测试代码
个人测试代码如下
SimpleXMLElement()对象
此函数用来实例化一个SimpleXML,如下代码
$index = new SimpleXMLElement('<doc></doc>');
实际代码测试如下
DOMDocument()类
参考文章:
https://blog.csdn.net/ssll2826/article/details/84080038
https://bbs.csdn.net/topics/360051568?list=19321717
实例测试如下图
特别注意:最初的php版本显示不了dom信息,需要php5.3以上才支持(必须加粗加红,看了半天)
漏洞实现
回显类
simplexml_load_string()函数,提交的post数据为,较好形式的XML字符串,如下图
SimpleXMLElement()对象和DOMDocument()类,测试与上图一致
无回显类
我们先读取我们想要的文件,然后为了传输方便,我们先来个base64编码,我们可以使用php伪协议读取文件(仅PHP支持)
在无回显的时候我们就需要引用外部实体了
下面是个人搭建的靶场
$postStr是个可控变量,$GLOBALS超全局变量,”HTTP_RAW_POST_DATA”是我们传的参数
simplexml_load_string()函数转换形式良好的XML字符串为SimpleXMLElement对象,如下图所示
构造代码
需要我们提交的xml形式的字符串,由于页面无法给我们回显,得尝试其他发放,首先我们需要上传的参数,首先声明文件,在DTD部分,定义file实体存储通过php伪协议读取的flag.php文件,然后引用外部实体,如下图所示
构造其中的1.xml文件,定义send实体,通过get方式向2.php传参,参数值为file实体,注意标红部分不得用%,必须转码,为了避免和上面的%号冲突,实际测试不转也不行,如下图所示
构造2.php文件,向3.txt文件写入file实体的内容,如下图所示
说一下大体流程
第一个图:我们提交的poyload,是通过php伪协议读取flag文件内容,报错到变量file中%remote调用DTD中的第二个元素,去访问一个远程的xml文件
第二个图:元素吧我们之前读到额flag文件作为传参值,去访问本地一个php文件
第三个图:php文件的作用是把接受到的get传参得到的内容保存到一个txt文件中
通过这个方式我们可以成功读取,告别了无回显不知道读取内容的尴尬,手动抱拳
抓包测试
打开burp,抓取数据包,修改为POST,并打上传参值,如下图所示
得到3.txt,如下图所示
漏洞防御
漏洞条件
1、当程序允许引用XML外部实体时
2、用户能自由控制输入
防御方案
目前对于XXE漏洞防御最主要的还是禁用加载外部实体的功能;以PHP为例,你只需在代码中配置
libxml_disable_entity_loader(true);
如果不禁用加载外部实体,只过滤用户的输入
- 白名单过滤-可行
- 黑名单过滤-不建议
- 字符转义-可行