介绍
在企业 Windows 这个奇妙的世界中,横向移动技术非常有限。攻击者用来执行远程命令和有效负载的技术及其变体非常有限。十多年前,随着 PowerShell 的兴起,大多数道德黑客可能都同意,当获取正确的(特权)凭据或身份时,Windows 远程管理 (WinRM) 成为其“横向移动工具包”的重要组成部分。借助Invoke-Command、*-PSSession和*-CimSession等“远程”命令,道德黑客可以乘上 WinRM 浪潮,因为 PowerShell 使这样做变得容易得多。
在当今环境下,PowerShell 肯定仍有其用例。然而,随着更好的检测光学和 5 以上版本中增强的可见性,PowerShell 在后期利用方面的吸引力已经降低。此外,现代工具已从 PowerShell 转向托管 .NET 和(回到)非托管 C/C++。尽管攻击趋势正在发生变化,但 WinRM 仍然是一个可行的选择(至少在我看来)。
在这篇文章中,我们将尽最大努力将 WinRM 与 PowerShell 分离,并介绍一些利用 WinRM 进行远程命令执行和横向移动的其他工具。此外,我们将展示如何利用WSMAN.Automation(一个非常有趣的 COM 对象)通过 WinRM 传输运行远程命令。为了实现这一点,我们将逐步介绍构建一个简单的概念验证 .NET C# 工具的过程。
让我们开始吧…
WinRM 简要概述
Windows 远程管理 (WinRM) “是 WS 管理协议 (Web 管理服务,又名 WSMan) 的 Microsoft 实现,这是一种基于标准简单对象访问协议 (SOAP) 的防火墙友好协议,允许来自不同供应商的硬件和操作系统进行互操作”( Microsoft Docs )。
作为远程管理的 DCOM 和 WMI 替代方案,WinRM 用于通过 WSMan 与远程计算机建立会话,WSMan 利用 HTTP/S 作为传输机制来传递 XML 格式的消息。在现代 Windows 系统中,WinRM HTTP 通信通过 TCP 端口 5985 进行,HTTPS (TLS) 通信通过 TCP 端口 5986 进行。WinRM 原生支持 NTLM 和 Kerberos(域)身份验证。初始身份验证后,WinRM 会话将受到 AES 加密的保护(Microsoft Docs)。
注意:必须配置并运行 WinRM 服务才能接受远程连接。可以使用winrm.cmd quickconfig命令或通过组策略快速设置。WinRM 接受连接可能需要几个步骤。请参阅此 Pentest Lab文章 了解更多信息。
WinRM 工具和功能
让我们快速了解一下 WinRM 的一些功能(PowerShell 之外):
执行程序
Winrs.exe是一个内置命令行工具,允许具有正确凭据的用户通过 WinRm 执行远程命令。该命令支持各种开关以及使用备用凭据进行身份验证的能力。示例命令用法如下:
winrs -r:corp-dc "whoami /all"
尽管该工具提供了一种调用远程命令的简单方法,但检测机会相对较少。正如 Matt Graeber(@mattifestation )在这条推文中指出的那样,成功执行命令的远程进程链如下:
svchost.exe (DcomLaunch)-> winrshost.exe -> cmd.exe [/c remote command] -> [remote command/binary]
此外,Winrs 事件在远程主机上记录为Microsoft-Windows-WinRM/Operational(事件 ID 91)。
Winrm.vbs(通过 Winrm.cmd 调用)
Winrm.vbs是一个 Visual Basic 脚本,允许管理员“配置 WinRM 并获取数据或管理资源”(Microsoft Docs )。正如 Matt Graeber 的白皮书“滥用 Windows 管理规范 (WMI) 构建持久、异步和无文件后门”中所述,WinRM(.vbs)允许通过 WinRM 传输进行 WMI 对象的远程交互。这很有趣,因为可以利用多个 WMI 类来执行远程命令。例如,一个非常著名的 WMI 类Win32_Process可用于通过利用Create方法生成(远程)进程。在以下Winrm(.vbs)示例中,invoke命令在名为corp-dc 的主机上生成一个远程notepad.exe进程:
winrm invoke Create wmicimv2/Win32_Process @{CommandLine="notepad"} -r:corp-dc
事件 XML 元数据中返回进程标识符( PID) 和返回值,以确认远程执行成功:
在远程主机上,进程执行链如下所示:
svchost.exe (DcomLaunch) -> wmiprvse.exe -> [remote command/binary]
第三方 WinRM 工具
还值得一提的是,Windows 之外还存在其他第三方 WinRM 功能,包括:
-
Metasploit – 包含辅助/scanner/winrm/*和exploit/windows/winrm/*中的模块
-
PyWinRM – 用于执行远程命令的 Python 客户端
-
CrackMapExec – 包含 Python WinRM 命令模块
-
Evil-WinRM – 是一款用 Ruby 实现的功能齐全的 WinRM shell
WS-Management 组件对象模型 (COM)
在我调查这个主题的时候,我注意到除了 PowerShell 之外,并没有太多的 Windows 工具可以利用 WinRM 进行远程命令执行/横向移动。我决定仔细研究一下,并在 Microsoft Doc/Windows Dev Center 和一些有趣的 StackOverflow/留言板帖子上发现了一些有关WinRM 脚本 API的信息。许多核心功能由一个被低估的 COM 类驱动,该类在幕后非常努力地工作 – WSMan.Automation。
WSMan.Automation COM 对象的公开方法和属性揭示了几个有趣的方法和属性:
快速查看WinRM.vbs的源代码表明,WsMan.Automation被用来建立 WinRM(远程)会话以进行管理、查询和调用:
此外,我们可以利用James Forshaw(@tiraniddo )的OleView.Net来更详细地了解 COM 类。请注意以下关键要点:
-
CLSID 为BCED617B-EC03-420B-8508-977DC7A686BD
-
进程内服务器名为WsmAuto.dll
-
该类型库称为Microsoft WSMAN Automation V1.0 Library,它在 WsmAuto.dll 库中实现
-
主要支持两个接口 – IWSMan和IWSManEx
现在,我们对可以(可能)用来开发自己的 POC WinRM 工具的载体有了一些了解。让我们开始吧……
在 .NET C# 中构建 POC WinRM 远程命令执行工具
在本节中,我们将介绍创建 POC 工具SharpWSManWinRm.exe的过程
关于 .NET COM Interop 的简要说明
对于 .NET,Visual Studio 使集成(许多)COM 组件(对象)变得非常无缝。通过在引用管理器中选择预定义组件或从磁盘中选择另一个组件文件(例如非托管库 (DLL) 或类型库 (TLB) 文件),可以将 COM 引用添加到程序集项目中。Visual Studio 解析类型库并将 COM 接口和类映射到项目中包含的自动生成的托管互操作库 (DLL) 中的命名空间结构。
在运行时,.NET通用语言运行时 (CLR) 创建“运行时可调用包装器”(RCW) 来保存接口指针并编组 .NET 和创建的 COM 对象(实例)之间的调用。从 .NET 的角度来看,这使得 COM 对象显示为 .NET 对象,并“简化”与各个 COM 对象协同工作所需的托管代码。
注意:有关 RCW 的更多信息,请参阅Microsoft Docs 上的COM Interop页面。在某些情况下,可能需要使用外部 COM 对象,这需要手动创建互操作定义。有关使用接口定义语言 (IDL) 或类型库手动创建包装器的信息,请参阅此 Microsoft Doc文章。
使用 Visual Studio 设置 WSMan/WinRM 项目
在我们创建一个新的 .NET Framework (4) 控制台应用程序项目后,通过右键单击解决方案资源管理器中的“引用”菜单并选择“添加引用”来添加 COM 引用:
在参考管理器中,选择浏览并从WindowsSystem32导入WsmAuto.dll文件:
或者,可以从参考管理器中的 COM 菜单中选择Microsoft WSMAN Automation V1.0 Type Library来实现相同的结果:
通过添加的Reference,我们现在可以利用using语句中的WSManAutomation命名空间来访问目标接口、方法和属性:
自动生成的互操作程序集
在继续之前,让我们快速浏览一下自动生成的Interop.WSManAutomation.dll 。使用dnSpy,我们可以“反编译”程序集以查看源代码:
我们可以看到 DLL 程序集如何以一种方便的方式包装接口和方法/属性等,以便在我们的 C# 控制台项目中调用。当编译项目代码时,此 DLL 将与输出程序集合并。
编写 WinRM POC
使用WSman.Automation对象,我们可以利用与之前WinRm.vbs中展示的相同的 WMI 类来执行远程命令。这在我们的 POC C# 代码(如下)中实现如下:
-
wsman是我们初始化的一个 .NET/C# 对象,它实现了iWSManEx接口,扩展了iWSMan接口的方法和属性。
-
options是一个 NET/C# 对象,它调用CreateConnectionOptions ()方法来设置IWSManConnectionOptions,该方法指定会话的用户名和密码(如果设置了)。
-
session是一个 NET/C# 对象,它调用CreatSession ()方法与指定目标 ( sessionUrl )建立连接。如果在CreateConnectionOptions ()中设置了用户名和密码,则SessionFlagCredUsernamePassword ()方法将为指定目标设置身份验证标志。
注意:可以设置其他标志来指定身份验证方法,例如Negotiate或Kerberos。
-
调用Invoke()方法来调用 WMI 类操作。在本例中,调用 WMI Create方法(操作)来指定创建远程进程(来自Win32_Process)。resource 是检索到的 WMI 类标识符,parameters包含XML输入,其中包括要执行的进程/命令。
运行 WinRM POC
编译项目程序集后,我们可以在目标机器上运行它并检索进程 ID 和返回信息:
命令 1-
SharpWSManWinRM.exe corp-dc notepad
命令 2(带凭证)–
SharpWSManWinRM.exe corp-dc notepad corpcorpmin CorpM@ster
在远程主机上,进程执行链如下所示:
svchost.exe (DcomLaunch) -> wmiprvse.exe -> [remote command/binary]
“WSMan-WinRM”项目
项目源代码可在WSMan-WinRM GitHub存储库中访问,其中包括 CSharp 版本以及其他几个利用 WMI Win32_Process类执行方法的 POC 实现。项目中包含以下内容:
-
SharpWSManWinRM.cs (CSharp)
-
CppWSManWinRM.cpp (C++)
-
WSManWinRM.vbs(Visual Basic 脚本)
-
WSManWinRM.js (JScript)
-
WSManWinRM.ps1(PowerShell – 类似于 Invoke-WSManAction cmdlet)
谍报技术
调用 Win32_Process 类并不是利用 WMI 类进行远程命令执行的唯一方法。Philip Tsukerman(@PhilipTsukerman )在“无需 Win32_Process – 扩展 WMI 横向移动武器库”博客文章以及本次演讲中发布了大量有关 WMI 横向移动技巧的重要信息。
防御考虑
当然,也存在一些可以检测和限制 WinRM 远程命令执行/横向移动的机会。请考虑以下几点:
-
监控源自wmiprvse.exe和winrshost.exe 的远程进程执行链
-
监控Microsoft-Windows-WinRM/Operational事件日志中是否存在可疑条目。注意:在测试 WMI 类交互(WinRM.vbs / SharpWSManWinRM /etc)期间,似乎没有在此处记录成功的连接会话。但是,不成功的错误已与 WMI 资源的名称一起记录。
-
考虑将受信任的主机列入白名单,以仅允许某些计算机连接到 WinRM 服务器。更多信息可在此 Red Canary博客文章中找到。注意:WinRM受信任的主机控制客户端可以连接到哪些主机。因此,此设置有利于以集中方式控制这一点,但更好的方法是利用跳转主机和(主机)防火墙规则来控制哪些计算机应该被允许连接到 WinRM 主机。
-
管理员并不是唯一可以利用 WinRM 进行远程管理的用户。远程管理用户本地/域组的成员可以通过 WinRM 连接到 WMI 资源。确保仅允许授权人员成为组成员。
结论
感谢您花时间阅读这篇博文。我相信这个领域还有更多有趣的研究机会(也许是 CSharp“PSSession”功能?)。我期待看到其他人将其提升到一个新的水平。最后,我想向 Leo Loobeek(@leoloobeek)致敬——感谢您在我们关于 COM 和编码的讨论中提供的精彩见解。这无疑有助于塑造这篇文章!
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):WS-Management COM:WinRM 横向移动的另一种方法