红蓝对抗第四课-检测进程注入

ETW介绍

历史

ETW (Event Tracing for Windows) 在 Windows 2000 引入,从这时候起,OS Kernel 和 Service 都会通过 ETW 记录。Windows Vista 之后引入了统一的事件提供程序模型和 API,并在 Windows7 得到增强。

由于 ETW 的功能和性能,第三方的日志系统逐渐式微。ETW 的优点包含

  • 提供 Process 与 ETW Session 相分离,应用程序的崩溃不会对 ETW 造成影响

  • 能够动态地启用和禁用日志记录

  • 关闭事件跟踪时间几乎不消耗系统资源

  • 自定义消息格式,便于扩展

  • 日志记录机制使用每个处理器的缓存,由非同步 Thread 将这些缓冲区内容写入磁盘

  • 收集事件的时间戳的时钟分辨率可精确到 100 ns

运作机制

ETW 的运作主要有三个角色,Controller、Provider、Consumer

Controller 负责控制 Session 开关,决定要不要在 Session 接收 Provider。每个 Session 可以同时从多个 Provider 抓取事件,Controller 也能在程序运行的途中开启或关闭 Session。

Provider 负责提供事件,把事件产生给 Session 处理。Provider 是可以扩展的,能够自己定义事件栏位。

Consumer 负责透过 Session 接收从 Provider 来的事件。


实际用途

蓝队

蓝队的部分,因为有 Callback 机制,可以被动且即时的收到事件

以 Provider Microsoft-Windows-Threat-Intelligence为例,它能够监测AllocationType、RegionSizes、ProtectionMask,其中的 ProtectionMask 如果是可读、可写、可执行的一块内存块,则比较有可能是恶意代码。虽然无法断言只要看到可读、可写、可执行的内存块就代表是恶意代码,不过经过种种方继续深入下去式寻找证据,就可以有一定的信心判断它是不是恶意代码 。

再以 Provider Microsoft-Windows-Kernel-Registry 为例,它可以监测有没有通过 Registry实现的 Persistence(维持权限)行为。比如检测一个程序是否有写入以下Registry键值

  • RunOnce

  • Run

  • RunServices

  • RunServicesOnce

  • RunEx

  • RunOnceEx

红队

既然 ETW 对于篮队是一个十分有效的工具,那红队这边当然也会有对应策略。

在 Usermode,也就是 Ring3 中,可以通过 Hook EtwEventWrite 的方式拦截事件写入的函数;或是使用 EtwEventUnregister 取消注册 ETW Event。

在 Kernelmode,也就是 Ring0 中,有個方法叫做 GITL(Ghost In The Logs),原理是通过 Hook Kernel API NtTraceEvent 达到绕过 ETW 的效果。


检测内存注入

要了解为什么 Microsoft 的ETW为什么在现代检测通常晦涩难懂的注入技术方面非常有用,首先让我们看看过去的防御者和安全供应商使用的最常见的注入检测技术是什么,以及他们的不足之处。


内存扫描

https://docs.trendmicro.com/all/ent/officescan/v10.6/zh-cn/osce_10.6_sp2_cdp_olh/00_chap_intro.html#id11B8D80045Z

类似于 AV 扫描文件的方式扫描进程内存中的签名,这是用于捕获内存驻留恶意软件的最古老和最简单的技术。根据具体的实现,扫描可以是选择性的,在新进程启动后进行,也可以对所有正在运行的进程进行定期扫描(又名持久性扫描)。

虽然从理论上讲,这种方法非常有吸引力,但也存在一些缺陷:

  • 首先,内存扫描因资源密集而臭名昭著。不断增长的平均 RAM 大小以及 x64 架构的广泛采用只会增加挑战。这意味着无论实现效果怎么样,都需要在准确性和性能之间进行平衡。

  • 因为周期性扫描器不能在短时间间隔内进行全内存扫描。它们更是倾向于先查找比较特别敏感的内存单元块,例如PAGE_EXECUTEMEM_RESERVE | MEM_COMMIT分配类型结合使用然后这些东西进而可以触发特定进程的完整内存扫描。

  • 传统的内存扫描程序缺乏上下文意识

    哪个进程和线程已创建/写入内存页面?

    这是远程还是本地进程内存分配?

    使用了什么样的 WinAPI 调用序列?这些API的参数是哪些?。

    什么时候扫描?

所有这些意味着传统内存扫描主要用于 AV 按需扫描,以及事件响应期间 - 通常用于“离线”内存转储。

大多数安全供应商安全解决方案都依赖于混合方法,沙盒执行 + 指纹识别和事件触发类型的实时扫描。

Callbacks and detours

事件触发类型的进程扫描技术的实现采用使用内核驱动程序回调,以及用户模式 Win32 API 内联挂钩(一些杀毒软件可以通过VT绕过PG实现内核挂钩),两者都有其优点和缺点。

内核驱动回调

Windows 允许驱动程序开发者编写注册回调例程,以便在发生特定类型的系统事件时调用。例如,如果我们对新进程创建事件感兴趣,我们可以通过调用PsSetCreateProcessNotifyRoutine. 下一次启动进程时,我们的驱动程序将收到通知。

关于驱动程序回调的一些问题:

  • 已知的绕过技术可以拿到SELoadDriverPrivilege权限加载一个易受攻击的签名驱动程序或其他方法来进入内核然后大杀四方。

  • 回调数量有限,根本不存在内存管理/进程注入 API的回调。我们可以拦截的事件类型只有:

    进程创建

    映像加载

    文件创建

    线程创建

    注册表操作

    Minifilter回调

  • 而且内核回调似乎还可能会受到漏洞的影响。虽然只是影响主动阻止执行,不会影响检测能力。

所以综上所言,虽然可以只使用驱动程序回调的进程创建、线程创建和映像加载来通知我们的内存扫描程序干活,但这样做并不能解决前面描述的问题。这就是为什么反恶意代码软件不得不求助于挂钩,甚至是内核模式的SSDT 挂钩来获得对所有内存和进程管理操作的可见性。

用户态挂钩

在用户态挂钩,我们可以拦截实际的内存管理(或其他)API 调用,并单独处理这些调用,这种方式比起回调有更好的可见性、准确性和性能。此外,我们不再受微软回调的类型数量限制,我们可以拦截任何我们认为对检测有用的任何API。

例如我们检测NtWriteVirtualMemory写入的缓冲区内容,对传递给调用的参数的可见性可以保证高准确性的检测。而不是持续扫描整个进程内存中是否存在恶意代码。

NTSTATUS
NtWriteVirtualMemory(
IN HANDLE ProcessHandle,
OUT PVOID BaseAddress,
IN PVOID Buffer,//直接检查Buffer中的内容就行了
IN ULONG BufferSize,
OUT PULONG NumberOfBytesWritten OPTIONAL
);


这种方法也不完美:

  • 函数序言可以脱钩,重新载入NTDLL也可以脱钩

  • 基于 APC 的 EarlyBird 注入等技术允许在加载保护 DLL 之前执行代码,并且可以比反病毒软件的DLL更先挂钩。。。

  • 直接使用NTDLL里的系统调用绕过用户空间挂钩

  • 由于PG的的出现,常规手段无法在X64系统上内核挂钩。这也意味着无法看到来自驱动程序的注入

Early Bird本质上是一种APC注入与线程劫持的变体,由于线程初始化时会调用ntdll未导出函数NtTestAlert,该函数会清空并处理APC队列,所以注入的代码通常在进程的主线程的入口点之前运行并接管进程控制权,从而避免了反恶意软件产品的钩子的检测

创建一个挂起的进程(通常是windows的合法进程)
在挂起的进程内申请一块可读可写可执行的内存空间
往申请的空间内写入shellcode
将APC插入到该进程的主线程
恢复挂起进程的线程

#include
#include
unsigned char shellcode[] = "";
int main() {
  STARTUPINFO si = {0};
  PROCESS_INFORMATION pi = {0};
  si.cb = sizeof(STARTUPINFO);

  CreateProcessA("C:\\Program Files\\internet explorer\\iexplore.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, NULL, (LPSTARTUPINFOA)&si, &pi);
  LPVOID lpBaseAddress = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  WriteProcessMemory(pi.hProcess, lpBaseAddress, (LPVOID)shellcode, sizeof(shellcode), NULL);
  QueueUserAPC((PAPCFUNC)lpBaseAddress, pi.hThread, NULL);
  ResumeThread(pi.hThread);
  CloseHandle(pi.hThread);

  return 0;
}



Mm & APC kernel tracing

2018 年末,Windows 10 添加了一个新的内核工具。

通过名为“Microsoft-Windows-Threat-Intelligence”的 ETW 提供程序跟踪从内核模式内存管理和 APC API 截获的事件,并且只用于PPL-Antimalware保护级别(反恶意软件服务和进程,PROCESS_TERMINATE将被拒绝)的进程。这在意味着实践中只有 Microsoft 认可的具有适当签名证书的安全供应商才能使用

在最新的 Windows 10 x64 版本上,任何内存分配 API 最终都会到达nt!MiAllocateVirtualMemory,然后再它里面会去调用相关日志记录函数EtwTiLogAllocExecVm,通过交叉引用EtwThreatIntProvRegHandle这个句柄,我们可以看到它在多个其他位置使用,从这些函数名称中可以很明显地看出,Provider在非常常用的恶意 API 上记录事件数据,例如VirtualAllocWriteProcessMemorySetThreadContextResumeThread这些 API 是进程空心化的基础。恶意软件常用API参考:https://malapi.io/

这种实现使任何绕过尝试都相当困难,这与 ntdll 内联挂钩不同。并且不在用户模式下运行意味着我们不会像 Net CLR ETW 和其他用户模式会话提供程序那样被轻易挂钩修改程序执行流程


事件类型

查看所有 Provider

指令logman query providers,回传结果如下图。输出有两栏,分别是 Provider 和 GUID,其中 GUID 是用来辨别 Provider 的唯一的 ID。

Microsoft-Windows-Threat-Intelligence Provider记录至少 14 个不同的内存和线程管理事件,分为LOCALREMOTE组,其中远程表示调用 API 的进程与目标进程不同,本地表示进程在自己的内存空间内进行更改。

类型结构包含大量有用的字段,包括源和目标进程签名信任级别 进程基础信息(MEMORY_BASIC_INFORMATION)和线程上下文环境(ThreadContext)等。

KERNEL_THREATINT_TASK_ALLOCVM_REMOTE (
  UInt32 CallingProcessId,
  FILETIME CallingProcessCreateTime,
  UInt64 CallingProcessStartKey,
  UInt8 CallingProcessSignatureLevel,
  UInt8 CallingProcessSectionSignatureLevel,
  UInt8 CallingProcessProtection,
  UInt32 CallingThreadId,
  FILETIME CallingThreadCreateTime,
  UInt32 TargetProcessId,
  FILETIME TargetProcessCreateTime,
  UInt64 TargetProcessStartKey,
  UInt8 TargetProcessSignatureLevel,
  UInt8 TargetProcessSectionSignatureLevel,
  UInt8 TargetProcessProtection,
  UInt32 OriginalProcessId,
  FILETIME OriginalProcessCreateTime,
  UInt64 OriginalProcessStartKey,
  UInt8 OriginalProcessSignatureLevel,
  UInt8 OriginalProcessSectionSignatureLevel,
  UInt8 OriginalProcessProtection,
  Pointer BaseAddress,
  Pointer RegionSize,
  UInt32 AllocationType,
  UInt32 ProtectionMask
)


POC

要想使用Microsoft-Windows-Threat-Intelligence`,我们需要作为 PPL 进程运行,因为 NTOSKRNL 只会将收集到的日志转发到受 PPL 保护的进程

https://blog.tofile.dev/2020/12/16/elam.html

https://github.com/xuanxuan0/TiEtwAgent


https://github.com/rshipp/awesome-malware-analysis/blob/main/%E6%81%B6%E6%84%8F%E8%BD%AF%E4%BB%B6%E5%88%86%E6%9E%90%E5%A4%A7%E5%90%88%E9%9B%86.md


请使用浏览器的分享功能分享到微信等