面向网络安全的-Powershell-自动化和脚本编程-二-

111 阅读1小时+

面向网络安全的 Powershell 自动化和脚本编程(二)

原文:annas-archive.org/md5/497778742979feec5fa142fe450d7d89

译者:飞龙

协议:CC BY-NC-SA 4.0

第三章:探索 PowerShell 远程管理技术和 PowerShell 远程

作为 PowerShell 的主要用途之一是自动化管理任务,PowerShell 远程PSRemoting)在同时管理多台计算机时扮演着重要角色:只需一条命令,你就可以在数百台计算机上执行相同的命令行。

但与使用单独的计算机时类似,PSRemoting 的安全性取决于你的配置:如果你不锁好房门,窃贼是可以闯入的。

同样的情况也适用于计算机,以及 PSRemoting:如果你没有加固配置并使用不安全的设置,攻击者可以利用这些漏洞,将你的计算机反过来用作攻击工具。

在本章中,你不仅会学习 PSRemoting 的基础知识以及如何启用和配置它——你还会发现如何保持安全的 PSRemoting 配置的最佳实践。尽管 PSRemoting 本身是安全的,但你仍然可以采取一些措施,确保配置保持安全。我们将详细探讨这些措施,帮助你保持 PSRemoting 设置的安全。

我们还将看到 PSRemoting 网络流量的表现,取决于所使用的身份验证协议。最后,你将学习如何配置它,避免哪些配置,以及如何使用 PSRemoting 执行命令。

在本章中,你将学习以下主题:

  • 使用 PowerShell 远程工作

  • 启用 PowerShell 远程

  • PowerShell 端点(会话配置)

  • PowerShell 远程身份验证和安全性考虑

  • 使用 PowerShell 远程执行命令

  • 使用 PowerShell 远程工作

  • PowerShell 远程最佳实践

技术要求

本章的技术要求如下:

使用 PowerShell 远程工作

PowerShell 旨在自动化管理任务,并简化系统管理员的工作。远程管理从一开始就是这一计划的一部分,正如 Jeffrey Snover 在 2002 年的《Monad 宣言》中所概述的:www.jsnover.com/blog/2011/10/01/monad-manifesto/。然而,为了尽快发布版本 1.0,某些功能(包括 PSRemoting)未包含在内,直到后来的版本才加入。PSRemoting 在 2.0 版本中正式推出,并在 3.0 版本中得到了进一步改进。

它迅速成为最重要的核心功能之一,现在支持 PowerShell 中的许多其他功能,如工作流。

虽然 PSRemoting 可以与多种身份验证方法一起使用,但域身份验证的默认协议是 Kerberos。这是 Active Directory 环境中最安全且最常用的身份验证方法,而大多数使用 PSRemoting 的人很可能都在这种环境下操作。因此,当 Kerberos 不可用时,PSRemoting 会回退到 NTLM,以支持工作组身份验证。

Windows PowerShell 支持通过不同技术进行远程管理。默认情况下,PSRemoting 使用 Windows 远程管理(WinRM) 作为传输协议。然而,值得注意的是,WinRM 只是多种可用于支持 PowerShell 远程管理的协议之一。PSRemoting 本身是一个特定的协议(PSRP),它规定了 PowerShell 如何管理输入、输出、数据流、对象序列化等内容。PSRP 可以通过多种传输方式进行支持,包括 WS-Management(WS-Man)安全外壳(SSH)Hyper-V 虚拟机总线(VMBus) 等。虽然 Windows 管理工具(WMI)远程过程调用(RPC) 是可以与 PowerShell 一起使用的远程管理技术,但它们不被视为 PSRemoting 协议的一部分。

这些远程管理技术之间的区别也体现在所使用的协议上:

表 3.1 – 连接方法和使用的协议概述

表 3.1 – 连接方法和使用的协议概述

PSRemoting 仅在 Windows Server 2012 R2 及更高版本中启用,且默认情况下仅允许来自管理员组成员的连接。然而,PowerShell Core 支持多种远程管理协议,包括 WMI、Web 服务管理(WS-Management)和 SSH 远程管理。需要注意的是,PowerShell Core 不支持 RPC 连接。

使用 WinRM 进行 PowerShell 远程管理

DMTF(前身为 分布式管理工作组)是一个非盈利组织,定义了开放的可管理性标准,如通用信息模型(CIM),以及 WS-Management。

WS-Management 定义了一种基于 简单对象访问协议(SOAP) 的协议,可以用于管理服务器和 Web 服务。

微软的 WS-Management 实现是 WinRM

一旦您尝试建立 PSRemoting 连接,WinRM 客户端将在 HTTPHTTPS 上通过 WS-Management 协议发送 SOAP 消息。

当使用 WinRM 时,PSRemoting 监听以下端口:

  • HTTP**: **5985

  • HTTPS**: **5986

无论使用 HTTP 还是 HTTPS,PSRemoting 流量在身份验证过程后始终会被加密 —— 具体取决于用于身份验证的协议。您可以在 身份验证 部分阅读更多有关不同身份验证协议的信息。

在远程主机上,WinRM 服务运行并配置为有一个或多个监听器(HTTP 或 HTTPS)。每个监听器都会等待通过 WS-Management 协议发送的 HTTP/HTTPS 流量。

一旦接收到流量,WinRM 服务会判断流量是要发送到哪个 PowerShell 端点或应用程序,并转发它:

图 3.1 – 如何通过 PSRemoting 使用 WinRM 和 WS-Management 进行连接

图 3.1 – 如何通过 PSRemoting 使用 WinRM 和 WS-Management 进行连接

通常,这张图已被抽象化,以简化你对 WinRM 工作原理的理解。PowerShell.exe并没有被调用;相反,调用的是Wsmprovhost.exe进程,它运行 PSRemoting 连接。

由于 WinRM 和 WS-Management 是建立远程连接时的默认选项,本章将主要聚焦于这些技术。为了完整性,本节会简要介绍所有其他可能的远程技术。

如果你希望更深入了解 WinRM 和 WS-Management,我推荐访问以下资源:

Windows 管理工具(WMI)和通用信息模型(CIM)

WMI是微软实现的 CIM(由 DMTF 设计的开放标准)。

WMI 是在 Windows NT 4.0 中引入的,并从 Windows 2000 开始被包括在 Windows 操作系统中。它仍然存在于所有现代系统中,包括 Windows 10 和 Windows Server 2019。

CIM 定义了 IT 系统元素如何表示为对象以及它们之间的关系。这为管理 IT 系统提供了一种很好的方式,不论制造商或平台如何。

WMI 依赖于分布式组件对象模型DCOM)和 RPC,后者是 DCOM 背后的基础机制,用于进行通信。

DCOM 是为使组件对象模型COM)能够在网络上进行通信而创建的,它是.NET Remoting 的前身。

本节将简要概述 WMI 和 CIM 的 cmdlet,帮助你理解本章中的远程管理技术。你将会在第五章中学到更多关于 COM、WMI 和 CIM 的内容,PowerShell 强大 – 系统与 API 访问

WMI cmdlet

从 PowerShell Core 6 开始,WMI cmdlet 被弃用,不应在 PowerShell 的新版本中使用。然而,值得注意的是,它们仍然在某些较旧版本的 PowerShell 中得到支持,例如 Windows 10 上的 PowerShell 5.1,并将在这些操作系统的支持生命周期内继续受到支持。如果可能,请改用较新的 CIM cmdlet,因为它们可以在 Windows 和非 Windows 操作系统上使用。

首先,让我们看看如何使用已经弃用,但仍然存在的 WMI cmdlet。

要查找所有名称中包含wmi字符串的 cmdlet 和函数,可以使用Get-Command cmdlet。通过使用-CommandType参数,可以指定要查找的命令类型。在此示例中,我正在搜索 cmdlet 和函数:

> Get-Command -Name *wmi* -CommandType Cmdlet,Function
CommandType  Name               Version    Source
-----------  ----               -------    ------
Cmdlet       Get-WmiObject      3.1.0.0    Microsoft.PowerShell.Management
Cmdlet       Invoke-WmiMethod   3.1.0.0    Microsoft.PowerShell.Management
Cmdlet       Register-WmiEvent  3.1.0.0    Microsoft.PowerShell.Management
Cmdlet       Remove-WmiObject   3.1.0.0    Microsoft.PowerShell.Management
Cmdlet       Set-WmiInstance    3.1.0.0    Microsoft.PowerShell.Management

一个使用 WMI 的示例是通过Get-WmiObject cmdlet。使用这个 cmdlet,你可以查询本地和远程计算机。

你可以使用-List参数来检索计算机上所有可用的 WMI 类:

> Get-WmiObject -List
   NameSpace: ROOT\cimv2
Name                  Methods Properties
----                  ------- ----------
CIM_Indication        {}      {CorrelatedIndications, IndicationFilterName, IndicationIde...
CIM_ClassIndication   {}      {ClassDefinition, CorrelatedIndications, IndicationFilterNa...
CIM_ClassDeletion     {}      {ClassDefinition, CorrelatedIndications, IndicationFilterNa...
...

这是一个使用Get-WmiObject来检索本地计算机上 Windows 服务信息的示例:

> Get-WmiObject -Class Win32_Service
ExitCode  : 0
Name      : AdobeARMservice
ProcessId : 3556
StartMode : Auto
State     : Running
Status    : OK
…

你不仅可以查询本地计算机,还可以通过使用-ComputerName参数来查询远程计算机,后跟远程计算机的名称。以下示例展示了如何从PSSec-PC02远程计算机获取相同的信息:

> Get-WmiObject -Class Win32_Service -ComputerName PSSec-PC02

上述代码返回了远程计算机上所有可用服务的列表。

通过使用-Query参数,你甚至可以指定要针对指定计算机的 CIM 数据库执行的查询。以下命令仅检索所有名称为WinRM的服务:

> Get-WmiObject -ComputerName PSSec-PC02 -Query "select * from win32_service where name='WinRM'"
ExitCode  : 0
Name      : WinRM
ProcessId : 6408
StartMode : Auto
State     : Running
Status    : OK

在此示例中,我们在PSSec-PC02远程计算机上运行了指定的select * from win32_service where name='WinRM'查询。

使用 PowerShell WMI cmdlet,你还可以调用 WMI 方法,删除对象,以及更多操作。

你知道吗?

RPC,WMI 所依赖的技术,在 PowerShell Core 6 中不再受到支持。这部分原因是 PowerShell 追求跨平台兼容性:从 PowerShell 7 版本及以上,RPC 仅在运行 Windows 操作系统的机器上受到支持。

CIM cmdlet

使用 PowerShell 3.0(随 Windows Server 2012 和 Windows 8 一起发布),引入了一套新的 cmdlet,用于管理符合 CIM 和 WS-Man 标准的对象。

一度,WMI cmdlet 偏离了 DMTF 标准,这阻止了跨平台管理。因此,微软通过发布新的 CIM cmdlet,重新遵循 DMTF CIM 标准。

要查找所有与 CIM 相关的 cmdlet,可以使用Get-Command cmdlet:

> Get-Command -Name "*cim*" -CommandType Cmdlet,Function
CommandType     Name                        Version    Source
-----------     ----                        -------    ------
Cmdlet          Get-CimAssociatedInstance   1.0.0.0    CimCmdlets
Cmdlet          Get-CimClass                1.0.0.0    CimCmdlets
Cmdlet          Get-CimInstance             1.0.0.0    CimCmdlets
Cmdlet          Get-CimSession              1.0.0.0    CimCmdlets
Cmdlet          Invoke-CimMethod            1.0.0.0    CimCmdlets
Cmdlet          New-CimInstance             1.0.0.0    CimCmdlets
Cmdlet          New-CimSession              1.0.0.0    CimCmdlets
Cmdlet          New-CimSessionOption        1.0.0.0    CimCmdlets
Cmdlet          Register-CimIndicationEvent 1.0.0.0    CimCmdlets
Cmdlet          Remove-CimInstance          1.0.0.0    CimCmdlets
Cmdlet          Remove-CimSession           1.0.0.0    CimCmdlets
Cmdlet          Set-CimInstance             1.0.0.0    CimCmdlets

在此示例中,我们正在寻找名称中包含cim的所有 cmdlet 和函数。

您可以在docs.microsoft.com/de-de/powershell/module/cimcmdlets/找到与 CIM 服务器交互的所有当前可用 CIM cmdlet 的概述。

开放管理基础设施(OMI)

为了帮助实现跨平台管理方法,微软于 2012 年创建了开放管理基础设施OMI)(github.com/Microsoft/o… SSH 远程管理的支持。

使用 SSH 进行 PowerShell 远程管理

为了在 Windows 和 Linux 主机之间启用 PSRemoting,微软在 PowerShell 6 中添加了对通过 SSH 进行 PSRemoting 的支持。

通过 SSH 进行 PSRemoting 的要求

要使用通过 SSH 的 PSRemoting,需要在所有计算机上安装PowerShell 版本 6 或更高版本SSH。从 Windows 10 版本 1809 和 Windows Server 2019 开始,OpenSSH for Windows 已集成到 Windows 操作系统中。

Linux 上的 PowerShell 远程管理

首先,要在 Linux 上使用 PowerShell,请按照您的操作系统的步骤安装 PowerShell Core,您可以在官方 PowerShell Core 文档中找到:docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux

在我的演示实验室中,我安装了 Debian 10 服务器。因此,步骤可能会有所不同,具体取决于所使用的操作系统。

使用您选择的编辑器配置/etc/ssh/sshd_config。在我的示例中,我使用vi

> vi /etc/ssh/sshd_config

首先,在配置中添加一个 PowerShell 子系统条目:

Subsystem powershell /usr/bin/pwsh -sshs -NoLogo

在 Linux 系统中,默认情况下,PowerShell 可执行文件通常位于/usr/bin/pwsh。请确保如果您在不同位置安装了 PowerShell,则调整此部分。

为了允许用户远程使用 SSH 登录,请配置PasswordAuthentication和/或PubkeyAuthentication

  • 如果您想允许使用用户名和密码进行身份验证,请将PasswordAuthentication设置为yes

    PasswordAuthentication yes
    
  • 如果您想启用更安全的方法,请将PubkeyAuthentication设置为yes

    PubkeyAuthentication yes
    

PubkeyAuthentication,代表公钥身份验证,是一种依赖于生成的密钥对的身份验证方法:生成一个私钥和一个公钥。而私钥被安全地保存在用户的计算机上,公钥则输入到远程服务器上。

当用户使用此私钥进行身份验证时,服务器可以使用其公钥验证用户的身份。公钥只能用于验证私钥的真实性或加密只有私钥可以加密的数据。

使用公钥认证进行远程访问不仅能防止暴力破解和字典攻击等密码攻击的风险,还能在服务器遭到攻破时提供额外的安全层。在这种情况下,只有公钥可以被提取,而私钥则保持安全。由于仅有公钥不足以进行认证,因此该方法提供的安全性优于使用用户名和密码,因为如果服务器被攻破,密码会被提取并重复使用。

你可以在 www.ssh.com/ssh/keygen/ 学习如何使用 ssh-keygen 工具生成密钥对。

如果你对公钥认证的工作原理感兴趣,可以在官方的 SSH 网站上了解更多:www.ssh.com/ssh/public-key-authentication

当然,两个认证机制可以同时配置,但如果你使用 PubkeyAuthentication 并且没有其他用户使用用户名和密码连接,你应该仅使用 PubkeyAuthentication

PasswordAuthentication no
PubkeyAuthentication yes

如果你想了解更多关于 sshd 配置文件的不同选项,我强烈建议你查看 man** **pagesmanpages.debian.org/jessie/openssh-server/sshd_config.5.en.html

Man 页面

Man 代表 manual。Man 页面用于获取有关 Linux/UNIX 命令或配置文件的更多信息,可以将其与 PowerShell 中的帮助系统进行比较。

重启 ssh 服务:

> /etc/init.d/ssh restart

更新后的配置会加载到内存中以激活更改。

PowerShell 远程管理 macOS

要通过 SSH 启用 PSRemoting 以管理 macOS 系统,步骤与在 Linux 系统上启用 PSRemoting 相似:最大的不同之处在于配置文件位于不同的位置。

首先,你需要在想要远程管理的 macOS 系统上安装 PowerShell Core:docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-macos

编辑 ssh 配置:

> vi /private/etc/ssh/sshd_config

为 PowerShell 创建子系统条目:

Subsystem powershell /usr/local/bin/pwsh -sshs -NoLogo

然后,定义你希望为此机器配置的认证类型:

  • 用户名和密码:

    PasswordAuthentication yes
    
  • 公钥认证:

    PubkeyAuthentication yes
    

若要了解更多关于可以在 sshd 配置中配置的选项,请查看我们之前讨论的 PowerShell 远程管理 Linux 部分。

重启 ssh 服务以加载新配置:

> sudo launchctl stop com.openssh.sshd
> sudo launchctl start com.openssh.sshd

服务将重启,新的配置将生效。

通过 SSH 在 Windows 上进行 PowerShell 远程管理

当然,也可以通过 SSH 管理 Windows 系统,但在本书中,我将使用通过 WinRM 的 PSRemoting 作为所有示例的方式,因为这是 Windows 系统上的默认设置。

然而,如果你想通过 SSH 在 Windows 系统上启用 PSRemoting,请确保安装了 OpenSSH,并按照如何在 Windows 上通过 SSH 设置 PSRemoting 的说明操作:

你知道吗?

通过 SSH 使用 PSRemoting 不支持远程端点配置,也不支持 Just Enough** **Administration** (JEA**)。

启用 PowerShell 远程管理

有多种方法可以为你的系统启用 PSRemoting。如果你只在实验室里操作几台机器,你可能想手动启用它。但一旦你希望在一个大型环境中启用 PSRemoting,你可能希望集中启用并配置 PSRemoting。在本节中,我们将探讨这两种方法。以下表格提供了每种方法执行的配置操作概览:

表 3.2 – 启用 PSRemoting – 不同方法

表 3.2 – 启用 PSRemoting – 不同方法

请注意,Enable-PSRemoting 方法是手动配置的一个子部分;要配置 HTTP 和 HTTPS 监听器,必须采取额外的步骤。我们来探讨一下手动配置 PSRemoting 所需的内容,这在测试场景中可能会很有用。

手动启用 PowerShell 远程管理

如果你想在单台机器上启用 PSRemoting,可以通过在提升权限的命令行界面上使用 Enable-PSRemoting 命令手动完成:

> Enable-PSRemoting
WinRM has been updated to receive requests.
WinRM service type changed successfully.
WinRM service started.
WinRM has been updated for remote management.
WinRM firewall exception enabled.
Configured LocalAccountTokenFilterPolicy to grant administrative rights remotely to local users.

在这个例子中,命令成功执行,因此 PSRemoting 在这台机器上被启用。

如果你想知道 Enable-PSRemotingwinrm quickconfig 之间的区别,事实上,技术上并没有太大区别。Enable-PSRemoting 已经包含了 winrm quickconfig 执行的所有操作,但还增加了特定于 Windows PowerShell 的环境更改。因此,简而言之,运行 Enable-PSRemoting 就足够了,你可以跳过运行 winrm quickconfig

Set-WSManQuickConfig 错误信息

根据你的网络配置,如果你尝试手动启用 PSRemoting,可能会显示错误信息:

WinRM firewall exception will not work since one of the network connection types on this machine is set to Public. Change the network connection type to either Domain or Private and try again.

该错误信息是由 Set-WSManQuickConfig 命令生成的,该命令在启用 PSRemoting 过程中被调用。

如果某个网络连接设置为公用网络,将显示此消息,因为默认情况下,PSRemoting 不允许在定义为公用网络的网络上使用:

> Get-NetConnectionProfile
Name             : Network 1
InterfaceAlias   : Ethernet
InterfaceIndex   : 4
NetworkCategory  : Public
IPv4Connectivity : Internet
IPv6Connectivity : NoTraffic

为了避免此错误,有两个选项:

  • 将网络配置文件设置为私有网络。

  • 强制执行 Enable-PSRemoting,以便跳过网络配置文件检查。

如果您确定网络配置文件不是公共网络,而是您信任的网络,可以将其配置为私有网络:

> Set-NetConnectionProfile -NetworkCategory Private

如果您不想将网络配置为受信任的私有网络,可以通过添加-****SkipNetworkProfileCheck参数来强制跳过网络配置文件检查:

> Enable-PSRemoting -SkipNetworkProfileCheck

在连接到公共网络连接的计算机上启用 PSRemoting 会使您的计算机面临重大风险,所以要小心。

检查您的 WinRM 配置

启用 PSRemoting 和 WinRM 后,您可能希望检查当前的 WinRM 配置。您可以使用winrm** **get winrm/config来实现这一点:

图 3.2 - 验证本地 WinRM 配置

图 3.2 - 验证本地 WinRM 配置

您可以在显示的输出中找到所有配置的选项。winrm get winrm/config命令提供了 WinRM 配置设置的摘要。

要更改本地 WinRM 配置,可以使用set选项:

> winrm set winrm/config/service '@{AllowUnencrypted="false"}'

或者,您可以使用wsman:\ PowerShell 驱动器访问和修改配置中的特定项。使用wsman:\提供程序允许您以更直观和类似 cmdlet 的方式访问和修改 WinRM 配置的特定项,并带有内置的帮助和文档。

要更改本地 WinRM 配置,您可以使用Set-Item cmdlet 与wsman:\提供程序访问和修改 WinRM 配置项。例如,要禁用未加密流量的使用,可以运行以下命令:

> Set-Item wsman:\localhost\Service\AllowUnencrypted -Value $false

在此示例中,我们正在配置 WinRM 服务允许未加密的连接。您可以使用类似的语法来配置其他 WinRM 选项 - 只需确保提供设置树中的整个路径,以及选项和值。

受信任的主机

如果您连接到未加入域的计算机,这可能是您手动配置的原因,那么 Kerberos 身份验证不是一个选项,应该使用 NTLM 协议进行身份验证。

在这种情况下,您需要在本地设备上的WS-Man中将远程机器配置为受信任的主机;否则,连接将失败。

要为远程主机配置TrustedHosts,可以使用Set-Item cmdlet,以及wsman:\localhost\client\TrustedHosts路径。默认情况下,此值为空,因此您需要添加远程主机的 IP 地址或域名。要添加新值而不替换现有值,请使用-Concatenate开关,如下所示:

> Set-Item wsman:\localhost\client\TrustedHosts -Value 172.29.0.12 -Concatenate -Force

这将将指定的 IP 地址附加到现有的TrustedHosts列表中。

要验证您的更改是否已应用,可以使用Get-Item cmdlet 显示当前的TrustedHosts配置:

> Get-Item wsman:\localhost\client\TrustedHosts
   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client
Type            Name             SourceOfValue   Value
----            ----             -------------   -----
System.String   TrustedHosts                     172.29.0.12

前面的示例表明,具有 IP 地址172.29.0.12的主机已在本地机器上配置为受信任的主机。

审核TrustedHosts列表以检测任何未经授权的更改也是一种好做法。这有助于检测系统上的篡改尝试。

通过 HTTPS 连接

可选地,你还可以配置一个证书来加密HTTPS上的流量。为了确保 PSRemoting 的安全,建议配置一个证书来加密 HTTPS 流量,特别是在 Kerberos 不可用于服务器身份验证的情况下。尽管 PSRemoting 流量默认是加密的,但加密可以被移除,且可以轻松强制执行基本认证(参见PowerShell 远程认证与安全性注意事项部分)。配置证书为你的环境添加了额外的安全层。

因此,为了提供额外的安全性,发布证书并通过 SSL 启用WinRM是有意义的。

如果你没有从有效的证书颁发机构CA)购买公开签名的 SSL 证书,你可以创建一个自签名证书来开始使用。然而,如果你是在工作组远程访问中使用它,你也可以使用内部 CA。这样可以提供额外的安全性和信任,因为你有一个组织内部的受信任源来签署证书。

本节仅涵盖如何发布和配置自签名证书。因此,如果你使用的是公开签名证书或内部 CA,请确保调整步骤。

首先,让我们获取一个自签名证书!如果你使用的是 Windows Server 2012 及以上版本,这一步非常简单 —— 你可以利用New-SelfSignedCertificate cmdlet:

> $Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "PSSec-PC01"

> Export-Certificate -Cert $Cert -FilePath C:\tmp\cert

确保通过-DnsName参数提供的值与主机名匹配,并且在你的 DNS 服务器中存在匹配的 DNS 记录。

添加 HTTPS 监听器:

> New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint –Force

最后,确保为防火墙添加例外。WinRM 通过 HTTPS 的默认端口是5986

> New-NetFirewallRule -DisplayName "Windows Remote Management (HTTPS-In)" -Name "Windows Remote Management (HTTPS-In)" -Profile Any -LocalPort 5986 -Protocol TCP

为了澄清,重要的是要注意,使用-Profile Any选项会将 WinRM 开放到公共或未识别的网络。如果你不在测试环境中,请确保使用适当的配置文件选项,如DomainPrivatePublic

如果你希望确保仅使用 HTTPS,则删除 WinRM 的 HTTP 监听器:

> Get-ChildItem WSMan:\Localhost\listener | Where -Property Keys -eq "Transport=HTTP" | Remove-Item -Recurse

此外,你可能需要检查并删除任何已配置的 HTTP 流量的防火墙例外。如果你之前没有配置任何例外,则此步骤不必要。

在某些情况下,你可能希望将 WinRM 监听器移动到不同的端口。如果你的防火墙设置不允许端口5986,或者你想出于安全原因使用非标准端口,这将是有用的。要将 WinRM 监听器移动到不同的端口,请使用Set-Item cmdlet:

> Set-Item WSMan:\Localhost\listener\<ListenerName>\port -Value <PortNumber>

<ListenerName>替换为你想要编辑的监听器名称,并将<PortNumber>替换为你想要配置的端口号。

接下来,我们将导入证书。然而,在此之前,了解一些关键点非常重要:通过 New-SelfSignedCertificate 等工具生成的证书已经内置了使用限制,确保它们仅用于客户端和服务器认证。如果您使用的是通过其他工具生成的证书(例如,内部 PKI),请确保它也有这些使用限制。此外,确保根证书得到了妥善保护,因为攻击者可以利用它伪造受信任网站的 SSL 证书。

一旦您拥有适当的证书,将其复制到您希望从中连接远程计算机的计算机上的安全位置(例如,在我们的示例中是 C:\tmp\cert),然后将其导入本地证书存储区:

> Import-Certificate -Filepath "C:\tmp\cert" -CertStoreLocation "Cert:\LocalMachine\Root"

指定您想用来登录并进入会话的凭据。-UseSSL 参数表示您的连接将使用 SSL 进行加密:

> $cred = Get-Credential

> Enter-PSSession -ComputerName PSSec-PC01 -UseSSL -Credential $cred

当然,您仍然需要输入凭据才能远程登录计算机。证书仅确保远程计算机的真实性,并帮助建立加密连接。

通过组策略配置 PowerShell 远程管理

在处理多台服务器时,您可能不希望在每台计算机上手动启用 PSRemoting,因此组策略是您的首选工具。

通过组策略,您可以使用一个 组策略对象(GPO) 配置多台计算机。

要开始,创建一个新的 GPO:打开 组策略管理,右键点击您希望创建新 GPO 的 组织单位(OU),然后选择 在此域中创建 GPO,并在此处链接

GPO 仅仅是一个配置工具——它不会启动服务。因此,您仍然需要找到一种方法来重新启动所有已配置的服务器或在所有服务器上启动 WinRM 服务。

如果您希望启用远程 PSRemoting,Lee Holmes 编写了一个非常实用的脚本,该脚本利用 WMI 连接(大多数系统都支持):www.powershellcookbook.com/recipe/SQOK/program-remotely-enable-powershell-remoting

允许 WinRM

在新创建的 GPO 中,导航到 计算机配置 | 策略 | 管理模板 | Windows 组件 | Windows 远程管理 | WinRM 服务,并将 允许通过 WinRM 进行远程服务器管理 策略设置为 启用

在此策略中,您可以定义 IPv4 和 IPv6 过滤器。如果您不使用某种协议(例如,IPv6),则可以将其留空,以防止用户通过该协议连接到 WinRM。

要允许连接,您可以使用通配符字符 *、IP 地址或 IP 范围。

在与客户合作或在我的演示实验室中,我发现发生 WinRM 无法工作的错误时,最常见的原因是配置此设置时使用了 IP 或 IP 范围。

因此,时至今日,我只在与防火墙 IP 限制结合使用时,才使用通配符(*****)来保护我的设置。我们将在本节稍后配置防火墙 IP 限制(见创建防火墙规则):

图 3.3 – 配置允许通过 WinRM 进行远程服务器管理

图 3.3 – 配置允许通过 WinRM 进行远程服务器管理

注意!

仅在您希望通过防火墙规则限制允许远程 IP 连接时,才使用通配符(*****)配置。

配置 WinRM 服务为自动启动

要配置 WinRM 服务使其自动启动,请按以下步骤操作:

  1. 使用相同的 GPO,并导航到计算机配置 | 策略 | Windows 设置 | 安全设置 | 系统服务

  2. 选择并配置**Windows 远程管理(WS 管理)**设置。

  3. 将打开一个新窗口。勾选定义此策略设置选项,并将服务启动模式设置为自动

  4. 通过点击确定按钮确认您的配置:

图 3.4 – 配置 Windows 远程管理服务,使其自动启动

图 3.4 – 配置 Windows 远程管理服务,使其自动启动

注意

此设置仅配置服务为自动启动,通常在计算机启动时发生。它不会为您启动服务,因此请确保重新启动计算机(或手动启动服务),以便 WinRM 服务自动启动。

创建防火墙规则

要配置防火墙设置,请按照以下步骤操作:

  1. 导航到计算机配置 | 策略 | Windows 设置 | 安全设置 | Windows Defender 防火墙(高级安全性) | Windows Defender 防火墙(高级安全性) | 入站规则

  2. 使用向导创建一个新的入站规则。

  3. 勾选预定义选项,并选择Windows 远程管理

图 3.5 – 创建预定义的 Windows 远程管理防火墙规则

图 3.5 – 创建预定义的 Windows 远程管理防火墙规则

  1. 点击下一步,并通过取消选择下图中显示的选项来移除公共防火墙配置文件:

图 3.6 – 取消选择公共网络配置文件

图 3.6 – 取消选择公共网络配置文件

  1. 最后,选择允许连接,然后点击完成按钮确认配置:

图 3.7 – 允许连接

图 3.7 – 允许连接

新规则将被创建,并显示在您的 GPO 中:

Figure 3.8 – 显示新的入站防火墙规则

图 3.8 – 显示新的入站防火墙规则

  1. 在退出 GPO 配置之前,确保通过双击重新打开新创建的防火墙规则。将打开Windows 远程管理(HTTP-In)属性窗口。

  2. 可选:如果您的计算机位于同一个域中,请导航到Advanced选项卡,并取消选择Private配置文件,以确保仅允许使用 WinRM 进行远程连接在Domain网络配置文件中:

Figure 3.9 – 仅允许在域网络配置文件中使用 WinRM

图 3.9 – 仅允许在域网络配置文件中使用 WinRM

  1. 然后,导航到Scope选项卡,并添加允许从中远程访问计算机的所有远程 IP 地址。例如,如果您的网络上有一个管理子网,可以将该子网中的 IP 地址添加到列表中:

Figure 3.10 – 配置允许连接的远程 IP 地址

图 3.10 – 配置允许连接的远程 IP 地址

在最佳情况下,只允许一个经过加固和安全管理的系统通过 PSRemoting 管理系统。

使用清洁的源原则构建管理系统,并使用推荐的特权访问模型进行访问:

PowerShell 端点(会话配置)

在本章中,您可能已经多次读到端点一词。

如果我们谈论端点,我们不是在谈论一个计算机:PSRemoting 设计用于在计算机上使用多个端点。

但是端点到底是什么?

当我们谈论 PowerShell 端点时,每个端点都是一个会话配置,您可以配置为提供某些服务或限制某些服务。

因此,每次运行Invoke-Command或进入 PowerShell 会话时,我们都是在连接到一个端点(也称为远程会话配置)。

如果没有设置限制,则提供更少的 cmdlet、函数和功能的会话称为受限制的端点

在启用 PSRemoting 之前,计算机上将没有配置任何端点。

您可以通过运行Get-PSSessionConfiguration命令查看所有可用的会话配置。

Figure 3.11 – 当未启用 PSRemoting 时不显示端点

图 3.11 – 当未启用 PSRemoting 时,未显示任何端点

当计算机上未启用 PSRemoting 时,不会显示任何端点。这是因为负责 PSRemoting 的 WinRM 服务默认未启动。然而,一旦启动 WinRM 服务,端点已经配置好并准备使用,但在启用 PSRemoting 之前不会暴露,也无法连接。

使用 Enable-PSRemoting 启用 PSRemoting,正如我们在上一节中所做的那样,会创建所有默认的会话配置,这些配置对于通过 PSRemoting 连接到此端点是必要的:

图 3.12 – 启用 PSRemoting 后,我们可以看到所有预填充的端点

图 3.12 – 启用 PSRemoting 后,我们可以看到所有预填充的端点

通常,在 Windows PowerShell 3.0 及以上版本中,客户端系统上会有三个默认预配置的端点:

)

服务器系统中,通常会有一个预定义的第四会话配置:

每台计算机会显示不同的默认端点。在上面的示例中,我在一台 Windows 10 客户端上运行命令,这将显示比 Windows Server 2019 更少的端点。

连接到指定的端点

默认情况下,microsoft.powershell 端点用于所有 PSRemoting 连接。但如果您希望连接到另一个指定的端点,您可以使用 -ConfigurationName 参数来实现:

> Enter-PSSession -ComputerName PSSec-PC01 -ConfigurationName 'microsoft.powershell32'

指定的配置可以是另一个默认端点的名称,也可以是自定义端点。

创建自定义端点——JEA 概览

创建自定义端点(也称为仅足够的管理JEA)允许您为委派的管理定义一个受限的管理环境。通过 JEA,您可以定义一组批准的命令和参数,允许特定用户在特定计算机上执行。这使您能够为用户提供执行工作职责所需的最低权限,而不授予他们完全的管理权限。这是保护远程连接的好方法:

  • 您可以限制会话,只运行预定义的命令。

  • 您可以启用记录功能,以便记录在此会话中执行的每个命令。

  • 你可以指定一个安全描述符(SDDL)来确定谁可以连接,谁不能连接。

  • 你可以配置脚本和模块,这些脚本和模块将在与此端点建立连接后自动加载。

  • 你甚至可以指定使用另一个账户来在端点上运行此会话中的命令。

要创建和激活端点,需要遵循两个步骤:

  1. 创建会话配置文件

  2. 将会话注册为新的端点

创建会话配置文件

使用New-PSSessionConfigurationFile,你可以创建一个空的骨架会话配置文件。你需要指定配置文件将保存的路径,因此-Path参数是必需的。会话配置文件以.pssc文件扩展名结尾,所以请确保文件命名正确:

> New-PSSessionConfigurationFile -Path <Path:\To\Your\SessionConfigurationFile.pssc>

请查看官方文档以获取更多信息:docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/new-pssessionconfigurationfile

你可以生成一个空的会话配置文件,然后稍后使用编辑器填写它,或者你也可以使用New-PSSessionConfigurationFile参数直接生成包含所有已定义配置选项的文件:

图 3.13 – New-PSSessionConfigurationFile 参数

图 3.13 – New-PSSessionConfigurationFile 参数

对于这个示例,我们将为RestrictedRemoteServer会话创建一个会话配置文件:

> New-PSSessionConfigurationFile -SessionType RestrictedRemoteServer -Path .\PSSessionConfig.pssc

通过使用-SessionType RestrictedRemoteServer,只有最重要的命令会被导入到此会话中,如Exit-PSSessionGet-CommandGet-FormatDataGet-HelpMeasure-ObjectOut-DefaultSelect-Object。如果你希望在此会话中允许其他命令,它们需要在角色能力文件中进行配置,我们将在第十章中详细讨论,语言模式和足够的 管理(JEA)

将会话注册为新的端点

创建会话配置文件后,你必须通过使用Register-PSSessionConfiguration命令将其注册为端点。

使用必需的-Name参数时,请确保只指定会话配置文件的名称,不包括文件扩展名:

> Register-PSSessionConfiguration -Name PSSessionConfig
WARNING: Register-PSSessionConfiguration may need to restart the WinRM service if a configuration using this name has recently been unregistered, certain system data structures may still be cached. In that case, a restart of WinRM may be required.
All WinRM sessions connected to Windows PowerShell session configurations, such as Microsoft.PowerShell and session configurations that are created with the Register-PSSessionConfiguration cmdlet, are disconnected.
   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin
Type            Keys                                Name
----            ----                                ----
Container       {Name=PSSessionConfig}              PSSessionConfig

会话配置将被注册,并且一个新的端点将被创建。有时,在注册端点后,可能需要重启 WinRM 服务:

> Get-PSSessionConfiguration -Name PSSessionConfig
Name          : PSSessionConfig
PSVersion     : 5.1
StartupScript :
RunAsUser     :
Permission    : NT AUTHORITY\INTERACTIVE AccessAllowed, BUILTIN\Administrators AccessAllowed, BUILTIN\Remote Management Users AccessAllowed

使用Get-PSSessionConfiguration,你可以验证端点是否已创建。如果你使用-Name参数指定端点名称,如前面的示例所示,你将只获得与指定端点相关的信息。

我们将在第十章《语言模式与恰到好处的管理(JEA)》中深入探讨可能的会话配置和注册参数。

PowerShell 远程认证和安全性注意事项

默认情况下,PSRemoting 流量是加密的——无论连接是通过 HTTP 还是 HTTPS 发起。所使用的底层协议是 WS-Man,它是解耦的,可以更广泛地使用。PSRemoting 使用认证协议,如 Kerberos 或 NTLM,来验证会话流量,SSL/TLS 用于加密会话流量,无论连接是通过 HTTP 还是 HTTPS 发起的。

但与其他计算机类似,PSRemoting 的安全性取决于已配置的计算机。如果你不保护管理员的凭证,攻击者可以提取并利用它们对付你。

因此,你也应该努力加强基础设施的安全性,并保护你最重要的身份。你将在第六章《Active Directory – 攻击与缓解》中了解更多关于 Active Directory 安全性和凭证管理的内容,并在第三部分《保护 PowerShell – 有效的缓解措施详细讲解中了解更多你可以采取的缓解措施。

了解启用 PSRemoting 并不会自动确保环境的安全非常重要。与任何远程管理技术一样,关键在于加固你的系统并采取适当的安全措施,以防范潜在的威胁。这不仅适用于 PSRemoting,还适用于其他远程管理技术,如 RDP。通过投入时间和精力来保护你的系统和环境,你可以降低潜在风险,更好地保护组织的资产。

首先,让我们看看在 PSRemoting 中如何使用认证。

认证

默认情况下,WinRM 使用Kerberos进行认证,若 Kerberos 认证不可用,则回退使用NTLM

在域中使用时,Kerberos 是认证的标准。要在 PSRemoting 中使用 Kerberos 认证,确保客户端和服务器计算机连接到同一域,并且 DNS 名称已正确配置且可达。还需要注意的是,从 Kerberos 的角度来看,服务器必须在 Active Directory 中注册。

通常,你可以指定连接远程计算机时应该使用哪种协议:

> Enter-PSSession -ComputerName PSSEC-PC01 -Authentication Kerberos

当建立 PSRemoting 会话时,如果没有指定-Authentication参数,则使用默认值Default,该值等于Negotiate。这意味着客户端和服务器根据双方系统支持的认证协议协商使用最佳的认证协议。

通常情况下,Kerberos 是首选协议,但如果不可用或不被支持,系统将回退使用 NTLM。关于 Negotiate 的更多信息可以在微软文档中找到,详见 Win32 应用程序中的 Negotiate:learn.microsoft.com/en-us/windows/win32/secauthn/microsoft-negotiate

什么情况下会回退到 NTLM?

PSRemoting 设计时是为了与 Active Directory 配合使用,因此 Kerberos 是首选的身份验证协议。但在某些情况下,Kerberos 身份验证不可用,此时将使用 NTLM。

Kerberos

  • 计算机已加入相同的域,或者它们都位于相互信任的域内。

  • 客户端能够解析服务器的主机名或 IP 地址。

  • 服务器在 Active Directory 中注册了有效的 服务主体名称SPN)。该 SPN 与你连接的目标匹配。

NTLM

  • 常用于连接非域加入的工作站

  • 如果使用的是 IP 地址而不是 DNS 名称

要通过 Kerberos 连接到 PSSec-PC01 计算机,我们可以使用以下命令:

> Enter-PSSession -ComputerName PSSec-PC01

如果没有明确指定凭据,并且当前用户有权限访问远程计算机,同时远程计算机已配置为接受 Kerberos 身份验证,则连接会自动建立,无需提供任何明确的凭据。这是使用 Kerberos 身份验证的一个优势,因为身份验证过程对于用户来说是隐式和无缝的。

如果当前用户没有权限访问远程计算机,我们还可以明确指定应使用的凭据,方法是使用 -Credential 参数。为了简化测试,我们使用 Get-Credential 来提示输入凭据,并将其存储在 $cred 安全字符串中:

$cred = Get-Credential -Credential "PSSEC\Administrator"

然后,我们通过 Kerberos 进行连接:

Enter-PSSession -ComputerName PSSEC-PC01 -Credential $cred

如果你使用 Wireshark 捕获流量,你会看到 WinRM 在其协议中将 Kerberos 包含为 content-type,这表明 Kerberos 被用于身份验证。虽然实际的 Kerberos 流量可能不会在 HTTP 数据包中直接显示,但通过检查 WinRM 流量中的报文头,仍然可以确认使用了 Kerberos 进行身份验证。此外,你还可以看到整个 HTTP 会话是加密的,提供了额外的安全保障:

图 3.14 – 使用 Wireshark 捕获的 WinRM HTTP 流量

图 3.14 – 使用 Wireshark 捕获的 WinRM HTTP 流量

如你所见,已经通过端口 5985(WinRM over HTTP)与 PSSec-PC01 建立了会话,使用的是 PowerShell 版本 5.1.17763.1490。请求是通过 WS-Man 发送的。

一旦初始身份验证过程完成,WinRM 会继续加密所有后续通信,以确保客户端和服务器之间交换的数据的安全性。当通过 HTTPS 建立连接时,TLS 协议将用于协商用于数据传输的加密方式。如果是 HTTP 连接,则用于消息级加密的加密方式由初始身份验证协议决定。

各种身份验证协议提供的加密级别如下:

  • 基本身份验证:没有加密。

  • NTLM 身份验证:使用 RC4 算法和 128 位密钥。

  • Kerberos 身份验证:TGS 票据中的 etype 决定了加密方式。在现代系统中,这通常是 AES-256。

  • CredSSP 身份验证:将在握手过程中协商的 TLS 密码套件被使用。

请注意,尽管使用的是 HTTP 协议作为连接协议,但内容是根据初始身份验证协议使用适当的加密机制进行加密的。关于 PSRemoting 的一个常见误解是,使用 WinRM 通过 HTTP 连接时没有加密。然而,正如你在下图所看到的,事实并非如此:

图 3.15 – 使用 Wireshark 捕获的 Kerberos TCP 流

图 3.15 – 使用 Wireshark 捕获的 Kerberos TCP 流

如果 DNS 名称无法正常工作,并且两个主机不在同一域内,则 NTLM 将作为回退选项使用。

如果你正在连接同一域内的远程计算机,并且 DNS 名称正常工作,当指定主机的 IP 地址而非主机名时,仍然会使用 NTLM 进行连接:

Enter-PSSession -ComputerName 172.29.0.12 -Credential $cred

再次使用 Wireshark 捕获流量显示,NTLM 被用于身份验证,并且流量也被加密了:

图 3.16 – 使用 Wireshark 捕获的 NTLM 流量

图 3.16 – 使用 Wireshark 捕获的 NTLM 流量

类似于使用 Kerberos 连接,你可以看到与主机 172.29.0.12 的连接是通过 HTTP(端口 5985)使用 WinRM 建立的。但这次,使用 NTLM 代替 Kerberos 来协商会话。使用 NTLM,你甚至可以捕获主机名、用户名、域名和挑战,这些信息用于身份验证。

深入查看 TCP 流时,可以明显看到即使使用 NTLM,通信也是加密的,如下图所示:

图 3.17 – 使用 Wireshark 捕获的 NTLM TCP 流

图 3.17 – 使用 Wireshark 捕获的 NTLM TCP 流

使用 NTLM 身份验证时,请注意,PSRemoting 仅在远程主机已添加到 TrustedHosts 列表中时才能正常工作。

使用 NTLM 身份验证时,了解受信主机列表的限制非常重要。虽然将远程主机添加到受信主机列表可以帮助你发现错误,但它并不是确保安全通信的可靠方法。这是因为 NTLM 无法保证你正在连接到预定的远程主机,这使得使用受信主机具有误导性。值得注意的是,NTLM 的主要弱点在于它无法验证远程主机的身份。因此,即使使用了受信主机,NTLM 连接也不应被视为更可信。

如果主机没有被指定为受信主机,并且没有明确提供凭据(就像我们在使用-Credential $cred时做的那样),则建立远程会话或远程运行命令将失败,并显示错误信息:

> Enter-PSSession -ComputerName 172.29.0.10
Enter-PSSession : Connecting to remote server 172.29.0.10 failed with the following error message : The WinRM client
cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not
joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts
configuration setting. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not
be authenticated. You can get more information about that by running the following command: winrm help config. For
more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -ComputerName 172.29.0.10
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (172.29.0.10:String) [Enter-PSSession], PSRemotingTransportException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

Kerberos 和 NTLM 并不是唯一的身份验证协议,但与其他协议相比,它们是最安全的。让我们看看还有哪些其他方法,并了解如何强制执行它们。

身份验证协议

当然,也可以通过指定-**身份验证**参数来配置应使用哪种身份验证方法。

身份验证协议

如果可以使用 Kerberos 身份验证,应该始终使用 Kerberos,因为该协议提供了大部分安全功能。

继续阅读第六章活动目录 – 攻击与缓解,了解更多关于身份验证的内容以及 Kerberos 和 NTLM 的工作原理。

以下是所有接受的-**身份验证**参数的值:

  • 默认:这是默认值。在这里,将使用协商

  • 基本:基本身份验证用于通过 HTTP 协议进行身份验证,但本身并不提供安全性——既不保护通过网络以明文传输的数据,也不保护凭据。然而,当与 TLS 配合使用时,这仍然是一种相对安全的机制,许多网站通常会使用它。

由于凭据仅使用 Base64 编码,编码可以很容易地被逆向解码,凭据也可以以明文形式提取出来。

如果凭据没有使用SSL**/**TLS加密,这种身份验证无法为提供的凭据提供机密性。

  • Credssp:使用CredSSP身份验证,PowerShell 会从客户端将用户凭据提供给远程服务器以进行身份验证。此模式在需要远程会话能够像你一样进行身份验证以便进行进一步的网络跳转时特别有用。在此身份验证之后,凭据以加密格式在客户端和服务器之间传递,以保持安全性。

当使用 CredSSP 身份验证机制时,PowerShell 将用户的完整凭据传递给远程服务器进行身份验证。这意味着,如果你连接到一个被攻破的机器,攻击者可以直接从内存中提取你的凭据。需要注意的是,这是 RDP 的默认身份验证机制,使得 PSRemoting 成为一个更安全的替代方案。

  • Digest:摘要认证是 Web 服务器可以使用的一种身份验证方法。在发送数据之前,用户名和密码会使用MD5加密算法进行哈希处理,并通过HTTP协议进行传输。在哈希处理之前,会添加一个 nonce 值以避免重放攻击。

与其他身份验证协议(例如基于密钥的身份验证)相比,它并不提供强大的身份验证,但它仍然比较弱的身份验证机制更强,应该作为弱基本认证的替代方案考虑。

  • Kerberos:这种身份验证方式使用 Kerberos 协议。Kerberos 是域认证的标准,并提供最高级别的安全性。

  • Negotiate:此选项允许客户端协商身份验证。当使用域账户时,身份验证将通过 Kerberos 进行;使用本地账户时,将回退到 NTLM。

  • NegotiateWithImplicitCredential:此选项使用当前用户的凭据进行身份验证(以当前用户身份运行)。

这些身份验证机制可以在所有 PSRemoting cmdlet 中使用。

它们也在AuthenticationMechanism** 枚举**中进行了指定,该枚举在微软文档中定义:docs.microsoft.com/en-us/dotne…

需要注意的是,PowerShell 将一些身份验证机制视为潜在危险,并且如果你尝试使用它们,可能会显示错误消息。在这种情况下,你需要明确地覆盖这些错误,才能继续使用这些危险的身份验证机制。

基本认证安全考虑事项

如果在没有其他加密层的情况下使用,基本认证是不安全的。在本节中,我们将探讨一个非常好的例子,说明为什么你不应使用基本认证,或者如果必须使用基本认证时,为什么你应该始终加密你的通信,使用传输层安全性TLS)。

注意!

不要在生产环境中配置此设置,因为该配置非常不安全,仅用于测试目的。如果你使用此配置,你将会使自己处于危险之中!

如果你想配置测试环境以使用基本认证并允许未加密的流量,你需要配置你的 WinRM 设置,以允许基本认证和未加密流量。

在这个例子中,PSSec-PC01是我们要连接的远程主机,使用未加密流量和基本认证进行连接。我们将从管理机器PSSec-PC02连接。

当我们尝试从PSSec-PC02连接到PSSec-PC01(IP 地址为172.29.0.12)时,使用-Authentication Basic参数时,我们会收到一条消息,提示我们需要提供用户名和密码,以便使用基本身份验证:

图 3.18 – 如果使用不安全的身份验证机制,将显示错误消息

图 3.18 – 如果使用不安全的身份验证机制,将显示错误消息

一旦提供了这些凭据,我们仍然无法进行身份验证,并且会收到一条错误消息,指出访问被拒绝。原因是基本身份验证在没有 TLS 保护的情况下是一种不安全的身份验证机制。因此,PSRemoting 不允许在未明确配置的情况下使用这种不安全的身份验证机制连接。

因此,让我们在演示设置中明确配置基本身份验证,知道我们会故意削弱配置。首先,允许PSSec-PC01上的未加密流量:

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

请记住区分服务客户端配置。由于我们想连接到PSSec-PC01,我们将连接到 WinRM 服务,因此我们正在配置服务

接下来,配置允许基本身份验证:

> winrm set winrm/config/service/auth '@{Basic="true"}'

在对 WinRM 配置进行更改后,重新启动 WinRM 服务以使新配置生效非常重要:

> Restart-Service -Name WinRM

现在,让我们配置PSSec-PC02,以便使用基本身份验证建立与其他设备的未加密连接。

首先,我们必须配置客户端,以便能够初始化未加密的连接:

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

然后,我们必须确保客户端允许使用基本身份验证建立连接:

> winrm set winrm/config/client/auth '@{Basic="true"}'

最后,重新启动 WinRM 服务以加载新配置:

> Restart-Service -Name WinRM

再次提醒,这种配置会暴露您的设备,并使它们变得脆弱。具体来说,它暴露了您的凭据,可能会被潜在的攻击者拦截连接时的网络流量。这可能允许攻击者未经授权访问您的系统,并可能危及敏感数据或执行恶意操作。

因此,我们仅在测试环境中应用此配置。在生产环境中,重要的是采取适当的安全措施,例如启用加密和使用安全的身份验证协议,以保护您的设备和数据。

一旦我们配置好脆弱的配置,就该使用基本身份验证进行连接了。我在PSSec-PC01上添加了一个名为PSSec的本地用户,接下来将在本示例中使用它。

让我们从PSSec-PC02连接到PSSec-PC01(IP 地址为172.29.0.12),使用-Authentication参数并指定Basic,同时提供PSSec用户的凭据:

> $cred = Get-Credential -Credential "PSSec"

> New-PSSession -ComputerName 172.29.0.12 -Authentication Basic -Credential $cred

正在建立会话。如果我使用 Wireshark 追踪流量,我将看到正在进行的 SOAP 请求。更糟糕的是,我能看到Authorization头部,其中暴露了 Base64 加密的用户名和密码:

图 3.19 – 使用未加密的基本身份验证进行身份验证的 Wireshark 捕获

图 3.19 – 使用未加密的基本身份验证进行身份验证的 Wireshark 捕获

Base64 可以很容易地解密,例如,使用 PowerShell 本身:

图 3.20 – 解密 Base64 加密的凭据

图 3.20 – 解密 Base64 加密的凭据

所以,攻击者很容易发现PSSec用户的密码是PS-SecRockz1234!,并可以通过中间人攻击注入会话,或使用该密码冒充PSSec用户——这是他们攻击整个环境的一个很好的起点。

我希望我能够使基本身份验证和未加密会话的风险更加透明,以便你只在测试环境中尝试此配置——并避免在生产环境中使用。

PowerShell 远程操作与凭据窃取

根据使用的身份验证方法,凭据可能被输入到远程系统中,且这些凭据可能被敌对方窃取。如果你有兴趣了解更多关于凭据窃取及其缓解措施的内容,缓解 Pass-the-Hash (PtH) 攻击与其他凭据窃取白皮书是一个宝贵的资源:www.microsoft.com/en-us/download/details.aspx?id=36036

默认情况下,PSRemoting 不会将凭据保留在目标系统上,这使得 PowerShell 成为一个出色的管理工具。

但如果例如使用带有 CredSSP 的 PSRemoting,凭据会进入远程系统,在那里它们可以被提取并用于冒充身份。

请记住,当使用 CredSSP 作为身份验证机制时,用于身份验证的凭据会被缓存到远程系统中。虽然这对于单点登录很方便,但也使得这些缓存的凭据容易被窃取。如果可以避免,请不要使用 CredSSP 作为身份验证机制。但如果你选择使用 CredSSP,建议启用 Credential Guard 来帮助减轻这一风险。

我们将更加深入地探讨身份验证,以及臭名昭著的 Pass-the-Hash 攻击如何工作,内容可以参考第六章Active Directory – 攻击 与缓解

使用 PowerShell 远程操作执行命令

有时,你可能想要远程运行一个命令,但尚未配置 PSRemoting。一些 cmdlet 提供了内置的远程技术,可以加以利用。

所有提供内置远程技术的命令都有一个共同点:通常,它们都有一个名为-ComputerName的参数,用于指定远程端点。

要获取本地可用命令的列表,这些命令支持远程执行任务,请使用Get-Command -CommandType Cmdlet -ParameterName** **ComputerName命令:

> Get-Command -ParameterName ComputerName
CommandType  Name               Version    Source
-----------  ----               -------    ------
Cmdlet       Connect-PSSession  3.0.0.0    Microsoft.PowerShell.Core
Cmdlet       Enter-PSSession    3.0.0.0    Microsoft.PowerShell.Core
Cmdlet       Get-PSSession      3.0.0.0    Microsoft.PowerShell.Core
Cmdlet       Invoke-Command     3.0.0.0    Microsoft.PowerShell.Core
Cmdlet       New-PSSession      3.0.0.0    Microsoft.PowerShell.Core
Cmdlet       Receive-Job        3.0.0.0    Microsoft.PowerShell.Core
Cmdlet       Receive-PSSession  3.0.0.0    Microsoft.PowerShell.Core
Cmdlet       Remove-PSSession   3.0.0.0    Microsoft.PowerShell.Core

请注意,此列表并不完整。

带有-ComputerName参数的 cmdlet 不一定使用 WinRM。有些使用 WMI,许多其他使用 RPC —— 这取决于 cmdlet 的底层技术。

由于每个 cmdlet 都有一个底层协议,它的防火墙配置和服务需要相应地进行配置。这可能意味着较大的管理开销。因此,在远程管理环境时,最好根据需要配置 PSRemoting:使用 WinRM 是防火墙友好且更易于配置和维护的。

不要混淆!

PSRemoting 不应与使用 cmdlet 的-ComputerName参数在远程计算机上执行命令混淆。这是两种不同的方式,具有不同的能力和使用场景。那些使用-ComputerName参数的 cmdlet 依赖于其底层协议,这些协议通常需要单独的防火墙例外规则才能运行。

执行单个命令和脚本块

你可以使用Invoke-Command cmdlet 在远程或本地计算机上执行单个命令整个脚本块

Invoke-Command -ComputerName <Name> -ScriptBlock {<ScriptBlock>}

以下示例显示如何重启PSSec-PC01远程计算机上的打印机后台处理程序,并显示详细输出:

> Invoke-Command -ComputerName PSSec-PC01 -ScriptBlock { Restart-Service -Name Spooler -Verbose }
VERBOSE: Performing the operation "Restart-Service" on target "Print Spooler (Spooler)".

Invoke-Command是运行本地脚本和命令到远程计算机的一个很好的选择。

如果你不想将相同的脚本复制到远程机器上,可以使用Invoke-Command-FilePath参数来在远程系统上运行本地脚本

> Invoke-Command -ComputerName PSSec-PC01 -FilePath c:\tmp\test.ps1

在使用-FilePath参数和Invoke-Command时,重要的是要记住,脚本所需的任何依赖项(如其他脚本或命令)也必须存在于远程系统上,否则脚本将无法按预期运行。

你还可以在多个系统上执行命令 – 只需在-ComputerName参数中指定你希望执行命令或脚本的所有远程系统。以下命令会重启PSSec-PC01PSSec-PC02上的打印机后台处理程序:

> Invoke-Command -ComputerName PSSec-PC01,PSSec-PC02 {Restart-Service -Name Spooler}

请查看官方 PowerShell 文档,了解Invoke-Command所提供的所有选项:docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command

使用 PowerShell 会话

-Session参数表示 cmdlet 或函数支持 PSRemoting 中的会话。

要查找所有支持-Session参数的本地可用命令,可以使用Get-Command -ParameterName** **session命令:

图 3.21 – 提供会话参数的所有命令

图 3.21 – 提供会话参数的所有命令

所有提供-Session参数的本地命令都会显示。

交互式会话

通过利用Enter-PSSession命令,你可以启动一个交互式会话。一旦会话建立,你可以在远程系统的 shell 上进行操作:

图 3.22 – 进入 PowerShell 会话,执行命令并退出会话

图 3.22 – 进入 PowerShell 会话,执行命令并退出会话

一旦工作完成,使用Exit-PSSession来关闭会话和远程连接。

持久会话

New-PSSession cmdlet 可以用来建立一个持久会话。

如前所述,我们再次使用Get-Credential将我们的凭证作为安全字符串存储在$****cred变量中。

使用以下命令,我们为PSSec-PC01PSSec-PC01远程计算机创建两个会话来执行命令:

$sessions = New-PSSession -ComputerName PSSec-PC01, PSSec-PC02 -Credential $cred

要显示所有活动的会话,你可以使用Get-PSSession命令:

图 3.23 – 创建持久会话并显示它们

图 3.23 – 创建持久会话并显示它们

现在,你可以使用$sessions变量,在你指定的所有远程计算机会话中运行命令。

一个常见的使用案例是检查所有远程计算机是否都应用了所有安全更新。在这种情况下,我们要检查是否所有远程计算机都安装了KB5023773热修复程序。我们也不希望在找不到热修复程序时显示任何错误信息,因此我们将在代码片段中使用-ErrorAction SilentlyContinue参数:

Invoke-Command –Session $sessions -ScriptBlock { Get-Hotfix -Id 'KB5023773' -ErrorAction SilentlyContinue }

以下是我们运行该命令后的输出:

图 3.24 – 在所有指定的会话中运行命令

图 3.24 – 在所有指定的会话中运行命令

结果表明,热修复程序仅安装在PSSec-PC01上,而第二台计算机PSSec-02上没有安装。

要执行此操作并安装缺失的更新,我们可以直接在会话中发送更多命令,或者可以通过指定会话 ID 交互式地进入会话——即Enter-PSSession -****Id 2

图 3.25 – 进入持久会话,运行命令并再次退出

图 3.25 – 进入持久会话,运行命令并再次退出

现在我们已经进入会话,可以运行Get-WindowsUpdate命令来安装缺失的更新。请注意,这个命令默认不可用,需要你安装PSWindowsUpdate模块:

Get-WindowsUpdate -Install -KBArticleID 'KB5023773'

在我们的命令执行完毕后,我们可以使用Exit-PSSession退出会话,这只会使我们与会话断开连接,但会话仍然保持开启。

注意

如果使用交互式会话,所有执行的模块(如 PSWindowsUpdate)需要安装在远程系统上。如果使用 Invoke-Command 在持久会话中运行命令,则只需要在运行命令的计算机上安装该模块:

**Invoke-Command – Session $sessions -ScriptBlock { Get-WindowsUpdate -Install -**KBArticleID ‘KB5023773’}

如果我们过一段时间后检查 KB5023773,我们会看到更新已经安装:

图 3.26 – 更新成功安装

图 3.26 – 更新成功安装

一旦我们完成工作且不再需要会话时,可以使用 Remove-PSSession 命令将其移除:

  • 在这里,我们可以使用之前指定的 $sessions 变量:

    Remove-PSSession -Session $sessions
    
  • 或者,我们可以通过使用 -****id 参数来移除单个会话:

    Remove-PSSession -id 2
    

移除一个或所有会话后,可以使用 Get-PSSession 来验证这一点:

图 3.27 – 移除所有持久会话

图 3.27 – 移除所有持久会话

使用 PSRemoting 执行命令可以极大简化日常管理工作。现在,您已经掌握了基本知识,可以将其与您的 PowerShell 脚本知识相结合。您将解决哪些问题,并自动化哪些任务?

最佳实践

为了确保在使用 PSRemoting 时的最佳安全性和性能,遵循产品强制执行的最佳实践至关重要。这些实践旨在减少安全漏洞的风险,并确保远程管理任务顺利运行。

认证

  • 如果可能,仅使用 Kerberos 或 NTLM 认证。

  • 尽量避免使用 CredSSP 和基本身份验证。

  • 最佳情况下,限制使用除了 Kerberos/NTLM 之外的所有其他认证机制。

  • SSH 远程访问 – 配置公钥认证并保护私钥。

限制连接

  • 通过防火墙限制来自管理子网的连接(如果可能,使用硬件和软件)。

PSRemoting 的默认防火墙策略根据网络配置文件有所不同。在 工作组私有 网络配置文件中,PSRemoting 默认对所有人开放(假设他们拥有有效凭证)。在 公共 配置文件中,PSRemoting 默认拒绝监听该适配器。如果强制启用,网络规则将限制访问仅限于同一网络子网的系统。

限制会话

  • 使用受限语言和 JEA。

  • 你将在第十章,“语言模式与足够的管理(JEA)”中深入了解 JEA、受限语言、会话安全性和 SDDLs。

审计不安全设置

  • 使用 WinRM 组策略在所有受管理系统上强制执行安全的 PSRemoting 设置,包括加密和身份验证要求。

  • Get-Item WSMan:\localhost\Client\AllowUnencrypted:此设置应设置为$true

  • 定期审计不安全的 WinRM 设置,以确保符合安全政策:

    Get-Item WSMan:\localhost\client\AllowUnencrypted
    
    Get-Item wsman:\localhost\service\AllowUnencrypted
    
    Get-Item wsman:\localhost\client\auth\Basic
    
    Get-Item wsman:\localhost\service\auth\Basic
    
  • 最终,使用所需状态配置DSC)来审计并应用你的设置。

以及前一章中提到的所有其他缓解方法,特别是 以下内容

  • 启用日志记录和转录,并监控事件日志。你可以在第四章,“检测 - 审计与监控”中阅读更多相关内容。

  • 消除不必要的本地和域管理员。

  • 启用并强制执行脚本签名。你将在第十一章,“AppLocker、应用控制和代码签名”中进一步了解脚本签名。

  • 配置DSC来加固你的系统并控制系统配置。

PSRemoting 是一种高效管理系统的好方法。当然,它的安全性取决于你的配置。如果配置得当,通过 PSRemoting 进行管理比交互式登录更安全。

摘要

阅读完本章后,你应该熟悉如何使用 PSRemoting 远程使用 PowerShell。你学习了 PowerShell 中用于建立远程连接的选项,这使你不仅能够管理 Windows 机器,还能管理其他操作系统,如 macOS 和 Linux。

你还学习了什么是端点,并且能够创建基本的自定义端点。你将在第十章,“语言模式与足够的管理(JEA)”中进一步加强这项能力,但你已经掌握了基础知识。

然后,你学习了很多可以使用的身份验证协议,还了解了使用这些协议时的安全考虑。你还应该意识到,如果使用弱身份验证协议,攻击者能够轻易地获得解密后的凭据。

你现在应该能够手动和集中配置 PSRemoting,这有助于你在生产环境中设置初始的 PSRemoting 配置。

最后但同样重要的是,你学习了如何使用 PSRemoting 执行命令,这使得你不仅可以在一个设备上运行一个命令,还可以自动化繁琐的管理任务。

在使用 PowerShell 时——无论是远程还是本地——审计和监控是非常重要的课题。使用转录和事件日志有助于蓝队发现对手并保护其环境。

因此,现在你已经熟悉了 PSRemoting,我们将在下一章讨论 PowerShell 中的检测和日志记录。

进一步阅读

如果你想进一步探索本章提到的一些话题,可以查看这些资源。

认证

CIM

DCOM

OMI

其他 有用资源

PowerShell 远程管理

WMI:

)

)

)

WS-Man:

)

你还可以在 GitHub 仓库中找到本章提到的所有链接,链接位于第三章 – 无需手动输入每个链接:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter03/Links.md

第四章:检测——审计与监控

尽管组织已经在努力加强其环境的安全性,但只有少数组织意识到,审计和监控是确保环境安全时最重要的两项工作。

多年来,在微软工作时,我一直倡导保护检测响应的策略。大多数公司只试图保护他们的设备,但他们仅停留在这一层面。要做到检测响应,不仅需要一个有效的安全运营中心SOC),还需要基础设施和资源。

这些人力和资源需要资金——这也是许多公司一开始不愿意投入的预算,除非他们已经遭遇了攻击。

在与客户合作时,我只见过少数环境中拥有有效的 SOC,并且具备部署安全信息与事件管理系统SIEM)的基础设施。当我离开这些客户时,我很高兴地看到大多数客户开始重新审视他们的安全策略,并改进了安全性、监控和检测。

然而,我也遇到过一些客户,在我第一次接触他们时,他们已经遭到攻击。这些客户曾经没有预算,也没有员工来进行检测,但一旦被攻击,他们就立刻有了改善的预算。

多年来,我了解到,问题不在于组织是否会被黑客攻击,而是何时会被攻击,以及攻击者在环境中逗留多长时间而不被察觉。如果他们最终被发现的话。

因此,我建议我遇到的每一位 IT 决策者都要假设已经遭到入侵,并保护好重要的资产。

多年来,我看到越来越多的组织实际上已经建立了运营中的安全运营中心(SOC),这让我感到非常高兴。但不幸的是——尤其是在中小型企业中——大多数组织要么没有监控机制,要么刚刚开始这方面的工作。

PowerShell 在攻击中的使用多次被媒体报道。勒索病毒通过发送恶意邮件来分发,邮件在后台启动 PowerShell 执行载荷,这是一种无文件攻击,恶意软件无需在客户端下载,而是直接在内存中运行,甚至合法的系统工具也被对手滥用来执行攻击(也被称为依赖本地资源攻击LOLbins)。

是的,攻击者喜欢利用他们在系统中找到的东西。然而,如果组织不仅采取了适当的缓解措施,还实施了正确的检测方式,那么这将使对手更难发起成功的攻击并保持隐匿。

许多对手在攻击中使用的工具几乎没有任何透明度,因此防御者(也就是蓝队)很难检测和分析这样的攻击。

与此相反,PowerShell 提供了如此强大的日志记录功能,使得分析和检测通过它发起的攻击变得非常容易。因此,如果你是蓝队成员,并且注意到自己遭遇了基于 PowerShell 的攻击,那么你算是走运了(就算你的基础设施遭到攻击,也算是走运吧)!这使得你更容易弄清楚发生了什么。

拥有一个广泛的(不仅限于)PowerShell 日志记录基础设施,可以帮助你的 SOC 团队识别攻击者并了解对手执行了哪些命令和代码。这也有助于提高你的检测能力和安全控制。

在本章中,你将学习使用 PowerShell 进行安全监控的基础知识,这将帮助你开始进行检测或改进检测。在本章中,你将对以下主题有更深入的了解:

  • 配置 PowerShell 事件日志

  • PowerShell 模块日志记录

  • PowerShell 脚本块日志记录

  • 保护的事件日志记录

  • PowerShell 转录

  • 分析事件日志

  • 开始使用日志记录

  • 最重要的与 PowerShell 相关的事件日志和事件 ID

技术要求

为了最大限度地发挥本章的作用,请确保你具备以下内容:

  • PowerShell 7.3 及以上版本

  • 第四章的 GitHub 仓库访问链接:

github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/tree/master/Chapter04

配置 PowerShell 事件日志

实施强大的 PowerShell 审计机制,帮助你监控、检测和防范潜在威胁,是确保 PowerShell 安全实践有效性的关键步骤。通过利用 PowerShell 日志记录,你可以捕捉到系统上 PowerShell 活动的详细信息,这对于检测和调查安全事件至关重要。PowerShell 日志记录可以帮助你识别可疑活动,例如恶意命令的执行或关键系统设置的修改。

在本节中,我们将讨论你可以启用的不同类型的 PowerShell 日志记录,包括 PowerShell 模块日志记录、PowerShell 脚本块日志记录、保护的事件日志记录和 PowerShell 转录。我们还将探讨如何配置这些日志记录功能,以满足你所在组织的具体安全需求。

PowerShell 模块日志记录

PowerShell 模块日志记录在 PowerShell 3.0 中新增。此功能提供对系统上执行的所有 PowerShell 命令的广泛日志记录。如果启用了模块日志记录,管道执行事件将生成并写入 Microsoft-Windows-Powershell/Operational 事件日志,事件 ID 为 4103

如何配置模块日志记录

您可以选择仅在当前会话中为某个模块启用模块日志记录,或者将其配置为永久开启。

仅在单个会话中启用它只有在您想要排查某个特定模块的行为时才有意义。如果您想要检测对手在您的基础设施中运行的命令,那么开启模块日志记录并使其保持常开是有意义的。

要仅在当前会话中为某个特定模块启用模块日志记录,您需要先导入该模块。在此示例中,我们将使用EventList模块:

> Import-Module EventList
> (Get-Module EventList).LogPipelineExecutionDetails = $true
> (Get-Module EventList).LogPipelineExecutionDetails
True

当然,您可以将模块名称EventList替换为任何您希望记录管道执行详细信息的模块名称:

Import-Module <Module-Name>
(Get-Module <Module-Name>).LogPipelineExecutionDetails = $true

如果您想要监控一个受管理的环境,您不希望在每台主机上手动启用 PowerShell 模块日志记录。在这种情况下,您可以使用组策略来启用模块日志记录。

创建一个新的组策略对象GPO)。由于 Windows PowerShell 和 PowerShell Core 被设计为共存并可以单独配置,因此取决于您想要配置哪个 PowerShell 版本:

  • 要配置 Windows PowerShell,请导航至计算机配置 | 策略 | 管理模板 | **Windows 组件 | **Windows PowerShell

  • 要配置 PowerShell Core,请导航至计算机配置 | **管理模板 | **PowerShell Core

我的 PowerShell Core .admx 模板在哪里?

如果您尚未将.admx模板导入到您的组策略中来配置 PowerShell Core,请参见第一章开始使用 PowerShell

选择并编辑启用模块日志记录策略。此时将打开一个窗口以配置模块日志记录:

图 4.1 – 通过组策略配置 Windows PowerShell 的模块日志记录

图 4.1 – 通过组策略配置 Windows PowerShell 的模块日志记录

对于 PowerShell Core,配置窗口几乎是一样的,唯一的不同是使用 Windows PowerShell 策略设置选项。如果选中此选项,PowerShell Core 将依赖现有的 Windows PowerShell 配置。

图 4.2 – 通过组策略配置 PowerShell Core 的模块日志记录

图 4.2 – 通过组策略配置 PowerShell Core 的模块日志记录

如果您只想使用一个 GPO 来配置模块日志记录,请启用使用 Windows PowerShell 策略设置。接下来,根据您的配置,在 Windows PowerShell 或 PowerShell Core 模块日志记录 GPO 中,进入模块名称,然后点击**显示…**按钮来配置需要开启模块日志记录的模块。此时将打开一个新窗口。

图 4.3 – 配置通配符 (*) 来记录所有模块

图 4.3 – 配置通配符 (*) 来记录所有模块

现在,你可以为单个模块配置启用模块日志记录,但对于安全监控来说,监控所有模块日志记录事件更有意义——无论执行的是哪个模块。

你可以通过配置通配符(*)作为模块名称来实现此操作。确认两次点击确定并退出 GPO 编辑器,使更改生效。

当然,你也可以通过指定模块名称作为值,单独为某个实例添加模块日志记录,而不是监控所有实例。不过,我建议记录所有 PowerShell 活动(*****),这对于防止攻击者导入自定义 PowerShell 模块特别有用。

由此配置生成的所有事件可以在 Microsoft Windows PowerShell 操作事件日志中找到(Microsoft-Windows-Powershell/Operational)。

PowerShell 脚本块日志记录

脚本块是由表达式和命令组成的集合,这些表达式和命令被组合在一起并作为一个单位执行。当然,单个命令也可以作为脚本块执行。

许多命令支持 -ScriptBlock 参数,例如 Invoke-Command 命令,你可以使用它来运行整个脚本块,本地或远程执行:

> Invoke-Command -ComputerName PSSec-PC01 -ScriptBlock {Restart-Service -Name Spooler -Verbose}
VERBOSE: Performing the operation "Restart-Service" on target "Print Spooler (Spooler)".

需要注意的是,所有在 PowerShell 中执行的操作都被视为脚本块,如果启用了脚本块日志记录,它们将被记录——无论是否使用 -****ScriptBlock 参数。

大多数情况下,企业和组织并不关心日志记录和事件日志分析,除非发生安全事件。然而,到了那时,已经为时过晚,无法事后启用日志记录。因此,PowerShell 团队决定默认记录所有安全相关的脚本块。

从 PowerShell 5 开始,默认启用脚本块日志记录的基础版本——只有常用于恶意攻击的脚本技术会被写入 Microsoft-Windows-Powershell/Operational 事件日志。

这种基础版本的脚本块日志记录并不能替代完整的脚本块日志记录;它应该仅仅作为最后的手段,如果在攻击发生时未启用日志记录时使用。

如果你想保护环境并检测恶意活动,仍然应该考虑开启完整的脚本 块日志记录

此外,在配置脚本块日志记录时,还有一个更详细的选项——脚本块 调用日志记录

默认情况下,只有在首次使用时,脚本块才会被记录。配置脚本块调用日志记录后,每次调用脚本块以及脚本启动或停止时,都会生成事件。

启用脚本块调用日志记录可能会生成大量事件,这可能会淹没日志,并将其他事件中的有用安全数据滚出。启用脚本块调用日志记录时要小心,因为会生成大量事件——通常情况下,你在事件分析时不需要它。

如何配置脚本块日志记录

配置脚本块日志记录有多种方法——手动配置以及集中管理的方式。让我们看看需要配置什么才能记录您环境中执行的所有代码。

要手动启用脚本块日志记录,您可以编辑注册表。要更改的设置位于以下注册表路径中:

HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging

使用EnableScriptBlockLoggingREG_DWORD)注册表项,可以配置启用脚本块日志记录:

  • 启用:将值设置为1以启用它

  • 禁用:将值设置为0以禁用它

如果启用了脚本块日志记录,您将在事件 ID 4104 下找到所有执行的代码。

使用EnableScriptBlockInvocationLoggingREG_DWORD)注册表项,可以配置启用脚本块调用日志记录(事件 ID 41054106):

  • 启用:将值设置为1以启用它

  • 禁用:将值设置为0以禁用它

如果启用了脚本块日志记录以及脚本块调用日志记录,将会生成事件 ID 41054106

如果启用了脚本块调用日志记录,则会生成大量噪音,日志文件的大小会增加。因此,应该重新配置最大日志大小(请参见增加日志大小部分)。对于一般的安全监控,您不需要配置详细的脚本块日志记录。

您可以通过在提升的 PowerShell 控制台中运行以下命令手动配置脚本块日志记录:

New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Force
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Name "EnableScriptBlockLogging" -Value 1 -Force

第一个命令会在注册表项不存在时创建所有注册表键,第二个命令启用脚本块日志记录。

启用ScriptBlockLogging时,使用上述命令,ScriptBlockLogging将同时为 32 位和 64 位应用程序启用。您可以通过以下方式验证两个设置是否已配置:

  • HKLM:\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging

  • HKLM:\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging

在受管环境中,将机器集中管理是有意义的。当然,这可以通过 PowerShell 和/或Desired State ConfigurationDSC)来完成,但也可以通过组策略来完成。

创建一个新的 GPO。根据您要配置的 PowerShell 版本,导航到以下任一项:

  • 计算机配置 | 策略 | 管理模板 | **Windows 组件 | **Windows PowerShell 用于 Windows PowerShell

  • 计算机配置 | **管理模板 | **PowerShell Core 用于 PowerShell Core

选择并编辑启用 PowerShell 脚本块日志记录策略。会打开一个窗口来配置模块日志记录。

如果您决定配置日志记录脚本块调用开始/停止事件选项,将会生成更多的事件,并且会产生大量噪音。根据您的使用案例,这个选项可能仍然是有意义的,但如果您刚开始进行安全监控,建议不要启用此选项。

增加脚本块调用日志记录的日志文件大小

如果启用了脚本块调用日志记录,并且使用日志记录脚本块调用开始/停止事件选项,日志文件的大小会增加,最大大小应重新配置。

只有在启用日志记录脚本块调用开始/停止事件选项时,才会生成事件 ID 41054106

在我们的示例中,我们将配置日志记录脚本块调用开始/停止事件以避免噪音;因此,我们将保持该复选框未选中:

图 4.4 – 为 Windows PowerShell 启用 PowerShell 脚本块日志记录

图 4.4 – 为 Windows PowerShell 启用 PowerShell 脚本块日志记录

在 PowerShell Core 策略中,您将会——与 PowerShell 模块日志记录策略及其他一些策略一样——找到将当前 Windows PowerShell 策略设置同时用于 PowerShell Core 的选项。

图 4.5 – 为 PowerShell Core 启用 PowerShell 脚本块日志记录

图 4.5 – 为 PowerShell Core 启用 PowerShell 脚本块日志记录

由此配置生成的所有事件可以在 Microsoft Windows PowerShell 操作事件日志中找到 (Microsoft-Windows-Powershell/Operational),或者在 PowerShell Core 中,可以在 PowerShell Core 事件日志中找到 (PowerShellCore/Operational)。

保护事件日志记录

事件日志记录是一个敏感话题。通常,像密码这样的敏感信息会被暴露并写入事件日志。

敏感信息在对手手中如同黄金一样珍贵,尤其是当对方可以访问此类系统时,因此,为了应对这一问题,从 Windows 10 和 PowerShell 版本 5 开始,微软引入了保护事件日志记录。

保护事件日志记录使用互联网工程任务组(IETF)密码消息语法CMS)标准加密数据,该标准依赖于公钥密码学。这意味着公钥会部署在所有需要支持保护事件日志记录的系统上。然后,使用公钥对事件日志数据进行加密,在转发到中央日志收集服务器之前。

在这台机器上,使用高度敏感的私钥解密数据,然后将数据插入 SIEM。这台机器是敏感的,因此需要特别保护。

保护事件日志记录默认是禁用的,目前仅能与 PowerShell 事件日志一起使用。

启用保护事件日志记录

要启用受保护的事件日志记录,可以部署一个base64 编码的 X.509证书或其他选项(例如,通过**公共密钥基础设施(PKI)**部署证书并提供指纹,或提供指向本地或文件共享托管证书的路径)。在我们的示例中,我们将使用base64 编码的 X.509证书。

以下是证书要求:

  • 证书还必须包含*“文档加密”* 增强密钥使用EKU),其 OID 号为(1.3.6.1.4.1.311.80.1)。

  • 证书属性必须包括“数据加密”或“密钥加密”密钥使用。

这里有一篇很棒的 SANS 博客文章,您可以查看如何检查证书的属性:www.sans.org/blog/powershell-protect-cmsmessage-example-code/

受保护的事件日志记录利用IETF CMS来保护事件日志内容。因此,您还可以参考Protect-CMSMessageUnprotect-CMSMessage cmdlet 的文档页面,了解有关使用 CMS 加密和解密的更多信息:

请注意,您计划部署的证书文件不能包含私钥。获得证书后,您可以手动启用它,或使用组策略启用它。

在博客文章PowerShell the blue team中,PowerShell 团队为您提供了Enable-ProtectedEventLogging函数,您可以使用该函数通过 PowerShell 启用受保护的事件日志记录:devblogs.microsoft.com/powershell/powershell-the-blue-team/#protected-event-logging

要使用此脚本,请将证书保存在$cert变量中,您将在第二个命令中使用该变量将公钥证书传递给Enable-ProtectedEventLogging函数,从而在本地系统上启用受保护的事件日志记录:

> $cert = Get-Content C:\tmp\PEL_certificate.cer –Raw

> Enable-ProtectedEventLogging –Certificate $cert

您还可以通过组策略启用受保护的事件日志记录。创建一个新的 GPO 或重复使用现有的 GPO,然后导航到计算机配置 | 策略 | 管理模板 | Windows 组件 | 事件日志记录

打开启用受保护事件 日志记录策略。

图 4.6 – 启用受保护的事件日志记录

图 4.6 – 启用受保护的事件日志记录

启用受保护的事件日志记录设置为启用,提供您的证书,并点击确定确认。

在安全且受保护的系统上使用Unprotect-CmsMessage cmdlet 解密数据,然后将其存储到你的 SIEM 中,前提是机器上已安装了适当的解密证书(即包含私钥的证书)。

要在将数据存储到 SIEM 中之前解密数据,请在安全且受保护的系统上使用Unprotect-CmsMessage cmdlet,前提是该系统上已安装包含私钥的适当解密证书:

> Get-WinEvent Microsoft-Windows-PowerShell/Operational | Where-Object Id -eq 4104 | Unprotect-CmsMessage

在这个示例中,所有来自操作 PowerShell 日志的事件 ID 4104的事件将被解密,前提是私钥存在。

还可以记录会话中执行了哪些命令以及显示了哪些输出。这个选项叫做记录,我们将在下一节中详细讨论。

PowerShell 记录

自 PowerShell 版本 1.0 以来,PowerShell 记录就作为Microsoft.PowerShell.Host模块的一部分提供。记录是监控 PowerShell 会话中发生事件的好方法。

如果启动了 PowerShell 记录,则所有执行的 PowerShell 命令及其输出都会被记录并保存到指定的文件夹中。如果没有另行指定,默认输出文件夹是当前用户的我的文档文件夹(%userprofile%\Documents)。

以下截图展示了此类记录的一个示例。

图 4.7 – PowerShell 记录的截图

图 4.7 – PowerShell 记录的截图

.txt文件的名称以PowerShell_transcript开头,后跟computername、一个随机字符串和时间戳。

这是一个典型的 PowerShell 记录文件名示例,该记录是在PSSec-PC01上启动的 – PowerShell_transcript.PSSEC-PC01.MUxdLMnA.20210320152800.txt

如何启动记录

启用记录的方式有几种。然而,记录 PowerShell 记录的最简单方法是直接在当前会话中输入Start-Transcript命令并按Enter。在这种情况下,只有在此本地会话中执行的命令才会被捕获。

直接运行Start-Transcript cmdlet 时,最常用的参数是-OutputDirectory-Append-NoClobber-IncludeInvocationHeader

  • -Append: 新的记录将被添加到现有文件中。

  • -IncludeInvocationHeader: 记录命令执行的时间戳,并在命令之间添加分隔符,以便通过自动化工具更容易解析记录。

  • -NoClobber: 该记录不会覆盖现有文件。通常,如果定义位置中已存在记录文件(例如,定义的文件与现有文件同名,或者文件名是通过-Path-LiteralPath参数配置的),Start-Transcript会覆盖该文件且不会发出警告。

  • -OutputDirectory:使用此参数,你可以配置存储转录文件的路径。

  • -UseMinimalHeader:此参数在PowerShell 版本 6.2中添加,确保仅添加简短的头部,而不是详细的头部。

了解Start-Transcript帮助文件中所有参数的完整列表,或者在官方 PowerShell 文档中查看:docs.microsoft.com/en-us/powershell/module/microsoft.powershell.host/start-transcript?view=powershell-7#parameters

确保你的转录安全

和你收集的任何安全日志一样,确保将转录文件安全存储,以防止攻击者篡改它们非常重要。确保配置一个安全路径,令攻击者难以访问,并考虑到企业身份被盗的可能性。一旦攻击者获得转录的访问权限,他们可以修改它们,从而使你的检测工作失效。

使用Start-Transcript初始化的转录只会在会话处于活动状态或执行Stop-Transcript命令时停止,后者会停止记录执行的 PowerShell 命令。

默认启用转录

要在系统上默认启用转录,你可以通过注册表或使用组策略来为多个系统配置转录。

通过注册表或脚本启用转录

配置 PowerShell 转录时,使用以下注册表项:

HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription

例如,要启用转录,使用调用头并设置C:\tmp输出文件夹,你需要将以下值配置到注册表键中:

  • [REG_DWORD]EnableTranscripting = 1

  • [REG_DWORD]EnableInvocationHeader = 1

  • [REG_SZ]OutputDirectory =** **C:\tmp

要管理多个机器,使用 GPO 更为方便,但在某些情况下,有些机器不属于 Active Directory 域,因此无法管理。对于本示例,我将Enable-PSTranscription函数添加到本书的 GitHub 存储库中:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter04/Enable-PSTranscription.ps1

Enable-PSTranscription函数加载到当前会话中,并指定转录文件应保存的文件夹,例如以下示例:

> Enable-PSTranscription -OutputDirectory "C:\PSLogs"

如果未指定-OutputDirectory,脚本将默认将转录写入C:\ProgramData\WindowsPowerShell\Transcripts

此函数仅配置所有已定义的值,并覆盖现有的注册表键。你可以根据需要调整此函数并重新使用它。

一旦新的会话启动,转录内容将被写入到配置的文件夹中。

使用组策略启用转录

在 Active Directory 管理的环境中,配置转录的最简单方法是使用组策略。

创建一个新的 GPO 或重用现有的 GPO。然后,导航至计算机配置 | 策略 | 管理模板 | **Windows 组件 | **Windows PowerShell

双击并打开启用 PowerShell 转录策略来配置 PowerShell 转录:

图 4.8 – 启用 PowerShell 转录

图 4.8 – 启用 PowerShell 转录

将策略设置为启用,并选择是否包含转录输出目录和调用头。如果未指定输出目录,转录内容将保存在当前用户的我的文档文件夹中(%userprofile%\Documents)。

为 PowerShell 远程会话启用转录

自定义端点是为 PowerShell 远程会话应用默认设置的绝佳方式。如果已经配置了转录,它将默认启用本地会话,但在足够的管理权限中额外配置它,可以在用于远程会话时按端点分组并收集日志。通过在自定义端点上配置转录和其他设置,您可以强制执行这些设置,以确保所有连接到该端点的远程会话都符合一致性和合规性要求。

要开始使用,请创建一个会话配置文件,使用New-PSSessionConfigurationFile cmdlet,并通过-TranscriptDirectory参数指定转录内容应该写入的目录:

> New-PSSessionConfigurationFile -Path "$env:userprofile\Documents\PSSession.pssc" -TranscriptDirectory "C:\tmp"

该命令创建一个新的会话配置文件,强制启用转录,并将其存储在%userprofile%\Documents\PSSession.pssc路径下,该路径是通过-Path参数定义的。

图 4.9 – 新创建的会话配置

图 4.9 – 新创建的会话配置

我们在第三章《探索 PowerShell 远程管理技术和 PowerShell 远程控制》中介绍了自定义端点,接下来我们将在第十章《语言模式和适当的管理权限(JEA)》中深入探讨足够管理。要了解有关自定义端点和适当的管理权限的更多信息,请确保查看这两章内容。

PowerShell 转录的最佳实践

作为安全最佳实践,对每个用户使用会话转录本。这并不意味着你的管理员在你的机器上做坏事,需要进行监控。我并不鼓励对自己员工的信任产生怀疑。然而,凭证窃取是一个真实的威胁,如果管理员的身份被盗用并加以滥用,你会很高兴能了解对方做了什么。

如果你使用转录本,请确保它们无法被修改。如果它们可以被攻击者篡改,那么它们几乎没有任何作用。

所以,确保提供一个指向预配置文件夹的路径,并通过 GPO、手动配置或会话配置文件来指定它。禁止所有用户修改或删除该文件夹中的任何数据。本地系统账户需要读取和写入权限,因此确保根据需要配置访问权限。

最后,最重要的是,将所有的转录文件转发到一个中央日志服务器或你的 SIEM,以便定期分析它们。

将转录文件集中存储的一个有效方法是将其目标配置为**统一命名规范(UNC)**路径,并使用动态文件名。例如,你可以将转录目录设置为一个具有只写权限的网络共享,使用 PowerShell 配置文件将所有活动记录到一个具有唯一名称的文件中,如下所示:

\\server\share$\env:computername-$($env:userdomain)-$($env:username)-$(Get-Date Format YYYYMMddhhmmss).txt

同时,确保这个共享对普通用户不可读。通过使用这种方法,你可以轻松地从所有机器中收集并分析日志,集中存储,使你能够更好地检测和响应安全事件,而不需要建立整个日志基础设施。

除了收集日志之外,分析它们同样重要。在接下来的部分,我们将探讨用于日志分析的技术和工具。

分析事件日志

有几种方法可以使用 PowerShell 操作 Windows 事件日志。当然,你可以将事件日志转发到你选择的 SIEM,但有时你可能需要直接分析某台机器上的事件日志。在这种用例下,查看 PowerShell 提供的选项是有意义的。

如果你只是想分析事件或创建新事件,最简单的选择是使用*-WinEvent cmdlets,它们在 PowerShell Core 7 中仍然可用。你可以使用Get-Command查找所有可用的 cmdlet:

图 4.10 – 可用的 *-WinEvent cmdlets

图 4.10 – 可用的 *-WinEvent cmdlets

在 PowerShell 5.1 中,也可以使用 *-EventLog cmdlets,但它们在 PowerShell Core 6 及以上版本中被移除。由于 PowerShell 5.1 默认安装在所有 Windows 10 操作系统上,因此这里提到 *-EventLog。同样,使用Get-Command查找所有可用的 cmdlet:

图 4.11 – 可用的 *-EventLog cmdlets

图 4.11 – 可用的 *-EventLog cmdlets

第三个选项是使用 wevtutil。这个命令行可执行文件并不容易理解,但可以用来操作和分析事件日志。使用 /? 参数,你可以获取更多关于用法的详细信息。

图 4.12 – wevtutil.exe 使用方法

图 4.12 – wevtutil.exe 使用方法

例如,清除 Security 事件日志可以通过以下命令实现:

> wevtutil.exe cl Security

请参考官方文档以获取有关 wevtutil 的更多详细信息:docs.microsoft.com/de-de/windows-server/administration/windows-commands/wevtutil

查找系统中存在的日志

如果你想查找系统中存在的哪些事件日志,可以使用 -ListLog 参数,后面跟一个通配符(*****)– Get-WinEvent -ListLog *

图 4.13 – 列出所有事件日志

图 4.13 – 列出所有事件日志

你可能希望将输出传递给 Sort-Object 以按记录数、最大日志大小、日志模式或日志名称进行排序。

一般查询事件

要开始,先看看我们如何分析 PowerShell 审计的最常见场景。

使用 Get-WinEvent 命令,你可以从指定的事件日志中获取所有事件 ID – Get-WinEvent Microsoft-Windows-PowerShell/Operational

图 4.14 – 查询 Microsoft Windows PowerShell 操作日志

图 4.14 – 查询 Microsoft Windows PowerShell 操作日志

在这个例子中,你会看到 PowerShell 操作日志中生成的所有事件 ID。

如果你只想查询最近的 x 个事件,-MaxEvents 参数将帮助你完成此任务。例如,要查询 Security 事件日志中的最后 15 个事件,请使用 Get-WinEvent Security -MaxEvents 15

图 4.15 – 查询安全事件日志中的最后 15 个事件

图 4.15 – 查询安全事件日志中的最后 15 个事件

这对于你想要分析最近的事件而不查询整个事件日志时特别有帮助。

使用 -Oldest 参数可以反转顺序,以便你查看日志中的最旧事件 – Get-WinEvent Security -MaxEvents 15 -Oldest

图 4.16 – 安全事件日志中的 15 条最旧事件

图 4.16 – 安全事件日志中的 15 条最旧事件

要查找所有在 Microsoft Windows PowerShell 操作日志中执行并被 ScriptBlockLogging 记录的代码,可以筛选事件 ID 4104Get-WinEvent Microsoft-Windows-PowerShell/Operational | Where-Object { $_.Id -eq 4104 } | fl

图 4.17 – 查找所有执行并记录的代码

图 4.17 – 查找所有执行并记录的代码

你还可以根据消息部分中的特定关键字进行过滤。例如,要查找所有消息中包含 "logon" 字符串的事件,可以使用 -match 比较运算符 – Get-WinEvent Security | Where-Object { $_.Message -match "****logon" }

图 4.18 – 查找所有消息中包含“logon”的事件

图 4.18 – 查找所有消息中包含“logon”的事件

你还可以使用基于 XPath 的查询进行过滤,使用 -****FilterXPath 参数:

Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" -FilterXPath "*[System[(EventID=4100 or EventID=4101 or EventID=4102 or EventID=4103 or EventID=4104)]]"

输出结果如下所示:

图 4.19 – 使用 XPath 查询进行过滤

图 4.19 – 使用 XPath 查询进行过滤

还可以通过指定的 哈希表 进行过滤,使用 -****FilterHashtable 参数:

> $eventLog = @{ ProviderName="Microsoft-Windows-PowerShell"; Id = 4104 }

> Get-WinEvent -FilterHashtable $eventLog

使用哈希表可以显著减少对Where-Object过滤子句的使用。

如果你想查询复杂的事件结构,可以使用 -FilterXml 参数并提供 XML 字符串。我已经准备了这样的示例,并将其上传到本书的 GitHub 仓库:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter04/Get-AllPowerShellEvents.ps1

图 4.20 – 使用 Get-AllPowerShellEvents.ps1 脚本

图 4.20 – 使用 Get-AllPowerShellEvents.ps1 脚本

这个示例查询了 Microsoft-Windows-PowerShell/OperationalPowerShellCore/OperationalWindows PowerShell 事件日志,并检索了我将在本章的 基本 PowerShell 事件日志 部分中描述的所有事件。

现在你已经知道如何处理事件日志并查询事件,接下来让我们看看如何检测和分析系统上运行了哪个代码。

系统上运行了哪个代码?

如果你决定手动执行此任务,过滤并滚动浏览所有包含已执行代码的事件可能是一项繁琐的工作。但是,幸运的是,PowerShell 允许你自动化此任务并快速找到你需要的内容。

一般来说,所有包含已记录代码的事件可以在 Microsoft Windows PowerShell 或 PowerShell Core 操作日志中找到,事件 ID 为 4104

> Get-WinEvent Microsoft-Windows-PowerShell/Operational | Where-Object Id -eq 4104
> Get-WinEvent PowerShellCore/Operational | Where-Object Id -eq 4104

为了更好地查找和过滤执行的代码,我编写了 Get-ExecutedCode 函数,你可以在本书的 GitHub 仓库中找到它:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter04/Get-ExecutedCode.ps1

降级攻击

由于 5.1 及以上版本引入了许多新的安全功能,较旧的 PowerShell 版本,如 2.0,变得对攻击者更具吸引力。因此,攻击者常用的一种手段就是所谓的降级攻击

可以通过在运行 powershell.exe 时指定版本号来执行降级攻击:

> powershell.exe -version 2 –command <command>

如果指定的版本已安装,命令将运行,使用的是已弃用的二进制文件,这意味着只有该版本编写时存在的安全功能才会生效。

所有运行 Windows 7 及以上版本的机器至少安装了 PowerShell 2.0 版本。虽然 Windows 7 已不再获得支持,也不再接收安全更新,但它仍然广泛使用。

此外,PowerShell 2.0 仍然依赖于.NET Framework 2.0,该版本不包含先进的安全功能,也没有高级日志记录功能。因此,这对那些不希望任何人知道他们在系统上做了什么的攻击者来说非常适用。

.NET Framework 2.0 默认不包括在 Windows 10 中,但可以手动安装——例如,由攻击者或管理员安装。在 Windows 10 之前的操作系统中,.NET Framework 2.0 是默认安装的。

在 Windows 8 上,可以通过在提升权限的控制台中运行以下命令来禁用 PowerShell 2.0:

Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root

运行 PowerShell 2.0 所需的 .NET Framework 2.0 默认不会安装在如 Windows 10 这样的较新系统上。

所以,如果你尝试运行powershell.exe -version 2,你会收到一个错误信息,提示缺少 .NET Framework 2.0 版本:

> powershell.exe -version 2
Version v2.0.50727 of the .NET Framework is not installed and it is required to run version 2 of Windows PowerShell.

由于 .NET Framework 2.0 可以手动安装——无论是系统管理员还是攻击者——请确保检查 PowerShell 2.0 版本并将其禁用。

运行以下命令检查 PowerShell 2.0 是否已启用或禁用:

> Get-WindowsOptionalFeature -Online | Where-Object {$_.FeatureName -match "PowerShellv2"}
FeatureName : MicrosoftWindowsPowerShellV2Root
State       : Enabled
FeatureName : MicrosoftWindowsPowerShellV2
State       : Enabled

所以,看起来 PowerShell 2.0 仍然在这台机器上启用。因此,如果缺少的 .NET Framework 2.0 被安装,那么该系统将容易受到降级攻击。

因此,让我们通过运行以下命令来禁用 PowerShell 2.0,从而加强系统安全:

Get-WindowsOptionalFeature -Online | Where-Object {$_.FeatureName -match "PowerShellv2"} | ForEach-Object {Disable-WindowsOptionalFeature -Online -FeatureName $_.FeatureName -Remove}

你会在输出中看到需要重启,所以在你重启电脑后,修改会生效,PowerShell 2.0 将被禁用:

> Get-WindowsOptionalFeature -Online | Where-Object {$_.FeatureName -match "PowerShellv2"} | ForEach-Object {Disable-WindowsOptionalFeature -Online -FeatureName $_.FeatureName -Remove}
Path          :
Online        : True
RestartNeeded : False
Path          :
Online        : True
RestartNeeded : False

所以,如果你再验证一次,你会看到状态被设置为禁用

> Get-WindowsOptionalFeature -Online | Where-Object {$_.FeatureName -match "PowerShellv2"}
FeatureName : MicrosoftWindowsPowerShellV2Root
State       : Disabled
FeatureName : MicrosoftWindowsPowerShellV2
State       : Disabled

然而,在 Windows 7 上,无法禁用 PowerShell 2.0。唯一不允许使用 PowerShell 2.0 的方式是利用应用程序控制AppLocker,我们将在第十一章中讨论,AppLocker、应用程序控制和 代码签名

对于对手而言,还有另一种运行降级攻击的方法 - 例如,如果编译的应用程序利用旧版本的 PowerShell,并链接到编译的 PowerShell v2 二进制文件,攻击者可以通过利用该应用程序发起降级攻击。因此,每当此应用程序运行时,PowerShell v2 也处于活动状态,如果攻击者设法利用该应用程序,则可以使用它。

在这种情况下,禁用 PowerShell 2.0 可以帮助防止此类攻击,方法是阻止全局程序集缓存(GAC)中的不推荐的二进制文件,或者完全移除 PowerShell 组件。然而,重要的是要注意,依赖这些二进制文件的其他应用程序也将被阻止,因为它们通常不会随所有 PowerShell 二进制文件一起发布。

通常,降级攻击是一个非常关键的问题,因此,您应该对其进行监控。您可以通过监控 Windows PowerShell 事件日志中的事件 ID 400 来执行此操作 - 如果指定版本低于 [Version] "5",则应进一步进行调查。

李·霍姆斯(Lee Holmes)曾是微软 Windows PowerShell 团队的一员,他在他的博客文章检测和防止 PowerShell 降级攻击中提供了一个很好的例子,通过查找 PowerShell 事件日志中的事件 ID 400 来监控潜在的降级攻击:www.leeholmes.com/detecting-and-preventing-powershell-downgrade-attacks/

使用此示例查找加载较低版本的 PowerShell 引擎的情况:

Get-WinEvent -LogName "Windows PowerShell" | Where-Object Id -eq 400 | Foreach-Object {
        $version = [Version] ($_.Message -replace '(?s).*EngineVersion=([\d\.]+)*.*','$1')
        if($version -lt ([Version] "5.0")) { $_ }
}

EventList

在我在微软担任高级现场工程师期间,我与许多刚刚从零开始建立 SOC 的客户合作过。这些客户不仅希望设置日志事件转发,还向我询问加固其 Windows 环境的最佳实践。

谈到加固 Windows 环境时,您不能忽视微软安全与合规工具包SCT):www.microsoft.com/en-us/download/details.aspx?id=55319

我将在稍后的第六章Active Directory – Attacks and Mitigation以及第十三章What Else? – Further Mitigations and Resources中更详细地讨论工具包的某些部分。总的来说,此工具包包含几个工具,用于比较和验证您的配置,以及所谓的基线

这些基线旨在提供加固指导 - 这些设置对您的安全姿态非常重要,以及监控配置

毫无疑问,您不应仅仅强制执行这些基线而没有一个结构化的计划,并了解您正在配置的设置的影响。

如果为某台计算机配置了基线,由于监控配置的帮助,新的事件将会生成在安全事件日志中。

当我与客户合作时,我总是建议在一个结构良好的计划之后应用 Microsoft 安全基线。

有一次,我在客户现场,刚刚建议他们应该应用 Microsoft 安全基线,以便查看更多事件 ID。在推荐应用这些基线后,客户问我是否有概览来查看启用特定基线后会生成哪些额外的事件 ID,比如Windows 2016 域控制器基线

我只知道一个文档,他们可以利用它自行查找相关信息,那就是Windows 10 和 Windows Server 2016 安全审计与监控 参考资料www.microsoft.com/en-us/download/details.aspx?id=52630

尽管本文档提供了关于所有高级审计策略配置项的惊人详细信息,涵盖了 754 页,但内容相当广泛。

所以,客户并不乐意研究这个庞大的文档,并要求我写下如果他们应用该基线会生成哪些事件。我并不喜欢这样的令人头昏的工作,但我开始为这个基线写下所有的事件。

正在进行时,客户走近我,意识到他们不仅有一种,而是多种基线需要在他们的环境中应用。而且,这些不仅是域控制器基线,还有适用于成员服务器和各种操作系统客户端计算机的基线。所以,他们让我列出所有现有基线的事件 ID。

正如你能想象的那样,我并不特别兴奋于这个新任务。这看起来像是一个非常枯燥且令人疲惫的工作,可能需要多年才能完成。

因此,我考虑到需要自动化基线与事件 ID 的匹配,这也就是我的开源工具EventList诞生的背景。

尽管最初它只是一个包含 Visual Basic 宏的 Excel 文档,但它在这期间变成了一个庞大的项目,背后有着庞大的数据库支持。

图 4.21 – EventList 标志

图 4.21 – EventList 标志

每当我需要处理事件 ID 时,我的 EventList 数据库就成了我唯一的可靠数据源,而且它还在不断增长。

使用 EventList 进行工作

要开始使用,EventList 可以轻松地从 PowerShell Gallery 安装:

> Install-Module EventList

EventList 是用 PowerShell 构建的;因此,即使你只想使用用户界面,也需要运行至少一个 PowerShell 命令。以管理员身份打开 PowerShell 控制台,并输入以下内容:

> Open-EventListGUI

按下Enter键进行确认。几秒钟后,EventList UI 出现。

图 4.22 – EventList 用户界面

图 4.22 – EventList 用户界面

在左上角,您可以选择现有基线并查看在 UI 中填充的MITRE ATT&CK技术和领域。因此,您可以直接查看应用某个基线时涵盖的 MITRE ATT&CK 技术。

您还有可能性导入您自己的基线或导出的 GPO 并删除现有的基线。

一旦您选择了一个基线并填写了 MITRE ATT&CK 复选框,请选择生成 事件列表

图 4.23 - EventList - 显示基线事件

图 4.23 - EventList - 显示基线事件

弹出窗口将打开,您可以选择是否仅为基线事件生成 EventList 或所有 MITRE ATT&CK 事件。

要查看应用某个基线时会生成哪些事件 ID,请选择仅基线事件。确认选择确定以查看您选择的基线/GPO 的 EventList。

图 4.24 - 生成的 EventList

图 4.24 - 生成的 EventList

生成了一个 EventList,在其中您可以看到应用此基线时将生成的每个事件 ID,以及(如果有的话)指向文档的链接以及关于是否应监视此事件的建议。

如果选中导出为 CSV,则可以选择输出保存的位置,并生成一个.csv文件。

由于高级审计日志,微软安全基线主要依赖于基线功能,EventList 在理解和揭示高级审计日志方面提供了很大帮助。

您可以通过在 CLI 上使用以下命令来实现相同的效果:

> Get-BaselineEventList -BaselineName "MSFT Windows Server 2019 - Domain Controller"

需要将基线导入 EventList 数据库,因此在使用Get-BaselineNameFromDB功能验证基线名称时,请确保显示基线名称。

当然,您还可以选择不同的 MITRE ATT&CK 技术和领域,并生成一个 EventList,查看哪些事件 ID 涵盖特定的 MITRE ATT&CK 领域。生成一个 EventList,选择所有 MITRE ATT&CK 事件,然后确认选择确定

弹出窗口将打开,您可以看到与所选 MITRE ATT&CK 技术相关联的所有事件 ID。

图 4.25 - MITRE ATT&CK EventList

图 4.25 - MITRE ATT&CK EventList

再次强调,这可以通过将基线或 MITRE ATT&CK 技术编号传递给Get-MitreEventList功能,使用-Identity参数来实现:

> Get-MitreEventList -Identity "T1039"

下图显示了命令的输出。

图 4.26 - Get-MitreEventList 功能也可以通过命令行运行

图 4.26 - Get-MitreEventList 功能也可以通过命令行运行

当然,EventList 提供了更多的功能。它还提供了生成适用于您自己用例的所有事件 ID 的转发代理片段的可能性。您还可以生成支持您自己用例的自己的 GPO 和查询。

然而,功能太多,无法在本书中详细描述。如果你有兴趣深入了解 EventList,请务必阅读该项目在 GitHub 上的文档,文档地址会在本节结尾提到。一些专家还发现手动查询 EventList 背后的数据库非常有用。

我编写了 EventList,以帮助全球的 SOC 理解需要监控的内容,并简化他们的事件 ID 转发。

我在不断改进 EventList,所以如果你想了解更多,欢迎下载并测试它。你可以从我的 GitHub 仓库 (github.com/miriamxyra/EventList) 下载并安装,或者从 PowerShell Gallery 安装:

> Install-Module EventList -Force

为了更全面地了解 EventList 的功能,我建议阅读文档和帮助文件,并观看我关于它的一些讲座录音:

如果你有任何关于 EventList 的改进建议,我很乐意听到更多,并期待你在 GitHub 上的 Pull Request 或通过 Twitter 或电子邮件与我联系。

开始日志记录

为了提高你的检测能力,建议设置一个 SIEM 系统来收集事件,这样你就能将所有事件日志集中在一个地方,方便你进行追踪并构建自动化告警。

如果你想选择一个 SIEM 系统,选择非常多——适应各种预算和场景。多年来,我见过许多不同的 SIEM 系统,每一个都非常适合各自的组织。

我见过的最流行的 SIEM 系统包括SplunkAzure SentinelArcSightqRadar和**“ELK 堆栈” (Elastic, LogStash, 和 Kibana),仅举几例。我还使用过Windows 事件转发**(WEF) 来实现事件日志监控。

当然,也可以分析本地机器上的事件,但这并不实际——根据配置,如果达到最大日志大小,旧事件会被删除,且很难将其与其他系统的日志相关联。

在本章中,我们还将直接在机器上(或如果你愿意也可以远程)分析事件,但对于实际的生产环境,我建议使用 SIEM 系统——只是确保它适合你的用例再开始使用。

重要的 PowerShell 相关日志文件概述

在我们开始之前,你可能希望配置所有你想要转发到 SIEM 或中央日志服务器的日志。

本节将概述我认为在 PowerShell 日志记录方面重要的所有日志。

基本 PowerShell 事件日志

在使用 PowerShell 时,有三个事件日志是我们关注的重点——Windows PowerShell 日志Microsoft Windows PowerShell 操作日志PowerShellCore 操作日志。我们将在以下小节中讨论每个日志。

Windows PowerShell 日志

Windows PowerShell 一直以来都非常注重安全性和日志记录,甚至在最早的版本中也是如此。实际上,与其他 shell 或脚本语言相比,PowerShell 的早期版本在安全日志记录方面已经具有显著更好的功能。然而,随着时间的推移,PowerShell 语言不断发展,其日志记录功能也得到了极大的扩展,如今提供了更为强大的日志记录能力。

尽管早期版本没有提供您今天在 PowerShell 版本中所知道的安全日志记录功能,但自从版本 1 起,当发生重要引擎事件时,Windows PowerShell 就会将事件写入Windows PowerShell 事件日志。当时,PowerShell 仅提供基本的日志记录功能,这些功能在当前的操作系统中仍然可用,如下所示:

  • 完整名称:Windows PowerShell

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Windows PowerShell.evtx

  • UI 中的路径:**应用程序和服务 | **Windows PowerShell

在这些事件日志中,最有趣的事件 ID 包括以下几种:

  • 事件 ID 200(警告):命令健康。

查找主机应用程序以获取有关执行命令的更多详细信息。

  • 事件 ID 400引擎状态从无 变为可用。

这个事件可能是最有趣的事件,因为它表明引擎何时启动,以及使用的是哪个版本。此事件对于识别和终止过时的 PowerShell 版本(监控HostVersion 小于 5.0)非常理想——并且通常用于降级攻击(有关更多信息,请参见检测降级攻击部分)。

  • 事件 ID 800命令行的管道执行详情 – *<命令行命令>*。**

尽管事件 ID 800 提供了包含 cmdlet 的命令行执行的详细信息,但它不包括其他可执行文件的信息,如wmic。为了获得更多详细信息,监视来自Microsoft Windows PowerShell 操作日志的事件 ID 41034104 可能更有用。

Microsoft Windows PowerShell 操作日志包含有关 PowerShell 使用的所有相关信息——例如,模块日志记录脚本块日志记录事件都会写入此日志。

Microsoft Windows PowerShell 操作日志

从 Windows Vista 开始,微软引入了一种新的日志记录系统,称为 ETW。作为这一变化的一部分,Microsoft Windows PowerShell 操作日志 被引入,包含了一系列事件 ID,如 41004103(尽管配置它们可能很具挑战性),以及 4096140862 等与 PowerShell 远程日志相关的事件 ID。

随着 KB3000850 的发布,像 模块日志记录脚本块日志记录转录 等高级审计功能可以移植到 PowerShell 版本 4(Windows Server 2012 R2 和 Windows 8.1)。随后,在 PowerShell 版本 5(Windows Server 2016 和 Windows 10)中,这些功能默认启用。

随着这些新的审计功能的引入,也有新的事件类型被加入,比如事件 ID 410441054106,它们为你提供了更高级的日志记录功能:

  • 完整 名称Microsoft-Windows-Powershell/Operational

  • 日志 路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-PowerShell%4Operational.evtx

  • UI 中的路径:**应用程序和服务 | **Microsoft** | **Windows** | **PowerShell** | **Operational

此事件日志中最有趣的事件 ID如下:

  • 事件 ID 4103执行管道/命令调用。如果启用了 PowerShell 模块日志记录,则会生成此事件

  • 事件 ID 4104创建 脚本块文本

如果启用了 ScriptBlockLogging,则会生成此事件。常见的恶意活动,如加载恶意模块或执行可疑命令,都会被记录,无论是否启用 ScriptBlockLogging

  • 事件 ID 4105ScriptBlock_Invoke_Start_Detail(消息:已启动/完成一个脚本块的调用)

如果启用了 ScriptBlockLogging,则会生成此事件。这记录了开始/停止事件。它非常嘈杂,未必适用于安全监控。

  • 事件 ID 4106ScriptBlock_Invoke_Complete_Detail(消息:已启动/完成一个脚本块的调用)

如果启用了 ScriptBlockLogging,则会生成此事件。这记录了开始/停止事件。它非常嘈杂,未必适用于安全监控。

  • 事件 ID 40961PowerShell 控制台正在 启动

该事件表示 PowerShell 控制台已打开。特别是通过此事件监控用户的异常行为(例如,如果 PowerShell 控制台是由不应登录此系统的用户执行,或者是由系统账户执行的)。

  • 事件 ID 40962PowerShell 控制台已准备好接收 用户输入

该事件表示 PowerShell 控制台已启动,并且现在已准备好接收用户输入。特别是通过此事件监控用户的异常行为(例如,如果 PowerShell 控制台是由不应登录此系统的用户执行,或者是由系统账户执行的)。

要筛选特定的事件 ID,可以将Get-WinEvent的输出通过管道传递给Where-Object

> Get-WinEvent Microsoft-Windows-PowerShell/Operational | Where-Object Id -eq 4104

在此示例中,您将获取所有事件 ID 为4104的事件,这表示已创建脚本块。

PowerShellCore 操作日志

当 PowerShell Core 被引入时,PowerShellCore 操作日志也随之推出。它提供了 PowerShell Core 事件日志的高级审计功能:

  • 完整名称PowerShellCore/Operational

  • 日志路径%SystemRoot%\System32\Winevt\Logs\PowerShellCore%4Operational.evtx

  • UI 路径应用程序和服务| **PowerShellCore** |操作日志

记录在此日志文件中的事件 ID 与记录在 Microsoft Windows PowerShell 操作日志中的事件 ID 相同。请参考前面部分的事件 ID。

Windows 远程管理 (WinRM) 日志

Microsoft Windows WinRM 操作日志记录了进出 WinRM 的连接。由于 PowerShell 依赖 WinRM 进行远程管理,因此你也可以在此事件日志中找到 PowerShell 远程连接。因此,监控和分析该日志中的事件 ID 是非常重要的。

  • 完整名称Microsoft-Windows-WinRM/Operational

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-WinRM%4Operational.evtx

  • UI 路径应用程序和服务| **Microsoft** | **Windows** |Windows 远程管理 | 操作日志

在使用 PowerShell 和 WinRM 时,以下是最值得关注的事件,它们通常会出现在 WinRM 事件日志中。

  • 事件 ID 6创建一个 WSMan 会话。

每当建立远程连接时,都会记录此事件。它还包含用户名、目标地址和使用的 PowerShell 版本。

  • 事件 ID 81处理来自客户端的 CreateShell 操作请求或处理来自客户端的 DeleteShell 操作请求。

  • 事件 ID 82:**为 CreateShell 操作进入插件,资源 URI 为 **<http://schemas.microsoft.com/powershell/Microsoft.PowerShell>

  • 事件 ID 134 CreateShell 操作发送响应。

  • 事件 ID 169用户*<domain>\<user>*使用 NTLM 身份验证成功登录。

可以使用Get-WinEvent Microsoft-Windows-WinRM/Operational查询 WinRM 日志中的所有事件。

安全性

安全性事件日志不仅与 PowerShell 相关,还帮助关联事件,如登录/注销和身份验证。

  • 完整名称安全性

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Security.evtx

  • UI 路径Windows 日志 | 安全性

虽然并非所有的安全日志中的事件 ID 都是默认生成的,但最重要的事件 ID 旨在帮助识别安全问题。如果您想实现全面的安全日志记录,我建议将 Microsoft 安全工具包中的 Microsoft 安全基准应用到您的系统中。然而,重要的是要注意,安全基准中的设置应与您组织的资源和能力相匹配。因此,在应用基准之前,建议评估哪些日志设置适合您组织的需求和能力。

您可以在此下载Microsoft 安全工具包www.microsoft.com/en-us/download/details.aspx?id=55319

此事件日志中的事件 ID 是一些最重要的安全监控事件。虽然并非所有事件 ID 都特定于 PowerShell,但它们仍然对维护安全环境至关重要。以下是此事件日志中最有趣的事件 ID

  • 事件 ID 4657注册表值 已修改

  • 事件 ID 4688新进程已创建。请查找“新进程名称”中包含 powershell.exe 的进程。您可以使用创建者进程 ID 来链接哪个进程启动了哪些 其他进程。

  • 事件 ID 1100事件日志服务已 关闭。

  • 事件 ID 1102审核日志 已清除。

  • 事件 ID 1104安全日志 已满。

  • 事件 ID 4624账户已成功 登录。

  • 事件 ID 4625账户登录失败。

安全日志内容丰富,包含大量重要的事件 ID。仅仅覆盖安全日志就可以写成一本完整的书;因此,这个列表并不完整,我这里只列出了与 PowerShell 相关的一些最重要的事件 ID。

然而,哪些安全事件 ID 重要的问题让我失眠了很多个夜晚,因此我开发了一个名为EventList的开源工具。如果你想了解哪些事件 ID 重要,可以查看本章中的转发和分析事件日志 – EventList部分。

系统

在系统日志中,会生成许多与系统相关的日志 ID:

  • 全名系统

  • 日志 路径%SystemRoot%\System32\Winevt\Logs\System.evtx

  • UI 中的路径Windows 日志 | 系统

在此事件日志中,最有趣的事件 ID 如下:

  • 事件 ID 104日志*<name>*已清除。 此事件表明名为 的事件日志已被清除,可能表示攻击者试图隐藏痕迹。特别使用此事件 ID 监控日志名为 “Windows PowerShell," “PowerShell Operational,"“PowerShellCore” 的日志,以检测与 PowerShell 相关的事件日志清除。

根据你监控的内容,在此日志中有许多有趣的事件——例如,每次安装的详细信息。

Windows Defender

从 Windows 10 和 Windows Server 2016 起,默认启用了 Windows Defender 日志,并提供了许多有用的事件。例如,它还包含与恶意软件扫描接口AMSI)相关的事件,AMSI 是 Windows Defender 的一部分:

  • 完整名称Microsoft-Windows-Windows Defender/Operational

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-Windows Defender%4Operational.evtx

  • UI 中的路径应用程序和服务| **Microsoft** | **Windows** | **Windows Defender** |操作日志

此事件日志中关于 PowerShell 安全日志记录的最有趣的事件 ID如下:

  • 事件 ID 1116Microsoft Defender Antivirus 已检测到恶意软件或其他潜在的 不需要的软件。

  • 事件 ID 1117Microsoft Defender Antivirus 已采取措施保护此计算机免受恶意软件或其他潜在的 不需要的软件的影响。

如果在你的机器上使用了 Microsoft Defender,你会在此事件日志中找到更多与 Defender 相关的有趣事件。你可以使用以下参考资料了解更多关于每个 Microsoft Defender 相关事件 ID 的信息:learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/troubleshoot-microsoft-defender-antivirus

我们将在第十二章中更详细地了解 AMSI,探索恶意软件扫描接口AMSI)。

Windows Defender 应用控制与 AppLocker

Windows Defender 应用控制WDAC)和AppLocker可用于允许列应用程序,以限制组织内允许使用的软件。两种解决方案都有助于防止未经授权的软件使用。

我们将在第十一章中更详细地了解 WDAC 和 AppLocker,AppLocker、应用控制和 代码签名

启用允许列表解决方案时,审计是第一步,因此,分析与 WDAC 和 AppLocker 相关的事件 ID 对于此过程至关重要。

Windows Defender 应用控制(WDAC)

WDAC 是微软最新的允许列表解决方案,随着 Windows 10 推出,并且之前被称为设备保护(Device Guard)。除了允许列应用程序外,WDAC 还可用于在 Windows 机器上强制实施代码完整性策略。

WDAC 有两个主要的事件日志——一个名为MSI 和脚本的事件日志与 AppLocker 共享,另一个事件日志用于记录代码完整性相关的事件。

代码完整性

  • 完整名称Microsoft-Windows-CodeIntegrity/Operational

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-CodeIntegrity%4Operational.evtx

  • 界面路径:**应用程序和服务日志 | **Microsoft** | **Windows** | **CodeIntegrity** | **Operational

PowerShell 安全日志中这个事件日志最有趣的事件 ID如下:

  • 事件 ID 3001未签名的驱动程序尝试在系统上加载。

  • 事件 ID 3023验证中的驱动程序文件未满足通过应用程序 控制策略的要求。

  • 事件 ID 3033验证中的文件未满足通过应用程序 控制策略的要求。

  • 事件 ID 3034如果执行了应用程序控制策略,验证中的文件未满足通过该策略的要求。由于该策略处于审核模式,文件被允许。

  • 事件 ID 3064如果应用程序控制策略已执行,验证中的用户模式 DLL 未满足通过应用程序控制策略的要求。由于该策略处于审核模式,DLL 被允许运行。

  • 事件 ID 3065如果应用程序控制策略已执行,验证中的用户模式 DLL 未满足通过应用程序 控制策略的要求。

  • 事件 ID 3076此事件是审核模式策略的主要应用程序控制阻止事件。它表明,如果执行策略,该文件将被阻止。

  • 事件 ID 3077此事件是执行策略的主要应用程序控制阻止事件。它表示该文件未通过你的策略并被 阻止。

你可以使用 Get-WinEvent Microsoft-Windows-CodeIntegrity/Operational 查询 WDAC 日志中的所有事件。监视和分析这些事件可以帮助识别潜在的安全漏洞,并改善系统的整体安全态势。

MSI** 和脚本**

所有与 Microsoft 安装程序和脚本相关的事件 ID 都可以在此事件日志中找到:

  • 完整名称Microsoft-Windows-AppLocker/MSI** 和脚本**

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-AppLocker%4MSI** 和脚本.evtx**

  • 界面路径应用程序和服务日志| **Microsoft** | **Windows** | **Applocker** | **MSI**和脚本

PowerShell 安全日志中最有趣的事件 ID如下:

  • 事件 ID 8028* 被允许运行,但如果执行了配置 CI 策略,则将被阻止。**

  • 事件 ID 8029* 由于配置 CI 策略,未能运行。**

  • 事件 ID 8036* 由于配置 CI 策略,未能运行。**

  • 事件 ID 8037* 通过了配置 CI 策略并被允许 运行。**

如果你想了解更多关于应用控制的事件 ID,可以查看 AppLocker 部分以及以下文档:learn.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/event-id-explanations

AppLocker

说到 AppLocker,根据使用场景的不同,你可能需要查看四个事件日志文件——EXE 和 DLLMSI 和脚本打包应用-部署,和 打包应用-执行

在 UI 中,你可以在相同的路径下找到所有四个日志——只需将 <日志名称> 替换为每个事件日志的名称,如下所示:

UI 中的路径应用程序和服务| **Microsoft** | **Windows** | **AppLocker** |<日志名称>

以下是每个与 AppLocker 相关的事件日志的完整名称和路径(请注意,必须启用审计才能显示这些事件日志):

  • EXE** 和 DLL**

所有与执行二进制文件(EXE)和 DLL 相关的事件 ID 都可以在此事件日志中找到:

  • 完整名称Microsoft-Windows-AppLocker/EXE** 和 DLL**

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-AppLocker%4EXE** 和 DLL.evtx**

  • MSI** 和脚本**

所有与 Microsoft Installer 和脚本相关的事件 ID 都可以在此事件日志中找到:

  • 完整名称Microsoft-Windows-AppLocker/MSI** 和脚本**

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-AppLocker%4MSI** 和脚本.evtx**

  • 打包应用-部署

如果部署了打包应用,你可以在此事件日志中找到所有相关的事件 ID:

  • 完整名称Microsoft-Windows-AppLocker/Packaged app-Deployment

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-AppLocker%4Packaged app-Deployment.evtx

  • 打包应用-执行

所有与打包应用执行相关的事件 ID 可以在此事件日志中找到。

  • 完整名称Microsoft-Windows-AppLocker/Packaged app-Execution

  • 日志路径%SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-AppLocker%4Packaged app-Execution.evtx

对于 PowerShell 安全日志记录而言,这些事件日志中最有趣的事件 ID 如下:

  • 事件 ID 8000(错误):*应用身份策略转换失败。状态 <%1> 这表示策略未正确应用于计算机。状态消息用于 故障排除目的。

  • 事件 ID 8001(信息)AppLocker 策略已成功应用于此计算机。这表示 AppLocker 策略已成功应用于 该计算机。

  • 事件 ID 8002(信息)<文件名> 被允许运行。这表示该 .exe 或 .dll 文件被 AppLocker 规则允许。

  • 事件 ID 8003 (警告)<文件名> 被允许运行,但如果启用了 AppLocker 策略,则会被阻止运行。仅在启用了“仅审核”执行模式时应用。它指定,如果启用了强制规则执行模式,则该 .exe 或 .dll 文件将被阻止运行。

  • 事件 ID 8004 (错误)<文件名> 未被允许运行。访问 <文件名> 被管理员限制。这仅在强制规则执行模式直接或通过组策略继承间接设置时应用。该 .exe 或 .dll 文件 无法运行。

  • 事件 ID 8005 (信息)<文件名> 被允许运行。这表示该脚本或 .msi 文件被 AppLocker 规则允许运行。

  • 事件 ID 8006 (警告)<文件名> 被允许运行,但如果启用了 AppLocker 策略,则会被阻止运行。仅在启用了“仅审核”执行模式时应用。它指定,如果启用了强制规则执行模式,则该脚本或 .msi 文件将被阻止运行。

  • 事件 ID 8007 (错误)<文件名> 未被允许运行。访问 <文件名> 被管理员限制。这仅在强制规则执行模式直接或通过组策略继承间接设置时应用。该脚本或 .msi 文件 无法运行。

  • 事件 ID 8008 (错误)AppLocker 在此 SKU 中被禁用。此功能在 Windows Server 2012 和 Windows 8 中添加。

如果你有兴趣了解更多关于 AppLocker 事件 ID 的信息,请参考以下链接:learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/applocker/using-event-viewer-with-applocker

当然,还有许多其他有趣的日志文件,例如 防火墙DSC。提到并描述所有这些文件会超出本书的内容,因此我只在涉及 PowerShell 安全时提到了其中一些最有趣的日志文件。

增加日志文件大小

每生成一个事件,日志文件就会增长。由于数千个事件可以在非常短的时间内写入,因此增加日志文件的最大大小非常有用——尤其是当你也希望在本地分析事件时。

当然,始终建议将日志转发到中央日志库,以确保日志不会丢失。但是,如果你希望在本地分析事件,增加日志文件大小也很有帮助。

Limit-EventLog cmdlet 可以帮助你在 Windows PowerShell 中完成此任务:

> Limit-EventLog -LogName "Windows PowerShell" -MaximumSize 4194240KB

此命令将 PowerShell 日志的最大大小设置为 4 GB。请注意,"MB" 和 "GB" 前缀也可以在此 cmdlet 中使用。

设置事件日志的最大大小时,重要的是要记住,事件日志条目的大小可能会有所不同,这取决于特定的事件日志和启用的事件数量。看看在你的环境中,一个事件通常占用多少空间。首先,你需要获取事件日志的日志大小。以下命令返回 KB 中 Windows PowerShell 事件日志的最大大小:

>Get-ItemProperty -Path  'HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Windows PowerShell\' -Name 'MaxSize' | Select-Object -ExpandProperty MaxSize

然后,将其除以条目的数量。这样你就可以计算出事件日志的预估大小,以及在事件日志被轮换之前,它应该能容纳多少个事件。

如果你使用的是 PowerShell 7,Limit-EventLog cmdlet 是不可用的。相反,你需要通过使用 New-ItemProperty 来修改注册表:

> New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Windows PowerShell\' -Name 'MaxSize' -Value 4000MB -PropertyType DWORD -Force

使用 Limit-EventLog 命令,你还可以指定当事件日志已满时的行为:docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/limit-eventlog

总结

在本章中,你学习了如何开始使用 PowerShell 的安全日志记录。你现在知道哪些事件日志是需要关注的,以及应该查找哪些事件 ID。由于安全监控是一个庞大的主题,你仅学习了如何开始和继续的基础知识。

你学习了如何为 Windows PowerShell 和 PowerShell Core 配置 PowerShell 模块日志记录、脚本块日志记录和 PowerShell 转录——无论是手动配置还是集中配置。

另一个重要的学习点是日志事件可能会被篡改,你可以通过使用受保护的事件日志来实施一定程度的保护。

最终,最好的做法是将你的日志事件转发到一个集中的 SIEM 系统,但如果这不可行,你也学会了如何使用 PowerShell 分析事件。

现在你已经获得了一些示例脚本和代码片段,你准备好调查客户端和服务器上的所有 PowerShell 活动了。

最后,如果你想更深入地了解安全监控,EventList 可以帮助你找出哪些事件是值得监控的。

当我们谈论审计、检测和监控时;本地系统也不可忽视。让我们深入探讨系统,并看看 Windows 注册表、Windows API、COM、CIM/WMI,及如何在不运行 powershell.exe 的情况下运行 PowerShell,下一章会介绍这些内容。

深入阅读

如果你想探索本章中提到的一些主题,可以参考以下资源:

你也可以在本章的 GitHub 仓库中找到所有提到的链接,无需手动输入每个链接:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter04/Links.md

第二部分:深入挖掘 – 身份、系统访问和日常安全任务

让我们深入探讨并将 PowerShell 与其他技术结合起来。本部分的技术章节主要探讨攻击者如何枚举、绕过、劫持和危及关键组件,如操作系统本身、Active Directory 以及 Azure AD/Entra ID。2023 年 7 月 11 日,微软将 Azure AD 更名为 Entra ID。由于这一变化在本书发布前刚刚宣布,因此在本部分我们将仅称其为 Azure Active Directory、Azure AD 或 AAD。本部分不仅对红队成员感兴趣,对蓝队成员同样重要,因为他们希望了解敌手如何试图滥用这些已建立的解决方案,以保护自己免受此类攻击。此外,你还将获得大量关于概念、协议、缓解措施以及更多有趣见解的实用信息。

我们将首先探讨 PowerShell 访问系统的能力:我们不仅会研究如何使用注册表和 WMI,还会了解如何利用 .NET 以及原生 Windows API,以及如何从 PowerShell 编译和运行自定义 DLL 和非托管代码。曾经想过如何在不调用 powershell.exe 的情况下运行 PowerShell 吗?别担心——通过本部分的学习,你将知道答案。

在 Active Directory 章节中,我们将深入探讨枚举——无论是否使用 Active Directory PowerShell 模块——以及访问权限、认证协议、凭证窃取和缓解策略。我们还将研究推荐的微软安全基线和安全合规工具包。

说到 Active Directory,Azure AD 自然也在其中;因此,我们还将从 PowerShell 安全的角度来研究这项技术。Azure AD 安全并不是一个广为人知的话题,在本章中,你将学习如何区分 Active Directory 和 Azure AD 以及 Azure AD 的基本概念。你将了解哪些帐户和角色是攻击者的有用目标,并且如何枚举 Azure AD。最后,我们将探讨几种凭证窃取技术,并讨论如何进行缓解。

第八章第九章 中,本书还为你提供了红队和蓝队的操作手册。两部分首先探讨了常见的 PowerShell 工具及其应用,然后提供了许多实用的 PowerShell 代码片段,你可以根据自己的需求使用这些片段——无论你是红队还是蓝队成员。

本部分包括以下章节:

  • 第五章PowerShell 强大 – 系统和 API 访问

  • 第六章Active Directory – 攻击与缓解

  • 第七章黑客入侵云端 – 利用 Azure Active Directory/Entra ID

  • 第八章红队任务与手册

  • 第九章蓝队任务与手册