php代碼注入漏洞PHP中的魔法函數(shù)反序列化漏洞原理(2)_php注入代碼
2022-04-26
序列化和反序列化簡介
() 將對象轉換為字符串, () 將字符串恢復為對象。在PHP應用中,序列化和反序列化一般用于緩存,比如緩存等。簡單來說,序列化就是將一個對象轉換成可以傳輸?shù)淖址葱蛄谢褪怯靡粋€對象替換原來的字符。
簡單示例
php
class test{
public $suifeng="shuai";
}
$a=new test(); //實例化一個對象
$b=serialize($a); //進行序列化
echo $b; //輸出序列化后的字符串
echo '
';
echo "我是分割線";
$c=unserialize($b); //把序列化后的字符串反序列化
echo '
';
echo $c->suifeng;
?>
下面我們來看看反序列化后輸出字符的含義
第一個輸出是
O:4:"test":1:{s:7:"";s:5:"";}
O->object
4->object的長度
test->object的名稱
1->object中變量個數(shù)
s->變量名數(shù)據(jù)類型
7->變量名長度
suifeng->變量名
S->變量值數(shù)據(jù)類型
5->變量值長度
shuai->變量的值
PHP 其他數(shù)據(jù)類型
a - array
b - boolean
d - double
i - integer
o - common object
r - reference
s - string
C - custom object
O - class
N - null
R - pointer reference
U - unicode string
PHP 常用魔法函數(shù)
() //創(chuàng)建對象時調用
() //在對象被銷毀之前調用
() //調用類中不存在的方法時執(zhí)行
() //調用類中不存在的靜態(tài)方法方法時執(zhí)行。
() //反序列化后會立即調用
() //在對象序列化之前調用
() //對象作為字符串時調用
() //用于從不可訪問的屬性中讀取數(shù)據(jù)
() //用于將數(shù)據(jù)寫入不可訪問的屬性
() //調用函數(shù)的方式,調用對象時的響應方式
() // 在不可訪問的屬性上調用 () 或 () 來觸發(fā)
() // 當 () 用于不可訪問的屬性時觸發(fā)
,, 序列化對象的區(qū)別
php v7.x在反序列化時對訪問類型不敏感
變量
直接變量名反序列化
變量
\x00 + * + \x00 + 變量名
您可以使用 S:5:"\00*\00op" 代替 s:5:"?*?op"
變量
\x00 + 類名 + \x00 + 變量名
反序列化漏洞的條件
1、函數(shù)的參數(shù)可控
2、后臺使用PHP中對應的魔術函數(shù)
反序列化漏洞原理
讓我們先運行下面的代碼
';
}
function __destruct(){
echo '調用了析構函數(shù)
';
}
function __wakeup(){
echo '調用了蘇醒函數(shù)
';
}
}
echo '創(chuàng)建對象a
';
$a=new ABC;
echo '序列化
';
$a_ser=serialize($a);
echo '反序列化
';
$a_unser=unserialize($a_ser);
echo '對象快死了!';
?>
PHP語言本身的漏洞
還有一個反序列化漏洞是由于PHP語言本身的一個漏洞遇到了某些特征而導致的
示例:導致失敗 (CVE-2016-7124)
php版本
在序列化字符串中,如果代表對象屬性個數(shù)的值大于實際屬性個數(shù),則跳過()的執(zhí)行
序列化問題
當 () 被調用或 .在php.ini中為1,PHP內(nèi)部調用會話管理器,將訪問用戶序列化后存放在指定目錄下(默認為/tmp)。
PHP中共有三種序列化處理器,如下:
處理器
對應的存儲格式
php
鍵名+豎線+()函數(shù)反序列化的值
鍵名長度+鍵名+()函數(shù)反序列化的值對應的字符
(php>=5.5.4)
()函數(shù)反序列化處理的數(shù)組
配置文件php.ini包含這些與存儲配置相關的配置項:
.="" -- 設置的存儲路徑,默認為/tmp
。 --指定會話模塊是否在請求開始時啟動會話網(wǎng)站開發(fā),默認為0不啟動
。 --定義用于序列化/反序列化的處理程序的名稱。默認使用php
.="" --設置用戶自定義存儲函數(shù),如果要使用PHP內(nèi)置的存儲機制php代碼注入漏洞,可以使用這個函數(shù)(數(shù)據(jù)庫等),比如存儲為文件默認情況下
并且PHP中默認使用PHP引擎。如果我們要修改到另一個引擎,我們需要添加代碼('.', 'The to be set'),例如:
;
:即元數(shù)據(jù)、壓縮文件的屬性等信息,以序列化方式存儲
:壓縮文件的內(nèi)容
:簽名,放在文件末尾
這里有兩個關鍵點,一個是文件標識符,必須以();?>結尾,但是對前面的內(nèi)容沒有限制,也就是說我們可以很容易的偽造一個圖片文件或者其他文件來繞過一些上傳限制;二是反序列化。存儲在phar中的元數(shù)據(jù)信息是以序列化的方式存儲的。當文件操作函數(shù)通過phar://偽協(xié)議解析phar文件時,數(shù)據(jù)會被反序列化,這樣的文件操作函數(shù)有很多
先決條件
Phar.=Off 在 php.ini 中設置
php >=5.3.0
演示測試
根據(jù)文件結構,我們自己構建一個phar文件。 PHP 有一個內(nèi)置的 Phar 類來處理相關操作
startBuffering();
$phar->setStub(""); //設置stub
$o = new TestObject();
$phar->setMetadata($o); //將自定義的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要壓縮的文件
//簽名自動計算
$phar->stopBuffering();
?>
很明顯是以序列化的形式存儲的
如果我們現(xiàn)在通過 phar:// 包裝器對現(xiàn)有的 Phar 文件執(zhí)行文件操作,它的序列化元數(shù)據(jù)將被反序列化。這意味著我們在元數(shù)據(jù)中注入的對象被加載到應用程序的范圍內(nèi)。如果這個應用程序有一個命名類并且定義了魔法方法() 或 has(),這些方法將被自動調用。這意味著我們可以在我們的代碼庫中觸發(fā)任何析構函數(shù)或喚醒方法。更糟糕的是,如果這些方法對我們注入的數(shù)據(jù)進行操作,這可能會導致更多漏洞。
以下是受影響的功能列表
此時可以使用phar://協(xié)議
使用條件
可以上傳phar文件
文件操作函數(shù)的參數(shù)可控,不過濾:,/phar等特殊字符
有一些魔術方法可用作“跳板”
反序列化字符轉義
當 PHP 反序列化時,底層代碼使用 ;作為字段分隔符,}作為結尾(字符串除外),根據(jù)長度判斷內(nèi)容。同時,反序列化過程必須嚴格按照序列化過程進行。成功實現(xiàn)反序列化的規(guī)則。
我們來分析一段代碼
';
echo $c->suifeng;
?>
發(fā)現(xiàn)序列化為O:4:"test":1:{s:7:"";s:5:"";},反序列化也正常進行。當我們修改序列化結果為 O:4:"test":1:{s:7:"";s:5:"";}i:1;s:4:"test";正常解析。
但是如果我們修改它的長度,就會報錯,比如O:4:"test":1:{s:7:"";s:4:"";}
知道了這個特性,下面我們來分析一下代碼
可以看到反序列化為a:2:{i:0;s:5:"";i:1;s:4:"1234";},當我們修改參數(shù)為 進程首先反序列化$user,然后執(zhí)行函數(shù)中的函數(shù),用它替換test,導致長度不一致,最終導致反序列化失敗。
a:2:{i:0;s:9:"";i:1;s:4:"1234";}
a:2:{i:0;s:9:"";i:1;s:4:"1234";}
假設這個代碼流是創(chuàng)建賬戶的代碼流,此時$可以被用戶控制,那么我們可以通過控制可控參數(shù)使反序列化字符轉義。它的本質其實和sql注入一樣,雙引號和大括號的閉合,但是反序列化字符的轉義需要滿足其特性的一些條件。接下來我們構建它。
因為它是用 ; 嚴格分隔的作為字段并以 } 結尾(字符串除外),我們可以這樣關閉它。
可以看到我們構造了$=";i:1;s:6:"";},它被序列化為a:2:{i:0;s:29:"";i: 1; s:6:"";}";i:1;s:4:"1234";},經(jīng)過這個序列化后,我們會反序列化它,紅色部分不會進入反序列化。但是可以看到替換后反序列化還是沒有成功,我們來分析一下。
替換后我們得到
a:2:{i:0;s:29:"";i:1;s:6:"";}";i:1;s:4:"1234";},紅色部分is 反序列化時會被忽略,要反序列化的字段是
a:2:{i:0;s:29:"";i:1;s:6:"";}
可以看到這里的 s:29:"" 顯然是錯誤的,所以我們的反序列化會失敗,那么我們?nèi)绾伪3终_呢?這是我們在反序列化字符轉義特征時需要考慮的。東西。
在 ('test','',$) 代碼中,test 被替換為比前一個 test 多一個字符,所以只要我們添加足夠多的 test 來替換它相同的長度,這將允許我們的反序列化正常進行。
我們構建
";i:1;s:6:"";}
這樣php代碼注入漏洞網(wǎng)站開發(fā),我們修改了零錢業(yè)務的密碼