序列化
首先說說什么是序列化
序列化是將某個對象轉(zhuǎn)換為以后可以恢復(fù)的數(shù)據(jù)格式的過程。 人們經(jīng)常序列化對象以將它們保存到存儲中,或作為通信的一部分發(fā)送。 反序列化與從某種格式獲取結(jié)構(gòu)化數(shù)據(jù)并將其重建為對象的過程相反。 今天,用于序列化數(shù)據(jù)的最流行的數(shù)據(jù)格式是JSON。在此之前,它是 XML。
a:4:{i:0;i:132;i:1;s:7:"Mallory";i:2;s:4:"用戶"; i:3;s:32:"b6a8b3bea87fe0e05022f8f3c88bc960";}
?
許多編程語言提供了用于序列化對象的本機(jī)功能。 這些原生格式通常提供比 JSON 或 XML 更多的功能,包括序列化過程的可定制性。 不幸的是,在對不受信任的數(shù)據(jù)進(jìn)行操作時,這些原生反序列化機(jī)制的功能可能會被重新用于惡意影響。 已經(jīng)發(fā)現(xiàn)對解串器的攻擊允許拒絕服務(wù)、訪問控制和遠(yuǎn)程代碼執(zhí)行攻擊。
已知受影響的編程語言PHP、Python、Ruby、JAVA、C、C++
?
只有數(shù)據(jù)被序列化。 代碼本身沒有序列化。 反序列化創(chuàng)建一個新對象并從字節(jié)流中復(fù)制所有數(shù)據(jù),以獲得與序列化的對象相同的對象。
?
?
在PHP,通過反序列化在特定條件下可以重建php對象并執(zhí)行php對象中某些magic函數(shù)。
在PHP應(yīng)用中,序列化和反序列化一般用做緩存,比如session緩存,cookie等。
舉一個簡單的例子
<?php class people{ public $name; public $age; public $sex; function __construct($name,$age,$sex){ //_construct:創(chuàng)建對象時初始化 $this->name = $name; $this->age = $age; $this->sex = $sex; } } $people=new people("hhy",20,"boy"); echo serialize($people); ?>
輸出結(jié)果:O:6:"people":3:{s:4:"name";s:3:"hhy";s:3:"age";i:20;s:3:"sex";s:3:"boy";}
“O”表示對象,6表示對象名長度為6
“people”為對象名,3表示有3個參數(shù)
“s”表示string對象
“i”表示int對象
?
反序列化輸出
$unpeople='O:6:"people":3:{s:4:"name";s:3:"hhy";s:3:"age";i:20;s:3:"sex";s:3:"boy";}'; var_dump(unserialize($unpeople)); //輸出用var_dump函數(shù)
或者 $u=unserialize('O:6:"people":3:{s:4:"name";s:3:"hhy";s:3:"age";i:20;s:3:"sex";s:3:"boy";}'); echo $u->name,$u->age,$u->sex;
輸出結(jié)果:object(people)#2 (3) { ["name"]=> string(3) "hhy" ["age"]=> int(20) ["sex"]=> string(3) "boy" }
輸出結(jié)果:hhy20boy
?
在JAVA中由ObjectOutputStream類中的writeObject()函數(shù)和ObjectInputStream類中的readObject()函數(shù)實現(xiàn)
?
PHP反序列化漏洞
原理:未對用戶輸入的序列化字符串進(jìn)行檢測,導(dǎo)致攻擊者可以控制反序列化過程,從而導(dǎo)致代碼?執(zhí)行,SQL 注入,目錄遍歷等不可控后果。在反序列化的過程中自動觸發(fā)了某些魔術(shù)方法。當(dāng)進(jìn)行?反序列化的時候就有可能會觸發(fā)對象中的一些魔術(shù)方法
序列化和反序列化本身沒有問題,但是如果反序列化的內(nèi)容是用戶可以控制的,且后臺不正當(dāng)?shù)氖褂昧薖HP中的魔法函數(shù),就會導(dǎo)致安全問題?
- unserialize()函數(shù)的參數(shù)可控
- php中有可以利用的類并且類中有魔術(shù)方法
常見的魔術(shù)方法
__construct(): 在創(chuàng)建對象時候初始化對象,一般用于對變量賦初值。
__destruct(): 和構(gòu)造函數(shù)相反,當(dāng)對象所在函數(shù)調(diào)用完畢后執(zhí)行。
__toString():當(dāng)對象被當(dāng)做一個字符串使用時調(diào)用。
__sleep():序列化對象之前就調(diào)用此方法(其返回需要一個數(shù)組)
__wakeup():反序列化恢復(fù)對象之前調(diào)用該方法
__call():當(dāng)調(diào)用對象中不存在的方法會自動調(diào)用該方法。
__get():在調(diào)用私有屬性的時候會自動執(zhí)行
__isset()在不可訪問的屬性上調(diào)用isset()或empty()觸發(fā)
__unset()在不可訪問的屬性上使用unset()時觸發(fā)
<head> <meta charset="UTF-8"> </head> <?php class T{ public $test=1; function __construct(){ echo '調(diào)用了_construct<br>'; } function __destruct(){ echo '調(diào)用了_destruct<br>'; } //function __sleep(){ // echo '調(diào)用了_sleep<br>' //} function __wakeup(){ echo '調(diào)用了_wakeup<br>'; } } $t=new T(); echo $t->test; echo "<br/>"; $t1=serialize($t); echo $t1; echo "<br/>"; $t2=unserialize($t1); echo $t->test; echo "<br/>";
?
當(dāng)程序執(zhí)行前,serialize() 函數(shù)會首先檢查是否存在一個魔術(shù)方法__sleep.如果存在,__sleep()方法會先被調(diào)用,然后才執(zhí)行序列化操作。這個功能可以用于清理對象,并返回一個包含對象中所有變量名稱的數(shù)組。如果該方法不返回任何內(nèi)容,則NULL被序列化,導(dǎo)致一個E_NOTICE錯誤。
unserialize()會檢查是否存在一個__wakeup方法。如果存在,則會先調(diào)用 __wakeup方法,預(yù)先準(zhǔn)備對象數(shù)據(jù)。
?
漏洞舉例? ? ? ?
class S{
var $test = "pikachu";
function __destruct(){
echo $this->test;
}
}
$s = $_GET['test'];
@$unser = unserialize($a);
payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
?
JAVA反序列化
WebGoat靶場
Releases · WebGoat/WebGoat (github.com)
分析一下源碼
?
?大概的內(nèi)容就是,用戶輸入了數(shù)據(jù),對數(shù)據(jù)進(jìn)行對象的還原,接著進(jìn)行命令執(zhí)行
?
防御
反序列化的問題是用戶參數(shù)的控制問題引起的,所以好的預(yù)防措施就是不要把用戶的輸入或者是用戶可控的參數(shù)直接放進(jìn)反序列化的操作中去。
?
?
本文摘自 :https://www.cnblogs.com/