一、前言攻击者可以通过各种方式利用COM劫持技术实现隐蔽加载及本地持久化,典型的例子包括CLSID遗留(子)键的引用、CLISID覆盖以及链接等。许多程序及实用工具都可以调用COM注册表载荷,比如Ru
一、前言
攻击者可以通过各种方式利用COM劫持技术实现隐蔽加载及本地持久化,典型的例子包括CLSID遗留(子)键的引用、CLISID覆盖以及链接等。
许多程序及实用工具都可以调用COM注册表载荷,比如Rundll32.exe
、Xwizard.exe
、Verclsid.exe
、Mmc.exe
以及Task Scheduler
(任务计划程序)。从传统角度来看,任何程序只要解析不存在且/或未引用的COM类,都有可能会受到“非预期的”加载攻击的影响(比如劫持攻击)。
劫持COM服务器程序(比如MMC)可以衍生出许多有趣的用例。攻击者可以使用-Embedding
参数以隐藏方式打开GUI程序。
可以考虑使用一些防御手段,比如采用强大的应用白名单策略、监控脱离正常父进程(如svchost.exe
)的某些命令行用法(如使用-Embedding
)及注册表键值(如TreatAs
、ScriptletUrl
)的创建操作等。
二、背景介绍
前阶段我写了篇文章,介绍了滥用COM注册表结构的一些技巧。在上一篇文章中,我们讨论了一些有趣的技术,比如如何寻找被遗弃的注册表键值、COM劫持、横向渗透、规避防御机制、绕过应用白名单以及持久化技术等。在这篇文章中,我们将更进一步,重点关注其他一些劫持方法以及可用于规避的加载技术,主要内容包括:
1、COM劫持技术;
2、用于规避及持久化的CLSID加载技术;
3、滥用COM服务端:MMC(Microsoft Management Console)使用案例;
4、防御方法。
三、COM劫持技术
为了在没有注册的情况下加载和执行COM载荷,攻击者必须以一定的方式去影响COM注册表结构,其中一种方法就是使用COM劫持(COM Hijacking)技术。关于COM劫持这个概念Mitre ATT&CK Framework已经给出了非常准确的定义:
COM(Microsoft Component Object Model,Microsoft组件对象模型)是Windows上的一个系统,可以通过操作系统实现软件组件之间的交互。攻击者可以使用该系统,通过劫持COM引用和关系在合法软件中插入恶意代码,达成持久化目标。劫持COM对象需要修改Windows注册表,替换某个合法系统组件的引用,该操作可能导致该组件无法正常执行。当系统组件通过正常系统调用执行时,攻击者的代码就会被执行。攻击者可能会劫持频繁使用的对象,以维持一定程度的持久化驻留,但不大会破坏系统内的常见功能,避免系统出现不稳定状态导致攻击行为被发现。
以上参考COM劫持(T1122),Mitre ATT&CK
接下来我们重点介绍常见的一些COM劫持技术。
利用被遗弃的COM键
InprocServer32
以及LocalServer32
(此外还包括InprocServer
和LocalServer
)的键值(key-values)是COM服务器(即DLL
、CPL
、EXE
以及OCX
程序)的引用点。当攻击者发现(存在漏洞的)一个引用点后,就可以在适当条件下(比如路径可写时)将载荷投放到已被遗弃的PE(Portable Executable)引用路径上。如果被调用时(比如加载器或者程序引用了COM键时),由于调用方会尝试实例化CLSID入口点下的COM对象,因此PE载荷就会得到加载机会。前一篇文章中我介绍了VMware vmnetbridge.dll
这个例子,这里再简单回顾一下。
在这个例子中,VMware Workstation卸载程序会遗留下一些COM键(处于未注册状态)。运行一个探测脚本后,我们可以发现LocalServer32
键指向了之前已被移除的一个DLL路径。攻击者可以简单替换这个文件,劫持COM节点结构,如下图所示:
图1. 被遗弃的COM键注册表路径
图2. 被遗弃的COM键文件路径
图3. 利用二进制引用替换法劫持被遗弃的键
覆盖COM键
覆盖COM对象可能是影响COM结构载荷的更为实用的方法。在HKCU
注册表中添加正确的键值后,当引用目标COM对象时,HKLM
中的键值就会被覆盖(并且“添加”到HKCR
中)。在Casey Smith(@subTee)给出的“SqibblyDoo”样例中,攻击者可以导入如下注册表文件,使用另一个类标识(CLSID)成功劫持scripting.dictionary
COM程序标识(ProgID):
图4. 包含Scripting.Dictionary
COM覆盖键值的注册表文件
实际上,任何程序或者脚本只要尝试实例化scripting.dictionary
COM程序或尝试加载被劫持的类标识时,都会调用攻击者布置的载荷。
链接COM键(使用TreatAs
键)
影响COM载荷加载的另一种方法就是使用TreatAs
键,该键实际上充当的是另一个(未注册的)CLSID键的快捷方式(或链接)。许多(原生的)Windows程序会引用不存在的CLSID注册表节点(注意:我们可以使用SysInternals的ProcMon工具来识别这些悬空式引用)。根据具体的加载程序以及CLSID键,攻击者可以使用带有TreatAs
引用的被劫持的CLSID节点结构,在CLSID键被引用时(如程序或者脚本启动时)达到加载目的。实际上攻击者可以通过以下两步完成这个任务:
1、劫持程序的未引用的COM CLSID路径或者带有TreatAs
键的合法路径;
2、然后将带有TreatAs
键的CLSID结构链接到另一个(被劫持的)COM CLSID键,后者包含恶意的加载器。
我们来看看Matt Nelson(@enigma0x3)和Casey Smith(@subTee)给的一个例子。Matt和Casey曾做过名为Windows Operating System Archaeology的专题演讲,其中提到了如下所示的注册表导入文件:
图5. TreatAs
注册表文件
在图5中,攻击者创建了2个主要的CLSID节点(如果HKLM
中存在这些CLSID值则会被覆盖掉)。一旦{3734FF83-6764-44B7-A1B9-55F56183CDB0}
这个CLSID键(橙色高亮部分)被引用(比如程序加载或者其他调用/加载方法),TreatAs
键就会充当一个超链接快捷键角色,“重定向”到{00000001-0000-0000-0000-0000FEEDACDC}
这个CLSID键(绿色高亮部分),调用相应的载荷。当调用者/加载者调用时,大致的抽象逻辑可以分为以下几个步骤:
1、直接引用CLSID节点
[调用方] -> [CLSID入口点] -> [COM服务器] -> [载荷(比如Scrobj.dll Scriptlet
)]
2、使用TreatAs
链接引用CLSID节点
[调用方] -> [第一个CLSID入口点] -> [TreatAs
键应用] -> [第二个CLSID入口点] -> [COM服务器] -> [载荷(比如Scrobj.dll Scriptlet
)]
注意:这里应该着重表扬下TrustedSec的Jason Lang(@curi0usJack),他在识别和利用这些未引用的COM路径方面做了许多杰出的工作。Jason在BlackHat 2018的TrustedSec Purple Team培训课程中详细介绍了这方面内容。此外,大家也可以参考Adam(@Hexacorn)的一篇文章,里面介绍了关于劫持TreatAs实例化过程的一些基本知识。
四、用于规避及持久化的CLSID加载技术
现在我们讨论下用于规避的COM加载技术。
引用加载器
如前文所述,如果脚本以及程序尝试实例化或者调用已被劫持COM节点的类以及/或者程序标识符时,就(很可能)会在执行的某个时刻加载其他载荷。覆盖或者链接恶意COM节点的操作通常需要考虑如下几个因素:
1、成功识别并劫持(缺失的)引用,并且不会对程序正常行为造成负面影响(比如造成程序崩溃);
2、可以承担未知后果的影响,选择可能不会(或者不大会)影响系统或者用户体验的COM节点(比如,没有任何明显的线索表明程序或者主机的行为存在异常);
3、此外,也可以尝试“修补”已劫持的路径,解决“程序执行流”(注意:这个概念很有意思,超出了本文的讨论范围)。
比如,当我们用Casey Smith的“SquibblyDoo”载荷劫持scripting.dictionary
COM节点然后运行WinRm
时,我们可以看到当scripting.dictionary
被实例化时会出现一些非预期的结果:
图6. 使用WinRM
加载被劫持的COM节点
注意:并不是所有被劫持的路径都会导致(可见的)程序性故障。有许多无缝的、可被劫持的路径不会对程序执行流造成负面影响,其中某些路径还可以作为隐蔽的持久化技术来使用。
Rundll32
如前一篇文章所述,通过CLSID键(或者PROGID)调用载荷的一种方法就是在rundll32
中使用-sta
(single threaded apartment)参数,这种方法并没有那么广为人知,具体命令为:
rundll32.exe -sta {CLSID}
或者
rundll32.exe -sta ProgID
-sta
参数并没有详细的说明文档,但该参数的确可用,并且有被滥用的潜在风险。如下图所示,我们使用这种方法来实现了前文描述的COM节点直接加载以及通过链接方式(TreatAs
)加载:
图7. COM节点的直接加载及链接(TreatAs
)加载
我们也可以使用rundll32
配合ProgID(Program Identifier,程序标识符)来调用我们劫持的COM节点:
图8. Rundll.exe:-sta
与ProgID配合执行
在使用AutoRuns
实现本地持久化方面,rundll32
命令无法规避过滤器的筛查,但可以使用隐藏的注册表载荷来迷惑人们的双眼:
图9. Rundll32 -sta登录启动项
利用计划任务实现持久化
几年以前,Matt Nelson(@enigma0x3)写了一篇文章,介绍了利用计划任务和COM处理程序劫持实现用户模式下的本地持久化技术。Matt在文章中介绍了如何寻找计划任务中Action
设置为Custom Handler
的可疑项。查看计划任务对应的XML文件后,我们可以看到这个Action
实际上是与“COM处理程序”对应的一个CLSID值。劫持这个CLSID结构后,载荷的利用就非常简单。当计划任务运行时(比如系统登录时),恶意载荷就会被运行。
图10. 计划任务配置文件(来源:Matt Nelson的文章)
利用Verclsid调用载荷
根据微软的说明文档,verclsid.exe
可以“在Windows资源管理器实例化一个COM对象前验证该对象”,这一点非常有趣。Nick Tyrer(@NickTyrer)在Github上演示了Verclsid
的一种用法,如下所示:
verclsid.exe /S /C {CLSID}
使用合适的CLSID运行上述命令后,就可以调用攻击者设定的载荷,如下所示:
图11. 利用CLSID执行Verclsid
利用Xwizard调用载荷
根据Nick Tyrer的描述,Xwizard
是加载CLSID节点的另一种方式。@harr0ey提供了一种运行方式,不会弹出错误信息:
xwizard.exe RunWizard /taero /u {CLSID}
注意:已经有钓鱼恶意软件攻击活动中使用了Verclsid.exe
这个工具,大家可参考这篇文章(来自Red Canary)了解详细信息。
五、滥用COM服务器
Windows系统中有一些内置程序能够在特定服务(如远程主机管理)的上下文环境中充当COM/DCOM服务器。经过正确的调用和实例化后,当使用-Embedding
参数调用DCOM/COM应用时,就可以利用这些应用的公开属性及方法(这一点需要进一步验证)。然而这里存在一个“有趣的”副作用,那就是(许多)具有GUI/可见窗口组件的启用COM的应用(如mmc.exe
、mspaint.exe
、winword.exe
、iexplore.exe
等)会以服务器模式来运行,但却不呈现GUI组件。我们来看些具体例子:
MMC(Microsoft Management Console)工具的功能和可扩展性非常强大,因此可能是Windows系统管理员最喜欢的得力助手。MMC允许(高权限)用户添加多个“snap-ins”(管理单元),在本地或者远程管理Windows系统,然而这个应用也会暴露一些攻击面,可能被攻击者滥用。去年年初时候,Matt Nelson(@enigma0x3)发现MMC对外公开了一种方法,通过该方法攻击者可以借助DCOM协议辅助执行远程命令。Matt在一篇文章中详细介绍了这种技术。
虽然这种方法不像常见的远程命令执行/横向渗透技术那样令人兴奋,但MMC可以用来调用CLSID载荷,实现规避加载以及通过Run
注册表键值实现本地驻留。下面我们可以开始配置MMC控制台文件,了解具体利用方法。
MMC:CLSID Web地址链接
首先,我们需要创建一个CLSID链接,将我们的配置信息保存成控制台文件(.msc
文件)。我们可以打开MMC,通过“Add/Remove Snap-In”窗口来设置载荷。为了简单起见,我们选择“the Link to Web Address”(指向Web地址的链接)这个snap-in来打开向导,在“Path or URL”文本框中输入被劫持的/引用的CLSID键,如下图所示:
图12. 添加MMC Snap-In:Web地址链接
接下来,为这个Snap-In设置一个名称,然后选择“Finish”,如下图所示:
图13. 添加MMC Snap-In:设置名称
经过这些操作后,“Console Root”节点下就会创建我们设置的“test”项。只要选择“test”菜单项,就会调用相应的CLSID链接。
图14. MMC Snap-In:在选中时启动CLSID载荷
MMC:MSC文件加载
创建并启用我们的载荷配置后,我们可以将控制台保存为test.msc
。确保相应的Snap-In标签(如test
)处于选中状态以保持当前控制台状态。如果没有选中,我们的载荷就无法在控制台文件打开时被调用。
为了进一步确认这个条件,我们可以使用文本编辑器打开这个控制台文件,验证配置信息以及CLSID指针的值是否正确:
图15. MMC XML配置文件
保存好控制台文件后,我们可以通过命令行启动msc文件,通过-Embedding
标志(注意:大小写敏感)以隐蔽的方式调用CLSID载荷:
mmc.exe -Embedding c:pathtotest.msc
图16. 利用-Embedding
参数实现MMC隐蔽启动
利用MMC实现本地持久化
在利用AutoRuns
实现本地持久化方面,由于mmc.exe
是经过微软签名的二进制程序,因此可以规避默认的过滤器,如下图所示:
图17. MMC AutoRuns Run注册表键值:过滤器处理结果
移除过滤器后,我们可以看到对应的启动项:
图18. MMC AutoRuns Run注册表键值:不使用过滤器的处理结果
在登录时,由于我们劫持了注册表键以及引用,所以系统会执行我们的载荷:
图19. MMC Run注册表键值:登录时执行
综合考虑后,mmc.exe
可能不是最实用的利用对象,然而如果其他COM程序以类似方式来调用,可能会具备更高的实用性。
六、防御策略
1、在完美的场景中,经过正确配置的应用程序白名单(AWL)解决方案与代码完整性保护机制结合起来后可能会阻止(许多)这类载荷的执行;
2、可以监控某些有趣的COM应用的使用情况以及Run
注册表键值。Embedding
参数可能是比较有趣的一个特征,但正常的DCOM远程管理和本地实例化过程中可能也会使用该参数。对COM应用的正常调用/实例化行为应该源自于Service Host(svchost.exe
)进程,来自其他父进程的调用可能都值得怀疑;
3、可以监控进程创建事件,比如感兴趣命令行操作以及CLSID调用程序的使用;
4、评估新创建的注册表键值,特别要注意包含TreatAs
以及/或者ScriptletURL
键值的新增内容。
七、他人研究成果
1、James Forshaw(@tiraniddo)在“COM In 60 Seconds”中详细介绍了COM的每一步工作流程(现在我仍在重复观看这个视频)。如果您不熟悉James的研究成果,我强烈推荐大家尽快去学习一下;
2、PhilipTsukerman(@PhilipTsukerman)在“New lateral movement techniques abuse DCOM technology”这篇文章中为我们介绍了COM技术的入门知识,也很好概述了DCOM横向渗透技术;
3、Rob Maslen(@rbmaslen)在“COM and the PowerThief”视频中介绍了COM与Internet Explorer交互的背景知识,此外我们还可以参考Rob开发的PowerThIEf工具来滥用正在运行的IE实例。