Windows事件日志的红队利用
你是否知道Windows事件日志中可能隐藏着什么?
2022年5月,我收到一篇Threat Post文章,介绍了一种在野发现的利用Windows事件日志维持持久性的新技术。我立即浏览了这篇文章(原文链接:Threat Post)和卡巴斯基的原始报告(链接:SecureList)。我既惊讶又沮丧地发现,利用Windows事件日志存储攻击载荷并维持持久性竟然如此简单。
当时文章发表时,我正在圣地亚哥参加WWHF: Way West 2022会议,因此计划回家后深入研究这一主题。
几周后,我终于有时间重新审视这篇文章,深入探索其工作原理、实现方式以及使用Windows事件日志作为载荷存储设备的限制。
Windows事件日志基础
Windows事件日志包含操作系统、服务(如Office和SQL Server)和应用程序的日志。日志使用结构化数据格式,便于搜索和分析。
访问Windows事件日志的最简单方法是使用事件查看器(eventvwr.exe)。
Windows系统的主要日志位于“Windows日志”文件夹中,该文件夹包含所有Windows系统标准的五个类别:
- 应用程序
- 安全
- 设置
- 系统
- 转发事件
事件查看器中还有一个名为“应用程序和服务日志”的文件夹,包含单个应用程序和基于硬件的事件的日志。Windows PowerShell日志就在此集合中。
每个日志条目都使用特定字段进行格式化,以实现通用结构。以下是一些最常被过滤的日志分析字段:
- 日志/键(例如:应用程序)
- 源(例如:Outlook)
- 日期/时间
- 事件ID
- 任务类别(应用程序定义)
- 级别
- 计算机
- 事件数据(消息和二进制数据)
Windows事件日志 – 用户约束
你是本地管理员吗?还是普通用户?
某些事件日志只有本地管理员才能写入,其他日志则所有人都可写入。虽然对于本篇博客来说不是超级重要,但根据后续技术的使用,这些用户无法写入某些日志的约束可能会发挥作用。
下图显示了常见Windows安装中用户对各种事件日志的权限图表:
(图表内容:显示不同日志类型的用户权限,例如系统日志需要管理员权限,而应用程序日志可能允许普通用户写入。)
如果还不明显,请让我明确记录:要能够在事件日志条目中存储载荷,你必须首先能够写入事件日志。根据你的用户上下文,你可能无法写入某些日志(如系统日志),除非你在本地管理员上下文中操作。
Windows事件日志 – 大小约束
另一个需要注意的约束是事件日志中可存储的数据量存在大小限制,基于事件消息字符串的最大字符限制为31,839个字符。
现在所有基础知识都覆盖了——哦,等等,还有一件事……
不仅可以创建任意事件日志条目,如果你是本地管理员,还可以创建全新的事件日志。记住这一点,我们稍后会回到这里。
现在基础知识已完成,我们可以开始创建一些事件日志条目。
创建事件日志条目
使用PowerShell和Write-EventLog命令,可以轻松创建任意事件条目,命令如下:
|
|
但需要注意几点:首先,-LogName参数必须是你的用户上下文可以写入的有效日志;其次,-Source参数需要是在Windows注册表中注册为特定日志的源。
在注册表中,你可以在Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\
找到事件日志,每个键下都有已注册到该事件日志的源列表。如上所示,我们选择使用事件日志“应用程序”和源“Edge”,因为Edge是注册到该事件日志的有效源。
为了演示,我们选择任意事件ID 31337,但你可以使用任何你选择的事件ID。不过,如稍后所示,选择有效的事件ID有助于限制日志中异常活动的指标。
创建事件日志条目时,需要使用-EntryType参数定义条目类型。有五种类型可用,但如果你试图不被发现,信息类型可能是最佳选择。
其次是类别,这是一个应用程序定义的字段,用于辅助过滤日志。这里我们将其设置为0,在事件查看器中等同于“无”。
在事件查看器中,我们可以看到我们的事件日志条目已成功创建在应用程序日志中,事件ID为31337,消息为“Here be dragons”。
需要注意的是,如果你使用上述命令为自己创建日志条目,你会在我们用户提供的消息“Here be dragons”之前看到以下文本:
“无法找到来自源edge的事件ID 31337的描述。要么未在本地计算机上安装引发此事件的组件,要么安装已损坏。你可以在本地计算机上安装或修复该组件。如果事件源自另一台计算机,则显示信息必须随事件一起保存。”
此消息附加到我们用户提供的消息的原因是,在源Edge的注册表键中,有一个名为EventMessageFile的属性,指向一个包含与该源相关的事件消息的DLL文件。在我们的案例中,我们提供了一个在EventMessageFile中未找到的事件ID,因此导致了我们在事件查看器中看到的日志条目消息。
如果你试图保持低调和未被检测到,建议你仅使用相关的源和后续事件ID。事件源在日常事件日志条目中生成此类消息并不常见,因此如果分析师观察到该事件,消息可能会引起怀疑。
注入载荷
既然已经证明创建事件日志条目很简单,下一步是弄清楚如何以及在哪里注入载荷。
如果你还记得Windows事件日志基础,条目的事件数据字段支持消息和二进制数据。通过简单地向我们的PowerShell命令添加一个参数,我们可以使用-RawData参数在事件日志条目中包含二进制数据。
为了能够在日志条目中嵌入二进制数据,我们必须将其作为字节数组传递给Write-EventLog命令。有多种方法可以做到这一点,但我选择将包含数据的十六进制文字字符串转换为字节数组,然后将该变量传递给-RawData参数。
打开新日志条目并点击“详细信息”选项卡,我们发现包含的二进制数据以字节形式以及数据的ASCII版本存储得很好。
砰!我们现在有了存储在日志条目中的用户定义二进制数据。我想你可以看到这走向何方……
逻辑上的下一步是在日志条目中包含实际载荷,而不仅仅是一些文本。首先,我使用msfvenom生成了一个简单的Windows exec载荷,输出格式为十六进制文字字符串。
接下来,我们必须使用上面的载荷字符串创建一个新的事件日志条目。为了复制使用此技术的威胁行为者的行动,我们没有使用应用程序日志和源Edge,而是使用了密钥管理服务日志和源KmsRequests,如下面来自卡巴斯基SecureList文章的图像所示。
(图像链接:https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2022/04/28153130/SilentBreak_APT_toolset_01.png)
回顾事件查看器,我们可以看到我们的日志条目已创建,我们的二进制载荷安全地存储在里面。
这太棒了,但我们有一个问题:我们有一个存储的载荷,但还没有办法使用它。是时候检索载荷了。
检索和执行载荷
可能有大约14,598,231种方法从我们创建的事件日志条目中提取载荷,但鉴于我们还需要执行载荷,我选择使用一个简单的C#程序,该程序将在密钥管理服务日志中搜索事件ID为31337的长条目,然后从所述条目中提取二进制数据。
以下代码是一个非常基本且粗糙编写的概念验证,从事件日志“密钥管理服务”中的第一个条目提取二进制载荷数据,然后使用非常常见的shellcode注入技术将该载荷注入到当前运行进程中。
此概念验证的代码可以在GitHub上找到:EventLogForRedTeams
使用Visual Studio编译PoC代码后,我们可以执行该程序,从事件日志中的存储二进制载荷弹出calc.exe。
我们中的精明人会注意到代码确实抛出了一个看似致命的错误,但这并没有阻止calc.exe的成功执行。请记住,这段代码设计为仅作为PoC勉强运行,因此只有一个致命错误在我看来就是胜利。
好了,二进制载荷存储在Windows事件日志中……等等,什么?你想要更多?我想也是,所以系好安全带,我们开始吧。
进阶利用:远程shell
弹出calc.exe很好,但利用这种技术我们可以做更多。远程shell怎么样?你说Metasploit?在2022年, surely not。让我们试试。
首先,我们需要使用msfvenom生成一个新的载荷。我选择使用载荷windows/x64/shell_reverse_tcp,主要是因为我觉得任何Metasploit载荷在2022年都是碰运气,但我发现无阶段载荷有更高的成功机会(但你的情况可能不同)。
创建新载荷的哈希文字字符串后,我必须使用新载荷创建一个新的事件日志条目。
由于C#代码采用简单的方法在事件日志中查找载荷,它只会从日志中找到的第一个条目中提取二进制数据,因此我在继续之前清空了密钥管理服务日志。
清空日志条目后,我可以创建带有更新二进制载荷的新日志条目。如下图所示,我们的载荷再次安全地存储在事件日志条目中,等待被使用。
最后一步是使用参数-nvlp 1337设置nc监听器。设置好监听器后,是时候执行我们的程序来注入我们的shellcode,并希望获得远程连接。为了方便这一点,我从Windows虚拟机SSH到Kali Linux虚拟机运行监听器。
如上图所示,在运行Windows Defender且未关闭任何设置的Windows 11 Pro主机上成功建立了会话。
胜利!!!
嗯,几乎……
你看,当我开始这项研究时,一切基本上都按预期工作。Windows Defender对大多数Metasploit载荷完全盲目,这很有趣。然后有些事情发生了变化,Defender开始在会话建立后捕获注入的载荷,然后吃掉载荷注入器。
这一切都不令人惊讶,特别是因为没有任何混淆努力来隐藏正在使用的载荷及其使用方式。只是2022年原封不动的Metasploit。然而,这恰恰表明使用日志条目注入技术存储载荷具有巨大潜力。
事实上,在前一张截图拍摄后不久,Defender抬起头来吞掉了我们的注入器,杀死了我们的会话。
像生活中的大多数事情一样,如果你付出一点努力并尝试理解周围发生的事情,惊人的事情就会发生,比如在完全打补丁的Windows 11 Pro系统上运行Cobalt Strike Beacon,且零混淆。
提示:HTTPS Beacons现在效果更好
所以,我再问一次,你的Windows事件日志中潜伏着什么?Shellcode?可能。如果不是今天,也许是明天。如我所展示的,将恶意载荷注入事件日志条目并在以后检索执行是微不足道的。虽然这篇文章没有涉及超出基础的内容,但我相信如果你读到这里,你已经有了如何利用这一点建立持久性和更多的想法。
如果你想更多地尝试这种技术,特别是作为一种持久化方法,我建议你查看Improsec在Github上的一个工具(链接:SharpEventPersist),该工具允许你使用Cobalt Strike的execute-assembly通过事件日志注入建立持久性。