本篇文章主要給大家介紹了關(guān)于PHP的相關(guān)知識(shí),序列化其實(shí)就是將數(shù)據(jù)轉(zhuǎn)化成一種可逆的數(shù)據(jù)結(jié)構(gòu),自然,逆向的過(guò)程就叫做反序列化。php將數(shù)據(jù)序列化和反序列化會(huì)用到兩個(gè)函數(shù):serialize 將對(duì)象格式化成有序的字符串、unserialize 將字符串還原成原來(lái)的對(duì)象,希望對(duì)大家有幫助。
(推薦教程:PHP視頻教程)
簡(jiǎn)介
序列化的目的是方便數(shù)據(jù)的傳輸和存儲(chǔ),在PHP中,序列化和反序列化一般用做緩存,比如session緩存,cookie等。
反序列化中常見(jiàn)的魔術(shù)方法
-
__wakeup() //執(zhí)行unserialize()時(shí),先會(huì)調(diào)用這個(gè)函數(shù)
-
__sleep() //執(zhí)行serialize()時(shí),先會(huì)調(diào)用這個(gè)函數(shù)
-
__destruct() //對(duì)象被銷毀時(shí)觸發(fā)
-
__call() //在對(duì)象上下文中調(diào)用不可訪問(wèn)的方法時(shí)觸發(fā)
-
__callStatic() //在靜態(tài)上下文中調(diào)用不可訪問(wèn)的方法時(shí)觸發(fā)
-
__get() //用于從不可訪問(wèn)的屬性讀取數(shù)據(jù)或者不存在這個(gè)鍵都會(huì)調(diào)用此方法
-
__set() //用于將數(shù)據(jù)寫入不可訪問(wèn)的屬性
-
__isset() //在不可訪問(wèn)的屬性上調(diào)用isset()或empty()觸發(fā)
-
__unset() //在不可訪問(wèn)的屬性上使用unset()時(shí)觸發(fā)
-
__toString() //把類當(dāng)作字符串使用時(shí)觸發(fā)
-
__invoke() //當(dāng)嘗試將對(duì)象調(diào)用為函數(shù)時(shí)觸發(fā)
反序列化繞過(guò)小Trick
php7.1+反序列化對(duì)類屬性不敏感
我們前面說(shuō)了如果變量前是protected,序列化結(jié)果會(huì)在變量名前加上x00*x00
但在特定版本7.1以上則對(duì)于類屬性不敏感,比如下面的例子即使沒(méi)有x00*x00
也依然會(huì)輸出abc
<?php class test{ protected $a; public function __construct(){ $this->a = 'abc'; } public function __destruct(){ echo $this->a; } } unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');
繞過(guò)_wakeup(CVE-2016-7124)
版本:
PHP5 < 5.6.25
PHP7 < 7.0.10
利用方式:序列化字符串中表示對(duì)象屬性個(gè)數(shù)的值大于真實(shí)的屬性個(gè)數(shù)時(shí)會(huì)跳過(guò)__wakeup的執(zhí)行
對(duì)于下面這樣一個(gè)自定義類
<?php class test{ public $a; public function __construct(){ $this->a = 'abc'; } public function __wakeup(){ $this->a='666'; } public function __destruct(){ echo $this->a; } }
如果執(zhí)行unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');
輸出結(jié)果為666
而把對(duì)象屬性個(gè)數(shù)的值增大執(zhí)行unserialize('O:4:"test":2:{s:1:"a";s:3:"abc";}');
輸出結(jié)果為abc
繞過(guò)部分正則
preg_match('/^O:d+/')
匹配序列化字符串是否是對(duì)象字符串開(kāi)頭,這在曾經(jīng)的CTF中也出過(guò)類似的考點(diǎn)
利用加號(hào)繞過(guò)(注意在url里傳參時(shí)+要編碼為%2B)
serialize(array(a ) ) ; / / a));//a));
//a為要反序列化的對(duì)象(序列化結(jié)果開(kāi)頭是a,不影響作為數(shù)組元素的$a的析構(gòu))
<?php class test{ public $a; public function __construct(){ $this->a = 'abc'; } public function __destruct(){ echo $this->a.PHP_EOL; } } function match($data){ if (preg_match('/^O:d+/',$data)){ die('you lose!'); }else{ return $data; } } $a = 'O:4:"test":1:{s:1:"a";s:3:"abc";}'; // +號(hào)繞過(guò) $b = str_replace('O:4','O:+4', $a); unserialize(match($b)); // serialize(array($a)); unserialize('a:1:{i:0;O:4:"test":1:{s:1:"a";s:3:"abc";}}');
利用引用
<?php class test{ public $a; public $b; public function __construct(){ $this->a = 'abc'; $this->b= &$this->a; } public function __destruct(){ if($this->a===$this->b){ echo 666; } } } $a = serialize(new test());
上面這個(gè)例子將$b
設(shè)置為$a
的引用,可以使$a
永遠(yuǎn)與$b
相等
16進(jìn)制繞過(guò)字符的過(guò)濾
O:4:“test”:2:{s:4:“%00*%00a”;s:3:“abc”;s:7:“%00test%00b”;s:3:“def”;}
可以寫成
O:4:“test”:2:{S:4:“