首頁 > 軟體

php淺析反序列化結構

2022-07-26 14:00:03

簡介

序列化的目的是方便資料的傳輸和儲存,在PHP中,序列化和反序列化一般用做快取,比如session快取,cookie等。

反序列化中常見的魔術方法

  1. __wakeup() //執行unserialize()時,先會呼叫這個函數
  2. __sleep() //執行serialize()時,先會呼叫這個函數
  3. __destruct() //物件被銷燬時觸發
  4. __call() //在物件上下文中呼叫不可存取的方法時觸發
  5. __callStatic() //在靜態上下文中呼叫不可存取的方法時觸發
  6. __get() //用於從不可存取的屬性讀取資料或者不存在這個鍵都會呼叫此方法
  7. __set() //用於將資料寫入不可存取的屬性
  8. __isset() //在不可存取的屬性上呼叫isset()或empty()觸發
  9. __unset() //在不可存取的屬性上使用unset()時觸發
  10. __toString() //把類當作字串使用時觸發
  11. __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:“0*061”;s:3:“abc”;s:7:“%00test%00b”;s:3:“def”;}

表示字元型別的s大寫時,會被當成16進位制解析。

到此這篇關於php淺析反序列化結構的文章就介紹到這了,更多相關php反序列化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com