技术改变世界,文化改变人心

实例化漏洞和XXE

一道实例化漏洞和XXE结合的题

题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//index.php
<?php
show_source(__FILE__);
class NotFound{
function __construct()
{
die('404');
}
}
spl_autoload_register(
function ($class){
new NotFound();
}
);
$classname = isset($_GET['name']) ? $_GET['name'] : null;
$param = isset($_GET['param']) ? $_GET['param'] : null;
$param2 = isset($_GET['param2']) ? $_GET['param2'] : null;
if(class_exists($classname)){
$newclass = new $classname($param,$param2);
var_dump($newclass);
foreach ($newclass as $key=>$value)
echo $key.'=>'.$value.'<br>';
}
1
2
3
4
//flag13Here.php
<?php
$flag = "HRCTF{X33_W1tH_S1mpl3Xml3l3m3nt}";
?>

解法分析

先看可控的点:

有三个get参数的点可以控制,分别是$classname,$param,$param2

再往后看,$classname可以让我们实例化一个类,这个类是我们可控的,而且可以控制该类构造方法的前两个参数

这个地方很容易想到PHP的内置类:SimpleXMLElement,可以进行xxe攻击,但是我们现在不知道flag文件的名字,这个时候可以用PHP中的另外一个内置类:GlobIterator,可以列出来所有匹配的文件名(这个类有点像glob://协议):

根据文档,很容易理解GlobIterator类的构造方式,而第二个参数控制的是输出的键值,可以选择0,所以构造payload:

?name=GlobIterator&param1=./*.php&param2=0

发现成功读出当前目录的文件

现在已经知道了flag的文件名,那么我们可以构造SimpleXMLElement类来进行XXE来读取flag文件的内容

先看一下SimpleXMLElement的构造方法

第一个参数可以是XML的文件路径,可以是XML文件内容,也可以是URL(需要第三个参数为true)

第二个参数为系统预定义的常量,具体的意义如下:

为了避免一些特殊字符的错误,我们将结果进行base64编码:

构造payload为:name=SimpleXMLElement&param=/Library/WebServer/Documents/PhpProjects/CTF_php/flag13Here.php&param2=2

即可读取到结果: