# CS 原生 shellcode 上线免杀
最近攻防在即所以想要尝试写免杀🐎钓钓鱼,所以小学了一手一些比较好用且免杀效果比较好的手法做一下总结,从几个角度去组合免杀。
# shellcode 免杀
sgn 编码 (内存自解密),可以很好的做到静态免杀的效果不需要做其他任何加密手段即可做到静态免杀,可以尝试 sgn 编码后传 vt 一般就是 0 查杀。
用法:将 shellcode 二进制文件例如 xx.bin 保存,使用 sgn.exe 进行编码,需要注意的是系统位数要对
原始 shellcode (用 winhex 等二进制编辑器打开):
sgn 进行编码:
编码后的 shellcode:
这种静态免杀效果很好基本上无需做其他任何加密处理,同时还做到了降熵,当然这里还可以将二进制文件托管到服务器上然后通过 http 请求来获取 shellcode,也可以配合图片隐写进行 shellcode 的隐藏。
# 代码与进程注入手法
CreateRemoteThread (远程线程注入)
注入流程:
1、根据进程名寻找 pid,用于后续进程注入
2、根据 pid 打开指定进程句柄
3、向指定进程申请可读可写可执行的内存区域
4、将 shellcode 或 dll 注入到该内存区域中
5、开辟一个新线程执行
1 |
|
这种直接的线程注入容易暴毙,建议搭配其他手段食用。
APC Injection (APC 注入)
每个线程都有自己的 APC 队列,应用程序通过调用 QueueUserAPC 函数将 APC 排队到线程中,调用线程在对 QueueUserAPC 的调用中指定 APC 函数的地址,当 APC 排队到线程中时,系统会发出软件中断。下次调度线程时,它将运行 APC 功能。
注入流程:
1、根据进程名确定 pid
2、通过 pid 遍历 tid
3、插入 APC 队列
1 |
|
Early Bird (进阶版 APC 注入)
先创建一个挂起的白进程并申请一块 RWX 内存用于写入 shellcode,再使用 APC 注入插入线程,再恢复线程。实际上就是在白进程上偷摸注入一个新线程跑 shellcode。
注入流程跟上述 APC 注入差不多
1 |
|
这个免杀手法十分的好用,推荐再稍微搭配一下其他规避手段就可以绕过绝大多数杀软做到无感上线,实际代码和上线效果贴在文末。
Mapping Injection (内存映射注入)
先在物理内存中开辟一段空间用于写入恶意 shellcode,后续利用 MapViewOfFile2 将该恶意内存区域映射到指定进程中的虚拟内存中去,达到 shellcode 注入的效果。
注入流程:
1、创建 Mapping 句柄
2、将 shellcode 复制到该物理内存地址中去
3、将该段物理内存映射到虚拟内存中
4、利用任意方法执行到该地址的 shellcode
1 |
|
可以和其他手段组合,比如 Early Bird 来达到强规避的效果
Bypass Session 0 Injection (系统进程注入绕过)
无法直接向系统进程内注入 shellcode 或者 dll,原因是 R3 的 CreateRemoteThread 在 R0 中的函数原型 ZwCreateThreadEx 在内部调用时会将第七个参数设为 1 导致会使新创建的线程处于挂起状态,所以我们的恶意 shellcode 无法被执行,只需要将第七个参数置 0 即可绕过。
注入流程:
1、利用函数原型自定义 ZwCreateThreadEx 函数
2、通过系统获取 ntdll.dll 并加载 ZwCreateThreadEx 函数
3、申请一块内存空间并将 shellcode 写入
4、利用 ZwCreateThreadEx 将 shellcode 注入到系统进程中,将第七个参数置 0
1 |
|
TLS Code Execute (TLS 代码执行)
线程局部存储(Thread Local Storage,TLS)用来将数据与一个正在执行的指定线程关联起来,其提供了回调函数因此可以利用该函数达到执行 shellcode 的效果,主要编写的是 Reason 其规定和 dll 调用时一样 DLL_PROCESS_ATTACH
1 |
|
只是一种执行手段,依然可以配合其他手段组合。
SEH Code Execute (SEH 异常处理代码执行)
SEH (Structured Exception Handling) 结构化异常处理,是 windows 操作系统默认的错误处理机制,通过主动抛出异常然后将恶意代码插入即可触发,可用于反调试。
1 |
|
需要主动触发异常,当然可以填充大量代码将触发异常的代码写的很隐蔽,还可以做到反调试的效果,也需要配合其他手段食用。
SetContext Hijack Thread (线程上下文环境劫持)
简单理解就是劫持线程的上下文环境,然后强行将 eip/rip 指向 shellcode 并执行。
劫持流程:
1、创建一个挂起的合法进程
2、将恶意 shellcode 写入该进程
3、将 eip/rip 指向该地址
4、恢复线程
1 |
|
# 本地测试效果和其他手法演示
本次编写的恶意样本手法组合为:sgn + Early Bird + RW/RX/NOA 转换 + 自写 Win32API + junkCode 填充 + Sleep (15000)(循环真睡眠) 规避主动内存扫描
主要代码:
1 |
|
编译完后还可以进一步操作,比如替换 ico 图标,添加伪签名等等。这里我只进行图标的替换测试了 360 (核晶模式)、windowDefinder (个人版、企业版、专业版)、卡巴斯基 (免费版),其中除了 wdf 专业版无法上线之外其他都能做到无感上线,并且可以直接执行 shell 命令 (当然这里我用的是 cs4.9 并且配置了 C2profile 有一定的流量规避效果)。
360 核晶:
wdf (真实环境远程上线 ==> 执行 screenshot):
卡巴斯基:
360 杀毒 + 360 核晶会报警告提示
# Ekko 睡眠混淆技术演示:
该项目也是 havoC2 的作者的,已经集成在了 havoc 上,在这我们单独把这个项目运行看看,将 github 上的项目拉取到本地即可,编译器用的是 visual studio2022。其混淆原理简单来说就是在一个周期内睡眠结束后的几十毫秒内将内存中代码段进行异或恢复到正常功能代码,并同时恢复 RX 属性。
我们需要关注的代码段就在 Ekko.c 中,这里我们单独提炼出来:
1 | ImageBase = GetModuleHandleA(NULL); //获取当前进程基址 |
这里获取内存镜像大小的代码我做了修改,原项目的代码在我本地运行时获取到的大小始终为 0,暂时也不清楚什么情况。
这里我们修改完后再编译即可,这里我们使用 messagebox 来模拟 c2 服务端发送的指令,使用 ProcessHacker 监控内存变换。
非睡眠时间段 (事件等待时间段):
睡眠混淆时间段: