0x1 定義
php使用serialize()這個過程被稱爲序列化,使用unserialize()這個過程被稱作反序列化。
0x2 serialize()
用於序列化對象或數組,並返回一個字符串。序列化會保存對象中的所有變量,不會保存對象的方法,只會保存類的名字。PHP序列化就是將內存的變量數據“保存”到文件的持久數據的過程
例子:
<?php
class User
{
/*類的變量*/
public $name = '';
public $age = 0;
/*方法:打印數據*/
public function PrintData(){
echo 'user'.' name:'.$this->name.' age:'.$this->age;
}
}
//創建一個對象
$user = new User();
$user->name = 'iring';
$user->age = 18;
//輸出數據
$user->PrintData();
echo "\n";
//輸出序列化後的數據
echo serialize($user);
可以發現對於對象,序列化後的格式爲:
O:strlen(類名):類名:類的變量個數:{類型:長度:值;類型:長度:值…}
注:對象中的常量在序列化後是不會保留的。如果存在類的繼承,會保留父類中的變量
其他類型的數據序列化後的格式爲:
String類型 : s:size:value;
Integer類型 : i:size:value;
Boolean類型 : b:value;
(保存1或0)
Null型 : N;
Array : a:size:{key definition;value definition}
0x3 unserialize()
函數用於將通過serialize()函數序列化後的對象或者數組進行反序列化,並返回原始對象的結構。可以將反序列化理解爲就是:將文件中的持久數據轉變成內存中的變量數據
//輸出序列化後的數據
$temp = serialize($user);
echo $temp."\n";
//反序列化
$ans = unserialize($temp);
echo $ans->PrintData();
0x4 PHP反序列化漏洞
需要了解PHP的“魔法函數”:以__(兩個下劃線)開頭的類方法被保留爲魔法方法。這些方法會在特定的時候被調用。例子
__construct() 當一個對象被創建時候被調用(構造方法)
__destruct() 當一個對象被銷燬的時候調用(析構方法)
__toString() 當一個對象被當做字符串時被調用
__wakeup() 當使用unserialize時候觸發
__sleep() 當使用serialize時候觸發
對象注入
因爲PHP允許對象序列化,因此用戶可以提交序列化的字符串,若沒有對請求進行嚴格的過濾,在傳遞給unserialize()函數後就可能造成PHP對象注入漏洞。
對象漏洞需要滿足的前提:
- unserialize()的參數可控的。
- 代碼中含有一個包含魔法方法的類,並且該類方法裏出現一些使用類成員變量作爲參數的存在安全問題的函數。
例子:
<?php
error_reporting(0);
class Test
{
var $test = "demo";
function __destruct()
{
@eval($this->test);
}
}
$a = $_POST['test'];//POST方法獲得前端數據
print_r($a);
$b = unserialize($a);//對傳入的字符串反序列化
程序結束時會銷燬變量,會觸發__destruct()函數,我們可以通過反序列化構造出變量的值,使得其中的內容被當做代碼去執行。構造一個Payload測試一下:
test=O:4:"Test":1:{s:4:"test";s:10:"phpinfo();";}
繞過魔法函數的反序列化
wakeup()魔法函數繞過
PHP5<5.6.25
PHP7<7.0.10
當在反序列化字符串中,表示屬性個數的值大於真實屬性個數時,會繞過__wakeup()函數的執行