冰蝎是一款基于Java开发的动态加密通信流量的新型Webshell客户端。
冰蝎的通信过程可以分为两个阶段:密钥协商和加密传输
(1)第一阶段:密钥协商
攻击者通过GET方式请求服务器密钥:
这个是代码:
这是服务端存储的$_SESSION变量
(2)服务器使用密钥解密
服务端使用随机数高16位作为密钥,并且存储到会话的$_SESSION变量中,并返回密钥给攻击者
当我们输入命令操作后,请求方式就会变成POST
这个是代码段:
因为我本地是有openssl扩展的,所以执行else里面的代码段
可以看到服务端用之前生成的密钥进行AES128解密请求的post数据
这个是我大概写的一个输出脚本:
base64解码:
1 @error_reporting(0);
2 function main($content)
3 {
4 $result = array();
5 $result["status"] = base64_encode("success");
6 $result["msg"] = base64_encode($content);
7 $key = $_SESSION['k'];
8 echo encrypt(json_encode($result),$key);
9 }
10
11 function encrypt($data,$key)
12 {
13 if(!extension_loaded('openssl'))
14 {
15 for($i=0;$i<strlen($data);$i++) {
16 $data[$i] = $data[$i]^$key[$i+1&15];
17 }
18 return $data;
19 }
20 else
21 {
22 return openssl_encrypt($data, "AES128", $key);
23 }
24 }$content="713fd3e0-d2c2-4536-8391-ae12c124a44f";
25 main($content);
然后服务端脚本继续往下执行:
这几行的代码就十分好懂了,用分割线生成数组,然后取数组第1位元素的值,最后eval执行
显然它将返回结果也加密了
(3)特征总结
a.ACCEPT字段
冰蝎2默认Accept字段的值很特殊,而且每个阶段都一样
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
b.UA字段
冰蝎内置了十余种 UserAgent ,每次连接 shell 会随机选择一个进行使用。但都是比较老的,容易被检测到,但是可以在burp中修改ua头。
c.Content-Length
Content-Length: 16, 16就是冰蝎2连接的特征
二、冰蝎3
对比冰蝎2,冰蝎3取消动态密钥获取,目前很多waf等设备都做了冰蝎2的流量特征分析,所以3取消了动态密钥获取;只有在无动态密钥交互失败后,才会进入常规的密钥交互阶段。
密钥生成可以看出,使用密码的md5结果的前16位。
特征分析:
1)Accept头有application/xhtml+xmlapplication/xmlapplication/signed-exchange属于弱特征
2)ua头该特征属于弱特征。通过burp可以修改,冰蝎3.0内置的默认16个userAgent都比较老。现实生活中很少有人使用,所以这个也可以作为waf规则特征。
数据包加密分析:
当我们去请求连接服务端的shell_bing3.0.php时,会在服务端的会话中存储一个值为"e45e329feb5d925b"的$_SESSION变量,也就是密钥$key
然后服务端用生成的密钥去解密请求的POST数据包内容
这是我写的小脚本(我其实就是想看看发送的POST数据包内容)
解密结果:
再次进行base64解密:
1 @error_reporting(0);
2 function main($content)
3 {
4 $result = array();
5 $result["status"] = base64_encode("success");
6 $result["msg"] = base64_encode($content);
7 $key = $_SESSION['k'];
8 echo encrypt(json_encode($result),$key);
9 }
10
11 function encrypt($data,$key)
12 {
13 if(!extension_loaded('openssl'))
14 {
15 for($i=0;$i<strlen($data);$i++) {
16 $data[$i] = $data[$i]^$key[$i+1&15];
17 }
18 return $data;
19 }
20 else
21 {
22 return openssl_encrypt($data, "AES128", $key);
23 }
24 }$content="Xg7QPeZL9pqCKhXs8Sug7C2Uxnoi39z7DQup7oysPVx60VpOEt2HgP1mGm95uA1b1xJ8tjz29YKZSHWDTFQ5MUbFDdzrx4buFBVj2taUJYTbHUq3fa763mSMOirkT9rs99vKdHEuHoZCqBpawjqQQUejU5aHE4FAHHcF24mOpPsL2TU9JgngUkPwPRJZRtXwF";
25 main($content);
@error_reporting(0); function main($content) { $result = array(); $result["status"] = base64_encode("success"); $result["msg"] = base64_encode($content); $key = $_SESSION['k']; echo encrypt(json_encode($result),$key); } function encrypt($data,$key) { if(!extension_loaded('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); } }$content="Xg7QPeZL9pqCKhXs8Sug7C2Uxnoi39z7DQup7oysPVx60VpOEt2HgP1mGm95uA1b1xJ8tjz29YKZSHWDTFQ5MUbFDdzrx4buFBVj2taUJYTbHUq3fa763mSMOirkT9rs99vKdHEuHoZCqBpawjqQQUejU5aHE4FAHHcF24mOpPsL2TU9JgngUkPwPRJZRtXwF"; main($con