[NISACTF 2022]popchains

[NISACTF 2022]popchains wp

题目代码:

Happy New Year~ MAKE A WISH
';

if(isset($_GET['wish'])){
    @unserialize($_GET['wish']);
}
else{
    $a=new Road_is_Long;
    highlight_file(__FILE__);
}
/***************************pop your 2022*****************************/

class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
    }
    public function __toString(){
        return $this->string->page;
    }

    public function __wakeup(){
        if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
        }
    }
}

class Try_Work_Hard{
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Make_a_Change{
    public $effort;
    public function __construct(){
        $this->effort = array();
    }

    public function __get($key){
        $function = $this->effort;
        return $function();
    }
}
/**********************Try to See flag.php*****************************/

是一道 PHP 反序列化题。

先来回顾一下 PHP 全部魔术方法及其触发条件

__construct()– 在创建对象时调用,用于初始化对象的属性和方法。
__destruct() – 在对象销毁时调用,用于释放资源和清理操作。
__call(args) – 在调用一个不存在的方法时触发。
__callStatic(args) – 在调用一个不存在的静态方法时触发。
__get($name) – 在访问一个不存在的属性时触发。
__set(value) – 在给一个不存在的属性赋值时触发。给私有属性,受保护属性赋值也能触发。
__isset($name) – 在判断一个不存在的属性是否存在时触发。
__unset($name) – 在销毁一个不存在的属性时触发。
__sleep() – 在序列化一个对象时触发。
__wakeup() – 在反序列化一个对象时触发。
__toString() – 在将对象转换为字符串时触发。echo,print,die,preg_match,strtolower等函数操作对象时触发,还有弱比较 == 也能触发。
__invoke($args) – 在将对象作为函数调用时触发。
__set_state($properties) – 在使用var_export()导出类时触发。
__clone() – 在将对象复制时触发。
__debugInfo() – 在使用var_dump()函数打印对象时触发。

构造 pop 链

include() 函数在 Try_Work_Hard 类的 append 方法里,并且该类的 __invoke() 方法调用了 append 方法;

Try_Work_Hard 类的 __invoke() 方法可以在 Make_a_Change 类的 __get 方法中被触发:return $function();

Make_a_Change 类的 __get 方法可以在 Road_is_Long 类的 __toString() 方法中被触发:return $this->string->page;

Road_is_Long 类的 __toString() 方法可以在 Road_is_Long 类的 __wakeup() 方法中被触发:preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page) ,原因是:

preg_match() 函数用于在字符串中执行正则表达式匹配。它接受一个字符串作为输入,而不是一个对象。如果你传递一个对象给 preg_match() 函数,PHP 会尝试将这个对象转换为一个字符串,就触发了该对象的 __toString() 方法

Road_is_Long 类的 __wakeup() 方法在反序列化时被触发;

这样,pop 链就构造完成了,以下是代码:

page = new Road_is_Long();
$demo->page->string = new Make_a_Change();
$demo->page->string->effort = new Try_Work_Hard();
echo urlencode(serialize($demo));

根据提示,我去读取 flag.php 文件,但是怎样都读取不出来,明明同样的代码,换成 /etc/passwd 都能读出来。后来看了大佬的 wp ,得知 flag 在根目录下,合着 flag.php 只是个幌子呗。

拿到 flag :

[NISACTF 2022]popchains_第1张图片

你可能感兴趣的:(ctf,web安全,网络安全)