重要声明: 本文档中的信息和工具仅用于授权的安全测试和研究目的。未经授权使用这些工具进行攻击或数据提取是非法的,并可能导致严重的法律后果。使用本文档中的任何内容时,请确保您遵守所有适用的法律法规,并获得适当的授权。
介绍
微软最近发表了一篇文章,记录了HAFNIUM威胁行为者如何利用计划任务在注册表中的存储方式存在的缺陷来隐藏自身踪迹。这清楚地表明,文中所提到的缺陷很可能不是影响计划任务组件的唯一缺陷。
我们开始研究如何滥用计划任务的注册表结构,以达成诸如横向移动和持久化等各种目标。
具体而言,我们研究了在不通过远程过程调用(RPC)等经典接口的情况下,创建任务的最低条件是什么。
微软的文章和SpectreOps关于功能抽象的研究都证实,所有计划任务最终都会存储在注册表的以下注册表项中:
HKLMSOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTasks
HKLMSOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTree问题在于,是否有可能创建相关的注册表项并创建一个任务,而且有可能不产生任何事件记录呢?
在本文中,我们将探讨两种可以实现相同结果的方法:创建或修改计划任务并执行它,同时不生成相关的遥测数据。首先,我们将探讨如何通过直接操作注册表来创建或修改任务,以及这种方式为何不会在事件日志中生成常见的记录项。最后,我们将介绍一种基于篡改任务计划程序事件跟踪(ETW)的替代方法,该方法将完全抑制与任务计划程序相关的大部分日志记录。
可用的监测
在尝试规避或绕过任务计划程序记录事件的方式之前,我们先简要介绍一下任务计划程序提供的日志记录类型。
在创建、修改、运行或删除任务时,将生成以下遥测数据:
-
“Microsoft-Windows-TaskScheduler”——这是一个ETW提供程序,可提供有关任务计划程序活动的原始监测数据。各种基于ETW的安全解决方案可以直接利用这个数据源。 -
事件日志中的“Microsoft-Windows-TaskScheduler/Operational”事件——如果启用了任务历史记录,这些事件将反映上述ETW提供程序捕获的内容。 -
事件4698到4702——要获取这些事件,需要在本地安全策略的高级审核选项中配置对象审核。这个来源包含与上述类似的信息,但最终会记录在“Security”事件日志中。稍后我们将了解它与“Microsoft-Windows-TaskScheduler/Operational”事件的区别。这些事件记录任务的创建和修改,但不记录任务的执行时间或特定任务执行的操作。在本文中,我们将简单地称其为“Security”事件日志。
通过分析常见的攻击者知识框架,例如ATT&CK,我们可以看到,在对“计划任务”技术的推荐审核中,我们同时有“Microsoft-Windows-TaskScheduler/Operational”事件和来自对象审核的4XXX事件。由于它们包含相似的信息,所以很容易认为它们可以互换使用。实际上,像Sigma这样的开源检测规则存储库会搜索由一个来源生成的事件,而不是两个来源的事件。
以下部分将记录用于规避各类事件的所有不同技术,以及这些技术在实际场景中的实用性。
注册表结构
如果我们分析上述注册表项的结构,可以观察到“Tree<taskName>”键下的条目存在以下值:
-
“Default”——留空 -
“Id”——是一个GUID(全局唯一标识符),指示“Tasks”键下的子项。 -
“Index”——DWORD(双字)值,不清楚其用途 -
“SD”——任务的安全描述符,微软已经讨论过
下面的图片是一个示例:
“Tasks”子项的值大多是二进制数据块和编码字符串,指示诸如以下的信息:
-
任务触发器 -
任务操作 -
“C:windowssystem32tasks”文件夹中XML文件的哈希值
除了上述内容,我们还发现了另一个未记录的注册表项,它在任务创建中起着重要作用:
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCachePlain{GUID}其中GUID是如上所述的任务的唯一标识符。在GUID子项下未配置任何值。我们将在任务创建部分了解这一点为何至关重要。
如上所述,我们的研究重点是如何在不通过RPC接口的情况下,仅使用直接的注册表操作来创建或篡改任务。以下部分将探讨如何实现这两个目标以及各自的注意事项,同时了解任务是如何保存在注册表中的。
任务创建
我们没有对负责创建任务的RPC服务器进行深入的逆向工程,而是导出了先前创建的任务的注册表值,修改了一些值,如任务GUID、统一资源标识符(URI)和路径,然后将这些键导入到注册表中。
注意:为了导入这些键,必须提升到SYSTEM权限。
导入完成后,可以看到任务出现在任务计划程序的图形用户界面(GUI)中,但在事件日志或任务计划程序ETW源中都没有生成任务创建事件。
然而,这种技术有一个很大的问题。当启动创建的任务时,会得到以下错误:
这使得这种技术几乎毫无用处,我们有一种很酷的创建任务的方法,但却无法运行它们!
经过多次试验和错误,我们为这个问题找到了两种解决方案:
-
重新启动“Schedule”服务将把任务“加载”到相关的svchost进程的内存中,从而允许任务运行。 -
修改任务定义也将强制把任务加载到内存中。
第一种方法尽管更引人注目且更具破坏性,但它没有生成任何额外的事件,并且现在可以执行新创建的任务了。请注意,如上一节所述,必须在“Plain”键下创建GUID子项,否则此方法将不起作用。
第二种方法不需要终止任何无辜的进程或重新启动服务,主要包括更新新创建的任务定义。
请注意,尽管示例中展示了“schtasks”实用程序的用法,但使用任务计划程序RPC接口也可以达到相同的结果。
现在,有趣的是,任务定义的更新将在事件日志中生成一个条目。
下面的屏幕截图显示了任务计划程序审核和任务计划程序ETW源的日志条目:
有趣的是,尽管任务定义的更改生成了事件,但“Microsoft-Windows-TaskScheduler/Operational”事件仅包含有关所应用更改的信息。在上述示例中,我们只更改了用于执行任务的用户,因此事件信息中没有其他额外信息。
任务计划程序安全日志则不同,因为任务定义中的每一次修改都会在事件日志中生成一个包含整个任务定义XML的条目,如下所示:
任务修改
虽然导出在攻击者主机上创建的任务是可行的,但我们仍然需要了解注册表中某些结构的含义。这将使我们能够直接在被攻陷的主机上修改现有任务,并有可能隐藏我们的活动。
由于攻击者可能对修改任务执行的操作感兴趣,我们将分析注册表中的“Actions”值。示例如下:
可以看到,该结构中存在两个Unicode字符串,即“Author”值和将要执行的命令。
对二进制数据块中的值进行更深入的检查后,得到以下结果:
“03 00”——似乎是静态字节
-
“Author”字符串的大小,似乎指示应该运行该任务的用户,例如,其他任务中发现有“LocalSystem”(本地系统),还有一些是“Authenticated Users”(已验证用户) -
“66 66”——对于启动另一个程序的任务来说,似乎是静态的,其他基于COM的任务被发现具有不同的值 -
“Action”字符串的大小——一个指示操作字符串长度的值 -
“Action”字符串——指示要执行的操作的字符串的Unicode表示形式
尽管我们无法完全理解每个字段的含义,但还是确定了一些常见的模式。
必须注意的是,攻击者不一定需要知道上述键中每个位的含义。实际上,可以在本地创建一个具有所需恶意操作的任务,导出该键,然后将其导入到目标系统中。
有了这些知识,攻击者可以编辑任务“操作”的相关字段并执行恶意操作。必须注意的是,应该使用上述任何一种方法将任务“加载”到内存中。
如果攻击者重新启动计划程序服务以将修改后的任务加载到内存中,安全事件日志或“Microsoft-Windows-TaskScheduler/Operational”日志中不会生成任何事件。
替代方法:ETW篡改
ETW修补是一种技术,攻击者利用ETW体系结构中的缺陷,旨在阻止特定进程或整个系统生成ETW遥测数据。MDSec的研究“隐藏您的.NET - ETW”和Palantir的“篡改Windows事件跟踪”推广了这种技术。例如,MDSec的研究重点是隐藏与.NET相关的事件,然而,考虑到ETW在Windows系统中无处不在,还存在许多其他滥用的机会。
在研究过程中,我们确实验证了所有任务计划程序日志都是由事件日志服务生成的,但事件信息是由计划程序服务使用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进行修改。这将避免所有基于“写时复制”的检测,这些检测也在像Moneta这样的开源扫描程序中实现。此外,一旦攻击者执行了他们的操作,删除VEH和断点相对简单,并且应该在被攻击的进程上留下最少的痕迹。使用不依赖于修补DLL的“.text”部分内存的不同挂钩技术,例如页面保护挂钩或类似技术,也可以实现类似的结果。
最后,使用这种技术将使攻击者能够避免更复杂的路径,例如前面描述的涉及修改注册表中二进制值的路径。将通过COM或RPC的经典计划任务部署与此绕过方法结合使用,在规避防御方面将有效地产生相同的效果。
总而言之,下表显示了各种任务计划程序日志源以及它们如何受到所提出技术的影响:
|
|
|
|
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注意:我们不打算在短期内发布任何自动化此攻击的工具。
滥用案例
总而言之,确定了以下滥用案例:
-
攻击者通过注册表创建恶意计划任务以建立持久性,并希望隐藏他们的活动。 -
攻击者篡改现有的良性任务以注入恶意操作。 -
攻击者通过RPC或注册表创建恶意任务,并将其伪装为良性任务。
第三种情况提出了一个有趣的场景,因为如果攻击者能够使用经典技术或这种变体创建任务,他们就可以“欺骗”“Actions”值,使任务看起来合法。如果修改了“操作”字段,其值将立即反映在任务计划程序GUI中。然而,如果任务定义未更新或主机重新启动,每次执行任务时,恶意操作将被触发,而不是预期的操作。
为了更好地解释这一点,下面提供一个示例:
-
攻击者在受害者主机上创建一个恶意任务A,该任务将执行“C:evil.exe”。 -
然后,攻击者修改新创建任务的注册表项,并将操作更改为“C:legitimate.exe”。 -
攻击者可以运行该任务,并且“C:evil.exe”将被执行。 -
试图在主机上发现恶意活动的防御者将看到,创建的任务应该执行“C:legitimate.exe”,但没有任务修改的日志记录。
请注意,在这个假设的场景中,攻击者不一定希望隐藏初始的任务创建活动。这主要是为了阻碍对主机的手动调查,因为任务计划程序GUI中的操作将与实际执行的任务不同。
额外内容:横向移动
由于权限限制,正如其他研究人员在公开可用的工具中提到的,通常无法手动修改与计划任务相关的注册表项。这是因为相关的注册表项具有访问控制列表(ACL),只有SYSTEM用户才能修改它们。
为了验证这一点,让我们尝试使用Impacket的reg.py脚本,以一个对远程主机具有管理员权限的帐户添加创建任务所需的键之一:
reg.py isengard.local/[email protected] add -keyName 'HKLMSOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTasks{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)的票据。不用说,为了执行银票攻击,您必须拥有与计算机帐户相关联的NTLM(NT LAN Manager)或AES(高级加密标准)密钥。这可以通过多种方式获得,例如使用“影子凭据”攻击,或使用像Impacket的secretsdump.py这样的工具通过远程注册表从远程主机中提取它。
现在,假设我们获得了一个计算机帐户的NTLM哈希值,接下来该怎么做呢?
使用Impacket的ticketer工具,我们可以使用“-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 'HKLMSOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTasks{61687CDA-FEBB-4F23-8E3B-5F2D8778CA7B}'
Impacket v0.9.25.dev1+20220218.140931.6042675a - Copyright 2021 SecureAuth Corporation
Successfully set subkey HKLMSOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTasks{61687CDA-FEBB-4F23-8E3B-5F2D8778CA7B}尽管上面的命令仅显示了创建一个任务所需的各种键中的一个的创建过程,但将整个过程自动化也相当简单。
检测与搜寻
从防御的角度来看,我们首先要提到的是,任务的创建和修改可能不会生成事件,但启动任务的操作会产生事件。
具体来说,每当一个任务启动诸如运行可执行文件(EXE)这样的操作时,你将会看到一个类似如下的事件:
请注意,此事件不会出现在任务计划程序的安全事件中,安全事件只会记录任务的创建、删除和修改。因此,如果任务计划程序服务上的ETW被篡改,那么任务启动的操作将不会被捕获。
另一种更可靠的方法是考虑父子进程关系,因为任务计划程序启动的所有进程都会以特定的svchost进程作为父进程。
从搜寻和检测的角度来看,查找那些影响本文中提到的注册表键、且并非源自svchost进程的注册表操作,可能是发现实施此类攻击的攻击者的一个好方法,而且无需过于复杂的手段。下面的第一张图片展示了一个由svchost进程生成的良性事件:
这张图片展示了一个类似的注册表操作,但它是由“reg.exe”进程而非svchost进程执行的:
不言而喻,攻击者可以轻松地生成一个svchost进程,或者注入到现有的svchost进程中以实施此攻击,但这可能(应该?)会触发其他的控制措施。
在ETW篡改方面,这些建议并非专门针对任务计划程序的滥用情况,而应主要集中在以下几点:
-
检测针对系统进程的内存注入——为了部署ETW补丁,攻击者很可能会将代码注入目标进程。检测进程注入是一个远远超出本研究范围的话题,因此我们不会在此花费过多时间讨论。 -
检测VEH的滥用——美国国家网络安全中心(NCC)发布了一篇关于如何应对此问题的有趣文章 。然而,所提出的检测方法主要集中在检测指向没有磁盘文件支持的内存区域的处理程序。高级攻击者可以通过将他们的代码隐藏在与磁盘上存在的文件相关联的内存页面上,或者在执行完操作后简单地删除VEH,从而轻松地避开这些检测指标。 -
检测ETW日志量的变化——特定源生成的日志量的快速变化应该被视为可疑情况,尽管攻击者在恶意操作完成后仍然可以恢复这些变化。请注意,在足够大的环境中实现这一点可能极其困难。
以下Sigma规则可用于搜寻那些试图从注册表手动修改计划任务的攻击者:
title: 任务篡改检测
status: 实验性
description: 检测通过注册表修改进行的手动计划任务篡改
author: 里卡多·安卡拉尼(Riccardo Ancarani)
date: 2022年3月5日
level: 高
logsource:
product: windows
service: sysmon
detection:
selection:
EventID: 13
TargetObject: 'HKLMSOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCache*'
filter:
- Image|endswith: 'svchost.exe'
condition: selection and not filter
上述Sigma规则利用了Sysmon的日志记录功能,并在用于此攻击的特定注册表键上查找事件ID 13(注册表写入)。它还会过滤掉所有由“svchost.exe”生成的活动。
该规则已针对Sigma的基线EVTX文件进行了测试,并未产生任何误报。
使用Chainsaw工具成功识别出真阳性的一个示例如:
结论
在本文中,我们研究了攻击者主要通过注册表操作来创建或篡改计划任务的各种技术。从规避防御的角度来看,这会限制防御者用于发现恶意活动的日志信息。
原文始发于微信公众号(网空安全手札):篡改计划任务
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论