XXE漏洞学习笔记
导读
1.XML基础知识
2.DTD基础知识-定义-内外DTD声明-优势
3.DTD基础知识-元素
4.DTD基础知识-实体-外部实体支持协议
5.XXE漏洞原理-有回显和无回显漏洞利用
6.其他危害-payload
7.检测和防御
1.XML基础知识
1.1XML定义:
XML 被设计用来传输和存储数据。
HTML 被设计用来显示数据
XML语言没有预定义的标签,允许作者定义自己的标签和自己的文档结构
- 元素
- 属性
- 实体
- PCDATA
- CDATA
HTML 元素的例子是 "body" 和 "table"。XML 元素的例子是 "note" 和 "message" 。元素可包含文本、其他元素或者是空的。空的 HTML 元素的例子是 "hr"、"br" 以及 "img"。
实例:
<body>body text in between</body>
<message>some message in between</message>
属性总是被置于某元素的开始标签中。属性总是以名称/值的形式成对出现的。下面的 "img" 元素拥有关于源文件的额外信息:
这样会产生 XML 错误:
< 1000 then</message>
为了避免这个错误,请用实体引用来代替 "<" 字符
当文档被 XML 解析器解析时,实体就会被展开。
1.6PCDATA
1.7CDATA
CDATA 是不会被解析器解析的文本。
在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
1.8XML的语法规则:
XML 文档必须有一个根元素
XML 元素都必须有一个关闭标签
XML 标签对大小敏感
XML 元素必须被正确的嵌套
XML 属性值必须加引导
<!--自定义的4个子元素,即girl对象的属性-->
<eye>大眼睛</eye>
<face>可爱的脸庞</face>
<summary>可爱美丽的女孩</summary>
<!--根元素的闭合-->
1.9XML 中的注释
<!-- This is a comment -->
2.DTD基础知识-定义-内外DTD声明-优势
2.1DTD (Document Type Definition)文档类型定义
上述XML代码基本分为三个部分:
第一部分是XML的声明;
第三部分是XML语句
DTD有两种构建方式,分别为内部DTD声明和外部DTD声明
2.2内部DTD声明:
<!DOCTYPE 根元素 [元素声明]>
2.3外部DTD声明
这是包含 DTD 的 "note.dtd" 文件:
2.4引用公共DTD(了解)
示例:
命名方法:以!DOCTYPE开始,configuration是文档根元素名称;
PUBLIC表示是公共DTD;-表示是非ISO组织;mybatis.org表示组织;
DTD 表示类型;Config 表示标签;3.0是标签后附带的版本号;
EN表示DTD语言是英语;最后是DTD的URL;
2.5为什么使用 DTD?
通过 DTD,您的每一个 XML 文件均可携带一个有关其自身格式的描述。
通过 DTD,独立的团体可一致地使用某个标准的 DTD 来交换数据。
而您的应用程序也可使用某个标准的 DTD 来验证从外部接收到的数据。
您还可以使用 DTD 来验证您自身的数据。
3. DTD基础知识-元素
3.1 声明一个元素
或者
3.2 空元素
例子:
XML例子:
3.3只有 PCDATA 的元素
<!ELEMENT 元素名称 (#PCDATA)>
例子:
<!ELEMENT from (#PCDATA)>
3.4带有子元素(序列)的元素
或者
例子:
当子元素按照由逗号分隔开的序列进行声明时,这些子元素必须按照相同的顺序出现在文档中。在一个完整的声明中,子元素也必须被声明,同时子元素也可拥有子元素。"note" 元素的完整声明是:
4.DTD基础知识-实体-外部实体支持协议
4.1简介
实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
实体引用是对实体的引用。
实体可在内部或外部进行声明。
4.2分类
XML 中的实体分为以下五种:字符实体,命名实体,外部实体,参数实体,内部实体,普通实体和参数实体都分为内部实体和外部
注意:libxml2.9.1及以后,默认不解析外部实体。测试的时候window下使用的是php5.2(libxml Version 2.7.7 ), php5.3(libxml Version 2.7.8)。Linux中需要将libxml低于libxml2.9.1的版本编译到PHP中,可以使用phpinfo()查看libxml的版本信息。
4.5一个内部实体(也有叫命名实体的,把嵌套实体当做内部实体)声明
语法:
例子:
一个实体由三部分构成:&符号, 实体名称, 分号 (;),这里&不论在GET还是在POST中都需要进行URL编码,因为是使用参数传入xml的,&符号会被认为是参数间的连接符号,示例:
4.6一个外部实体声明
语法:
例子:
当XML解析器解析xml文档是,会将URL中的值读出,并把读出内容替换掉xxe,变成file:///ect/passwd的内容。
默认协议
外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,具体内容如下所示:
PHP拓展协议
4.7参数实体声明
示例
外部evil.dtd中的内容。
可以看到win.ini中的敏感文件都已经被读取出来
这里,一定要注意流程,参数实体在DTD中解析是优先于XML文本中的内部实体解析。
参数实体有几个特性,这几个特性也决定了它能被利用的程度:
l 只能在DTD内部
l 立即引用
l 实体嵌套
5.XXE漏洞原理-有回显和无回显漏洞利用
5.1 XXE漏洞简介
从安全角度理解成XML External Entity attack 外部实体注入攻击。
近期看到OWASP TOP 10 2017 版中添加了XXE的内容便对XXE的一些知识进行梳理和总结,XXE可以使用例如http,file等协议,所以可以利用支持的协议进行内网探测和内网入侵,这部分的内容后续在SSRF中补充。
要点:libxml2.9.1及以后,默认不解析外部实体。测试的时候window下使用的是php5.2(libxml Version 2.7.7 ), php5.3(libxml Version 2.7.8)。Linux中需要将libxml低于libxml2.9.1的版本编译到PHP中,可以使用phpinfo()查看libxml的版本信息。
参考链接:
http://vulhub.org/#/environments/php_xxe/
5.2测试源码
有回显有报错测试代码:
无回显无报错测试代码:
5.3使用DTD的利用方式
一般xxe利用分为两大场景:有回显和无回显。有回显的情况可以直接在页面中看到Payload的执行结果或现象,无回显的情况又称为blind xxe,可以使用外带数据通道提取数据。
1. 有回显情况:
有回显的情况可以使用如下的两种方式进行XXE注入攻击。
外部实体声明
参数实体声明
外部evil.dtd中的内容。
2. 无回显的情况:
可以使用外带数据通道提取数据,先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。
evil.dtd的内容,内部的%号要进行实体编码成 %
有报错直接查看报错信息。
无报错需要访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。
6.其他危害
6.1DDOS
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]>
<lolz>&lol9;</lolz>
这个的原理就是递归引用,lol 实体具体还有 “lol” 字符串,然后一个 lol2 实体引用了 10 次 lol 实体,一个 lol3 实体引用了 10 次 lol2 实体,此时一个 lol3 实体就含有 10^2 个 “lol” 了,以此类推,lol9 实体含有 10^8 个 “lol” 字符串,最后再引用lol9。
待补充
7.防御
漏洞检测
1)观察请求中是否存在 Content-Type为xml相关的数据包,以及是否发送xml请求数据,则程序后端很大概率存在xml解析逻辑
2)业务上传xml文件数据的请求接口,可通过上传含外部实体加载的POC去验证是否存在漏洞
漏洞防御
主要介绍Java和php的通用防御方式。
1)Java
- dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true); //禁用DTD (doctypes),几乎可以防御所有XXE攻击
- 如果不能禁用DTD,可以使用下两项,必须两项同时存在
- bf.setFeature("http://xml.org/sax/features/external-general-entities",false); //防止外部普通实体POC 攻击
- dbf.setFeature("http://xml.org/sax/features/external-parameter-entities",false); //防止外部参数实体POC攻击
2)php
libxml_disable_entity_loader(true); //禁止加载外部实体