PHP反序列化漏洞

2021-10-05 15:02:24 字數 3283 閱讀 7254

前幾天安恆月賽兩道web題中有一道題是關於php反序列化的,然後剛好前幾天剛好看過這個知識點,於是乎這次比賽才沒有爆零,總算是寫出來了一道題/doge

所有php裡面的值都可以使用函式serialize()來返回乙個包含位元組流的字串來表示。unserialize()函式能夠重新把字串變回php原來的值。 序列化乙個物件將會儲存物件的所有變數,但是不會儲存物件的方法,只會儲存類的名字。

示例:

<?php

class

demo}$a

=array

('fir'

,'sec'

,'lalala');

$b=serialize($a

);// a:3:

// 其中i指int

var_dump

(unserialize($b

));echo''

;// array(3) $c=

newdemo()

;echo$c;

echo''

;// __tostring called

// this is demo.tostring()$b=

serialize($c

);echo$b;

echo''

;// o:4:"demo":3:

// 其中s指的是string,指變數名儲存為字串$d=

unserialize($b

);echo$d;

// __tostring called

// this is demo.tostring()

總之我的理解,就是序列化是將乙個物件或者變數轉化為字串方便儲存,然後反序列化就是將乙個序列化後得到的字串再還原原來的物件

可以觀察到,在乙個自己定義的類demo中,變數的型別不同(publicprotectedprivate),在序列化字串中變數名是有相應的變化的

o:4:"demo":3:
當乙個物件被序列化時,會呼叫該物件的__sleep()方法

當乙個序列化字串被反序列化為物件時,會呼叫該物件的__wakeup()方法

ps:當成員屬性數目大於實際數目時可繞過wakeup方法(cve-2016-7124)

<?php

show_source

("index.php");

function

write

($data

)function

read

($data

)classa}

classb}

classc}

$a=newa

($_get

['a'],

$_get

['b'])

;//省略了儲存序列化資料的過程,下面是取出來並反序列化的操作$b=

unserialize

(read

(write

(serialize($a

))))

;

分析源**可以知道,很明顯問題出在read()write()這兩個函式上,chr(0)*chr(0)strlen之後可以知道長度為3,而單引號包裹的'\0\0\0'是不進行轉義的,所以長度為6,read和write函式使序列化字串長度產生了變化,但是兩個函式是互補的,所以一般不會出問題,除非當a中的username和password中本來就有\0\0\0,於是就可能出問題了

假設post的資料a=abc,b=def,本地嘗試的反序列化後的字串為

o:1:"a":2:
如果我們可以構造乙個使用者名稱和密碼,讓序列化後的字串經過read和write函式的過濾,仍然能正確地反序列化,但是反序列化後的物件中的變數儲存的值卻是另乙個物件,這樣就可以構成任意物件注入

首先觀察源**,class c是用來讀取flag內容的,flag在flag.php中,當c的__tostring()方法被呼叫時就可以getflag,再觀察class b,b物件在析構時會呼叫__destruct()方法,將變數$b與字串a連線後輸出

於是我們可以想到,使得class a的password變數為乙個class b的物件,而class b的物件中的變數b是乙個class c的物件,這樣,class b中的析構方法會觸發class c中的__tostring()方法,從而getflag

payload

首先構造password變數的內容,

本地構造class c的乙個例項$c並使得$c->c='flag.php'

然後構造class b的例項$b並使得$b->b=$c,反序列化得到:

o:1:"b":1:;}

然後就是構造username和password

username = \0 *36

pass = efghsssssssss";s:8:"password";o:1:"b":1:;}

上面的示例在序列化之後成為

ser = o:1:"a":2:;};}";}

然後經過read和write之後,長度為72的\0 *36被換成了長度為36的chr(0)*chr(0) *12

即為ser_ = o:1:"a":2:;};}";}

ps:星號之間有不可見字元chr(0)

當反序列化函式讀取到72時,pop()到最後乙個chr(0)*chr(0)時,字串長度只有36,於是反序列化函式會繼續pop()後面的字元,也就是 ";s:8:"pass...

一直pop()到...hsssssssss時,長度剛好為72,而之後剛好被雙引號閉合,於是反序列化後,變數username和password的內容為

username = ************";s:8:"password";s:88:"efghssssss";}

password = o:1:"b":1:;}

成功構造了class b和class c,序列化字串後面多餘的";}不會影響getflag

ps:

可以getflag,但是貌似反序列化是不成功的,再次unserialize($b)時會得到b:0;

php反序列漏洞 例項 PHP反序列化漏洞

雖然胳膊廢了,也不能停止我更新的腳步。寫個簡單點的吧 0x00 何為類和物件 說到序列化和反序列化就不得不提到兩個詞 類和物件 那麼什麼是類,什麼是物件 教科書式的答案是類是物件的抽象,物件是類的例項 那啥叫個抽象,啥叫個例項呢 簡單的說,類就是物件的乙個標準模板,而物件就是按照模板做出來的實物 一...

PHP反序列化漏洞

序列化簡單利用 serialize 序列化 使用函式serialize 可將例項序列化為字串 unserialize 反序列化 使用函式unserialize 可將序列化的字串還原 示例 class example unserialize get code 漏洞利用 構造漏洞利用的 儲存為test....

php反序列化漏洞

序列化函式 serialize,反序列化函式 unserialize,例 class test test new test var dump serialize test 輸出如下 string 84 o 4 test 3 其中 o 代表資料型別是物件object,4 代表該物件名有4個字元,tes...