1. 程式人生 > 其它 >挖洞經驗 | 記一次曲折的Getshell過程

挖洞經驗 | 記一次曲折的Getshell過程

最近在挖某框架的漏洞,其中挖到一枚Getshell,挖的過程有點曲折感覺可以寫篇文章總結一下,方便與各位大牛交流交流。

因為此框架有大量使用者,並且此漏洞並未修復,故此隱去所有有關此框架的資訊,連文章中出現的程式碼都是我自己另寫的,重在思路,希望大家理解。

首先通過審計定位到可能導致漏洞的程式碼(路徑:/edit/creat.php):

其中 $GP 是合併 $GET 和 $_POST 的變數。

可以看到寫入的檔案路徑和寫入的部分內容都是可控的,看到這裡不禁露出了一絲笑容,沒想到一枚 getshell 如此輕鬆。

好吧,先測試一下,把$file的值設定為:

<?php echo 1111; ?>.php

post 到 /index.php? control=edit&action=creat

(此框架是單入口)

預計生成的檔案內容是:

好了,那訪問一下生成的檔案,URL:

右鍵檢視一下原始碼,發現輸出的內容是:

居然被過濾了? 回溯之前的程式碼,在 index.php 檔案中發現程式碼:

關鍵在開始的兩行程式碼上,htmlEncode ? 搜尋這個函式,找到這個函式的程式碼如下:

結合起來,就是對 post 和 get 獲取到的所有內容進行htmlspecialchars,所以才會出現上面所看到的尖括號被過濾的情況。

看到這裡,臉上的笑容都消失了,哎呀,果然沒那麼容易。尖括號過濾了,那就沒辦法寫入PHP 程式碼的解析標籤了,想不到什麼突破的辦法,難道就這樣放棄麼?開始犯愁…

一直想著:過濾了尖括號怎麼辦?過濾了尖括號怎麼辦?過濾了尖括號怎麼辦……

那我能不能不用尖括號呢?不用尖括號能不能解析?要怎麼才能解析?想到這裡,突然就想到模板!這個框架的模板和大多數 MVC 的模板一樣,使用大括號作為標記:

這樣就可以使用模板的標記 {} 來繞過尖括號 <> 的過濾,但是根據這個框架的路由協定,模板不能隨便被包含,所以只能覆蓋原有的模板。

按照這個思路,找一個有載入模板的功能,覆蓋載入的模板,覆蓋之後訪問了就可以解析了。按照這個思路,找到一個載入了模板的功能,URL是:

/index.php? control=basic&action=index

程式碼路徑在/basic/index.php,程式碼最後就有呼叫 view(‘index’);

載入的模板路徑在:

/themes/basic/index.html

按照這些資訊,應該構造 $file 的值為:

../../themes/basic/index.html

但是這樣又有一個問題了,雖然構造這樣的值可以覆蓋原有的模板檔案,但是寫入的檔案內容就是:

這樣的話就沒有寫入需要的 Webshell 了,怎麼辦呢?!

根據 URL 的特性,./1.php 和 ./test/../1.php 訪問的內容是一樣的,都是 1.php 這個檔案,但是 test 這個目錄名我是可以隨便寫的,再根據模板虛擬碼的格式構造一個控制 $file 的測試 POC:

(根據 view() 函式的程式碼,有一個{php }虛擬碼標籤,處理的時候會替換為 <?php >。其實就算是沒有這標籤也可以用其他非組合的標籤代替)

生成的檔案內容為:

訪問 URL:

/index.php? control=basic&action=index

右鍵檢視原始碼,輸出的內容為:

證明程式碼執行了,那構造一個包含一句話的 POC,按照上一個 POC 的思路,應該把 file 的值構造為:

但是訪問後發現輸出的內容為:

想起 $file 的值是通過框架封裝的 $GP 的值都經過了 htmlencode,怎麼辦呢?! 根據 PHP 的特性,$_POST[‘w’] 獲取值的時候可以把引號去掉,所以可以把 poc 改為:

訪問 URL:/index.php? control=basic&action=index ,給引數 w傳值 echo 1111;

右鍵檢視原始碼,內容為:

證明 post 的程式碼確實被執行了,到伺服器上執行:

至此,getshell 完成,雖然過程有點艱辛,但還是拿下了。

最後總結一下:

1. 剛開始遇到過濾尖括號等的 HTML 字元的時候,利用了 MVC 模板中的虛擬碼代替繞過了 2. 遇到覆蓋檔案時候填寫完整路徑不能寫入payload 的問題,使用了構造一個不存在的目錄(目錄的名稱就是 payload)的方法進行 payload 的寫入 3. 最後寫入 payload 的時候發現也過濾了引號導致不能寫入 $POST[‘w’] ,根據 PHP 的特性,去掉引號依然可以獲取 w 下標的內容,所以替換為 $POST[w] 4. 寫入最終構造好的 payload,Getshell 完成!