php淺析反序列化結構
2022-07-26 14:00:03
簡介
序列化的目的是方便資料的傳輸和儲存,在PHP中,序列化和反序列化一般用做快取,比如session快取,cookie等。
反序列化中常見的魔術方法
- __wakeup() //執行unserialize()時,先會呼叫這個函數
- __sleep() //執行serialize()時,先會呼叫這個函數
- __destruct() //物件被銷燬時觸發
- __call() //在物件上下文中呼叫不可存取的方法時觸發
- __callStatic() //在靜態上下文中呼叫不可存取的方法時觸發
- __get() //用於從不可存取的屬性讀取資料或者不存在這個鍵都會呼叫此方法
- __set() //用於將資料寫入不可存取的屬性
- __isset() //在不可存取的屬性上呼叫isset()或empty()觸發
- __unset() //在不可存取的屬性上使用unset()時觸發
- __toString() //把類當作字串使用時觸發
- __invoke() //當嘗試將物件呼叫為函數時觸發
反序列化繞過小Trick
php7.1+反序列化對類屬性不敏感
我們前面說了如果變數前是protected,序列化結果會在變數名前加上x00*x00
但在特定版本7.1以上則對於類屬性不敏感,比如下面的例子即使沒有x00*x00
也依然會輸出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";}');
繞過_wakeup(CVE-2016-7124)
版本:
PHP5 < 5.6.25
PHP7 < 7.0.10
利用方式:序列化字串中表示物件屬性個數的值大於真實的屬性個數時會跳過__wakeup的執行
對於下面這樣一個自定義類
<?php class test{ public $a; public function __construct(){ $this->a = 'abc'; } public function __wakeup(){ $this->a='666'; } public function __destruct(){ echo $this->a; } }
如果執行unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');
輸出結果為666
而把物件屬性個數的值增大執行unserialize('O:4:"test":2:{s:1:"a";s:3:"abc";}');
輸出結果為abc
繞過部分正則
preg_match('/^O:d+/')
匹配序列化字串是否是物件字串開頭,這在曾經的CTF中也出過類似的考點
利用加號繞過(注意在url裡傳參時+要編碼為%2B)
serialize(array(a ) ) ; / / a));//a));
//a為要反序列化的物件(序列化結果開頭是a,不影響作為陣列元素的$a的解構)
<?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";}'; // +號繞過 $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());
上面這個例子將$b
設定為$a
的參照,可以使$a
永遠與$b
相等
16進位制繞過字元的過濾
O:4:“test”:2:{s:4:“%00*%00a”;s:3:“abc”;s:7:“%00test%00b”;s:3:“def”;}
可以寫成
O:4:“test”:2:{S:4:“