- UID
- 1288
- 积分
- 160
- 精华
- 0
- 沃币
- 6 枚
- 注册时间
- 2023-3-30
|
楼主 |
发表于 2023-11-29 15:37:17
|
显示全部楼层
因此,我们可以直接进入 loggers 数组并找到每个进程的注册进程,而不是扫描系统中每个进程的句柄表:
- function EtwLoggersWithConsumerProcesses()
- {
- let dbgOutput = host.diagnostics.debugLog;
- let hostSiloGlobals = host.getModuleSymbolAddress("nt", "PspHostSiloGlobals");
- let typedhostSiloGlobals = host.createTypedObject(hostSiloGlobals, "nt", "_ESERVERSILO_GLOBALS");
- let maxLoggers = typedhostSiloGlobals.EtwSiloState.MaxLoggers;
- for (let i = 0; i < maxLoggers; i++)
- {
- let logger = typedhostSiloGlobals.EtwSiloState.EtwpLoggerContext[i];
- if (host.parseInt64(logger.address, 16).compareTo(host.parseInt64("0x1")) != 0)
- {
- dbgOutput("Logger Name: ", logger.LoggerName, "\n");
- let consumers = host.namespace.Debugger.Utility.Collections.FromListEntry(logger.Consumers, "nt!_ETW_REALTIME_CONSUMER", "Links");
- if (consumers.Count() != 0)
- {
- for (let consumer of consumers)
- {
- dbgOutput("\tProcess Name: ", consumer.ProcessObject.SeAuditProcessCreationInfo.ImageFileName.Name, "\n");
- dbgOutput("\tProcess Id: ", host.parseInt64(consumer.ProcessObject.UniqueProcessId.address, 16).toString(10), "\n");
- dbgOutput("\n");
- }
- }
- else
- {
- dbgOutput("\tThis logger has no consumers\n\n");
- }
- }
- }
- }
复制代码
调用这个函数应该会得到与之前完全相同的结果,而且速度更快!获得这部分内容后,可以继续搜索另一条可能有用的信息,向日志会话提供事件的 GUID 列表。
查找 Provider GUIDs
找到 ETW 日志会话的使用者只是成功的一半,我们还想知道哪些 Providers 通知每个日志会话。我们之前看到可以从性能监视器获取该信息,看看如何从调试器会话中获取它,因为当实时计算机不可用或查找未提供的详细信息时,它可能很有用通过诸如性能监视器之类的用户模式工具。
如果查看 WMI_LOGGER_CONTEXT 结构,将不会看到有关通知日志会话的 Providers 的任何详细信息。要查找此信息,我们需要返回到之前的 ETW_SILODRIVERSTATE 结构并查看 EtwpGuidHashTable 字段。这是存储所有已注册 Providers GUID 的存储桶数组。出于性能原因,将 GUID 哈希后的数据存储在 64 个存储桶中,每个桶包含三个链接 ETW_GUID_ENTRY 结构的列表,每个 ETW_GUID_TYPE 有一个列表:
- EtwpTraceGuidType
- EtwpNotificationGuidType
- EtwpGroupGuidType
每个 ETW_GUID_ENTRY 结构都包含一个具有八个条目的 EnableInfo 数组,每个条目都包含有关 GUID 为其提供事件的一个日志会话的信息 (这意味着事件 GUID 条目可以为以下对象提供事件,最多八个不同的日志会话):
- dt nt!_ETW_GUID_ENTRY EnableInfo.
- +0x080 EnableInfo : [8]
- +0x000 IsEnabled : Uint4B
- +0x004 Level : UChar
- +0x005 Reserved1 : UChar
- +0x006 LoggerId : Uint2B
- +0x008 EnableProperty : Uint4B
- +0x00c Reserved2 : Uint4B
- +0x010 MatchAnyKeyword : Uint8B
- +0x018 MatchAllKeyword : Uint8B
复制代码
从视觉上看,这就是整个事情的样子:
正如我们所看到的, ETW_GUID_ENTRY 结构包含一个 LoggerId 字段,我们可以将其用作 EtwpLoggerContext 数组的索引来查找日志会话。
考虑到这些新信息,我们可以编写一个简单的 JavaScript 函数来打印与记录器 ID 匹配的 GUID。在本例中,我选择一次只遍历一个 ETW_GUID_TYPE 以使此代码更清晰一些。然后可以更进一步解析 ETW_REG_ENTRY 列表每个 GUID 条目,来找出哪些进程通知它,或者它是否是内核模式 Providers:
- function GetGuidsForLoggerId(loggerId, guidType)
- {
- let dbgOutput = host.diagnostics.debugLog;
- let hostSiloGlobals = host.getModuleSymbolAddress("nt", "PspHostSiloGlobals");
- let typedhostSiloGlobals = host.createTypedObject(hostSiloGlobals, "nt", "_ESERVERSILO_GLOBALS");
- let guidHashTable = typedhostSiloGlobals.EtwSiloState.EtwpGuidHashTable;
- for (let bucket of guidHashTable)
- {
- let guidEntries = host.namespace.Debugger.Utility.Collections.FromListEntry(bucket.ListHead[guidType], "nt!_ETW_GUID_ENTRY", "GuidList");
- if (guidEntries.Count() != 0)
- {
- for (let guid of guidEntries)
- {
- for (let enableInfo of guid.EnableInfo)
- {
- if (enableInfo.LoggerId === loggerId)
- {
- dbgOutput("\tGuid: ", guid.Guid, "\n");
- let regEntryLinkField = "RegList";
- if (guidType == 2)
- {
- // group GUIDs registration entries are linked through the GroupRegList field
- regEntryLinkField = "GroupRegList";
- }
- let regEntries = host.namespace.Debugger.Utility.Collections.FromListEntry(guid.RegListHead, "nt!_ETW_REG_ENTRY", regEntryLinkField);
- if (regEntries.Count() != 0)
- {
- dbgOutput("\tProvider Processes:\n");
- for (let regEntry of regEntries)
- {
- if (regEntry.DbgUserRegistration != 0)
- {
- dbgOutput("\t\tProcess: ", regEntry.Process.SeAuditProcessCreationInfo.ImageFileName.Name, " ID: ", host.parseInt64(regEntry.Process.UniqueProcessId.address, 16).toString(10), "\n");
- }
- else
- {
- dbgOutput("\t\tKernel Provider\n");
- }
- }
- }
- break;
- }
- }
- }
- }
- }
- }
复制代码
作为示例,以下是所有跟踪提供程序 GUID 以及通知它们 ETW 会话 UBPM 的进程 (在我的示例中为 LoggerId 31):
- dx @$scriptContents.GetGuidsForLoggerId(31, 0)
- Guid: {9E03F75A-BCBE-428A-8F3C-D46F2A444935}
- Provider Processes:
- Process: "\Device\HarddiskVolume3\Windows\System32\svchost.exe" ID: 2816
- Guid: {2D7904D8-5C90-4209-BA6A-4C08F409934C}
- Guid: {E46EEAD8-0C54-4489-9898-8FA79D059E0E}
- Provider Processes:
- Process: "\Device\HarddiskVolume3\Windows\System32\dwm.exe" ID: 2268
- Guid: {D02A9C27-79B8-40D6-9B97-CF3F8B7B5D60}
- Guid: {92AAB24D-D9A9-4A60-9F94-201FED3E3E88}
- Provider Processes:
- Process: "\Device\HarddiskVolume3\Windows\System32\svchost.exe" ID: 2100
- Kernel Provider
- Guid: {FBCFAC3F-8460-419F-8E48-1F0B49CDB85E}
- Guid: {199FE037-2B82-40A9-82AC-E1D46C792B99}
- Provider Processes:
- Process: "\Device\HarddiskVolume3\Windows\System32\lsass.exe" ID: 1944
- Guid: {BD2F4252-5E1E-49FC-9A30-F3978AD89EE2}
- Provider Processes:
- Process: "\Device\HarddiskVolume3\Windows\System32\svchost.exe" ID: 16292
- Guid: {22B6D684-FA63-4578-87C9-EFFCBE6643C7}
- Guid: {3635D4B6-77E3-4375-8124-D545B7149337}
- Guid: {0621B9DF-3249-4559-9889-21F76B5C80F3}
- Guid: {BD8FEA17-5549-4B49-AA03-1981D16396A9}
- Guid: {F5528ADA-BE5F-4F14-8AEF-A95DE7281161}
- Guid: {54732EE5-61CA-4727-9DA1-10BE5A4F773D}
- Provider Processes:
- Process: "\Device\HarddiskVolume3\Windows\System32\svchost.exe" ID: 4428
- Guid: {18F4A5FD-FD3B-40A5-8FC2-E5D261C5D02E}
- Guid: {8E6A5303-A4CE-498F-AFDB-E03A8A82B077}
- Provider Processes:
- Kernel Provider
- Guid: {CE20D1C3-A247-4C41-BCB8-3C7F52C8B805}
- Provider Processes:
- Kernel Provider
- Guid: {5EF81E80-CA64-475B-B469-485DBC993FE2}
- Guid: {9B307223-4E4D-4BF5-9BE8-995CD8E7420B}
- Provider Processes:
- Kernel Provider
- Guid: {AA1F73E8-15FD-45D2-ABFD-E7F64F78EB11}
- Provider Processes:
- Kernel Provider
- Guid: {E1BDC95E-0F07-5469-8E64-061EA5BE6A0D}
- Guid: {5B004607-1087-4F16-B10E-979685A8D131}
- Guid: {AEDD909F-41C6-401A-9E41-DFC33006AF5D}
- Guid: {277C9237-51D8-5C1C-B089-F02C683E5BA7}
- Provider Processes:
- Kernel Provider
- Guid: {F230D19A-5D93-47D9-A83F-53829EDFB8DF}
- Provider Processes:
- Process: "\Device\HarddiskVolume3\Windows\System32\svchost.exe" ID: 2816
复制代码
将所有这些步骤放在一起,我们终于有办法知道计算机上正在运行哪些日志会话、哪些进程通知会话中的每个 GUID,以及哪些进程订阅了它们。这可以帮助我们了解机器上运行的不同 ETW 日志会话的用途,例如识别 EDR 软件或感兴趣的硬件组件使用的日志会话。这些脚本还可以根据需要进行修改,以识别 ETW 违规行为,例如为了迷惑安全产品而禁用的日志会话。从攻击者的角度来看,收集这些信息可以告诉我们机器上使用了哪些 ETW Providers,哪些被忽略,因此不会给我们带来任何检测风险。
总的来说,ETW 是一个非常强大的机制,因此更深入地了解其内部运作对于攻击者和防御者都非常有用。这篇文章只触及了表面,在这个领域还有很多工作可以做。
本文中显示的所有 JavaScript 函数都可以在此 GitHub 存储库中 https://github.com/trailofbits/W ... twKernelRoutines.js 找到。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|