基本介绍
微软最近发表了一篇文章,记录了HAFNIUM威胁参与者如何利用计划任务存储在注册表中的缺陷来隐藏它们的存在,这清楚地表明所呈现的漏洞很可能不是影响计划任务组件的唯一缺陷,我们开始研究如何滥用计划任务的注册表结构来实现各种目标,例如:横向移动和持久性
具体来说我们调查了创建任务的最低条件是什么,而不通过远程过程调用 (RPC)等经典接口,从微软的文章和SpectreOps对Capability的研究都证实所有计划任务最终都会存储在注册表中的以下注册表项下:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree
那么是否可以创建相关的注册表项并创建任务,并且不生成事件呢?
在这篇文章中我们将探讨两种可用于实现方法:创建或修改计划任务并执行它,而不生成相关的记录数据,首先我们将探讨如何使用直接注册表操作来创建或修改任务,以及这如何不会在事件日志中生成通常的条目,最后将提出基于篡改任务计划程序ETW的替代路线,这将完全抑制与任务计划程序相关的大部分日志记录
测绘数据
在试图规避任务计划程序如何记录其事件之前,先简要介绍一下任务计划程序提供的日志记录类型,当我们在创建/修改/运行/删除任务时,将生成以下测绘数据:
通过分析ATT&CK等常见攻击者的知识框架,我们可以看到在计划任务技术的推荐审计中,既有Microsoft-Windows-TaskScheduler/Operational,也有来自Object Auditing的4XXX事件,由于它们包含相似的信息,因此认为它们可以互换使用是正常的,事实上像Sigma这样的开源检测规则存储库会搜索由一个来源生成的事件,但不会同时搜索两者
以下部分将记录用于逃避哪些类型的事件以及在现实生活场景中的实用性的所有各种技术
注册表结构
如果我们分析上述注册表项的结构,可以观察到Tree\<taskName>键下的条目存在以下值:
下图就是一个例子:
Tasks子键的值主要是二进制blob和编码字符串,它们指示以下信息:
除了上述之外还发现了另一个未记录的注册表项,该注册表项在任务创建中发挥了重要作用
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Plain\{GUID}
其中GUID是上述任务的唯一标识符,GUID子项下未配置任何值,我们将在任务创建部分看到这是如何基本的
如上所述,我们的研究重点是如何在不通过RPC接口的情况下创建或篡改任务,而只使用直接的注册表操作,以下部分将探讨如何实现这两个目标及其各自的注意事项,同时了解如何将任务保存在注册表中
任务创建
在没有深入研究负责创建任务的RPC服务器的逆向工程的情况下,我们导出了之前创建的任务的注册表值,修改了一些值,例如任务GUID、URI和路径,并将密钥导入注册表.
注意:为了导入密钥,必须提升到SYSTEM
导入完成后,可以看到任务出现在任务计划程序GUI中,但在EventLog或任务计划程序ETW源中都没有生成任务创建事件
然而这项技术有一个大问题,启动创建的任务时会得到如下错误:
这使得这项技术变得毫无用处,我们有一种很酷的创建任务的方法,但无法运行它们,经过反复试验,针对此问题确定了两种解决方案:
第一种方法尽管噪音更大且更具破坏性,但没有产生任何额外的事件,现在可以执行新创建的任务,请注意如上节所述,必须在Plain键下创建GUID子键,否则这将不起作用
第二种方法不需要杀死无辜进程和重新启动服务,主要包括更新新创建的任务定义
请注意尽管示例显示了schtasks实用程序的用法,但使用任务调度程序RPC 接口可以实现相同的结果,现在有趣的部分是任务定义的更新将在事件日志中生成一个条目,下面的屏幕截图显示了TaskScheduler审计和 TaskScheduler ETW 提要的日志条目:
有趣的是尽管任务定义更改生成了事件,但Microsoft-Windows-TaskScheduler/Operational事件仅包含有关已应用更改的信息,在上述案例中我们仅更改了用于执行任务的用户,因此事件信息中不存在其他信息,任务计划程序安全日志并非如此,因为任务定义中的每次修改都会在事件日志中生成一个条目,其中包含整个任务定义 XML,如下所示:
任务修改
虽然导出在攻击者主机上创建的任务有效,但仍然有必要了解注册表中某些结构的含义,这将允许我们直接在受感染主机上修改现有任务,并可能隐藏我们的活动,由于攻击者可能会对修改任务执行的操作感兴趣,因此我们将分析注册表中的操作值,一个例子如下所示:
可以看出结构中存在两个Unicode字符串,值Author和将执行的命令,对二进制blob中的值进行更深入的检查得出以下结论:
尽管不可能完全理解每个字段的含义,但还是确定了一些常见模式,需要注意的是攻击者不一定需要知道上面提到的密钥每一位的含义,实际上可以在本地创建具有所需恶意操作的任务,导出密钥,然后将其导入目标系统
有了这些知识,攻击者就可以编辑任务“操作”的相关字段并执行恶意操作,必须注意的是,应该使用上面提出的任何方法将任务“加载”到内存中,如果攻击者重新启动调度程序服务以将修改后的任务加载到内存中,则安全事件日志或“Microsoft-Windows-TaskScheduler/Operational”日志中不会生成任何事件
ETW篡改
ETW篡改是一种攻击者滥用ETW架构中的缺陷以防止特定进程或整个系统生成ETW遥测的技术,这通过MDSec的研究隐藏您的 .NET - ETW和Palantir的篡改Windows事件跟踪而得到普及,例如,MDSec的研究重点是隐藏 .NET 相关事件,但是考虑到ETW在Windows系统上的普遍存在,还存在许多其他滥用机会
在研究过程中实际上可以验证所有的Task Scheduler日志都是由Eventlog服务生成的,但事件信息是由Scheduler服务使用ETW发送的,这意味着如果攻击者能够篡改调度程序服务上的 ETW,则不会生成日志
CCob最近对无补丁AMSI绕过的研究表明,可以结合硬件断点和向量异常处理程序(VEH)来修改函数的行为方式,在绕过AMSI的情况下,断点设置为“AmsiScanBuffer”函数的开头,自定义VEH处理程序只需返回一个预定义的值并恢复执行流程,就好像“AmsiScanBuffer”函数正常终止一样。我们不会详细介绍该技术的工作原理,因为上面的博客文章在解释所需概念方面做得很好
从博客作者发布的初始PoC开始,将其适应ETW篡改非常容易,唯一的主要修改是提供的PoC中的VEH和断点仅应用于当前线程,因此为了使其适用于整个进程,有必要遍历所有进程的线程并相应地配置断点和VEH . 此外还添加了一个定期扫描新线程的逻辑,因为调度程序服务新创建的线程不会受到这种绕过
修改后的PoC被编译为Windows DLL并注入到托管调度程序服务的 svchost.exe进程中,以下视频显示了攻击的结果:
可以看出在攻击之前,在执行或修改任务之后会按预期生成各种事件,但是在将恶意DLL注入目标svchost进程后,没有更多事件发送到事件日志
尽管视频显示了使用进程黑客执行DLL注入,但在现实生活场景中,可以将 DLL转换为反射DLL并使用隐蔽的进程注入技术进行注入
与经典的ETW函数修补相比,这种篡改方法具有多个OpSec优势,因为没有对内存中的DLL进行任何修改,这将避免所有基于Write on Copy的检测,这些检测也在Moneta等开源扫描仪中实现,此外一旦攻击者执行了他们的操作,删除VEH和断点就相对微不足道,并且应该在被攻击的进程上留下最少的痕迹,使用不依赖于修补DLL的.text部分的内存的不同挂钩技术(例如:Page Guard挂钩或类似方法)可以获得类似的结果
最后使用这种技术将允许攻击者避免更复杂的路径,例如之前描述的涉及修改注册表中的二进制值的路径,将通过COM或RPC进行的经典计划任务部署与此绕过结合使用将在防御规避方面有效地产生相同的效果
总而言之下表显示了各种任务调度程序日志源以及它们如何受到建议技术的影响:
滥用案例
总而言之,确定了以下滥用案例:
第三种情况呈现了一个有趣的场景,因为如果攻击者可以创建任务 - 无论是使用经典技术还是这种变体 - 他们就可以“欺骗”“Actions”值以使任务看起来合法。如果修改了“操作”字段,其值将立即反映在任务计划程序 GUI 中。但是,如果没有更新任务定义或重新启动主机,则每次执行任务时,都会触发恶意操作
为了更好地解释这一点,下面提供了一个示例:
请注意在这个提议的假设场景中,攻击者可能不一定想要隐藏初始任务创建活动,这主要是为了阻止对主机的手动调查,因为任务计划程序GUI中的操作与正在执行的实际任务不同
横向运动
由于权限限制,正如其他研究人员在公开可用的工具中提到的那样,通常无法手动修改与计划任务关联的注册表项,这是因为相关的注册表项具有ACL,因此只有SYSTEM用户才能修改它们
为了验证这一点让我们尝试使用Impacket的reg.py脚本添加创建任务所需的密钥之一,并使用对远程主机具有管理员权限的帐户:
reg.py isengard.local/administrator@WIN-FCMCCB17G6U.ISENGARD.LOCAL add -keyName 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{61687CDA-FEBB-4F23-8E3B-5F2D8778CA7B}'
Impacket v0.9.25.dev1+20220218.140931.6042675a - Copyright 2021 SecureAuth Corporation
[*] Service RemoteRegistry is in stopped state
[*] Starting service RemoteRegistry
[-] DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied
那么现在的问题是,我们是否可以远程使用SYSTEM帐户并使用我们发现的内容来远程执行此攻击?简短的回答是肯定的,但让我们探讨一下注意事项
在我们的实验中,我们发现可以使用Silver Ticket技术来制作在PAC中具有 SYSTEM SID(S-1-5-18)的票证,为了执行Silver Ticket攻击,您必须拥有与计算机帐户关联的NTLM或AES密钥,这可以通过多种方式获得,例如使用Shadow Credentials攻击或通过使用远程注册表和诸如Impacket的 secretsdump.py之类的工具从远程主机中提取它
现在假设我们获得了一个计算机帐户的NTLM哈希,下一步是什么?
使用Impacket的票务器,我们可以使用-extra-sid参数伪造银票:
ticketer.py -nthash [NTLM] -domain-sid S-1-5-21-861978250-176888651-3117036350 -domain isengard.local -dc-ip 192.168.182.132 -extra-sid S-1-5-18 -spn HOST/WIN-FCMCCB17G6U.isengard.local WIN-FCMCCB17G6U$
Impacket v0.9.25.dev1+20220218.140931.6042675a - Copyright 2021 SecureAuth Corporation
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for isengard.local/WIN-FCMCCB17G6U$
[*] PAC_LOGON_INFO
[*] PAC_CLIENT_INFO_TYPE
[*] EncTicketPart
[*] EncTGSRepPart
[*] Signing/Encrypting final ticket
[*] PAC_SERVER_CHECKSUM
[*] PAC_PRIVSVR_CHECKSUM
[*] EncTicketPart
[*] EncTGSRepPart
[*] Saving ticket in WIN-FCMCCB17G6U$.ccache
现在票已保存,我们可以将其与其他impacket工具一起使用并将更改应用到注册表:
export KRB5CCNAME=/tmp/WIN-FCMCCB17G6U\$.ccache
reg.py -k -no-pass 'ISENGARD.LOCAL/WIN-FCMCCB17G6U$'@WIN-FCMCCB17G6U.ISENGARD.LOCAL add -keyName 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{61687CDA-FEBB-4F23-8E3B-5F2D8778CA7B}'
Impacket v0.9.25.dev1+20220218.140931.6042675a - Copyright 2021 SecureAuth Corporation
Successfully set subkey HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{61687CDA-FEBB-4F23-8E3B-5F2D8778CA7B}
尽管上面的命令只显示了创建任务所需的各种键之一的创建,但它足够简单以自动化整个过程
检测狩猎
从防御的角度来看,我们首先要提到的是任务的创建和修改不会产生事件,启动任务的动作会,具体来说,每次任务启动诸如运行EXE之类的操作时,您都会有一个如下所示的事件:
请注意,此事件不存在于任务计划程序的安全事件中,它将仅记录任务的创建、删除和修改,因此如果ETW在Scheduler服务上被篡改,则不会捕获由任务启动的操作
另一种更强大的方法将包括父子进程关系,因为任务计划程序启动的所有进程都将具有特定的 svchost 作为父进程
从狩猎和检测的角度来看,寻找影响本文中提到的并非源自 svchost 进程的密钥的注册表操作可能是发现执行此攻击的攻击者的好方法,而无需太复杂。下面的第一张图片显示了从 svchost 生成的良性事件:
此图显示了类似的注册表操作,但由reg.exe进程而不是svchost 执行:
不言而喻,攻击者可以轻松生成 svchost 进程或注入现有进程来执行此攻击,但这可能(应该?)触发其他控制。
在ETW篡改方面,这些建议并非针对调度程序滥用,而应主要集中在:
以下Sigma规则可用于寻找试图从注册表手动修改计划任务的攻击者:
title: Task Tampering Detection
status: experimental
description: Detects manual Scheduled Task tampering via registry modification
author: Riccardo Ancarani
date: 03/05/2022
level: high
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 13
TargetObject: 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\*'
filter:
- Image|endswith: '\svchost.exe'
condition: selection and not filter
上面的Sigma规则利用Sysmon的日志记录功能,并在用于此攻击的特定密钥上查找事件ID 13(注册表写入),它还过滤从svchost.exe生成的所有活动
该规则针对Sigma的基线EVTX文件进行了测试,没有产生任何误报,使用Chainsaw工具成功识别的真阳性示例:
文末小结
在这篇文章中,我们研究了攻击者可以用来创建或篡改计划任务的各种技术,这些技术主要使用注册表操作,从防御规避的角度来看这将限制防御者用来发现恶意活动的日志,本篇文字提供了高级检测策略以帮助蓝队成员寻找此类滥用行为