面向网络安全的 Powershell 自动化和脚本编程(五)
原文:
annas-archive.org/md5/497778742979feec5fa142fe450d7d89译者:飞龙
第九章:蓝队任务与食谱
作为蓝队成员,你的主要目标是保护组织的系统和网络免受网络威胁。然而,这不是一项简单的任务。威胁环境不断变化,你可能面临一些挑战,如管理和分析大量数据、与其他团队协调以及确保遵守规定。
本章中,我们首先将更详细地探讨保护、检测和响应方法及蓝队员面临的一些挑战。接下来,我们将介绍一些有用的 PowerShell 开源工具概览,这些工具可以帮助你作为蓝队员在日常工作中提高效率。最后,我们将探讨蓝队食谱——这是一些 PowerShell 代码片段的集合,可以在你作为蓝队从业者的日常工作中派上用场。
在本章中,我们将讨论以下主题:
-
理解保护、检测和响应方法
-
常见的 PowerShell 蓝队工具
-
蓝队食谱
技术要求
为了最大化地从本章中获益,请确保你具备以下条件:
-
Windows PowerShell 5.1
-
PowerShell 7.3 或更高版本
-
Visual Studio Code
-
访问本章的 GitHub 仓库:
保护、检测和响应
成为一个蓝队成员并非易事。你需要不断跟进不断变化的威胁环境,并保持最新状态。尽管红队员只需要找到一个漏洞就能成功,但蓝队员则需要注意所有细节,因为一个小小的错误就可能导致你的网络遭到入侵。
蓝队员不仅需要配置和管理他们的系统,还需要分析大量数据并与其他团队协调。他们还需要确保遵守相关的规定和标准。在做这些工作的同时,他们需要保持安全性与可用性之间的正确平衡,确保用户不会因过多的安全措施而感到困扰,并试图绕过它们。
为了帮助跟踪需要考虑的所有事项,将任务分类为保护、检测和响应类型会有所帮助。这是保护组织系统和网络的一种方法,结构分为三个不同的领域——保护、检测和响应。每个支柱都同样重要,以确保你的基础设施安全。
图 9.1 – 保护、检测和响应方法
许多公司仅关注保护部分,尽管检测和响应同样对保持敌人远离网络至关重要。
让我们在接下来的小节中深入探讨每个领域的内容。
保护
保护措施的目标是减轻安全风险并实施控制,以减少和阻止威胁的发生,在它们发生之前。保护措施可能包括以下内容:
-
定期更新系统并监控它们,以修复可能被攻击者利用的漏洞。
-
实施用户身份验证和授权,确保只有授权用户才能访问数据和系统。同时也需要遵循最小权限原则。
-
加密敏感数据,以减少未经授权用户访问的风险。加密硬盘,以防止具有物理访问权限的人盗取凭证,甚至在设备被盗时发生数据泄露。
-
实施安全策略、基准和访问控制,以确保系统尽可能安全地配置。同时还需要引入强密码策略。
-
部署防火墙和入侵检测系统(IDSs)/入侵防御系统(IPSs),以阻止未经授权的活动并检测可疑活动。
当然,保护机制也可能有第二个目的,例如 IDS 或 IPS,它不仅能阻止可疑活动,还能检测并提醒你这些活动。因此,这种解决方案也可以是检测领域的一部分。
检测
在检测阶段,目标是尽快识别和报告潜在的安全威胁。你可以做各种事情来改善你的检测能力,例如:
-
收集和分析关于潜在安全漏洞的事件日志,如失败的登录尝试或配置更改。
-
监控网络活动中的异常和可疑行为,例如用户登录到他们通常从未登录过的机器,或者尝试访问受限资源。另一个例子是,如果从通常不运行代码的工作站(如会计或市场部门的员工)执行了 PowerShell(或其他)代码。
-
评估来自杀毒软件和 IDSs/IPSs 的安全警报。
-
定期扫描你的网络漏洞,以识别可能被对手利用的潜在弱点。同时,定期聘请外部渗透测试人员检查你的安全性。
实施良好的检测措施将有助于提高你对网络中发生的事件的意识。这使你能够在响应阶段对潜在的安全威胁作出反应。
响应
如果检测到安全威胁,意味着你需要迅速采取行动,以减少风险并将系统恢复到安全状态。这可能涉及多种活动,例如:
-
隔离受损的系统,以防止进一步的损害和威胁在环境内传播。
-
从受影响的系统中收集法医数据并进行分析。这有助于识别攻击来源并确定损害的程度。它还可以帮助减轻未来的威胁。
-
恢复系统至安全状态,这可能涉及根据 NIST 网络安全框架(NIST CSF)指南修复或重新安装系统:
www.nist.gov/cyberframework/framework
- 实施额外的安全控制措施,以防止未来类似的威胁。
这三大支柱共同构建了保护、检测和响应的生命周期,应该始终平等重视。
也有许多开源工具可以支持蓝队成员采用保护、检测和响应的方法。在接下来的章节中,我们将探讨其中一些工具。
常见的 PowerShell 蓝队工具
作为蓝队成员,你时刻在寻找能够帮助你保护组织系统和网络免受网络威胁的工具和技术。
在本节中,我们将探索一些常见的 PowerShell 开源工具,这些工具对蓝队成员特别有帮助。这些工具可以协助执行诸如分析系统日志、收集系统信息和检测恶意活动等任务。有些工具还可以帮助分析系统的攻击面、识别和解码潜在的恶意数据,以及搜索入侵指示符。通过利用这些工具,你可以简化工作流程,更有效地保护组织免受网络威胁。
PSGumshoe
PSGumshoe 是一个强大的 PowerShell 模块,旨在协助执行实时响应、追踪和取证等任务。由 Carlos Perez 开发,这个开源工具专为蓝队成员设计,帮助他们从各种来源收集证据。无论你是在调查安全事件、进行入侵指示符(IOC)的搜寻,还是执行取证分析,PSGumshoe 都可以成为你工具箱中的一个宝贵资产。它还包括支持从 Sysmon 生成的事件中检索数据,或跟踪 Windows Management Instrumentation(WMI)活动的功能。
你可以通过 PowerShell Gallery 使用 Install-Module PSGumshoe 命令安装 PSGumshoe,或者从 GitHub 下载: github.com/PSGumshoe/PSGumshoe。
PowerShellArsenal
PowerShellArsenal 是 Matt Graeber 开发的 PowerShell 模块,旨在帮助逆向工程师完成多种任务。凭借其广泛的功能和能力,这个工具可以帮助你反汇编代码、执行 .NET 恶意软件分析、分析和解析内存结构等等。无论你是经验丰富的逆向工程师,还是刚刚入门,PowerShellArsenal 都能成为你工具箱中的有力助手。
它可以作为模块从 GitHub 下载并安装: github.com/mattifestation/PowerShellArsenal。
AtomicTestHarnesses
AtomicTestHarnesses 是一个 PowerShell 模块,允许你模拟和验证攻击技术的执行。它具有适用于 Windows 的 PowerShell 组件,以及适用于 macOS 和 Linux 的 Python 组件,可以跨平台使用。
AtomicTestHarnesses 由 Mike Haag、Jesse Brown、Matt Graeber、Jonathan Johnson 和 Jared Atkinson 开发,是蓝队成员在测试防御并确保能够应对现实攻击时的宝贵资源。
你可以通过 Install-Module -Name AtomicTestHarnesses 命令从 PowerShell gallery 安装 AtomicTestHarnesses,或者通过以下链接从 GitHub 下载:github.com/redcanaryco/AtomicTestHarnesses。
PowerForensics
PowerForensics 是由 Jared Atkinson 开发的强大硬盘取证框架。目前支持 NTFS(新技术文件系统)和 FAT(文件分配表)文件系统,该工具旨在协助分析 Windows 遗留物、Windows 注册表、引导扇区和应用程序兼容性缓存等任务,并能够创建取证时间线。
PowerForensics 具备广泛的功能和能力,是蓝队成员进行硬盘取证分析的重要资源。你可以通过 Install-Module PowerForensics 命令从 PowerShell gallery 安装 PowerForensics,或者通过以下链接从 GitHub 下载:github.com/Invoke-IR/PowerForensics。
NtObjectManager
NtObjectManager 是一个广泛的 PowerShell 模块,允许你访问 NT 对象管理器命名空间。它是沙盒攻击面分析工具包的一部分(这个工具包也绝对值得一看!),由 James Forshaw 开发。对象管理器本身是 Windows 中的一个子系统,负责管理系统的对象,这些对象代表着各种系统资源,如进程、线程、文件和设备。
对象管理器还负责创建和删除对象,以及维护对象之间的关系。它还处理对象访问请求,确保只有授权实体能够访问特定对象。对象管理器是操作系统的一个重要组成部分,涉及系统操作的多个方面,包括内存管理、进程和线程管理以及 I/O 操作。
NTObjectManager 模块提供了多种功能,包括处理符号链接、审计 RPC 服务器、操作对象管理器,以及通常操作 Windows 操作系统。
NtObjectManager 可以通过 Install-Module -Name NtObjectManager 命令轻松安装,源代码可以在 GitHub 上找到,链接为:github.com/googleprojectzero/sandbox-attacksurface-analysis-tools。
DSInternals
DSInternals 是由 Michael Grafnetter 开发的强大 Active Directory 套件,包含两个部分——一个框架,暴露了 Active Directory 的各种内部组件,可以从任何 .NET 应用程序中访问;另一个是 PowerShell 模块,提供了一系列基于该框架构建的 cmdlet。该模块功能广泛,包括能够审计 Azure AD FIDO2 密钥、AD 密码和密钥凭证,并执行域控制器的裸机恢复。
DSInternals 可以通过 Install-Module DSInternals 命令轻松安装,或者通过以下 GitHub 链接下载:github.com/MichaelGrafnetter/DSInternals。
凭借其众多特性和功能,DSInternals 是蓝队员管理和保护其 Active Directory 环境的重要资源。
PSScriptAnalyzer 和 InjectionHunter
PSScriptAnalyzer 是一款帮助你提高 PowerShell 脚本和模块质量与安全性的工具。它会根据预定义规则检查你的代码,并为发现的潜在缺陷提供建议。你可以使用 Install-Module PSScriptAnalyzer 命令安装 PSScriptAnalyzer,或者通过以下 GitHub 链接下载:github.com/PowerShell/PSScriptAnalyzer。
InjectionHunter 是由 Lee Holmes 开发的一个模块,帮助你检测自己 PowerShell 脚本中潜在的代码注入机会。要使用 InjectionHunter,你需要先安装 PSScriptAnalyzer,因为它依赖于 ScriptAnalyzer.Generic.DiagnosticRecord 输出类型并使用自定义检测规则。你可以通过 Install-Module InjectionHunter 命令安装 InjectionHunter,或者在 PowerShell Gallery 中找到它,链接为:www.powershellgallery.com/packages/InjectionHunter/1.0.0。
另请参考关于 InjectionHunter 的官方博客文章:devblogs.microsoft.com/powershell/powershell-injection-hunter-security-auditing-for-powershell-scripts/。
在 第十三章 还有什么?——更多缓解措施和资源 中,我们还将更深入地了解这两个工具以及如何使用它们。
Revoke-Obfuscation
Revoke-Obfuscation是由 Daniel Bohannon 和 Lee Holmes 开发的 PowerShell 混淆检测框架。它兼容 PowerShell v3 及更高版本,帮助蓝队员大规模检测混淆的 PowerShell 脚本和命令。与依赖简单妥协指示器(IOCs)或正则表达式匹配的其他解决方案不同,Revoke-Obfuscation 使用 PowerShell 的抽象语法树(AST)从脚本中提取特征,使其在检测未知混淆技术时更加可靠。
你可以通过Install-Module Revoke-Obfuscation命令轻松安装 Revoke-Obfuscation,或者你也可以通过以下 GitHub 链接下载:github.com/danielbohannon/Revoke-Obfuscation。
Posh-VirusTotal
作为防御者,定期检查文件、域名、IP 和 URL 以发现恶意软件是至关重要的。VirusTotal(www.virustotal.com)是一个常用服务,允许你快速检查文件哈希或 URL 是否被认为是恶意的,并且它是否会被一个或多个安全厂商检测到。然而,手动上传每个文件或逐个检查 URL 可能会耗时且繁琐。
这就是 PowerShell 模块Posh-VirusTotal的作用所在。由 Carlos Perez 开发,这个工具可以自动化你的 VirusTotal 提交,节省你宝贵的时间。它兼容 PowerShell v3 及更高版本,并且可以使用 VirusTotal 提供的公共或私有版本 2 API。
你可以通过Install-Module Posh-VirusTotal命令轻松安装 Posh-VirusTotal,或者你也可以通过以下 GitHub 链接下载:github.com/darkoperato…
如果你使用的是较旧版本的 PowerShell(如 v3),你也可以使用iex (New-Object** **Net.WebClient).DownloadString("https://gist.githubusercontent.com/darkoperator/9138373/raw/22fb97c07a21139a398c2a3d6ca7e3e710e476bc/PoshVTInstall.ps1")命令来安装 Posh-VirusTotal。
使用 Posh-VirusTotal,你可以简化恶意软件检查,并走在威胁的前面。
EventList
EventList是我开发的一个有用工具,旨在帮助你提升审计能力,构建一个更有效的安全运营中心(SOC)。EventList 结合了 Microsoft 的安全基准和 MITRE ATT&CK,能够帮助你为 SIEM 系统生成猎杀查询,无论你使用的是哪个产品。
通过利用 EventList 的强大功能,你可以采取主动的方式来检测和应对安全威胁。
它可以通过Install-Module EventList命令安装,或者从 GitHub 下载:github.com/miriamxyra/EventList。
JEAnalyzer
Just Enough Administration(JEA)是一个强大的工具,用于保护管理员和用户在您的环境中允许使用的 PowerShell 命令。然而,配置和审计 JEA 角色可能是一项繁琐且耗时的任务。这就是 JEAnalyzer 派上用场的地方。
由 Miriam Wiesner 和 Friedrich Weinmann 开发,这个工具简化了 JEA 的实现和管理,并提供了扫描命令潜在危险的工具,当命令暴露在 JEA 端点时,可以轻松创建 JEA 端点。
您可以通过Install-Module JEAnalyzer命令轻松安装 JEAnalyzer,或者您可以从 GitHub 下载它,链接如下:github.com/PSSecTools/…
所有这些 PowerShell 模块对蓝队员非常有用,因为它们可以帮助执行诸如实时响应、猎杀、取证和逆向工程等任务。这些工具可以通过分析系统日志、收集系统信息、检测恶意活动、分析攻击面、识别并解码潜在的恶意数据、寻找妥协的指标以及许多其他用例,帮助简化工作流程并防御网络威胁。
蓝队菜谱
在以下小节中,您将找到一些对蓝队 PowerShell 从业者日常工作很有帮助的代码片段。蓝队工作范围广泛,因此您不会找到每个场景的用例,而是一些基础的用法。
此外,参阅第八章,红队任务和菜谱,您将在那里找到许多红队代码片段和脚本,这些内容有时也对蓝队员有帮助。
检查已安装的更新
您想要找出一个或多个远程系统上已安装的更新。
解决方案
您可以使用Get-InstalledUpdates.ps1脚本扫描 IP 范围内已安装的 Windows 更新。您可以在本章的 GitHub 仓库中找到此脚本:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter09/Get-InstalledUpdates.ps1。
使用此示例扫描172.29.0.10-20 IP 范围内已安装的更新:
> .\Get-InstalledUpdates.ps1 -BaseIP "172.29.0" -MinIP 10 -MaxIP 20 -Verbose
-MinIP表示最小的最后一个 IP 地址八位组,而-MaxIP表示最大的最后一个 IP 地址八位组。启用-Verbose参数会使脚本显示其操作的详细输出。还可以使用-MaxJobs参数定义可以并行运行多少个任务来检查更新。
检查缺失的更新
您想要找出一个或多个远程主机上缺少的更新。
解决方案
你可以使用 Scan-RemoteUpdates.ps1 脚本检查缺失的 Windows 更新——可以在本地主机上检查,也可以在一个或多个远程主机上检查。你可以在本章的 GitHub 仓库中找到这个脚本:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter09/Scan-RemoteUpdates.ps1。
仅扫描本地主机的方法如下:
> .\Scan-RemoteUpdates.ps1
扫描多个远程主机的方法如下:
> .\Scan-RemoteUpdates.ps1 -remoteHosts "PSSec-PC01", "PSSec-PC02", "PSSec-Srv01"
如果指定了 -Force 参数,wsusscn2.cab 文件(如果存在)将会被删除,并下载新版本。使用 -CabPath 参数来指定 wsusscn2.cab 文件的下载位置。如果未指定,它将被下载到 $env:temp\wsusscn2.cab。如果存在 -DoNotDeleteCabFile,则在检查后 wsusscn2.cab 文件不会被删除。
查看所有用户的 PowerShell 历史记录
在事件响应期间,你希望查看系统上所有用户的 PowerShell 历史记录。
解决方案
Get-History cmdlet 仅会获取当前 shell 的历史记录,这并不太有帮助。要查看每个用户的整个 PowerShell 历史记录,你可以遍历系统中的 ConsoleHost_history.txt 文件:
$UserHistory = @(Get-ChildItem "C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt").FullName;
$UserHistory += @(Get-ChildItem "c:\windows\system32\config\systemprofile\appdata\roaming\microsoft\windows\powershell\psreadline\consolehost_history.txt" -ErrorAction SilentlyContinue).FullName;
foreach ($Item in $UserHistory) {
if ($Item) {
Write-Output ""
Write-Output "###############################################################################################################################"
Write-Output "PowerShell history: $item"
Write-Output "###############################################################################################################################"
Get-Content $Item
}
}
在这个示例中,你将遍历所有用户的 ConsoleHost_history.txt 文件,以及系统配置文件(如果可用)。
检查远程主机的事件日志
你想检查远程主机的事件日志并搜索特定的模式。
解决方案
你可以使用 Get-WinEvent 获取(远程)主机上的所有事件,并筛选特定的模式。请注意,为了使 Get-WinEvent cmdlet 能够远程工作,远程主机上需要运行 RemoteRegistry 服务:
$ComputerName = "PSSec-PC01.PSSec.local"
$EventLog = "Microsoft-Windows-Powershell/Operational"
$LogEntries = Get-WinEvent -LogName $EventLog -ComputerName $ComputerName
$LogEntries | Where-Object Id -eq 4104 | Where-Object Message -like "*Mimikatz*"
使用这个示例,你将连接到远程主机 PSSec-PC01.PSSec.local,并检索 Microsoft-Windows-Powershell/Operational 事件日志中的所有事件,将它们保存到 $LogEntries 变量中。这样你可以通过操作变量,而不必每次都远程连接来快速处理事件。
使用 $LogEntries 变量,你可以筛选特定的事件或字符串。在这个例子中,我们筛选了事件 ID 为 4104 的事件,这些事件的消息体中包含 "Mimikatz" 字符串。通配符 * 表示在搜索词 "Mimikatz" 前后可能会有其他字符。
请注意,如果你想查询 PowerShell Core 日志,您需要将$EventLog变量更改为"PowerShellCore/Operational"。
PowerShell 远程访问与 -ComputerName 参数
值得一提的是,PowerShell 远程执行可以用来远程执行任何 cmdlet,无论该 cmdlet 是否有-ComputerName参数。这在-ComputerName参数因 DCOM 端口关闭或其他原因无法使用的情况下尤其有用。例如,要从远程计算机检索日志条目,你可以使用以下命令:– Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-WinEvent -LogName $EventLog | Where-Object Id -eq 4104 | Where-Object Message -like "****Mimikatz" }。
你还可以通过使用foreach循环来评估多个远程主机,如以下示例所示:
$ComputerNames = @("DC01", "PSSec-PC01", "PSSec-PC02", "PSSec-Srv01")
$EventLog = "Microsoft-Windows-Powershell/Operational"
$LogEntries = foreach ($Computer in $ComputerNames) {
Get-WinEvent -LogName $EventLog -ComputerName $Computer -ErrorAction SilentlyContinue
}
$LogEntries | Group-Object -Property MachineName
$LogEntries | Where-Object {($_.Id -eq 4104) -and ($_.Message -like "*Mimikatz*")} | Select-Object -Property TimeCreated, MachineName, Id, LevelDisplayName, Message | ft
你可以评估使用$LogEntries变量收集的事件。要概览从哪些主机收集了多少事件,你可以使用Group-Object并按MachineName分组。
监控以绕过 powershell.exe
你希望监控没有使用powershell.exe二进制文件的 PowerShell 执行。
解决方案
要在不使用powershell.exe二进制文件的情况下监控 PowerShell 的执行,有两种解决方案。第一种方案是使用 Windows PowerShell 事件日志,并查找400事件 ID:
> Get-WinEvent -LogName "Windows PowerShell" | Where-Object Id -eq 400 | Where-Object Message -notmatch "HostApplication.*powershell.exe" | fl Message,TimeCreated
由于有许多合法的理由需要在没有powershell.exe二进制文件的情况下执行 PowerShell,你可能需要根据你的环境调整这个查询。在一台常规的 Windows 10 客户端系统上,其中也使用了 PowerShell ISE,以下代码片段可能会有帮助:
> Get-WinEvent -LogName "Windows PowerShell" | Where-Object Id -eq 400 | Where-Object { ($_.Message -notmatch "HostApplication.*powershell.exe") -and ($_.Message -notmatch "HostApplication.*PowerShell_ISE.exe") -and ($_.Message -notmatch "HostApplication.*sdiagnhost.exe") } | fl Message,TimeCreated
对于第二种方案,你需要在所有你想要检测powershell.exe二进制文件绕过的系统上安装 Sysmon。Sysmon 是 Sysinternals 工具包的一部分,可以在这里下载:learn.microsoft.com/en-us/sysinternals/downloads/sysmon。
一旦 Sysmon 安装并配置完毕,你将需要通过 Sysmon 的事件 ID 7,"**加载的镜像"**,查找以下 DLL 文件:
-
System.Management.Automation.dll -
System.Management.Automation.ni.dll
现在,你可以搜索潜在的powershell.exe二进制文件绕过,如以下示例所示:
$ComputerName = "PSSec-PC01.PSSec.local"
$EventLog = "Microsoft-Windows-Sysmon/Operational"
$LogEntries = Get-WinEvent -LogName $EventLog -ComputerName $ComputerName
$LogEntries | Where-Object Id -eq 7 | Where-Object (($_.Message -like "*System.Management.Automation*") -or ($_.Message -like "*System.Reflection*"))
如果你已经部署了一个可以帮助你检测类似事件的 EDR 系统,那么你当然不需要 Sysmon 来检测 PowerShell .NET 程序集的调用。
获取特定的防火墙规则
你想使用 PowerShell 过滤特定的防火墙规则。
解决方案
你可以获取所有防火墙规则,并使用Get-NetFirewallRule cmdlet 过滤特定规则:
> Get-NetFirewallRule -<parameter> <value>
使用Get-NetFirewallRule有许多参数过滤选项。例如,要获取所有启用的防火墙规则,这些规则的方向是入站并且是允许规则,可以使用以下命令:
> Get-NetFirewallRule -Direction Inbound -Enabled True -Action Allow
您还可以使用Get-NetFirewallProfile cmdlet,结合Get-NetFirewallRule,来检索为特定防火墙配置文件创建的所有防火墙规则。通过以下示例,您可以获取为Public防火墙配置文件创建的所有防火墙规则:
> Get-NetFirewallProfile -Name Public | Get-NetFirewallRule
仅允许 PowerShell 通信通过私有 IP 地址范围
您希望限制 PowerShell 通信仅在您自己的网络内进行,并避免 PowerShell 与潜在的 C2 服务器进行通信。
解决方案
使用New-NetFirewallRule创建新的防火墙规则,只允许 PowerShell 通信通过私有 IP 地址范围。
以下示例创建了一个新的防火墙规则,名为Block Outbound PowerShell connections,它限制 Windows PowerShell 仅能与本地网络中的 IP 地址建立连接:
> New-NetFirewallRule -DisplayName "Block Outbound PowerShell connections" -Enabled True -Direction Outbound -Action Block -Profile Any -Program "%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -RemoteAddress "Internet"
使用此示例并根据需要进行调整。由于大多数组织仍然将 Windows PowerShell 作为默认的 PowerShell 实例,因此此示例也参考了 Windows PowerShell。如果您使用 PowerShell Core 作为默认的 PowerShell 实例,您可能需要调整程序的路径。
隔离被攻破的系统
您希望隔离一个已被攻破的系统。
解决方案
您可以使用New-NetFirewallRule和Disable-NetAdapter cmdlet 来实现。以下代码片段演示了如何远程隔离设备。首先,它向所有当前登录到PSSec-PC01的用户发送消息,然后它远程创建防火墙规则,阻止所有进出连接,并禁用所有网络适配器:
$ComputerName = "PSSec-PC01"
msg * /server $ComputerName "Security issues were found on your computer. You are now disconnected from the internet. Please contact your helpdesk: +0012 3456789"
$session = Invoke-Command -ComputerName $ComputerName -InDisconnectedSession -ScriptBlock {
New-NetFirewallRule -DisplayName "Isolate from outbound traffic" -Direction Outbound -Action Block | Out-Null;
New-NetFirewallRule -DisplayName "Isolate from inbound traffic" -Direction Inbound -Action Block | Out-Null;
Get-NetAdapter|foreach { Disable-NetAdapter -Name $_.Name -Confirm:$false }
}
Remove-PSSession -Id $session.Id -ErrorAction SilentlyContinue
只需将PSSec-PC01替换为您选择的计算机名称,并且可以自由调整将发送给计算机用户的消息。
检查远程安装的软件
您希望查找远程 PC 上安装了哪些软件。
解决方案
您可以使用Get-CimInstance cmdlet 来查看远程 PC 上安装了哪些软件。
以下示例代码将允许您连接到名为PSSec-PC01的计算机,并查找它当前安装了哪些软件:
$ComputerName = "PSSec-PC01"
Get-CimInstance -ClassName Win32_Product -ComputerName $ComputerName | Sort-Object Name
启动转录
您希望启用肩膀上方的转录功能,以跟踪 PowerShell 会话中的操作。
解决方案
在您希望跟踪 PowerShell 会话中发生的事情的机器上启用转录。这可以通过通过组策略启用转录来实现,方法是配置开启 PowerShell 转录选项,路径为Windows 组件 | **管理模板 | **Windows PowerShell,或者通过 PowerShell 配置注册表来实现,如博客文章PowerShell ♥ the Blue Team 中所示:devblogs.microsoft.com/powershell/powershell-the-blue-team/
以下代码片段展示了Enable-PSTranscription功能,源自本文:
function Enable-PSTranscription {
[CmdletBinding()]
param(
$OutputDirectory,
[Switch] $IncludeInvocationHeader
)
$basePath = "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription"
if (-not (Test-Path $basePath)) {$null = New-Item $basePath -Force}
Set-ItemProperty $basePath -Name EnableTranscripting -Value 1
if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("OutputDirectory")) {Set-ItemProperty $basePath -Name OutputDirectory -Value $OutputDirectory}
if ($IncludeInvocationHeader) {Set-ItemProperty $basePath -Name IncludeInvocationHeader -Value 1}
}
如果你使用此功能启用对 C:\tmp 文件夹的转录,语法如下:
> Enable-PSTranscription -OutputDirectory "C:\tmp\"
你还可以使用 通用命名约定(UNC) 路径将转录保存到网络文件夹。确保保护该路径,以防潜在的攻击者访问和/或删除它。
要集中管理 PowerShell 转录并保持安全的审计跟踪,你可以,例如,将转录目标配置为一个带有动态文件名的 UNC 路径。这涉及将转录目录设置为具有写入权限的网络共享,并使用 PowerShell 配置文件将所有活动记录到一个基于系统和用户变量的唯一文件名中,如下所示:
> Enable-PSTranscription -OutputDirectory "\\fileserver\Transcripts$\$env:computername-$($env:userdomain)-$($env:username)-$(Get-Date -Format 'YYYYMMddhhmmss').txt"
这将为每个用户和计算机组合创建一个唯一的转录文件,文件名中将包含当前日期和时间。通过将转录存储在具有受限访问权限的集中位置,可以确保所有活动都被记录,并在需要时可以进行审查和分析。
这将把所有转录写入指定的文件服务器位置,然后可以由授权人员进行访问,以便进行审查和分析。
检查过期证书
你需要检查证书存储中已经过期或将在未来 60 天内过期的 SSL 证书。
解决方案
你可以使用以下脚本检查证书存储中已经过期或将在未来 60 天内过期的 SSL 证书:
$certificates = Get-ChildItem -Path "Cert:\" -Recurse | Where-Object { $_.Subject -like "*CN=*"} | Where-Object { $_.Extensions | Where-Object { $_.Oid.Value -eq "2.5.29.37" } | Where-Object { $_.Critical -eq $false } }
$expiringCertificates = @()
foreach ($certificate in $certificates) {
if (($certificate.NotAfter) -and (($certificate.NotAfter -lt (Get-Date).AddDays(60)) -or ($certificate.NotAfter -lt (Get-Date)))) {
$expiringCertificates += $certificate
}
}
Write-Output "Expired or Expiring Certificates in the next 60 days:"
foreach ($expiringCertificate in $expiringCertificates) {
Write-Output $expiringCertificate | Select-Object Thumbprint, FriendlyName, Subject, NotBefore, NotAfter
}
你还可以修改路径 Cert:\LocalMachine\My 仅评估个人存储中的证书。对于 根 存储中的证书,请将路径更改为 Cert:\LocalMachine\Root。
检查文件或脚本的数字签名
你想通过检查数字签名来验证软件或脚本的真实性和完整性。
解决方案
你可以使用 Get-AuthenticodeSignature cmdlet 来检查数字签名的状态:
> Get-AuthenticodeSignature "C:\Windows\notepad.exe" | Format-List
使用 Get-AuthenticodeSignature,你可以获取有关数字签名的各种有用信息,例如证书链,下面的截图展示了这一点:
图 9.2 – 查询文件的数字签名信息
然而,如果你仅想查询状态,也可以使用 (Get-AuthenticodeSignature "****C:\Windows\notepad.exe").Status 命令。
检查文件和文件夹的权限
你想列举文件和文件夹的访问权限。
解决方案
要列举文件和文件夹的访问权限,你可以使用 Get-ChildItem 和 Get-Acl cmdlet。例如,要递归列举 Windows Defender 目录中的所有文件和文件夹,可以使用以下代码片段:
$directory = "C:\Program Files\Windows Defender"
$Acls = Get-ChildItem -Path $directory -Recurse | ForEach-Object {
$fileName = $_.FullName
(Get-Acl $_.FullName).Access | ForEach-Object {
[PSCustomObject]@{
FileName = $fileName
FileSystemRights = $_.FileSystemRights
AccessControlType = $_.AccessControlType
IdentityReference = $_.IdentityReference
IsInherited = $_.IsInherited
}
}
}
$Acls
如果你只想列举一级,请确保移除 -Recurse 参数。
显示所有正在运行的服务
你想显示所有正在运行的服务及其命令路径。
解决方案
尽管你可以使用Get-Service cmdlet 来显示所有正在运行的服务,你也可以使用Get-CimInstance来访问服务的 WMI 信息,并获得更多的信息,如命令路径或ProcessId:
> Get-CimInstance win32_service | Where-Object State -eq "Running" | Select-Object ProcessId, Name, DisplayName, PathName | Sort-Object Name | fl
停止服务
你想要停止一个正在运行的服务。
解决方案
要停止一个正在运行的服务,你可以使用Stop-Service cmdlet。以下示例展示了如何将Get-Service与Stop-Service结合使用,以停止maliciousService服务:
> Get-Service -Name "maliciousService" | Stop-Service -Force -Confirm:$false -verbose
请记住,如果你使用-Confirm:$false参数,确认提示将被绕过,命令将在没有任何进一步确认的情况下执行。建议在使用此参数时要小心,并且仅在你完全意识到潜在风险和后果的情况下使用。了解使用此参数的影响非常重要,并根据你的具体用例做出明智的决定。
显示所有进程
你想显示所有进程,包括它们的所有者和命令行。
解决方案
你可以使用Get-WmiObject win32_process来显示所有进程及其更多信息。要显示所有进程,包括它们的所有者和命令行,你可以使用以下代码片段:
> Get-WmiObject win32_process | Select ProcessID,Name,@{n='Owner';e={$_.GetOwner().User}},CommandLine | Sort-Object Name | ft -wrap -autosize
停止进程
你想要停止一个进程。
解决方案
要停止一个进程,你可以使用Stop-Process cmdlet。比如,要停止Id 8336的进程,你可以使用以下代码片段:
> Get-Process -Id 8336 | Stop-Process -Force -Confirm:$false -verbose
当然,你也可以通过Get-Process cmdlet 的-Name参数按名称选择一个进程来停止它。如果有多个同名进程,可能会停止多个进程。
请记住,如果你使用-Confirm:$false参数,确认提示将被绕过,命令将在没有任何进一步确认的情况下执行。建议在使用此参数时要小心,并且仅在你完全意识到潜在风险和后果的情况下使用。了解使用此参数的影响非常重要,并根据你的具体用例做出明智的决定。
禁用本地账户
你想禁用一个本地账户。
解决方案
要禁用本地账户,你可以使用Disable-LocalUser cmdlet。
提高 Windows 安全性的一种方法是创建一个具有管理员权限的新用户,并禁用默认的Administrator账户。这有助于防止通常针对默认账户进行的暴力破解攻击。为了实现这一点,你可以使用Disable-LocalUser cmdlet。
这是一个示例,展示了如何使用Disable-LocalUser cmdlet 禁用Administrator账户:
> Disable-LocalUser -Name "Administrator"
运行命令后,你可以使用Get-LocalUser cmdlet 来验证账户是否已被禁用:
> Get-LocalUser -Name "Administrator"
启用本地账户
你想启用一个本地账户。
解决方案
要启用本地账户,你可以使用Enable-LocalUser cmdlet。使用以下示例,Administrator账户将被启用:
> Enable-LocalUser -Name "Administrator"
使用Get-LocalUser cmdlet,你可以验证该账户是否已启用:
> Get-LocalUser -Name "Administrator"
禁用域账户
你想禁用一个域账户。
解决方案
要禁用域账户,你可以使用Disable-ADAccount cmdlet,它是ActiveDirectory模块的一部分。使用以下示例,vvega域账户将被禁用:
> Import-Module ActiveDirectory
> Disable-ADAccount -Identity "vvega"
使用Get-ADUser cmdlet,你可以验证该账户是否已禁用:
> (Get-ADUser -Identity vvega).enabled
启用域账户
你想启用一个域账户。
解决方案
要启用域账户,你可以使用Enable-ADAccount cmdlet,它是ActiveDirectory模块的一部分。使用以下示例,vvega域账户将被启用:
> Import-Module ActiveDirectory
> Enable-ADAccount -Identity "vvega"
使用Get-ADUser cmdlet,你可以验证该账户是否已禁用:
> (Get-ADUser -Identity vvega).enabled
获取所有最近创建的域用户
你想获取最近创建的所有域用户。
解决方案
要获取过去 30 天内创建的所有用户,你可以使用以下代码片段:
Import-Module ActiveDirectory
$timestamp = ((Get-Date).AddDays(-30)).Date
Get-ADUser -Filter {whenCreated -ge $timestamp} -Properties whenCreated | Sort-Object whenCreated -descending
检查特定端口是否开放
你想检查远程系统的特定端口是否开放。
解决方案
要检查特定端口是否开放,你可以使用以下代码片段;此示例检查计算机DC01上的端口445是否开放:
$result = Test-NetConnection -ComputerName DC01 -Port 445
$result
$result.TcpTestSucceeded
以下截图显示了前面代码片段的输出:
图 9.3 – 检查 DC01 上的 445 端口是否开放
这种方法是测试单个端口或极少数端口的好方法,因为Test-NetConnection cmdlet 在进行完整端口扫描时可能非常耗时。因此,如果你想扫描远程系统的所有端口,应该改用nmap。
显示 TCP 连接及其启动进程
你想显示所有 TCP 连接、启动进程,以及用于打开 TCP 连接的命令行。
解决方案
你可以使用Get-NetTCPConnection并通过使用Get-Process和Get-WmiObject作为Select-Object表达式来创建手动属性:
> Get-NetTCPConnection | Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort,State,@{Label = 'ProcessName';Expression={(Get-Process -Id $_.OwningProcess).Name}}, @{Label="CommandLine";Expression={(Get-WmiObject Win32_Process -filter "ProcessId = $($_.OwningProcess)").CommandLine}} | ft -Wrap -AutoSize
这个示例显示了所有 TCP 连接、当地地址和端口、远程地址和端口、连接状态、进程名称,以及启动连接的命令行。
显示 UDP 连接及其启动进程
你想显示所有 UDP 连接、启动进程,以及用于打开 UDP 连接的命令行。
解决方案
你可以使用Get-NetUDPConnection并通过使用Get-Process和Get-WmiObject作为Select-Object表达式来创建手动属性:
> Get-NetUDPEndpoint | Select-Object CreationTime,LocalAddress,LocalPort,@{Label = 'ProcessName';Expression={(Get-Process -Id $_.OwningProcess).Name}}, @{Label="CommandLine";Expression={(Get-WmiObject Win32_Process -filter "ProcessId = $($_.OwningProcess)").CommandLine}} | ft -Wrap -AutoSize
此示例展示了所有 UDP 连接、创建时间、地方地址和端口、进程名称以及执行命令行的连接初始化过程。
使用 Windows 事件日志搜索降级攻击
你希望使用 Windows 事件日志搜索过去的降级攻击。
解决方案
你可以使用以下代码片段,通过 Windows 事件日志搜索过去的降级攻击,这段代码最初由 Lee Holmes 编写:
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")) { $_ }
}
在 Windows PowerShell 事件日志中监控400事件 ID。如果EngineVersion低于5,你应该进一步调查,因为这可能表示降级攻击。
防止降级攻击
你希望防止降级攻击发生,因此使用Windows Defender 应用程序控制(WDAC)来禁用 PowerShell 版本 2 二进制文件。
解决方案
如果System.Management.Automation.dll和System.Management.Automation.ni.dll程序集被阻止,即使安装了.NET Framework 版本 2 并启用了 PowerShell 版本 2,PowerShell 版本 2 也无法加载。
使用以下代码片段查找二进制文件的位置并阻止它们,可以使用 WDAC 或你选择的其他应用程序控制软件:
> powershell -version 2 -noprofile -command "(Get-Item ([PSObject].Assembly.Location)).VersionInfo"
> powershell -version 2 -noprofile -command "(Get-Item (Get-Process -id $pid -mo | ? { $_.FileName -match 'System.Management.Automation.ni.dll' } | % { $_.FileName })).VersionInfo"
如果从前面的代码片段中删除-version 2,你会发现其他二进制文件被用于现代 PowerShell 版本。因此,如果你的系统依赖现代 PowerShell 版本,并且想要全局禁止 PowerShell 版本 2 二进制文件,你不必担心会破坏任何东西。
既然你已经找到了 PowerShell 二进制文件的位置,你可以使用 WDAC 来阻止这些旧版本。确保阻止本地映像以及**Microsoft 中间语言(****MSIL)**程序集。
请参考 Lee Holmes 的博客文章,了解更多关于检测和防止 PowerShell 降级攻击的信息:www.leeholmes.com/detecting-and-preventing-powershell-downgrade-attacks/。
总结
本章首先探讨了保护、检测和响应方法,强调了每个支柱的重要性及其在确保组织安全中的作用。
接着,我们提供了常用 PowerShell 工具的全面概述,这些工具对蓝队员防御组织免受安全威胁至关重要。
最后,探讨了蓝队手册,这是一个用于安全分析和防御的脚本和代码片段的集合。该手册涵盖了广泛的任务,包括检查更新、监控绕过、分析事件日志、进程、服务和网络连接。蓝队手册是信息安全从业人员的宝贵资源,提供了针对各种安全挑战的实用解决方案。
现在我们已经讨论了日常蓝队操作,让我们进一步探讨一些可以帮助你在使用 PowerShell 时保护环境的缓解选项。在下一章中,我们将深入探讨语言模式和最低权限 管理(JEA)。
进一步阅读
如果你想深入探讨本章提到的某些主题,可以参考以下资源:
-
蓝队笔记: github.com/Purp1eW0lf/…
-
蓝队员可能使用的 PowerShell 函数和脚本集合:
github.com/tobor88/PowerShell-Blue-Team -
通过远程过程调用(RPC)通过 SMB 使用 NtObjectManager 远程创建和启动 Windows 服务:
blog.openthreatresearch.com/ntobjectmanager_rpc_smb_scm -
检测和防止 PowerShell 降级攻击:
www.leeholmes.com/detecting-and-preventing-powershell-downgrade-attacks/ -
目录服务内部博客:
www.dsinternals.com/en/ -
调查 PowerShell 攻击:
www.fireeye.com/content/dam/fireeye-www/global/en/solutions/pdfs/wp-lazanciyan-investigating-powershell-attacks.pdf
)
-
PowerForensics - PowerShell 数字取证:
powerforensics.readthedocs.io/en/latest/ -
PowerShell ♥ 蓝队:
devblogs.microsoft.com/powershell/powershell-the-blue-team/ -
使用 AtomicTestHarnesses 测试对手技术变种:
redcanary.com/blog/introducing-atomictestharnesses/ -
使用 PSGumshoe 跟踪 WMI 活动:
www.darkoperator.com/blog/2022/3/27/tracking-wmi-activity-with-psgumshoe -
Windows 沙盒攻击面分析:
googleprojectzero.blogspot.com/2015/11/windows-sandbox-attack-surface-analysis.html
你还可以在 GitHub 仓库的第九章中找到本章提到的所有链接—无需手动输入每个链接:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter09/Links.md。
第三部分:保护 PowerShell—详细的有效缓解措施
在这一部分,我们将主要集中在帮助您高效保护环境的缓解措施上。然而,尽管我们将重点讲解大量蓝队内容,这一部分同样有助于红队成员了解缓解技术的工作原理,它们包含的风险,以及对手如何尝试开发绕过策略。
首先,我们将探索足够的管理(JEA),这是一个帮助将管理任务委派给非管理员用户的功能。虽然这个功能并不广为人知,但它可能是一个改变游戏规则的工具。在这一部分,我们将深入探讨 JEA 及其配置选项,并学习如何简化初始部署。
接下来,我们将探讨代码签名和应用程序控制。您将学习如何规划部署应用程序控制,并在整个过程中,我们将使用微软的应用程序控制解决方案 AppLocker 和Windows Defender 应用程序控制(WDAC)。您将熟悉这些解决方案的配置和审计方式。您还将了解到,当配置应用程序控制时,PowerShell 将会发生哪些变化。
深入了解反恶意软件扫描接口(AMSI)—了解它的工作原理以及它在对抗恶意软件中的重要性。我们还将探讨对手如何通过替代或混淆恶意代码来绕过这一有用功能。
许多其他功能可以帮助您降低环境中的风险;因此,在这一部分结束时,我们将简要介绍许多不同的功能,帮助您提高安全防护。我们将研究安全脚本编写、期望状态配置、系统和环境的加固策略,以及利用端点检测与响应(EDR)软件进行攻击检测。我们不会在最后一部分深入探讨,您完全可以进一步探索一些提到的功能,了解更多信息,并可能将其应用到您的环境中。
本部分包括以下章节:
-
第十章,语言模式与足够的管理(JEA)
-
第十一章,AppLocker、应用程序控制和代码签名
-
第十二章,探索反恶意软件扫描接口(AMSI)
-
第十三章,还有什么?—进一步的缓解措施与资源
第十章:语言模式和仅足够管理(JEA)
我们已经学习了 PowerShell 提供的出色日志记录和审计功能,探索了如何访问本地系统以及 Active Directory 和 Azure Active Directory。我们还查看了日常的红队和蓝队任务。在本书的这一部分,我们将更深入地探讨缓解功能以及 PowerShell 如何帮助你构建一个强大且更安全的环境。
我们将首先探讨语言模式,理解受限语言模式和仅足够管理(JEA)之间的区别。然后,我们将深入了解 JEA,并探索配置你自己的第一个 JEA 端点所需的内容。
你将学习角色能力和会话配置文件的作用,并学习如何在你的环境中部署 JEA。如果你手头有合适的工具,比如 JEAnalyzer,创建初始的 JEA 配置并不困难。
最后,你将理解如何在使用 JEA 时充分利用日志记录,并了解应该避免哪些风险命令或绕过方法,以强化你的 JEA 配置和环境。
在本章中,你将深入了解以下主题:
-
PowerShell 中的语言模式是什么?
-
理解 JEA
-
使用 JEAnalyzer 简化你的部署
-
在 JEA 会话中的日志记录
-
最佳实践—避免风险和可能的绕过
技术要求
为了最大化本章的学习效果,请确保你具备以下内容:
-
PowerShell 7.3 及以上版本
-
已安装 Visual Studio Code
-
访问第十章的 GitHub 仓库:
PowerShell 中的语言模式是什么?
PowerShell 中的语言模式决定了会话中允许使用哪些 PowerShell 元素。你可以通过运行$ExecutionContext.SessionState.LanguageMode来查看当前会话的语言模式——当然,这只有在你被允许运行该命令时才有效:
图 10.1 – 查询语言模式
在截图中显示的示例中,当前会话启用了完整语言模式。
有四种不同的语言模式可供选择,我们将在接下来的章节中更深入地探讨这些模式。
完整语言(FullLanguage)
完整语言模式是 PowerShell 的默认模式,所有命令和元素都被允许。
用户可能遇到的唯一限制是,如果他们没有足够的 Windows 权限来运行某个命令(例如管理员权限),但这种行为不受语言模式的限制。
受限语言(RestrictedLanguage)
受限语言模式是一种数据特定形式的 PowerShell 语言,主要用于支持 Import-LocalizedData 使用的本地化文件。虽然在此模式下可以执行 cmdlet 和函数,但不允许运行脚本块。需要注意的是,受限语言模式并不打算在大多数场景中显式使用,应仅在处理本地化文件时使用。
并且从 PowerShell 7.2 开始,如果配置了系统锁定模式,New-Object cmdlet 会被禁用。
默认情况下仅允许以下变量:
-
$****True -
$****False -
$****Null -
$****PSCulture -
$****PSUICulture
默认情况下仅允许以下运算符:
-
-****eq -
-****gt -
-****lt
请参阅 第二章,PowerShell 脚本基础,以了解更多关于运算符的详细信息。
无语言模式 (NoLanguage)
“无语言模式”只能通过 API 使用,并且不允许任何类型的脚本。
类似于受限语言模式,从 PowerShell 7.2 开始,如果配置了系统锁定模式,New-Object cmdlet 会被禁用。
受限语言模式 (ConstrainedLanguage)
正如我们在本书的 第五章 中学到的,PowerShell 的强大—系统和 API 访问,滥用 PowerShell 的最危险方式之一是滥用 COM 或 .NET,或者使用 Add-Type 来运行和复用用其他语言(如 C#)编写的代码。
受限语言模式防止了这些危险的场景,同时仍然允许用户使用合法的 .NET 类以及所有 cmdlet 和 PowerShell 元素。它旨在支持日常的管理任务,但限制用户执行风险较大的操作,例如调用任意 API:
图 10.2 – 在受限语言模式下,无法运行来自任意 API 的函数
要配置测试语言模式,可以通过命令行简单设置:
> $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
在生产环境中使用此设置并不推荐——如果对手获得系统访问权限,他们可以轻易更改此设置,从而危及系统安全:
> $ExecutionContext.SessionState.LanguageMode = "FullLanguage".
还有一个未记录的 __PSLockDownPolicy 环境变量,一些博客推荐使用它。然而,这个变量仅用于调试和单元测试,不应用于强制执行,因为同样的原因:攻击者可以轻松覆盖它,且它应仅用于测试。
为了有效地使用受限语言模式来保护 PowerShell 环境,关键是与强大的应用控制解决方案(如 Windows Defender 应用控制(WDAC))结合使用:
如果没有采取这些措施,攻击者可以轻松绕过受限语言模式,通过使用其他脚本引擎或创建自定义恶意软件(如 .exe 或 .dll 文件)来实现。
我们还将在第十一章中进一步探讨 AppLocker 和应用程序控制,AppLocker、应用程序控制和 代码签名。
请务必参考 PowerShell 团队关于受限语言模式的博客文章:
devblogs.microsoft.com/powershell/powershell-constrained-language-mode/
受限语言模式是一个很好的选择,但如果能够进一步限制会话中或特定用户允许哪些具体命令和参数,那不是更好吗?这正是 JEA 的作用所在。
理解 JEA
JEA 完全符合其名称的含义:它允许你定义哪些角色可以执行哪些命令,并只授予足够的管理权限。
假设你有多个人在同一服务器系统上工作:可能有管理员和支持人员,他们可能需要执行某些操作,比如不时重启一个服务(例如,在打印服务器上重启打印缓冲服务)。这类操作需要管理员权限,但对支持人员来说,管理员账户意味着过多的权限——如果支持人员的凭证被窃取,这些权限可能会被攻击者滥用。
使用 JEA,系统管理员可以定义某个角色可以执行哪些命令,甚至可以限制参数。因此,支持人员可以通过 PowerShell Remoting** (PSRemoting**) 登录,快速重启打印缓冲服务,并返回到他们的日常工作中。除了配置的命令,无法使用其他任何命令。
此外,JEA 依赖于 PSRemoting,这也是避免在目标系统上留下凭证的一个好方法。甚至可以配置在目标系统上使用虚拟账户代表操作人员。一旦会话终止,虚拟账户将被销毁,无法再使用。
JEA 概述
JEA 依赖于 PSRemoting:一种让你能够远程连接到定义的端点的技术,我们在第三章中进一步探讨了这一点,探索 PowerShell 远程管理技术和 PowerShell Remoting。
有两个重要文件需要配置 JEA 基础设置——角色能力文件和会话配置文件。在 PSRemoting 会话中使用这两个文件,JEA 才能发挥其作用。
当然,你还需要限制所有其他访问方式(如通过远程桌面)到目标服务器,以防止用户绕过你的 JEA 限制。
下图展示了 JEA 连接的工作原理概述:
图 10.3 – 如何连接到 JEA 的高级概述
使用 JEA 甚至可以允许非管理员用户访问服务器,执行为该用户角色预定义的管理任务。
根据配置,虚拟帐户可以代表用户使用,从而允许非管理员的远程用户完成需要管理员权限的任务。别担心;当然,在虚拟帐户下执行的每个命令都会被记录,并可以追溯到原始用户。
你可能听说过很多关于 PSRemoting 会话的内容,但在这幅图中,你能找到 JEA 吗?
一切从启动与远程服务器的交互式会话开始——例如,使用 Enter-PSSession。
你也可以将会话选项添加到会话中——这是你能找到 JEA 的地方吗?不,但会话选项在你不想连接到普通 PowerShell 会话时非常有用。例如,如果你需要连接到一个代理,-SessionOption 可以帮助你识别这些细节。
会话选项非常有用,但它们不属于本章内容。所以,如果你想了解更多关于它们的信息,请参考 New-PSSessionOption cmdlet 提供的选项:
docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/new-pssessionoption
然后,你可以选择使用 -ConfigurationName 参数将配置添加到会话中。这是 JEA 隐藏的地方吗?差不多,但我们还没到那里。你可以在下面的图中看到选项、配置和 JEA 最终适配的位置:
图 10.4 – JEA 所在位置
JEA 真正发挥作用的地方是在配置中,其中创建了角色定义。因此,JEA 是建立的会话的一部分,通过 安全描述符定义语言(SDDL)保护,并包含特定的角色定义。SDDL 定义了用户或组对资源访问的权限。
JEA 规划
在使用 JEA 之前,有几个事项需要先考虑。JEA 已包含在 PowerShell 5.0 中,因此请确保安装了正确的版本(5.0 或更高版本)。你可以使用 $PSVersionTable.PSVersion 检查当前版本。
由于 JEA 依赖于 PSRemoting 和 WinRM,请确保两者都已配置并启用。有关更多细节,请参见 第三章,探索 PowerShell 远程管理技术和 PowerShell 远程连接。
你还需要具有系统的管理员权限,才能配置 JEA。
不仅需要安装正确的 PowerShell 版本,还需要安装正确的操作系统版本。以下截图显示了服务器操作系统的所有支持版本,以及确保 JEA 正常运行所需采取的步骤:
图 10.5 – 服务器操作系统的 JEA 支持性
JEA 也可以在客户端操作系统上使用。以下截图显示了每个版本的可用功能以及在每个操作系统上使 JEA 运行所需的步骤:
图 10.6 – 客户端操作系统的 JEA 支持性
最后,你需要确定要限制的用户和/或组,以及每个用户应该拥有的权限。这听起来可能有些挑战。在本章中,你将找到一些有用的技巧和工具,帮助你完成这项任务。
但在我们深入探讨之前,让我们先了解一下 JEA 包含了哪些内容。首先,JEA 背后有两个主要文件,如下所示:
-
角色能力文件
-
会话配置文件
让我们首先探索一下角色能力文件是什么,以及如何配置它。
角色能力文件
角色能力文件决定了每个角色可以运行哪些命令。你可以指定特定角色中的用户可以执行哪些操作,并将这些角色限制为仅使用某些 cmdlet、函数、提供程序和外部程序。
通常会为某些角色定义角色能力文件——例如打印服务器管理员、DNS 管理员、一级帮助台等。由于角色能力文件可以作为 PowerShell 模块的一部分进行实现,因此你可以轻松地与他人共享它们。
使用New-PSRoleCapabilityFile,你可以创建你的第一个骨架 JEA 角色能力文件:
> New-PSRoleCapabilityFile -Path .\Support.psrc
一个名为Support.psrc的空文件被创建,并预填充了可以填写和编辑的参数:
图 10.7 – 一个空的骨架角色能力文件
在选择角色能力文件的名称时,请确保它反映了实际角色的名称——因此,请小心选择每个文件的名称。在我们的示例中,我们创建了Support.psrc角色能力文件,这是配置支持角色的一个很好的起点。
你可以在本书的 GitHub 仓库中找到一个未配置的生成骨架文件:
允许 PowerShell cmdlet 和函数
让我们从一个简单的角色能力文件例子开始。假设你是一个组织的管理员,帮助台报告了打印服务器的常见问题。那么,一个解决方案是给予帮助台管理员权限,允许他们操作所有打印服务器,但这会给所有帮助台员工过多的权限,并可能使你的环境面临风险。
因此,你可能只想赋予帮助台员工在打印服务器上重启服务的权限。
你可能听说过Restart-Service,它正是用于这个目的:重启服务。但它是一个cmdlet还是一个function?还是一个alias?
如果你对某个命令不确定,Get-Command cmdlet 可以帮助你查找更多信息:
图 10.8 – 使用 Get-Command 查找命令类型
借助Get-Command,我们现在知道Restart-Service是一个cmdlet,我们可以继续配置它。如果你查看生成的骨架.psrc文件,你可以看到多个以Visible开头的部分。通过这些部分,你可以定义在你的 JEA 会话中将提供哪些内容。你可以在角色能力文件中配置的所有参数与New-PSRoleCapabilityFile cmdlet 提供的参数一致:
> New-PSRoleCapabilityFile -Path <path> -ParameterName <values>
例如,如果你想配置一个简单的 JEA 配置并只允许Restart-Service cmdlet 可用,你可以使用以下命令:
> New-PSRoleCapabilityFile -Path .\Support.psrc -VisibleCmdlets 'Restart-Service'
在这个例子中,我们使用-VisibleCmdlets参数将Restart-Service cmdlet 配置为在Support角色中可用,所以让我们更仔细地看看使用此配置选项时可以做什么。
VisibleCmdlets
使用-VisibleCmdlets参数来定义哪些cmdlet是可见的,并且可以被配置的角色使用。所有定义的 cmdlet 需要在目标系统上可用,以避免错误。
创建了Support.psrc角色能力文件后,你也可以直接使用你选择的文本编辑器编辑它。你不仅可以在创建角色能力文件时使用-VisibleCmdlets参数,还可以在角色能力文件中直接配置此选项。
如果你只想配置 cmdlet,而不限制其参数,你可以将它们放入单引号中,并用逗号分隔。在这个例子中,配置的角色将能够重启服务以及重启计算机:
VisibleCmdlets = 'Restart-Service', 'Restart-Computer'
在使用通配符配置 cmdlet 时,必须意识到可能涉及的风险。虽然使用通配符来允许一系列命令看似方便,但你可能无意中授予了比必要更多的权限,从而在你的设置中创建了漏洞。使用以下命令时,该角色将能够运行所有以Get-开头的命令:
VisibleCmdlets = 'Get-*'
但是,允许一个角色使用所有以 Get- 开头的命令也可能会通过 Get-Content cmdlet 暴露敏感信息,即使这并不是该角色的预期用途。因此,仔细考虑允许的命令并定期审查和调整权限是非常重要的,以维护系统的安全性。
为了限制 cmdlet 的参数,你可以构建简单的哈希表,如下所示:
VisibleCmdlets = @{ Name = 'Restart-Service'; Parameters = @{ Name = 'Name'; ValidateSet = 'Dns', 'Spooler' }},
@{ Name = 'Restart-Computer'; Parameters = @{ Name = 'Name'; ValidateSet = 'Confirm', 'Delay', 'Force', 'Timeout' }}
@{ Name = 'Get-ChildItem'; Parameters = @{ Name = 'Path'; ValidatePattern = '^C:\\Users\\[^\\]+$' }}
使用前面的示例,配置的角色将允许执行三条命令:第一条允许的 cmdlet 是 Restart-Service,但是这个角色只允许重新启动 dns 和 spooler 服务。第二条允许的 cmdlet 授权角色也可以重启计算机,但仅能使用 -Confirm、-Delay、-Force 和 -Timeout 参数。最后,但同样重要的是,第三条允许的 cmdlet 是 Get-ChildItem,但根据 ValidatePattern 中指定的配置,拥有该角色的用户只能查询 C:\Users 路径下的子文件夹。
VisibleFunctions
VisibleFunctions 定义了哪些函数是可见的,并且可以被配置的角色使用。所有定义的函数需要在目标系统上可用,或者在当前角色能力文件的 FunctionDefinitions 部分定义,以避免错误。
函数的定义方式类似于 cmdlet:
VisibleFunctions = 'Restart-NetAdapter'
这个示例将允许 Restart-NetAdapter 函数;如果执行该函数,它会通过禁用并重新启用网络适配器来重新启动网络适配器。
对于函数,你也可以使用哈希表来定义更复杂的限制和通配符,这些也类似于 cmdlet —— 这些仍然需要非常小心地使用。
VisibleAliases
VisibleAliases 定义了哪些别名是可见的,并且可以被配置的角色使用。所有定义的别名需要在目标系统上可用,或者在当前角色能力文件的 AliasDefinitions 部分定义,以避免错误:
VisibleAliases = 'cd', 'ls'
这个示例将允许 cd 别名使用 Set-Location cmdlet,ls 别名使用 Get-ChildItem cmdlet。
别名的配置方式与在角色能力文件中的 cmdlet 和函数类似。有关更多示例,请参阅这些部分(VisibleCmdlets 和 VisibleFunctions)。
VisibleExternalCommands
VisibleExternalCommands 定义了哪些传统的 Windows 可执行文件是可见的,并且可以被配置的角色使用。所有定义的外部命令需要在目标系统上可用,以避免错误。外部命令的示例包括独立的可执行文件或已安装的程序。始终测试你的配置,确保所有的依赖项都已被配置考虑。
使用此设置,你可以允许外部命令和 PowerShell 脚本。使用以下示例,你将允许一个名为putty.exe的可执行文件,该文件位于C:\tmp\putty.exe,以及一个名为myOwnScript.ps1的 PowerShell 脚本,该脚本位于C:\scripts\myOwnScript.ps1:
VisibleExternalCommands = 'C:\tmp\putty.exe', 'C:\scripts\myOwnScript.ps1'
确保你已彻底审查并测试了你将暴露的脚本,并且已经实施了适当的措施以防止未经授权的篡改。如果你暴露的是脚本或可执行文件,务必确保你对它有完全的控制,并且确信它不会危及你的配置。
VisibleProviders
默认情况下,在 JEA 会话中没有可用的 PowerShell 提供程序,但通过使用VisibleProviders,你可以定义哪些提供程序是可见的,并且可以由配置的角色使用。所有定义的提供程序需要在目标系统上可用,以避免出现错误。
要获取提供程序的完整列表,可以运行Get-PSProvider,如以下截图所示:
图 10.9 – 获取可用提供程序的完整列表
例如,如果你希望使Registry提供程序可用,并且随之也使其HKEY_LOCAL_MACHINE(HKLM)和HKEY_CURRENT_USER(HKCU)驱动器可用,配置将如下所示:
VisibleProviders = 'Registry'
仅在角色确实需要时才使提供程序可用。如果此角色不经常与注册表操作,考虑编写脚本或函数来代替,如果该任务是可重复的。
ModulesToImport
使用ModulesToImport参数,你可以定义当前会话中将要导入的模块。请注意,模块必须事先安装,才能导入。
ModulesToImport = @{ModuleName='EventList'; ModuleVersion='2.0.2'}
同样,你可以使用哈希表来指定更多详细信息。前面的示例将导入版本为2.0.2的EventList模块。请确保使用VisibleFunctions和/或VisibleCmdlets来限制此会话中可以使用的函数或 cmdlet。
ScriptsToProcess
指定的脚本文件将在会话建立后执行,类似于启动脚本。脚本的路径需要定义为完整路径或绝对路径。
ScriptsToProcess 参数允许你将已配置的脚本添加到该角色的 JEA 会话中,然后在会话的上下文中运行。当然,脚本需要在目标系统上可用。
指定的脚本会在建立与此会话的连接时立即运行:
ScriptsToProcess = 'C:\Scripts\MyScript.ps1'
如果ScriptsToProcess在角色能力文件中为某个角色配置,它仅适用于该角色。如果在会话配置文件中进行配置,则适用于所有与该会话关联的角色。
AliasDefinitions
你可以使用此部分定义在目标系统上未定义且仅在当前 JEA 会话中使用的别名:
AliasDefinitions = @{Name='ipc'; Value='ipconfig'; Description='Displays the Windows IP Configuration'; Options='ReadOnly'}
VisibleAliases = 'ipc'
别忘了还要将别名添加到VisibleAliases中,以使其在会话中可用。
FunctionDefinitions
你可以使用此部分定义目标系统上不可用且仅在当前 JEA 会话中使用的函数。
如果你在FunctionDefinitions中定义了函数,确保在VisibleFunctions部分也进行配置:
VisibleFunctions = 'Restart-PrintSpooler'
FunctionDefinitions = @{
Name = 'Restart-PrintSpooler'
ScriptBlock = {
if ((Get-Service -Name 'Spooler').Status -eq 'Running') {
Write-Warning "Attempting to restart Spooler service..."
Restart-Service -Name 'Spooler'
}
else {
Write-Warning "Attempting to start Spooler service..."
Start-Service -Name 'Spooler'
}
}
}
这个示例创建了一个Restart-PrintSpooler自定义函数,首先检查打印机服务是否正在运行。如果正在运行,它将重新启动;如果没有运行,它将尝试启动。
如果你引用了其他模块,请使用完全限定模块名称(FQMN)而不是别名。
与其编写大量自定义函数,不如编写一个 PowerShell 脚本模块并配置VisibleFunctions和ModulesToImport。
VariableDefinitions
你可以使用此部分定义只在当前 JEA 会话中使用的变量。变量通过哈希表来定义。变量可以静态设置或动态设置:
VariableDefinitions = @{ Name = 'Variable1'; Value = { 'Dynamic' + 'InitialValue' } }, @{ Name = 'Variable2'; Value = 'StaticValue' }
以下代码行是使用VariableDefinitions设置静态变量和动态变量的示例:
VariableDefinitions =@{TestShare1 = '$Env:TEMP\TestShare'; TestShare2 = 'C:\tmp\TestShare'}
这个示例将定义两个变量:第一个变量$TestShare1是动态设置的,指向$Env:TEMP环境变量所指向的位置;第二个变量$TestShare2是静态的,始终指向'C:\tmp\TestShare'。
变量也可以配置选项。此参数是可选的,默认值是None。可接受的参数有None、ReadOnly、Constant、Private或AllScope。
EnvironmentVariables
你可以使用此部分定义仅在当前 JEA 会话中使用的环境变量。环境变量通过哈希表来定义:
EnvironmentVariables = @{Path= '%SYSTEMROOT%\system32; %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;C:\Program Files\PowerShell\7\;C:\Program Files\Git\cmd'}
上面的示例会将环境Path变量设置为包含'%SYSTEMROOT%\system32; %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;C:\Program Files\PowerShell\7\;C:\Program Files\Git\cmd'字符串,从而使像 Windows PowerShell、PowerShell 7 和 Git 等程序能够找到它们的可执行文件并无需提示用户即可运行。
TypesToProcess
你可以使用TypesToProcess来指定应该添加到配置会话中的types.ps1xml文件。类型文件通常指定为.ps1xml文件。使用完整或绝对路径在角色能力文件中定义类型文件:
TypesToProcess = 'C:\tmp\CustomFileTypes.ps1xml'
你可以在官方文档中找到关于类型文件的更多信息:
docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_types.ps1xml
FormatsToProcess
你可以使用FormatsToProcess参数来指定当前会话中应该加载哪些格式化文件。类似于类型文件,格式化文件也配置在以.ps1xml结尾的文件中。另外,对于FormatsToProcess,路径必须指定为完整路径或绝对路径:
FormatsToProcess = 'C:\tmp\CustomFormatFile.ps1xml'
你可以在官方文档中找到更多关于格式化文件的信息:
docs.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_format.ps1xml
AssembliesToLoad
为了使二进制文件中包含的类型对你编写的脚本和函数可用,可以使用AssembliesToLoad参数来指定所需的程序集。这样,你就可以在 JEA 会话中利用这些程序集提供的功能:
AssembliesToLoad = "System.Web","FSharp.Compiler.CodeDom.dll", 'System.OtherAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
如果你想了解更多关于 JEA 角色功能文件以及更多选项,比如为某个角色创建专用的自定义函数,请参考官方文档:
docs.microsoft.com/zh-cn/powershell/scripting/learn/remoting/jea/role-capabilities
如果你希望更新角色功能文件,可以随时通过保存对角色功能文件的更改来完成。任何在更改后建立的新的 JEA 会话都将反映这些更新的更改。
当用户被授予多个角色功能时,这些角色功能也可以合并。请参考官方文档了解在这种情况下将应用哪些权限:
docs.microsoft.com/zh-cn/powershell/scripting/learn/remoting/jea/role-capabilities#how-role-capabilities-are-merged
现在你已经定义了你的角色——为了更好的概览,可以将每个角色创建在单独的角色功能文件中——接下来是将这些角色分配给特定用户和组,并定义会话特定的参数。这可以通过会话配置文件来完成。
会话配置文件
使用会话配置文件,你可以指定谁可以连接到哪个端点。你不仅可以将用户和组映射到特定的角色,还可以配置全局会话设置,比如连接到会话时应该执行哪些脚本、日志策略或连接时将使用哪个身份(例如,虚拟账户或组托管服务账户(gMSAs))。如果需要,你还可以按每台机器配置会话文件。
你可以使用New-PSSessionConfigurationFile cmdlet 创建骨架会话配置文件:
New-PSSessionConfigurationFile -Path .\JEA_SessionConfigurationFile.pssc
类似于创建骨架角色功能文件,会创建一个可以编辑的预填充会话配置文件:
图 10.10 – 一个空的骨架会话配置文件
在会话配置文件中,还有一些通用参数帮助您描述此文件。以下是其中的一些:
-
SchemaVersion:描述此文档的模式版本号,通常是2.0.0.0,如果没有另行指定。 -
GUID:GUID 是一个唯一的、随机生成的 UID,用于标识此文件。 -
Author:创建此文档的作者。 -
Description:此会话配置文件的描述。最好具体描述,这样您可以轻松编辑和操作日益增长的配置文件库。
让我们看看您还可以使用会话配置文件配置哪些其他选项。
会话类型
会话类型指示创建了哪种类型的会话(按语言模式划分)以及允许哪些命令。在 JEA 会话配置文件中,您应该始终配置 SessionType = '****RestrictedRemoteServer'。
在常规会话文件中,您可以为此参数使用以下值:
-
Default:此配置提供不受限制的 PowerShell 终端。这意味着用户可以运行系统上可用的任何命令。在配置 JEA 时不推荐使用此会话类型。 -
Empty:会话中未添加任何模块和命令。仅当您在会话配置文件中配置了VisibleCmdlets、VisibleFunctions和其他参数时,您的会话才会被填充。在配置 JEA 时不要使用这些设置,除非您有用例需要限制在配置RestrictedRemoteServer时允许的 cmdlet。 -
RestrictedRemoteServer:当创建 JEA 会话配置文件时,应使用此值。它适当地限制了语言模式,并且仅导入一小部分基本命令,如Exit-PSSession、Get-Command、Get-FormatData、Get-Help、Measure-Object、Out-Default和Select-Object,这些足以完成大多数管理任务。此配置提供更高的安全级别,因为它限制了访问潜在危险的 cmdlet 和函数。
在创建基础会话配置文件时,您可以使用 -SessionType 参数直接配置会话类型,如下所示:
> New-PSSessionConfigurationFile -SessionType RestrictedRemoteServer -Path .\JEA_SessionConfigurationFile.pssc
TranscriptDirectory
会话记录会记录特定会话中运行的所有命令以及其输出。建议对每个用户使用会话记录并审计正在执行的命令。这可以通过使用 TranscriptDirectory 参数实现。
首先,确保在 JEA 端点上预先配置一个文件夹来存储转录文件。此文件夹需要是一个受保护的文件夹,以确保普通用户无法修改或删除该文件夹中的任何数据。此外,确保本地系统帐户已配置为具有读写访问权限,因为该帐户将用于创建转录文件。
最好确保转录文件定期上传并解析到你的安全信息和事件管理(SIEM)系统中,以便它们存储在一个集中位置。还要确保实现日志文件轮换机制,以避免硬盘空间耗尽。
一切都配置好了吗?很好!现在,是时候在会话配置文件中配置预先配置的文件夹路径了,具体如下:
TranscriptDirectory = 'C:\Jea-Transcripts'
使用前述配置将所有转录写入C:\Jea-Transcripts文件夹。新文件将始终使用时间戳生成,以确保没有文件被覆盖。
除了TranscriptDirectory参数之外,还要确保实现适当的审计。有关详细信息,请参阅第四章,检测 – 审计与监控。
配置 JEA 身份
使用 JEA 时,你不会在目标系统上使用常规帐户。那么,实际上会使用哪个帐户呢?
在 JEA 中,身份有两种选择:使用虚拟帐户或gMSA。除非在 JEA 会话中需要访问网络资源,否则你应该始终优先选择使用虚拟帐户。在接下来的部分中,我们将详细了解这两种选择,并探讨为什么虚拟帐户是更安全的选项。
虚拟帐户
如果有疑问,配置虚拟帐户应该始终是你的首选选项。虚拟帐户是一个临时管理员帐户,在 JEA 会话开始时创建,并在会话结束时销毁。这意味着它只在远程会话期间存在,是提供临时管理员访问的安全选项。一个巨大优势是,在任何时候,都没有可重用的凭据进入系统。
当连接到端点时,非管理员用户会以特权虚拟帐户身份连接并在会话中运行所有命令。此帐户是域控制器(DCs)上的本地管理员或域管理员帐户,但仍然受到限制,只能运行此角色允许的命令。
为了更容易跟随这个示例,我创建了一个简单的脚本来创建一个ServerOperator角色,并与一个会话配置一起注册,让连接用户以虚拟帐户身份连接。让我们使用这个配置来演示本章中的示例。
你可以在本书的 GitHub 仓库中找到脚本,地址为github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter10/JEA-ServerOperator.ps1。
在我的示例中,我在PSSec-Srv01上执行所有命令,这是一台加入PSSec域的 Windows 2019 服务器。
首先,确保你要为其配置ServerOperator角色的帐户已存在于你的环境中,并且可能需要调整脚本中的用户名。在我的示例中,用户是PSSec\mwiesner。
然后,从 GitHub 仓库运行JEA-ServerOperator.ps1脚本,确保ServerOperator JEA 端点已成功创建。
一旦端点成功创建,使用ServerOperator JEA 会话建立到本地主机的会话:
> Enter-PSSession –ComputerName localhost –ConfigurationName ServerOperator -Credential $ServerOperator
一旦建立了依赖虚拟帐户的 JEA 会话,让我们通过在单独的提升权限的 PowerShell 控制台中运行Get-LocalUser命令,来检查实际的本地用户帐户。如你所见,没有为 JEA 连接创建额外的本地帐户:
图 10.11 – 未创建额外的本地帐户
为了验证在当前机器运行时间内哪些虚拟帐户已登录或正在登录,我编写了一个脚本,帮助你查看为 JEA 会话创建了哪些虚拟帐户:
该脚本使用Get-CimInstance检索有关登录用户及其登录会话的信息,合并这些信息,并显示哪些虚拟帐户已创建以及会话是仍然活跃还是不活跃。
以下截图展示了Get-VirtualAccountLogons.ps1脚本的输出:
图 10.12 – 可以使用 Get-VirtualAccountLogons.ps1 脚本评估当前运行时间的虚拟帐户使用情况
所有在操作系统重启之前创建的虚拟帐户都会缓存到通用信息模型(CIM)表中,因此你可以看到过去和当前的虚拟帐户连接。如果会话仍然建立,脚本会显示ActiveSession: True。
所有通过已建立的 JEA 会话生成的虚拟帐户名称都遵循 "WinRM VA_<number>_<domain>_<username>" 方案。如果同一用户帐户建立了多个会话,则该数字会相应增加。
你知道吗?
还可以通过使用已弃用的 Get-WmiObject win32_process).GetOwner().User** **Windows Management** **Instrumentation** (WMI**) 命令来检索当前所有用户的列表。
因此,如果你不需要访问网络资源,配置 JEA 会话身份的最佳选择是使用虚拟帐户。
gMSA
如果你需要访问网络资源(例如,其他服务器或网络共享),则 gMSA 是虚拟帐户的替代方案。
你可以在官方文档中找到有关如何创建和配置 gMSA 的更多信息:
docs.microsoft.com/en-us/windo…
你可以使用 gMSA 帐户对域进行身份验证,从而访问任何已加入域的计算机上的资源。用户通过 gMSA 帐户获得的权限由将要访问的资源决定。只有在显式授予 gMSA 帐户管理员权限时,使用该帐户的用户才会拥有管理员权限。
gMSA 是由 Active Directory 管理的帐户,并且会定期更改其密码。因此,密码可能会被对手重新使用——如果被捕获——但仅限于有限的时间。
最理想的情况是使用虚拟帐户;仅在你的任务确实需要访问某些网络资源时,才使用 gMSA 帐户,典型的情况包括:
-
在 gMSA 身份下,确定是谁执行了哪些操作更加困难,因为同一个帐户是所有连接到同一 gMSA 会话的用户共享使用的。要确定是哪位用户执行了哪项操作,你需要将 PowerShell 会话的转录文件与事件日志中的相应事件进行关联。
-
有可能授予比 JEA 配置计划更多的权限,因为 gMSA 帐户可能有权访问许多不需要的网络资源。始终遵循最小权限原则,以有效限制你的 JEA 会话。
gMSA 仅适用于从 Windows PowerShell 5.1 或更高版本开始,并且只能在已加入域的计算机上使用。当然,如果你不希望将计算机加入生产域,也可以使用独立域。
选择 JEA 身份
一旦你选择了想要用于连接 JEA 会话的身份,就可以开始配置它。你需要配置一个虚拟帐户或 gMSA,并可以在 JEA 会话配置文件中进行设置。
使用以下选项配置本地虚拟帐户:
-
RunAsVirtualAccount = $****true -
RunAsVirtualAccountGroups = '****NetworkOperator', 'NetworkAuditor'
使用RunVirtualAccountGroups参数,你可以定义虚拟帐户应该在哪些组中存在。为了防止虚拟帐户默认被添加到本地或域管理员组中,你需要指定一个或多个安全组。
使用GroupManagedServiceAccount参数定义 gMSA,如下所示:
GroupManagedServiceAccount = 'MyJEAgMSA'
另外,参考官方的会话配置文档:
docs.microsoft.com/en-us/powershell/scripting/learn/remoting/jea/session-configurations
ScriptsToProcess
类似于ScriptsToProcess,它可以在角色能力文件中进行配置。请参阅名为角色能力文件的章节中的ScriptsToProcess子节,了解更多信息以及如何配置它。
如果在角色能力文件中为角色配置了ScriptsToProcess,它只适用于该角色。如果在会话配置文件中配置,它适用于所有与此特定会话关联的角色。
角色定义
角色定义将你在角色能力文件中配置的角色与当前会话配置文件连接,并可以在哈希表中进行配置,如下所示:
RoleDefinitions = @{
'CONTOSO\JEA_DNS_ADMINS' = @{ RoleCapabilities = 'DnsAdmin', 'DnsOperator', 'DnsAuditor' }
'CONTOSO\JEA_DNS_OPERATORS' = @{ RoleCapabilities = 'DnsOperator', 'DnsAuditor' }
'CONTOSO\JEA_DNS_AUDITORS' = @{ RoleCapabilities = 'DnsAuditor' }
}
你可以将一个或多个角色能力分配给用户帐户或活动目录组。
条件访问
JEA 本身已经是一个限制角色在终端上执行特定命令的极佳选择,但所有分配了角色的用户或组都能够运行配置的命令。但如果你希望设置更多的限制,比如—例如—强制用户还使用多因素 认证(MFA)呢?
这时,额外的访问控制起作用了。使用RequiredGroups参数,你可以强制要求连接的用户属于一个定义的组——你可以使用这个组来强制对用户施加更多的条件。
使用And或Or有助于你定义更细化的规则。
使用以下示例,所有连接的用户必须属于名为MFA-logon的安全组;只需使用And条件:
RequiredGroups = @{ And = 'MFA-logon' }
有时,你可能有不同的认证方式或额外的安全要求。所以,如果你希望连接的用户属于MFA-logon 或 smartcard-logon组,可以使用Or条件,如以下示例所示:
RequiredGroups = @{ Or = 'MFA-logon', 'smartcard-logon' }
当然,你也可以通过结合And和Or条件来创建更复杂的嵌套条件。
在以下示例中,连接的用户需要是elevated-jea组的成员,并且需要通过 MFA 或智能卡进行登录:
RequiredGroups = @{ And = 'elevated-jea', @{ Or = 'MFA-logon', 'smartcard-logon' }}
然而,无论你使用哪种配置选项,始终确保测试你的条件是否按计划应用。
用户驱动
通过配置和利用用户驱动器,可以从 JEA 会话中远程复制文件。例如,你可以从会话中复制日志文件,以便稍后在你的正常工作计算机上进行详细分析。
要配置一个容量为 10MB 的用户驱动器,请使用以下配置:
MountUserDrive = $true
UserDriveMaximumSize = 10485760
访问已配置用户驱动器的 JEA 会话后,你可以轻松地从会话中复制文件或将文件复制到会话中。
以下示例展示了如何将myFile.txt文件复制到你的$ServerOperator JEA 会话中:
Copy-Item -Path .\myFile.txt -Destination User: -ToSession $ServerOperator
下一个示例展示了如何从$ServerOperator JEA 会话中的远程计算机复制access.log文件到本地会话:
Copy-Item -Path User:\access.log -Destination . -FromSession $jeasession
尽管你可以从 JEA 会话中复制文件或将文件复制到该会话中,但无法在远程计算机上指定文件名或子文件夹。
如果你想了解更多关于 PowerShell 驱动器的信息,可以查看docs.microsoft.com/en-us/powershell/scripting/samples/managing-windows-powershell-drives。
访问权限(SDDL)
JEA 会话的访问权限是通过 SDDL 进行配置的。
因此,当你使用 JEA 时,SDDL 将在为会话配置分配用户/组**访问控制列表(ACL)时自动进行配置。组和安全标识符(SID)**会被查找并自动添加到会话配置中,确保拥有适当级别的访问权限。
你可以通过运行**(Get-PSSessionConfiguration –Name <会话配置名称>).SecurityDescriptorSddl** 命令来查找会话配置的 SDDL:
图 10.13 – 查找会话配置的 SDDL
请参考官方文档了解更多关于 SDDL 语法的信息:
docs.microsoft.com/en-us/windo…
部署 JEA
要部署 JEA,你需要了解你想要限制的用户使用了哪些命令。如果你问我,这是 JEA 中最难的部分。
但是有一些工具,例如我自己编写的开源项目 JEAnalyzer,可以大大简化这项任务。稍后我会在本章中回到这个工具。
确定了要限制的命令和用户/组后,首先创建一个会话能力文件和一个角色能力文件。下图展示了部署 JEA 所需的步骤:
图 10.14 – 部署 JEA 的步骤
创建了两个必需的文件之后,请确保在使用Test-PSSessionConfigurationFile -Path <会话配置文件的路径> cmdlet 部署文件之前检查会话配置文件的语法。
如果需要更改 JEA 会话配置,例如,将用户映射或移除到角色中,你将始终需要取消注册并重新注册 JEA 会话配置。如果只想更改角色能力文件中配置的角色,仅需更改配置,无需重新注册会话配置。
你还可以通过运行**Get-PSSessionCapability –ConfigurationName -**Username <username>来验证特定用户在特定会话中会获得哪些能力。
一旦准备好进行部署,你需要决定使用哪种部署机制。可以选择手动注册会话或使用期望状态配置(DSC)进行部署。
手动注册
如果你只想在少数机器上测试配置,或者只需要管理小型环境,那么手动注册机器是一个不错的选择。当然,你也可以使用手动注册命令来编写部署脚本,但你仍然需要找到一种方法来部署你的脚本。
因此,对于大型环境,DSC 可能是更适合的解决方案。
在手动注册之前,请确保至少向RoleCapabilities文件中添加了一个角色,并且已经创建并测试了附带的会话配置文件。
为了成功注册 JEA 配置,你需要在系统上具有本地管理员权限。
如果一切就绪,请根据你的配置调整以下命令并在终端上运行它进行配置:
Register-PSSessionConfiguration -Path .\MyJEAConfig.pssc -Name 'JEAMaintenance' -Force
注册会话后,确保重启 WinRM 服务,以确保新会话已加载并处于活动状态:
Restart-Service -name WinRM
有关工作示例,请参考本书 GitHub 仓库中的演示配置文件:
通过 DSC 进行部署
在大型环境中,利用 DSC 可能是值得的。DSC 是一种非常酷的方式,可以让你的远程服务器“照做”,并定期应用你选择的配置。
即使有人更改了服务器上的配置,通过配置 DSC 后,你的服务器也可以自我重置,无需管理员干预,因为它们可以定期拉取并调整其配置,确保与预设的基准一致。
DSC 是一个很大的话题,因此我无法详细描述整个技术,但如果你想了解更多,查看第十三章**,其他内容?– 进一步的缓解措施和资源,并查看官方文档。
有关基本 JEA DSC 配置,请参阅注册 JEA 配置文档:
docs.microsoft.com/en-us/powershell/scripting/learn/remoting/jea/register-jea?#multi-machine-configuration-with-dsc
连接到会话
一旦你设置好 JEA 会话,请确保应该连接到 JEA 会话的用户已配置 从网络访问此计算机 的用户权限。
现在是关键时刻,你可以连接到 JEA 会话了:
Enter-PSSession –ComputerName <computer> –ConfigurationName <configuration name>
默认情况下,无法在命令行上使用 Tab 键自动完成命令。如果你希望能够使用这一功能,建议使用 Import-PSSession,它允许像 Tab 补全这样的功能正常工作,而不影响安全性:
> $jeasession = New-PSSession –ComputerName <computer> –ConfigurationName <configuration name>
> Import-PSSession -Session $jeasession -AllowClobber
不建议将 TabExpansion2 函数配置为可见函数,因为它会执行各种代码,对你的安全环境构成风险。
要显示本地计算机上所有可用的会话配置,运行 Get-PSSessionConfiguration。
一旦你成功配置、部署并测试了 JEA 会话,确保删除连接用户的所有其他访问方式。即使你部署了最好的 JEA 配置,如果用户可以通过其他连接方式绕过它,那也是毫无意义的——例如,通过远程桌面连接。
部署 JEA 一开始看起来像是需要大量工作,对吧?但别担心——实际上有一些方法可以简化你的工作,比如 JEAnalyzer。
使用 JEAnalyzer 简化你的部署
当我第一次了解 JEA 时,我曾热衷于推广它,并告诉每个人这个解决方案有多么强大。将用户可以运行的命令严格限制为仅需的命令,难道不是很棒吗?通过 JEA 和虚拟账户完全避免传递哈希值,配置虚拟账户难道不令人惊叹吗?
是的,确实如此!但当我向客户介绍 JEA 和它的强大功能时,我很快就收到了重复的问题:我们如何找出用户和管理员正在使用哪些命令?我们如何以 最简单的方式创建这些角色能力文件?
这也是我想到 JEAnalyzer 模块的时刻。在我启动这个项目后,我的朋友 Friedrich Weinmann 也对这个项目产生了浓厚的兴趣。当我换了工作,几乎不再和客户讨论除 Microsoft Defender for Endpoint 以外的其他话题时,我很高兴他接管了我开始的项目,维护了该仓库,并将我们剩余的共同愿景融入其中。
你可以在 GitHub 上找到 JEAnalyzer 仓库:
github.com/PSSecTools/JEAnalyzer
JEAnalyzer 是一个 PowerShell 模块,可以通过 PowerShell Gallery 轻松安装,使用Install-Module JEAnalyzer -Force命令。安装过程中同意所有弹出窗口,由 NuGet 等提供的弹窗后,模块将被安装并可以使用Import-Module JEAnalyzer导入。
在本书写作时,JEAnalyzer 的最新版本是 1.2.10,包含 13 个功能,如下所示:
图 10.15 – JEAnalyzer 的可用功能
每个功能都有很好的文档说明,因此我不会描述所有功能,只会介绍一些最重要的功能,帮助你找出用户使用的命令,以及如何通过 JEAnalyzer 简单创建你的第一个角色能力和会话配置文件。
将脚本文件转换为 JEA 配置
如果你有某些脚本逻辑需要在 JEA 会话中运行,并且只想将脚本转换为端点配置,JEAnalyzer 可以帮你实现。
作为一个示例脚本文件,我使用了导出 AD 用户到 CSV脚本,该脚本最初由 Victor Ashiedu 于 2014 年编写。你可以在这里找到该脚本的版本:
github.com/sacroucher/ADScripts/blob/master/Export_AD_Users_to_CSV.v1.0.ps1
下载脚本并将其保存在 C:\DEMO\ext\Export_AD_Users_to_CSV.v1.0\Export_AD_Users_to_CSV.v1.0.ps1 路径下。同时,在 C:\JEA\ 目录下创建一个文件夹来存储输出文件。
在做好准备后,从本书的 GitHub 仓库下载脚本,并确保逐条执行命令。不要一次性运行整个脚本,确保你理解每个步骤——脚本有详细的注释。
本示例中使用的 JEAnalyzer 最重要的命令列出如下:
-
Read-JeaScriptFile:解析并分析脚本文件中的合格命令。确保使用-Path参数指定脚本路径。 -
Export-JeaRoleCapFile:将命令列表转换为 JEA 角色能力文件。
进入新创建的会话并分析配置的命令后,你可以看到所有使用的命令以及标准会话功能在该会话中都是允许的:
图 10.16 – 显示所有允许的功能和命令
但有时,单纯审计和配置脚本文件是不够的;有时你还需要为用户和管理员配置会话,允许使用常用命令和功能。
使用审计来创建你的初始 JEA 配置
要跟随这个示例,你需要从 GitHub 仓库中获取本节的脚本:
类似于转换脚本文件的演示脚本,不要一次性运行整个脚本,而是逐条命令运行,以便理解示例。
作为先决条件,请确保安装 ScriptBlockLoggingAnalyzer 模块,该模块由 Dr. Tobias Weltner 创建:
> Install-Module ScriptBlockLoggingAnalyzer
此外,在我们能够利用审计之前,我们需要启用 ScriptBlockLogging。因此,您可以手动在本地计算机上启用 ScriptBlockLogging,或者确保在多台计算机上启用它。更多关于 ScriptBlockLogging 的内容,请参见第四章,检测 - 审计与监控。
使用这些命令,你可以在本地计算机上手动启用 ScriptBlockLogging,如下所示:
> 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
在脚本的某些部分,你将被要求以另一个用户身份运行一些命令。在我的演示环境中,我以 mwiesner 用户身份运行命令。如果你为演示目的配置了其他用户,请确保在自定义用户账户下运行此会话,并根据需要调整脚本。
要以 mwiesner 或其他用户身份运行命令,请右键单击 PowerShell 控制台并选择 以不同用户身份运行。根据系统的配置,可能需要按住 Shift 键并右键单击 PowerShell 控制台,以使此选项显示出来。
在此会话中运行一些演示命令。你可以在脚本中找到一些示例。只需确保按顺序运行每个命令,不要将其作为一个大的脚本块运行。
然后,按照脚本的示例,分析命令,并从已审计的命令中创建初始的 JEA 配置。此脚本中使用的最重要的命令如下所示:
-
Get-SBLEvent(ScriptBlockLoggingAnalyzer模块):从 PowerShell 审计日志中读取ScriptBlockLogging事件 -
Read-JeaScriptblock:解析并分析传入的代码以获取合格的命令,当使用-****ScriptCode参数时指定。 -
Export-JeaRoleCapFile:将命令列表转换为 JEA 角色能力文件
使用该脚本探索如何从已审计的命令创建初始的 JEA 会话,并根据需要调整使用的命令。这样,你就可以轻松地创建一个初始的 JEA 角色能力文件,并在之后进行调整和精细化。
但是,一旦开始使用 JEA,审计在你的 JEA 会话中非常重要。接下来的章节将介绍如何利用审计并链接与你的用户的 JEA 会话相关的重要事件。
在 JEA 会话中的日志记录
使用 JEA 时,当然可以进行日志记录,且你应该实现它并定期审查审计日志,以确保你的 JEA 配置不会以意外的方式被滥用。
我们已经在 第四章 中详细介绍了日志记录,检测 – 审计和监控,因此这里只做一个关于 JEA 日志记录的重要性的小结。
监视记录
始终为通过 JEA 会话运行命令的用户配置监视记录。监视记录可以通过 会话配置文件 中的 TranscriptDirectory 参数进行配置,正如我们在 TranscriptDirectory 部分所讨论的那样。
确保保护配置的文件夹,以防其内容被对手篡改。同时定期转发、解析并审查转录记录。
监视记录包含有关用户、虚拟用户、会话中执行的命令等信息。
PowerShell 事件日志
PowerShell 事件日志不仅仅用于找出谁运行了哪些命令,当启用脚本块日志记录时,所有 PowerShell 操作也会记录在常规 Windows 事件日志中。
启用脚本块日志记录以及模块日志记录,并在 PowerShell 操作日志 中查找事件 ID 4104。在远程机器上,如果使用的是虚拟账户,你需要查找的用户是 WinRM 虚拟用户。如果使用的是 gMSA 账户,则需要注意这个账户。以下截图显示了一个虚拟账户的脚本块日志记录事件:
图 10.17 – 虚拟账户显示为用户名
特别关注 PowerShell 操作日志中的事件 ID 4100、4103 和 4104。在某些情况下,你会看到连接的用户是实际用户,而指定的用户是 WinRM 虚拟账户。
其他事件日志
与 PowerShell 操作日志和转录记录不同,其他日志机制无法捕获连接的用户。要找出哪些用户在何时连接,你需要进行事件日志关联。
要做到这一点,请在 WinRM 操作日志 中查找事件 ID 193,以找出哪个用户请求了哪个虚拟账户或 gMSA:
图 10.18 – 使用 WinRM 操作日志进行关联
你还可以通过查找事件 ID 4624 和 4625 从安全日志中获取更多详细信息。在以下示例截图中,我们看到两个事件 ID 为 4624(账户已成功登录)的事件,它们是在同一时间生成的——一个显示的是常规账户登录,另一个显示的是虚拟账户登录:
图 10.19 – 比较常规账户和虚拟账户登录
如果你想查找更多其他事件日志中的活动,使用 Logon ID 值来关联活动与已识别的登录会话。
账户注销可以通过事件4634识别。有关更多关于 Windows 事件日志的信息,请参考 第四章,检测 – 审计与监控。
最佳实践 – 避免风险和可能的绕过方法
JEA 是加固你的环境的一个好选择,它允许管理员和用户只执行他们日常工作所需的命令。但像其他技术一样,JEA 也可能配置错误,存在一些你需要注意的风险。
不要授予连接用户管理员权限以绕过 JEA——例如,允许命令编辑管理员组,如Add-ADGroupMember、Add-LocalGroupMember、net.exe 和 dsadd.exe。恶意管理员或被攻击的账户可能会轻易提升权限。
另外,不要允许用户运行任意代码,如恶意软件、漏洞利用或自定义脚本来绕过保护。你需要特别注意的命令有(但不限于)Start-Process、New-Service、Invoke-Item、Invoke-WmiMethod、Invoke-CimMethod、Invoke-Expression、Invoke-Command、New-ScheduledTask、Register-ScheduledJob等。
如果你的管理员确实需要其中一些高风险命令,你可以尝试通过配置专用参数或创建并允许自定义函数来细化配置。
尽量避免使用通配符配置,因为它们可能被篡改,并且在使用帮助你创建配置的工具时要小心;在生产环境中使用之前,务必仔细审查和测试配置。
为了保护你的角色能力和会话配置文件免受篡改,请使用签名。确保实施适当的日志记录机制,并确保转录文件和事件日志的安全。还要定期审查它们。
最后但同样重要的是,当系统上线时,要意识到,如果你不撤销管理员权限和远程桌面访问权限,以上所说的任何措施都没有意义!
概述
本章中,你了解了语言模式是什么以及它们与 JEA 的区别。你还学习了什么是 JEA 以及如何设置它。
你现在知道了可以使用哪些参数来创建你自己的定制 JEA 角色能力和会话配置文件(或者至少知道在哪里查找它们),以及如何注册和部署你的 JEA 端点。
按照本书 GitHub 仓库中的示例,你已经成功创建并探索了自己的 JEA 会话,并且你已经获得了如何在自己的环境中使用 JEAnalyzer 创建简单配置的选项。当然,你仍然需要对配置进行微调,但第一步已经轻松完成。
你已经了解了如何解读日志文件,以便在不同的事件日志中关联 JEA 会话,以及在创建 JEA 配置时需要注意的风险。
JEA 是定义哪些命令可以由哪些角色执行的一个重要步骤,但有时你可能希望完全禁止某个特定应用程序,或者仅允许某些应用程序和脚本在你的环境中运行。在下一章中,我们将探索如何通过 AppLocker、应用程序控制和脚本签名来实现这一目标。
进一步阅读
如果你想深入探索本章中提到的一些话题,可以参考以下资源:
-
PowerShell 受限语言模式:
devblogs.microsoft.com/powershell/powershell-constrained-language-mode/ -
about_Language_Modes:
docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_language_modes -
Just Enough Administration(官方 Microsoft 文档):
docs.microsoft.com/en-us/powershell/scripting/learn/remoting/jea/overview -
GitHub 上的 JEAnalyzer:
github.com/PSSecTools/JEAnalyzer -
PowerShell ♥ 蓝队:
devblogs.microsoft.com/powershell/powershell-the-blue-team/
你还可以在 GitHub 仓库中找到本章提到的所有链接:第十章——无需手动输入每个链接:
第十一章:AppLocker、应用程序控制和代码签名
在企业环境中,控制安装了哪些软件以及哪些软件被排除在环境之外至关重要——不仅为了保持对可用软件的概览,还为了帮助抵御恶意脚本或恶意软件(如勒索病毒)等威胁。
但是,代码签名和应用程序控制如何帮助您更好地保护环境,如何实施它们呢?在规划实施应用程序控制解决方案时,您需要做什么,并且 Windows 操作系统上有哪些内建的应用程序控制解决方案?
在本章中,我们将深入探讨关于 AppLocker、应用程序控制和代码签名的内容。您将在本章中对以下主题有更深入的了解:
-
使用代码签名防止未经授权的脚本执行
-
控制应用程序和脚本
-
熟悉 Microsoft AppLocker
-
探索 Windows Defender 应用程序控制
技术要求
为了充分利用本章内容,请确保您具备以下条件:
-
PowerShell 7.3 及以上版本
-
已安装的 Visual Studio Code
-
用于测试目的的运行 Windows 10 或以上版本的虚拟机
-
第十一章的 GitHub 仓库访问:
github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/tree/master/Chapter11
使用代码签名防止未经授权的脚本执行
如果您想验证执行的脚本是否是合法代码,并且是否允许公司执行,您需要实施一个适当的代码签名策略。这是保护您定期执行的脚本不被篡改的绝妙方法——或者至少,如果有人篡改了您的脚本,在您的环境配置正确的情况下,它们将不会被执行。
需要注意的是,动态运行时在实施应用程序控制策略时可能会成为一个常见的盲点。虽然 PowerShell 在确保 PowerShell 运行时可以通过应用程序控制规则进行限制方面取得了显著进展,但其他动态运行时,如 Python、Node、Perl、PHP 等,可能仍然允许您运行未受限制的代码,这可能会带来漏洞,尤其是如果没有适当管理的话。如果您的客户端不需要其他动态运行时,最好将它们阻止或尽可能限制,以保持强大的安全态势。
WSH 语言家族通过一种非常直接的方式实现了应用程序控制意识:它们只是阻止执行任何不被政策允许的脚本。
当我们在早些章节讨论执行策略时,例如在第一章,PowerShell 入门中,我们查看了AllSigned或RemoteSigned参数。如果配置了AllSigned,则所有未签名的 PowerShell 脚本将被阻止运行;如果配置了RemoteSigned,则仅允许本地未签名脚本。当然,执行策略可以随时被绕过,因为它不是安全边界—但是,这可以防止用户无意中运行他们不知情的脚本。
将代码签名与其他工具(如 AppLocker 或WDAC)结合使用非常强大,因为你可以确保在你的基础设施中,只有配置的签名脚本可以运行,其他任何脚本都不被允许。
但要开始代码签名,首先我们需要一个证书来签署代码。你可以选择使用不同类型的证书。你可以选择自签名证书或公司为你购买的企业证书(可以是森林级或公共级证书)。
自签名证书通常仅用于测试目的,如果你希望将代码签名基础设施投入生产环境,你至少应该考虑使用由公司证书授权机构(CA)签名的证书,以使你的部署更加安全。
以下图示应为你提供一个关于代码签名不同场景的概览:
图 11.1 – 代码签名证书的不同可能性概览
本章中,我们将使用自签名证书来签署我们的脚本—如果你希望在生产环境中使用,请确保调整你的证书。
自签名证书仅在本地计算机上有效,可以使用New-SelfSignedCertificate cmdlet 创建。在早期,makecert.exe 被用来创建自签名证书,但自从 Windows 8 引入了New-SelfSignedCertificate后,你可以直接使用 PowerShell 创建自签名证书并签署脚本。
使用此 cmdlet 创建的证书可以存储在当前用户的个人证书存储中,路径为证书 | 当前用户 | 个人(Cert:\CurrentUser\My),也可以存储在本地计算机的个人证书存储中,路径为证书 | 本地计算机 | 个人(Cert:\LocalMachine\My)。在本地计算机的证书存储中创建的证书可供整个计算机使用,而在当前用户存储中创建的证书仅限于当前用户。
让我们创建一个自签名证书并将其添加到计算机的根证书存储区,以及计算机的受信任发布者存储区。首先,我们必须在本地计算机的证书存储区中创建一个名为**“测试证书”的新证书,并将输出保存在$testCert变量中。我们稍后将需要这个变量来注册authenticode 证书**:
> $testCert = New-SelfSignedCertificate -Subject "Test Certificate" -CertStoreLocation Cert:\LocalMachine\My -Type CodeSigningCert
完成此操作后,我们将把 authenticode 证书添加到计算机的根证书存储区。根证书存储区是一个受信任的根 CA 证书列表,因此存储区中的每个证书都会被信任。
我们必须将新创建的证书从中间 CA 存储移动到根 证书存储区:
> Move-Item Cert:\LocalMachine\CA\$($testCert.Thumbprint) Cert:\LocalMachine\Root
现在,你的证书应该出现在两个不同的位置:
-
本地计算机的个人证书存储区:此证书将作为代码签名证书使用。
-
本地计算机的根证书存储区:将证书添加到计算机的根证书存储区可以确保本地计算机信任个人证书存储区以及受信任发布者证书存储区中的证书。
你可以通过使用 PowerShell 或者通过使用mmc和本地计算机的证书管理单元来验证所有证书是否都在正确的位置(运行mmc,添加证书管理单元,并选择本地计算机范围),如下图所示:
图 11.2 – 查找新创建的测试证书
如果你想使用 PowerShell 检查所有证书是否已创建,可以运行以下命令:
> Get-ChildItem Cert:\LocalMachine\ -Recurse -DnsName "*Test Certificate*"
你可以在以下截图中看到此命令的输出:
图 11.3 – 验证所有证书是否都在正确的位置
现在我们已经创建了本地证书,可以开始使用Set-AuthenticodeSignature cmdlet 来对脚本进行自签名。
在这个示例中,我重用了我们在第一章中创建的HelloWorld.ps1 PowerShell 脚本,开始使用 PowerShell,该脚本可以从本书的 GitHub 仓库下载:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter01/HelloWorld.ps1。
将脚本保存在C:\tmp\HelloWorld.ps1下。
如果你在会话中仍然可以使用之前创建证书时使用的$testCert变量,你当然可以重用它,但大多数情况下,当你想要签署脚本时,时间已经过去,你可能已经关闭了会话,这样该变量就无法使用了。
因此,首先,将证书分配给一个变量,以便您用它来签署脚本:
> $signingCertificate = Get-ChildItem Cert:\LocalMachine\ -Recurse -DnsName "*Test Certificate*"
请确保指定您之前创建的证书的正确名称。
为确保文件上的签名保持有效,即使证书在一年后过期,在签名脚本时使用一个可信的时间戳服务器也非常重要。您可以使用Set-AuthenticodeSignature来做到这一点。时间戳服务器会将时间戳添加到签名代码中,表示代码签名的确切日期和时间。这个时间戳用于证明代码是在证书过期之前签名的,即使证书已经过期。
因此,建议始终使用一个可靠且知名的时间戳服务器,以确保签名代码的长期有效性和真实性。时间戳协议(TSP)标准定义在RFC3161中,您可以在这里阅读更多内容:www.ietf.org/rfc/rfc3161.txt。
由 David Manouchehri 发布了一个很棒(但当然不是完整的)列表,您可以使用它来选择您首选的时间戳服务器:gist.github.com/Manouchehri/fd754e402d98430243455713efada710。
对于我们的示例,我使用的是http://timestamp.digicert.com服务器:
> Set-AuthenticodeSignature -FilePath "C:\tmp\HelloWorld.ps1" -Certificate $signingCertificate -TimeStampServer "http://timestamp.digicert.com"
一旦脚本成功签名,输出将类似于以下内容:
图 11.4 – 脚本签名成功
您可以通过使用Get-AuthenticodeSignature -FilePath C:\tmp\HelloWorld.ps1 | Format-List命令来验证脚本是否已签名,如以下截图所示:
图 11.5 – 验证文件是否已签名
但这不是验证文件是否已签名的唯一方法。如果您右键点击一个已签名的文件并打开其属性,在数字签名选项卡下,您将看到用于签名的证书已被添加:
图 11.6 – 使用文件属性验证文件是否已签名
此外,如果您打开新签名的脚本,您会看到其内容发生了变化:除了代码之外,您还会看到签名——由# SIG # Begin signature block引入,并由# SIG # End signature block结束,中间是一个巨大的签名块。如以下截图所示,我已经缩短了签名块,因为签名会太大,无法在本书中显示为图片:
图 11.7 – 签名后的文件现在包含签名块
如果我们启用ExecutionPolicy AllSigned并尝试运行自签名脚本,则会询问我们是否真的想要从此不受信任的发布者运行软件:
图 11.8 – 执行策略提示
要执行此脚本,我们必须选择[R] Run once。如果您希望每次都无需提示即可永久运行来自此发布者的脚本,可以使用[A] Always** **Run选项。
如果您希望无需任何提示即可运行来自此发布者的脚本,可以将自签名证书添加到受信任的发布者存储中。这允许您在发布者和您的计算机之间建立一个信任关系,确保来自发布者的脚本自动受信并且无中断地执行。
如果我们希望永久运行来自此发布者的脚本而无需提示,我们需要将自签名证书添加到计算机的受信任的发布者证书存储中:
> $publisherCertStore = [System.Security.Cryptography.X509Certificates.X509Store]::new("TrustedPublisher","LocalMachine")
> $publisherCertStore.Open("ReadWrite")
> $publisherCertStore.Add($testCert)
> $publisherCertStore.Close()
通过将证书添加到受信任的发布者存储中,您可以确保所有由您的自签名证书签名的代码都是可信的。由于不能使用Copy-Item从一个存储复制证书到另一个存储,因此我们必须使用证书存储 API接口来访问受信任的发布者证书存储,然后以读写权限打开它,添加我们之前创建的证书,然后再次关闭存储。
现在,如果我们再次执行HelloWorld.ps1脚本,它将在不提示我们的情况下运行,而未经签名的文件将被拒绝:
图 11.9 – 经过签名的文件可以无问题执行
如果您已经实施了任何应用程序控制机制,例如 AppLocker 或 WDAP,则只允许运行经过签名的文件 – 如果 发布者已添加为信任的应用程序控制机制运行的可信来源。根据所使用的应用程序控制系统,可以通过策略中的发布者规则或其他类似机制来信任发布者。
由于脚本签名为签署的确切文件添加了签名,如果要保持签名的有效性,则无法修改该文件。如果您修改了已签名文件的内容,并使用Get-AuthenticodeSignature验证签名,您会发现签名的哈希值不再与文件内容匹配。因此,签名将无效,如果已应用未签名脚本的保护机制,则无法再执行该文件:
图 11.10 – 修改已签名文件内容后的哈希不匹配
因此,每当您修改已签名文件的内容时,您需要再次对其进行签名。如果您有一个持续集成/持续交付(CI/CD)管道,脚本签名可以通过Set-AuthenticodeSignature cmdlet 轻松自动化。
如果您是 CI/CD 概念的初学者,有多种方法可以构建 CI/CD 管道。仅举几例,CI/CD 管道可以通过 Azure DevOps 或 GitHub 来实现。
以下是一些帮助您入门的资源:
- 使用 Azure 设计 CI/CD 管道 DevOps:
learn.microsoft.com/en-us/azure/devops/pipelines/architectures/devops-pipelines-baseline-architecture
)
- 如何用 GitHub Actions 构建 CI/CD 管道的四个简单步骤:
github.blog/2022-02-02-build-ci-cd-pipeline-github-actions-four-steps/
同时,确保在计划在生产环境中使用代码签名时,遵循最佳实践也非常重要。微软发布了一个代码签名最佳实践文档,您可以将其作为参考:download.microsoft.com/download/a/f/7/af7777e5-7dcd-4800-8a0a-b18336565f5b/best_practices.doc
代码签名是确保您的脚本合法且未被篡改的好方法。但正如您在本书前面学到的,仅凭执行策略并不是安全边界,且很容易被绕过。因此,仅依赖执行策略并不是一个好主意。如果您想防止未经授权的脚本在您的环境中运行,您需要实施应用程序控制解决方案。
控制应用程序和脚本
应用程序控制解决方案不仅可以防止未经授权的 PowerShell 脚本,还可以用于定义哪些应用程序、可执行文件和 DLL 被允许在环境中运行。
需要牢记的是,尽管 PowerShell 攻击可能是许多专业人员关心的问题,但它们只占通过系统传播的恶意软件的一小部分。必须重视传统的可执行文件和 DLL 攻击所带来的威胁,切勿忽视这一点。
应用程序控制解决方案通常提供禁止单个不需要的应用程序的功能,但理想的结果应始终是禁止所有应用程序并配置所有允许的应用程序。如您在第五章中所回忆的,PowerShell 非常强大——系统和 API 访问,即使您在环境中阻止了PowerShell.exe,也仍然可以通过使用本地 API 函数来运行它,无论是否有必要阻止 PowerShell(当然,您不应该这么做;更好的做法是实施并利用正确的日志记录和安全策略)。
如果你只是禁止不需要的应用程序,攻击者总是能找到绕过你限制的方法——要屏蔽的东西实在太多,仅仅禁止不需要的应用程序会让你的环境始终处于攻击的脆弱状态。
最好从直接审计你环境中使用和需要的软件开始,实施适当的应用控制策略,并防止其他一切程序的运行。
市场上有很多应用控制工具,但在本书中,我们只关注微软的 AppLocker 和 WDAC。
应用控制规划
在将严格的规则强制应用于你的生产环境之前,确保你始终审计并创建一个已使用应用程序的软硬件目录。你不希望对员工产生如此大的影响,导致他们无法正常工作。
即使你只是实施审计策略,你也已经显著改善了 SIEM 中的信噪比。考虑一下这种情况:在实施应用控制之前,你的 SIEM 每天都会被成千上万的事件淹没,这些事件来自已知和授权的应用程序,这使得识别潜在的恶意软件或不需要的软件变得极其具有挑战性。
但是,如果你只能实施 80%的应用控制策略,因此只启用审计功能,那么事件的数量就会减少到一个可管理的水平。在这种情况下,你每天只会剩下几百个事件,这些事件包含合法的软件操作以及潜在的不需要的软件或恶意软件。这种方法已经显著减少了你的 SIEM 中的噪音,并使你能够以更好的方式保护你的环境。
一旦你创建了第一个策略,确保在推出之前进行测试。一旦你准备好部署,按照以下推出策略进行:
-
在测试环境中测试你的策略。
-
尽早宣布你的配置更改是非常有用的,这样员工就能更好地进行规划。
-
将你的技术部门划分为几个小组,然后慢慢为第一个小组推出策略,审查审计日志,并及时修复问题。一旦修复完毕,就为下一个小组推出策略,依此类推。
-
如果在上一步部署时一切正常,将你的策略推广到你环境中的高级用户。不言而喻,在推出此类策略之前,始终与可能受影响的人进行沟通。
-
在修复所有可能的配置问题后,慢慢按部门推出策略。始终确保你将每个小组划分为子小组,并在强制更改之前与受影响的员工进行沟通。
定期审查你封锁的应用程序。这不仅有助于你识别用户可能遇到的问题,还能帮助你发现攻击的初期迹象。
确定正在使用哪些应用程序并相应调整配置需要一些时间,但这是值得的,它将大大帮助您加固环境。
首先,我们来看看在 Windows 操作系统上有哪些可用的应用程序控制选项。
内建的应用程序控制解决方案
多年来,微软一直在开发多种应用程序控制解决方案,从 Windows XP 的 SRP 到 Windows 8 引入的 AppLocker,再到最终在 Windows 10 中发布的 WDAC。
多年来,功能得到了极大的改进,每个工具都为其前版本带来了优势。如果可能,请始终使用 WDAC 进行应用程序控制,因为它会不断得到改进。但如果您仍在使用需要限制的较旧操作系统版本,可以同时运行这三种解决方案。
下图为您提供了这三种解决方案的简化比较:
图 11.11 – SRP、AppLocker 和 WDAC 的简化比较
当然,这不是所有功能的完整列表。请参阅以下链接,了解 SRP、AppLocker 和 WDAC 之间的差异的更详细概述:
- 软件限制策略与 AppLocker 之间有哪些功能不同?: [
docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/applocker/what-is-applocker#what-features-are-different-between-software-restriction-policies-and-applocker](docs.microsoft.com/en-us/windo…
)
- Windows Defender 应用程序控制和 AppLocker 功能 可用性:
learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/feature-availability
这些解决方案是庞大的话题,因此您只会看到每种技术的概述,以及一些帮助您开始实施自己应用程序控制规则的技巧。由于本书的重点是 PowerShell,我们将在本章中主要关注限制和使用 PowerShell。
熟悉 Microsoft AppLocker
AppLocker 是微软推出的 SRP 的继任者,并在 Windows 7 中引入。您可以使用它扩展 SRP 的功能以及它的特性。
与 SRP 相比,AppLocker 策略可以限制特定的用户或组,并且也可以在强制执行规则之前进行审计。可以通过多种方式并行部署 SRP 和 AppLocker 策略;请查看以下文档:
-
在同一 域中使用 AppLocker 和软件限制策略:
learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/applocker/use-applocker-and-software-restriction-policies-in-the-same-domain -
使用软件限制策略和 AppLocker 策略:
learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/applocker/using-software-restriction-policies-and-applocker-policies
要部署 AppLocker 的计算机需要安装允许强制执行 AppLocker 策略的操作系统,如 Windows Enterprise。你也可以在运行 Windows Professional 的计算机上创建 AppLocker 规则。然而,只有当这些系统通过 Intune 进行管理时,才能强制执行 AppLocker 规则。如果没有强制执行 AppLocker 规则,它们将不生效,且无法提供任何保护。
如果你想限制在不受支持的操作系统上的应用程序,可以同时部署 SRP 规则,或者使用 WDAC。
为了使 AppLocker 正常工作,要求 应用程序身份 服务必须在运行。
部署 AppLocker
你可以使用 GPO、Intune、Microsoft 配置管理器和 PowerShell 部署 AppLocker。当然,你也可以使用本地组策略编辑器进行测试。但通过此方法无法强制执行 AppLocker 规则,因此你应避免在生产环境中使用。
在使用 AppLocker 时,你可以配置五种不同的规则类型:
-
可执行规则:使用 可执行规则,你可以限制以
.exe和.com结尾的可执行文件。 -
Windows 安装程序规则:通过配置 Windows 安装程序规则,你可以限制
.msi、.mst和.mspWindows 安装程序文件。 -
脚本规则:使用 脚本规则,你可以限制
.ps1、.bat、.cmd、.vbs和.js脚本文件。 -
DLL 规则:你可以使用 DLL 规则来限制
.dll和.ocx文件。
尽管由于性能问题,DLL 规则曾经被认为是可选的,但在当今的安全环境中,没有启用 DLL 强制执行的应用程序控制系统是不完整的,会使您的环境容易受到攻击。这些规则必须在使用和配置之前启用,并且可以使用 GPO 或本地组策略进行配置。如果您正在使用 GPO 进行配置,请转到计算机配置 | 策略 | Windows 设置 | 安全设置 | 应用程序控制策略 | **AppLocker。然后,右键单击AppLocker,选择属性** | 高级 | 启用 DLL 规则集合。
- 打包应用规则:使用打包应用规则,您可以限制
.appx包文件。
对于您创建的每个规则,您需要选择一个操作。在这里,您必须决定文件是应该被允许还是被阻止,通过选择允许或拒绝。通常,您希望阻止一切,只允许选定的应用程序。
使用 AppLocker 规则,也可以将规则范围限定到特定的用户或组。如果没有特别指定,规则适用于所有人。
您还需要决定规则应包含的主要条件。对于打包应用规则,您只能配置一个发布者条件;对于所有其他规则,可以应用路径和文件哈希条件 - 除了发布者条件:
-
路径:使用路径条件,您可以指定一个路径,该路径将被规则允许或拒绝。您还可以定义一个异常。使用路径条件是最不安全的条件,因为文件和路径名称很容易被更改以绕过您的规则。如果可能的话,尽量避免路径规则。
-
发布者:使用发布者条件时,文件需要进行数字签名。使用此条件,您不仅可以指定发布者 - 还可以指定产品名称、文件名以及文件版本,以确定文件是否应该被允许或拒绝。也可以定义异常。
-
文件哈希:将为此文件计算一个加密文件哈希。如果文件发生更改,文件哈希也将发生变化。因此,哈希只能应用于一个文件,如果使用此条件,您需要为要允许或拒绝的每个文件配置一个文件哈希条件。
所有这些规则、操作、用户范围和条件都适用于所有配置方法。
在您的环境中配置 AppLocker 可能需要一些时间,但一旦实施,它就是值得的。为了帮助您进行初始配置,Aaron Margosis 在 GitHub 上发布了 AaronLocker:github.com/microsoft/AaronLocker。
这个脚本和文档集合应该有助于使您的初始配置以及维护您的 AppLocker 规则尽可能简单。
AaronLocker 的背后 - 名字是从哪里来的?
AaronLocker这个名字并不是 Aaron 自己想出来的——这是我的朋友兼长期导师 Chris Jackson 的主意。不幸的是,他在不久前去世了(愿 Chris 安息!)。Aaron 并不特别喜欢将他的产品命名为自己的名字,但由于他一时想不出更好的名字,于是他妥协了,接受了 Chris 的建议,AaronLocker这个名字也就诞生了。
然而,我们目前仅了解了 AppLocker 规则的组成部分,并未学习如何通过不同的部署方法来部署和配置这些规则。因此,接下来的步骤是探索如何管理 AppLocker。
GPO
如果您使用 GPO 或本地组策略进行配置,请导航到计算机配置 | 策略 | Windows 设置 | 安全设置 | 应用程序控制策略 | **AppLocker。在此部分,您将看到可执行规则**、Windows 安装程序规则、脚本规则和打包应用规则选项,如下所示:
图 11.12 – 使用 GPO 配置 AppLocker
要启用强制执行或审计行为,右键单击AppLocker并选择属性。在弹出的窗口中,您可以配置哪些 AppLocker 规则应被强制执行或审计。
如果您使用 GPO 作为配置方法,请确保您要配置的所有系统至少安装了 Windows 10 企业版。否则,您无法强制执行 AppLocker 规则。
如果您还想启用 DLL 规则,可以通过右键单击AppLocker并选择属性 | 高级 | 启用 DLL 规则集合来实现。请参考 DLL 规则的描述以了解更多信息。启用 DLL 规则后,它们将在 AppLocker 下显示。
Intune
在您通过 Intune 配置 AppLocker 之前,您需要使用 GPO 或本地组策略创建一个 AppLocker 策略。配置完成后,通过右键单击AppLocker并选择导出策略来导出策略:
图 11.13 – 导出 AppLocker 策略
将弹出一个窗口,您需要选择导出策略保存的路径。选择一个路径并确认;您的 AppLocker 策略将成功导出为.****xml文件。
不幸的是,您不能仅将文件内容复制并粘贴到 Intune 配置中。因此,使用编辑器打开文件并搜索每个规则类型的部分。该部分由**<RuleCollection …> … **标签表示,来自RuleCollection。
每种规则类型都有一个RuleCollection部分,因此,如果您想获取所有可执行文件的RuleCollection部分,请选择<RuleCollection Type="Exe" EnforcementMode="NotConfigured">之间的所有内容,包括周围的标签,如下图所示。如有需要,重复此操作以获取其他可用规则类型的部分:
图 11.14 – 选择可执行规则的 RuleCollection 部分
使用 Intune 配置 AppLocker 依赖于 AppLocker 配置服务提供程序(CSP):docs.microsoft.com/en-us/windows/client-management/mdm/applocker-csp.
CSP 提供了一个接口,允许移动设备管理(MDM)解决方案控制、配置、读取、删除和编辑正在管理的设备的配置设置。可以使用开放移动联盟统一资源标识符(OMA-URI)字符串配置 Windows 10 设备的自定义配置。
多亏了 Intune 和 AppLocker CSP,大多数操作系统可以配置为在执行模式下使用 AppLocker:
)
- 通过 Intune 部署 OMA-URI 以针对 CSP,及与 本地部署的对比:
learn.microsoft.com/en-us/troubleshoot/mem/intune/device-configuration/deploy-oma-uris-to-target-csp-via-intune
现在,在 Intune 中,转到 设备 | 配置文件,然后点击 创建配置文件。
在 平台下选择Windows 10 及以后版本,在配置文件类型下选择模板,在模板下选择自定义,然后点击 创建:
图 11.15 – 创建配置文件
在下一页中,为您的 AppLocker 策略命名—例如,AppLocker 策略—然后点击 下一步。
在 OMA-URI 设置部分,选择 添加 来添加您的 AppLocker 规则配置。在这里,您将使用从 .xml 导出的片段创建实际的策略。
首先,输入一个能够很好地代表策略的名称,例如 Exe 策略,如果您想开始为您的环境中的 .exe 文件配置策略。
在 OMA-URI 字段中,按照您刚刚配置的策略输入字符串:
-
Exe**: **./Vendor/MSFT/AppLocker/AppLocker/ApplicationLaunchRestrictions/apps/EXE/Policy -
MSI**: **./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/apps/MSI/Policy -
**脚本
: **./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/apps/Script/Policy -
DLL**: **./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/apps/DLL/Policy -
Appx**: **./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/apps/StoreApps/Policy
将数据类型更改为字符串,并粘贴你之前从导出的.xml文件中复制的RuleCollection行。点击保存。对于每个要配置的规则类型,在OMA-URI 设置区域中添加一个策略。一旦完成,点击审核 + 保存以保存你的配置:
图 11.16 – 配置 OMA-URI 设置
下一步,你可以添加这些规则应该应用的计算机组。点击下一步直到进入审核 + 创建部分,审查你的规则。如果一切正常,点击创建来创建你的 AppLocker 规则。
微软配置管理器
配置管理器以前被称为系统中心配置管理器(SCCM)。配置管理器包含许多预配置的配置选项和软件包,但不幸的是,没有为 AppLocker 预配置的选项。然而,它仍然可以通过自定义配置选项进行部署。
在合规性设置下,创建一个新的配置项;在创建配置项向导区域,指定新策略的名称,并在没有配置管理器客户端的设备设置下选择Windows 8.1 和 Windows 10:
图 11.17 – 使用配置管理器创建自定义 AppLocker 策略
类似于使用 Intune 进行的配置,我们也可以使用 AppLocker CSP 来配置配置管理器。
接下来,选择你要配置 AppLocker 的平台——在我的示例中,我只选择了Windows 10并点击下一步。
下一步,不要选择任何设备设置;相反,勾选配置不在默认设置组中的附加设置复选框,然后点击下一步。
在附加设置窗格中,点击添加。将打开浏览设置窗口。接下来,点击创建设置…。一个名为创建设置的新窗口将打开,如下所示:
图 11.18 – 指定策略的名称和 OMA-URI
在创建设置对话框中,输入设置的名称并指定 OMA-URI 的字符串,就像我们在Intune 配置部分所做的那样(这也是你可以在本书中找到总结的 OMA-URI 字符串的地方)。点击确定。
下一步,通过双击刚刚创建的设置来指定此设置的规则,并输入一个有意义的名称,在规则类型下选择值,并确保EXE 策略(或你之前配置的设置名称)等于我们在Intune部分创建的RuleCollection XML 片段。
通常,配置管理器项目用于查询状态。如果状态与期望的结果不同,你可以选择配置规则,使其在支持的情况下自动修复不合规的规则。
对每种规则类型重复此步骤,直到所有规则都按要求配置完毕。
点击下一步,直到创建配置项向导任务显示为成功完成。
现在,创建一个配置基准任务,输入一个有意义的名称,然后点击添加。选择之前创建的策略将其添加到此基准,并点击确定确认。
最后但同样重要的是,通过选择基准并配置合规评估计划来部署新的配置基准,以定义检查和应用基准的间隔时间。在我的例子中,我已经设置该基准应该每天运行一次。再次确认此操作并点击确定。
PowerShell
当然,你也可以使用 PowerShell 配置和读取 AppLocker 规则。可以使用名为 AppLocker 的模块,该模块已经包含了多个功能,帮助你完成这项工作。
以下截图提供了所有与 AppLocker 相关的 PowerShell 命令的概览:
图 11.19 – AppLocker 模块中的功能
初看起来,这个模块提供的功能非常有限,但让我们深入研究每个函数,它们的功能比你预期的要多得多,允许你比使用用户界面更加高效地工作。
Get-AppLockerPolicy帮助你找出是否存在 AppLocker 策略。使用-Effective参数,你可以看到是否已经指定了策略:
图 11.20 – 使用 Get-AppLockerPolicy 获取有效的 AppLocker 策略
你也可以使用-Local参数查看本地 AppLocker 策略中定义的内容。-Domain参数与-Ldap参数结合使用,帮助你查看当前域配置的 AppLocker 策略。当然,你还可以使用-Xml参数从.xml文件中调查策略。
使用Get-AppLockerFileInformation可以获取来自文件、路径或事件日志的所有信息:
图 11.21 – 使用 Get-AppLockerFileInformation 检索 AppLocker 文件信息
在前面的截图中,你可以看到我们代码签名示例中两个演示脚本的 AppLocker 信息。通常,如果脚本是由企业或公共 CA 签名的,你还会看到发布者信息,但由于我们使用的是自签名脚本,这个证书仅用于测试目的,因此没有发布者信息,因此我们无法使用它来创建 AppLocker 发布者规则。
通常,生成 AppLocker 规则最常见的方法是基于服务器或客户端系统的黄金镜像创建策略,而不是手动选择单个文件和目录。为此,你可以使用Get-AppLockerFileInformation cmdlet 来识别图像上所有被授权运行的文件,然后使用New-AppLockerPolicy cmdlet 为每个文件自动生成相应的 AppLocker 规则。
以下示例将C:\驱动器中的所有文件进行处理,并为每个文件生成一个规则—生成的文件将保存在C:\tmp\Applocker.xml中:
> Get-AppLockerFileInformation -Directory 'C:\' -Recurse -ErrorAction SilentlyContinue | New-AppLockerPolicy -RuleType Publisher,Hash -User Everyone -RuleNamePrefix PSTmp -Xml | Out-File -FilePath "C:\tmp\Applocker.xml"
一旦文件创建完成,你需要对其进行测试和微调,以便为你的黄金镜像部署 AppLocker 规则。
另一种非常有效的部署 AppLocker 的方法是捕获来自现有已知良好系统的事件,这些系统已安装所需的软件,并且被认为是没有被攻击的。使用这些事件通过 PowerShell 生成策略可以节省你大量的时间和精力。甚至可以通过管道输入事件日志中的文件信息来自动生成 AppLocker 规则。当处理大型复杂环境时,这尤其有用,因为手动创建规则可能是一个艰巨的任务:
> Get-AppLockerFileInformation -EventLog -EventType Audited | New-AppLockerPolicy -RuleType Publisher,Hash -User Everyone -RuleNamePrefix AuditedApps -Xml | Out-File -FilePath "C:\tmp\AuditedApps-Applocker.xml"
然后,你可以使用Set-AppLockerPolicy cmdlet 来配置组策略或本地组策略,并应用指定的 AppLocker 配置:
Set-AppLockerPolicy -XmlPolicy "C:\tmp\AppLockerPolicy.xml"
要在远程域控制器上配置 GPO,确保使用-Ldap参数,并配置 LDAP 路径到策略所在的位置。如果你想将现有策略与新配置的策略合并,确保指定-Merge参数。
此 cmdlet 仅适用于组策略或本地策略。如果你通过 AppLocker CSP 配置了 AppLocker,则此 cmdlet 将无法工作。
使用Test-AppLockerPolicy cmdlet,你可以测试 AppLocker 策略,看看在指定策略应用的情况下,某个文件是否会被允许执行:
图 11.22 – 使用 Test-AppLockerPolicy 来查看 notepad.exe 或 putty.exe 是否被允许运行
在这个截图中,你可以看到,使用此 AppLocker 策略,notepad.exe将被允许运行,而putty.exe将被禁止运行,因为没有配置匹配的允许规则。
在开始以强制规则执行模式部署 AppLocker 之前,您需要定期使用仅审核执行模式审核哪些应用程序和脚本可以在您的环境中使用。这样,您可以在执行规则之前将它们列入允许名单。您可以通过查看事件日志来利用日志功能实现这一点。
审核 AppLocker 事件
使用事件日志时,您不仅可以找出在使用仅审核执行模式时哪些应用程序会被阻止——还可以获得更多有趣的信息,了解您的 AppLocker 策略是如何应用的,或者哪些应用程序在强制规则 执行模式下运行。
使用 PowerShell,您可以通过运行Get-WinEvent -****ListLog *AppLocker*快速概览所有与 AppLocker 相关的事件日志:
图 11.23 – AppLocker 事件日志
若要从特定日志中获取所有事件 ID,使用Get-WinEvent,后跟事件日志的名称。例如,如果您想获取Microsoft-Windows-AppLocker/EXE 和 DLL日志中的所有事件 ID,您可以运行Get-WinEvent "Microsoft-Windows-AppLocker/EXE** **and DLL"。
您可以在第四章中找到关于 AppLocker 事件日志及所有事件 ID 的更多详细信息,检测 – 审核 和监控。
在规划 AppLocker 部署时,查看哪些应用程序被允许、拒绝或审核的统计数据也是非常有用的。您可以使用Get-AppLockerFileInformation来实现这一点,如下图所示:
图 11.24 – 审核应用程序的统计数据
使用EventType,您可以选择已允许、已拒绝或已审核。这样,您可以查看有关文件的所有信息,以及它尝试运行应用程序的频率和文件是否被允许或是否会被拒绝的决定。
请参考以下链接了解如何使用 AppLocker 监控应用程序使用情况:docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/applocker/monitor-application-usage-with-applocker。
探索 Windows Defender 应用程序控制
随着 Windows 10 的推出,Windows Defender 应用程序控制(WDAC)允许组织控制其环境中使用的应用程序和驱动程序。WDAC 作为操作系统的一部分实现,也曾以设备保护的名称出现。
建议将 WDAC 与 基于虚拟化的安全(VBS)结合使用。与 VBS 配合使用时,WDAC 的安全性通过虚拟化隔离得到加强,使得攻击者更难绕过你配置的应用控制限制。虽然技术上 VBS 对 WDAC 并不是必需的,但它可以显著增强系统的整体安全性,且如果可能的话应始终启用。
与 AppLocker 规则相比,WDAC 规则会部署到整个机器,并影响每个登录到此机器的用户。但 WDAC 还提供更多功能,并被认为比 AppLocker 更安全。其原则是在信任被获得之前不信任任何东西。
例如,从微软应用商店安装的应用程序被认为是可信的,因为每个进入商店的应用都经过严格的审核过程。默认的 Windows 应用程序也被认为是可信的,无需单独列入允许名单。其他应用程序也可以通过 Microsoft Intelligence Security Graph 获得信任。
是否允许应用程序在系统上执行由所谓的 代码 完整性策略 来确保。
创建代码完整性策略
代码完整性确保只有受信任的系统文件和驱动程序在系统启动和运行时被加载到内存中。它在允许文件运行之前验证文件的数字签名,并防止未签名或签名不正确的文件加载。
用于配置自定义 WDAC 规则的策略称为 代码完整性策略(CI 策略)。与其他应用程序控制机制类似,建议先在审计模式下部署策略,并在启用强制执行模式之前监控是否有意外行为。
在每个支持 WDAC 的 Windows 系统中,你可以在 C:\Windows\schemas\CodeIntegrity\ExamplePolicies 下找到一些示例策略,如以下截图所示:
图 11.25 – 内置示例代码完整性策略
如果你创建自定义策略,建议从现有的示例策略开始,然后根据需要进行修改,以构建你自己的自定义策略。以下列表将帮助你确定哪个 示例策略 最适合作为添加自定义规则的基础:
-
AllowAll.xml:如果你打算禁止不需要的应用程序,这是一个很好的基础——你只需要添加所有拒绝规则。请记住,保护系统免受未经授权访问的最佳方法是控制所有应用程序,只允许选定的应用程序。 -
AllowAll_EnableHVCI.xml:应用此策略后,您可以启用内存完整性/虚拟化保护代码完整性,以防止内存攻击。有关此主题的更多信息,请参阅以下文档:support.microsoft.com/en-us/windows/core-isolation-e30ed737-17d8-42f3-a2a9-87521df09b78。 -
AllowMicrosoft.xml:此策略允许 Windows、第三方硬件和软件内核驱动程序、Windows 商店应用以及由 Microsoft 产品根证书签名的应用。 -
DefaultWindows_Audit.xml:审计模式允许 Windows、第三方硬件和软件内核驱动程序以及 Windows 商店应用。 -
DefaultWindows_Enforced.xml:强制模式允许 Windows、第三方硬件和软件内核驱动程序以及 Windows 商店应用,但阻止所有未配置的内容。 -
DenyAllAudit.xml:此策略用于跟踪关键系统上的所有二进制文件——它审计如果所有内容被阻止时将会发生什么。如果启用此策略,可能会导致 Windows Server 2019 操作系统长时间启动。
在大多数使用场景中,DefaultWindows_Audit.xml和DefaultWindows_Enforced.xml策略是创建自定义策略并根据需要通过自定义规则扩展它们的最佳选择。
还有一份 Microsoft 推荐的阻止规则列表,您应当遵循:learn.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-block-rules。
此列表中的建议还可以帮助您减轻降级攻击。这是一种攻击,攻击者利用旧版 PowerShell v2 绕过较新版本的安全功能和日志机制。我们在第四章中探讨了这种攻击,检测 – 审计 和监控。
尽管此列表中的许多项目在常见策略中默认可能是允许的,但重要的是要仔细考虑在您的场景中明确需要哪些可执行文件和二进制文件,并阻止所有不必要的文件。
在使用配置管理器管理的设备上,C:\Windows\CCM\DeviceGuard目录下有一个额外的示例策略。此策略可以作为基础策略,用于通过配置管理器部署 WDAC 策略。
一旦选择了你想用作基础的示例策略,你可以开始修改所选策略的副本。你可以配置许多选项,所以你可能想要通过查看官方文档中所有可用的配置选项来开始:learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/design/select-types-of-rules-to-create。
你可以编辑示例策略 XML 文件,或者使用 PowerShell 自动化创建代码完整性策略的过程。以下截图显示了可以操作代码完整性策略的 cmdlet:
图 11.26 – 代码完整性策略相关的 cmdlet
一个例子是,使用 WDAC 策略向导,它利用了我们将在后续章节中查看的 WDAC CI cmdlet,并作为一个包装器,通过图形用户界面(GUI)来创建 CI 策略。你可以从官方网站下载这个有用的工具:webapp-wdac-wizard.azurewebsites.net/。
也可以使用New-CIPolicy cmdlet 创建自定义的 XML 策略:一种方法是扫描参考系统并创建一个参考 XML 策略。
扫描参考系统以创建 XML CI 策略
以下示例展示了如何扫描 System32 路径和 Program Files 文件夹,并随后将两者的策略合并为一个。
首先,让我们扫描 Windows System32 路径:
> New-CIPolicy -FilePath "C:\AppControlPolicies\Windows.xml" -Level Publisher -UserPEs -ScanPath "C:\Windows\System32"
虽然-ScanPath参数表示应该被New-CIPolicy扫描的路径,-UserPEs参数表示也会扫描用户模式文件。只有在你没有提供驱动程序文件或规则,而是希望扫描参考系统或路径时,才使用-UserPEs和-ScanPath参数。
使用-FilePath参数,你可以指定新创建的 CI 策略应该保存到的输出文件夹。在此示例中,我们将其保存到了C:\AppControlPolicies\Windows.xml。
还有-Level参数,表示 CI 策略的级别。通过它,你可以指定允许运行哪些类型的文件。在此情况下,策略被设置为Publisher级别,意味着所有代码必须由受信任的发布者签名才能运行。
还可以使用以下级别:
-
None:禁用代码完整性强制执行。没有规则被执行。如果你想配置一个稳健的 CI 策略,这个级别没有意义。 -
Hash:仅允许在其哈希值与指定值匹配时,应用程序才能运行。 -
FileName:仅允许在应用程序位于特定文件路径时运行。这个级别一开始可能听起来很诱人,但它带来了更多的风险。如果攻击者能够访问系统上的文件,他们可能会轻松地将现有文件替换为恶意文件。最好不要使用这个选项。 -
SignedVersion:仅允许在应用程序具有特定签名版本时运行。 -
Publisher:仅允许在应用程序由指定发布者签名时运行。 -
FilePublisher:仅允许在应用程序由指定发布者签名且位于特定文件路径时运行。 -
LeafCertificate:仅允许在应用程序由指定的叶证书签名时运行。 -
PcaCertificate:仅允许在应用程序由指定 PCA 证书签名时运行。 -
RootCertificate:仅允许在应用程序由指定根证书签名时运行。 -
WHQL:仅允许加载经过Windows 硬件质量实验室(WHQL)认证的签名驱动程序。 -
WHQLPublisher:仅允许加载经过 WHQL 认证并由特定发布者签名的驱动程序。 -
WHQLFilePublisher:仅允许加载经过 WHQL 认证、由特定发布者签名并位于特定文件路径的签名驱动程序。
接下来,让我们扫描Program Files文件夹,以从指定的参考系统创建策略:
> New-CIPolicy -FilePath "C:\AppControlPolicies\ProgramFiles.xml" -Level Publisher -UserPEs -ScanPath "C:\Program Files" -NoScript -Fallback SignedVersion,FilePublisher,Hash
再次说明,我们已将用户模式文件包含在扫描中,并希望确保所有包含在策略中的文件都由指定发布者签名。我们必须定义将新创建的策略保存到C:\AppControlPolicies\ProgramFiles.xml。为了避免脚本文件被包含在这个参考策略中,我们必须指定-NoScript参数。
使用-Fallback参数,您可以指定回退顺序;在这种情况下,如果在FilePublisher级别没有匹配项,策略引擎将回退到SignedVersion、FilePublisher和Hash级别——恰好是这个顺序。
最后但同样重要的是,我们需要将策略合并为一个。为此,我们可以使用Merge-CIPolicy cmdlet:
> Merge-CIPolicy -PolicyPaths "C:\AppControlPolicies\Windows.xml", "C:\AppControlPolicies\ProgramFiles.xml" -OutputFilePath "C:\AppControlPolicies\AppControlPolicy.xml"
使用-PolicyPaths参数,我们可以指定应合并的策略,而使用-OutputFilePath,我们可以定义合并后的策略保存的位置。在这个例子中,我们将把最终的策略保存到C:\AppControlPolicies\AppControlPolicy.xml。
策略以审计模式创建,因此它无法阻止应用程序,只会审计应用程序的使用。这对于测试和评估哪些应用程序应该被阻止非常有用。
一旦您准备好将阻止策略应用到您的系统,您可以使用以下命令从您的策略中移除仅审计配置:
> Set-RuleOption -FilePath "C:\AppControlPolicies\AppControlPolicy.xml" -Option 3 -Delete
要部署新生成的策略,您需要将其转换为二进制格式。
将 XML 文件转换为二进制 CI 策略
一旦你获得了 CI 策略的 XML 配置文件,你需要将其转换为二进制格式以进行部署。可以使用 ConvertFrom-CIPolicy cmdlet 完成此操作:
> ConvertFrom-CIPolicy -XmlFilePath "C:\AppControlPolicies\AppControlPolicy.xml" -BinaryFilePath "C:\Windows\System32\CodeIntegrity\AppControlPolicy.bin"
这里,我们之前生成的 AppControlPolicy.xml CI 策略将被编译成 AppControlPolicy.bin 二进制文件,并保存在 C:\Windows\System32\CodeIntegrity\AppControlPolicy.bin 下。
如果一个二进制 CI 策略保存在 C:\Windows\System32\CodeIntegrity\ 下,那么在相关系统重启后,它会立即启用。策略被移除后,再次重启系统,CI 策略引入的所有更改都会被撤销。
当然,如果你计划使用 Intune、MEM、GPO 或其他需要二进制配置文件的部署机制来部署 WDAC,你也可以将转换后的 CI 策略保存在你选择的其他路径下。
还有其他方法可以创建 CI 策略 XML 文件——例如,从审核事件中创建。
使用事件日志中的审核事件作为参考
创建 WDAC 策略的另一种方式是通过在审计模式下运行 WDAC,并使用审计日志来创建策略。类似于 AppLocker,如果 WDAC 处于审计模式,则任何在当前 WDAC 配置启用时会被阻止的应用程序都会被记录到审计日志中。
根据应用程序类型,这些事件可以在以下某个事件日志中找到:
-
二进制相关事件
:应用程序和服务日志| **Microsoft** | **Windows** | **CodeIntegrity** |操作 -
MSI 和脚本相关事件
:应用程序和服务日志| **Microsoft** | **Windows** | **AppLocker** | **MSI**和脚本
记录到这些事件日志中的所有事件现在可以被用来创建一个全新的 CI 策略,或者将审核的配置合并到现有策略中:
> New-CIPolicy -FilePath "C:\AppControlPolicies\AuditEvents.xml" -Audit -Level FilePublisher -Fallback SignedVersion,FilePublisher,Hash –UserPEs -MultiplePolicyFormat
此命令会在 C:\AppControlPolicies\AuditEvents.xml 路径下创建一个新的 CI 策略。-Audit 参数指定应使用事件日志中的实际审计事件来创建策略。
-MultiplePolicyFormat 参数使我们能够同时使用多个策略,因为策略将以多策略格式存储,这一格式在 Windows 10 中被引入。
现在,你可以在将新创建的策略与其他现有策略合并和/或将其转换为二进制格式以供进一步使用之前,进行审核和编辑。
使用 New-CIPolicyRule cmdlet 创建 CI 策略
如果你想更精细地定义哪些应用程序应该出现在你的 CI 策略中,New-CIPolicyRule cmdlet 可以帮助你:
> $Rules = New-CIPolicyRule -FilePathRule "C:\Program Files\Notepad++\*"
> $Rules += New-CIPolicyRule -FilePathRule "C:\Program Files\PowerShell\7\*"
> New-CIPolicy -Rules $Rules -FilePath "C:\AppControlPolicies\GranularAppControlPolicy.xml" -UserPEs
上述代码将为Notepad++ 文件夹及其子文件夹创建一个 CI 策略规则,并为PowerShell 7路径创建另一个规则,并将这两个规则保存在$****Rules变量中。
然后,这两个规则可以用来创建一个新的 CI 策略,并保存在 C:\AppControlPolicies\GranularAppControlPolicy.xml 路径下。
之后,你可以使用Merge-CIPolicy将其与其他策略结合,或借助ConvertFrom-CIPolicy将其转换为二进制格式,以便用于其他用途。
你可以使用 ConfigCI PowerShell 模块来探索与代码完整性相关的其他操作方式:learn.microsoft.com/en-us/powershell/module/configci。
虽然从技术上讲并非强制要求,但应启用基于虚拟化的安全功能,如安全启动,以确保代码完整性正常工作。安全启动确保系统仅以受信任的状态启动,并且所有启动文件都带有受信任的签名。这防止了启动过程被篡改,并确保操作系统及其驱动程序的完整性。
基于虚拟化的安全(VBS)
VBS 使用虚拟化作为基础,将内存中的某些区域与普通操作系统隔离。通过这种方式,可以通过加密可用内存和与该内存区域的通信,更好地保护被隔离的区域。
通过这种隔离,内存区域可以更好地保护,免受操作系统中活跃漏洞的影响。
其中一个例子是保护本地安全机构(LSA)中的凭证,这使得从操作系统中提取和窃取凭证变得更加困难。
另一个例子是虚拟化保护的代码完整性(HVCI),它使用 VBS 来实现代码完整性。
虚拟化保护的代码完整性(HVCI)
HVCI,也叫做内存完整性,是 VBS 的关键组件。HVCI 利用 VBS 技术通过确保内核和关键系统组件的完整性,防止内核模式攻击。它通过仅允许受信任和授权的代码在内核模式下运行来实现这一点。
如果 HVCI 激活,CI 功能会被转发到同一台机器上的一个安全虚拟环境中,在该环境中执行 WDAC 功能以确保完整性。如前所述,HVCI 使用 VBS 技术防止内核模式攻击。它通过验证仅允许已知和受信任的代码在内核模式下运行,来强制执行内核和关键系统组件的完整性。但从技术上讲,VBS 对于 WDAC 并不是必须的。
HVCI 利用现代 CPU 中的硬件特性,如虚拟化扩展和受信任的平台模块(TPM),来创建一个安全的执行环境。TPM 用于存储系统引导固件、UEFI 和操作系统二进制文件的哈希值。在系统启动过程中,TPM 会对这些组件进行度量,并将度量结果提供给 HVCI 系统。HVCI 使用这些度量结果验证是否只有已知和受信任的组件被加载到内存中,从而防止未经授权的代码在内核模式下运行。
如果你想为 CI 策略启用 HVCI 选项,可以使用Set-HVCIOptions cmdlet:
> Set-HVCIOptions -Enabled -FilePath "C:\AppControlPolicies\GranularAppControlPolicy.xml"
您还可以通过使用-Strict参数进一步加强这一点:
> Set-HVCIOptions -Strict -FilePath "C:\AppControlPolicies\GranularAppControlPolicy.xml"
如果使用了-Strict选项,这意味着在应用此策略后,只允许加载 Microsoft 和 WHQL 签名的驱动程序。
要从 CI 策略中删除所有 HVCI 设置,您可以指定-None参数:
> Set-HVCIOptions -None -FilePath "C:\AppControlPolicies\GranularAppControlPolicy.xml"
另一个有用的 VBS 功能是安全启动,它可以显著增强您的 Windows 系统的安全性。
启用安全启动
安全启动确保系统以受信任的状态启动。这意味着所有用于启动系统的文件必须具有经组织信任的签名。通过这样做,如果这些文件被篡改,系统将无法启动。设备需要配备 TPM 芯片才能支持安全启动。
要验证您的计算机是否启用了安全启动,您可以使用Confirm-SecureBootUEFI cmdlet:
> Confirm-SecureBootUEFI
如果启用了安全启动,cmdlet 将返回True,如下图所示;如果没有启用,则返回False:
图 11.27 – 启用安全启动
如果您的 PC 硬件不支持安全启动(Secure Boot),您将收到一条错误信息,提示此平台不支持 Cmdlet。
图 11.28 – 硬件不支持安全启动
如果您想了解更多关于安全启动的信息,请查看以下链接:
攻击者常常使用恶意驱动程序和篡改的系统文件。安全启动与代码完整性结合使用,确保已启动的操作系统及其使用的驱动程序是可信的。
部署 WDAC
部署 WDAC 有多种方式:MDM 或 Intune、配置管理器(Configuration Manager)、组策略(GPO)以及 PowerShell。
由于详细描述每种部署方法会超出本书的篇幅,请参阅官方部署指南,您可以在其中找到每种部署方法的详细说明:docs.microsoft.com/en-us/windo…
在接下来的章节中,我们将探讨每种不同部署方法的优缺点。
组策略(GPO)
组策略并不是配置 WDAC 的首选方法;它只支持单一策略格式的CI 策略,并且文件类型为 .bin、.p7b 或 .p7。这种格式用于 Windows 10 版本 1903 之前的设备。作为最佳实践,应使用除 GPO 之外的部署机制。
但是,如果你仍然希望使用这种部署方式,可以在计算机配置 | 管理模板 | 系统 | 设备保护 | 部署 Windows Defender 应用程序控制下找到 WDAC GPO 设置。通过此设置,你可以部署 CI 策略。
你想要部署的二进制 CI 策略需要位于文件共享中,或者复制到每台你想要限制的机器的本地系统上。
有关如何通过 GPO 部署 WDAC 的详细文档,可以在这里找到:learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/deployment/deploy-wdac-policies-using-group-policy。
Intune
你可以使用 MDM 解决方案来配置 WDAC,例如 Intune。通过 Intune,应用控制内置了一些可配置的策略,你可以配置这些策略,以便客户机只能运行 Windows 组件、第三方硬件和软件内核驱动程序、来自 Microsoft Store 的应用,以及由 Microsoft Intelligence Security Graph 信任的信誉良好的应用(可选)。
当然,也可以使用 OMA-URI 创建自定义的 WDAC 策略,这与通过 Intune 配置 AppLocker 策略的方式类似。
在每个 XML CI 策略文件中,你可以找到一个策略 ID。复制此 ID,并将{PolicyID}替换为以下字符串,以获取自定义策略的 OMA-URI:
./Vendor/MSFT/ApplicationControl/Policies/{PolicyID}/Policy
请注意,你还需要替换大括号。以下截图显示了你可以找到PolicyID的位置:
图 11.29 – 你可以在 XML CI 策略文件中找到策略 ID
使用此PolicyID,相应的 OMA-URI 如下所示:
./Vendor/MSFT/ApplicationControl/Policies/A244370E-44C9-4C06-B551-F6016E563076/Policy
你可以在learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/deployment/deploy-wdac-policies-using-intune了解更多关于如何使用 Intune 部署 WDAC 的信息。
Microsoft 配置管理器
使用配置管理器时,它本身会成为一个可信源。这意味着通过配置管理器安装的每个应用程序和软件都被视为可信并允许运行。此选项需要通过内置策略进行配置。
类似于使用 Intune 部署,Configuration Manager 还提供了一些内置的策略,使您可以配置客户端仅运行来自 Microsoft Store 的 Windows 组件和应用程序。您还可以选择信任具有良好声誉的应用程序,这些应用程序已由Intune 服务网关(ISG)验证。Configuration Manager 还带有另一个可选的内置策略:可以允许已经安装在指定文件夹中的应用程序和其他可执行文件。
您可以通过以下链接了解更多关于如何使用 Configuration Manager 部署 WDAC:learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/deployment/deploy-wdac-policies-with-memcm。
PowerShell
根据操作系统的不同,使用 PowerShell 部署 WDAC 的方式也有所不同,因为并非所有操作系统版本都具备所有功能。WDAC 策略刷新工具也需要下载并部署到每个受管理的端点:www.microsoft.com/en-us/download/details.aspx?id=102925。
对于这种方法,您还需要获取策略的二进制文件并将其复制到每个受管理的端点。然而,与 GPO 相比,您可以部署多个 WDAC 策略。要部署签名策略,您还需要将二进制策略文件复制到设备的 EFI 分区。签名策略通过确保仅应用由受信任实体签名的策略,为端点提供额外的安全层。如果使用 Intune 或 CSP 进行部署,此步骤将自动完成。
Matt Graeber 的 WDACTools 也是简化部署过程的宝贵资源。这些工具专门设计用于简化构建、配置、部署和审核 WDAC 策略的过程。您可以从 Matt 的 GitHub 仓库下载它们:github.com/mattifestation/WDACTools。
有关如何使用 PowerShell 部署 WDAC 的详细信息,请参阅:learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/deployment/deploy-wdac-policies-with-script。
当强制执行应用程序控制时,PowerShell 会发生什么变化?
当强制执行应用程序控制时,PowerShell 充当保护措施,防止潜在对手滥用其功能。通过主动实施应用程序控制措施,PowerShell 确保其强大的脚本语言不能被攻击者轻易滥用,从而绕过已施加的限制。
PowerShell 可以通过多种方式受到限制,包括禁用运行 PowerShell 脚本的能力或只允许运行已签名的 PowerShell 脚本。
在第五章,PowerShell 的强大——系统和 API 访问中,我们讨论了如何在系统不受限制的情况下,使用 PowerShell 运行任意.NET代码,甚至执行编译后的代码。这会使防范恶意代码变得非常困难。在强制应用控制的情况下,可以消除如Add-Type、任意.NET 脚本和其他常用绕过安全机制的代码执行方法。
PowerShell 包括内置的受限语言模式,我们在第十章,*语言模式与足够的管理权限(JEA)*中进行了探讨。受限语言模式限制了 PowerShell,阻止用户执行危险的语言元素,如访问任意 API。
这意味着某些危险的语言元素,如Add-Type、COM 对象和一些可以用于执行任意代码的.NET 类型,无法使用。如果强制执行,受限语言模式(Constrained Language mode)可以限制攻击者执行任意代码和修改系统配置的能力。在受限语言模式下,PowerShell 环境仅保留传统较弱交互式 shell 的核心基本功能,类似于 CMD、Windows 资源管理器或 Bash。
确保 PowerShell 代码可信任的一种有效方法是强制使用签名脚本。在应用控制的情况下,如果脚本被信任并允许在完全语言模式下运行,则会按照要求执行。但是,如果脚本不被信任,则它将始终在受限语言模式下运行,这意味着如果脚本尝试调用任意 API 和其他危险语言元素,将会失败。
当应用控制被强制执行,并且 PowerShell 在受限语言模式下运行时,如果你尝试直接从.NET 调用方法,它们将会失败,如下图所示:
图 11.30 – 启用应用控制时,无法访问.NET 类型
使用Add-Type从 PowerShell 中添加并访问 C 类型也会失效——你会收到以下错误消息:
图 11.31 – 强制执行应用控制时,Add-Type 失败
这些并不是唯一会失败的命令,但它们应该能演示启用应用控制后,PowerShell 体验的不同。
如果您允许在应用控制策略中使用签名的 Windows 文件,这意味着与 Windows 安装一起提供的 PowerShell 模块也将被允许在完整语言模式下运行。然而,自定义创建的模块将以受限语言模式运行,除非它们已在您的应用控制设置中被配置为可信。这有效地减少了系统的攻击面。
如本章前面提到的,在撰写时,PowerShell 和 WSH 家族是唯一可以通过应用控制进行限制的动态运行时,而其他运行时仍然允许无限制的代码执行。因此,PowerShell 在使用应用控制策略锁定环境时具有巨大优势。
总结来说,实施应用控制机制,如 WDAC 和 AppLocker,可以显著提升 PowerShell 安全性。通过强制执行如受限语言模式等约束,限制 PowerShell 脚本执行任意代码或修改系统配置的能力。通过实施这些措施,显著减少系统的攻击面,并使攻击者更难执行恶意代码。
总结
在本章中,您学习了如何将现有的 PowerShell 脚本配置为可信,并将其加入允许列表,但不仅仅是 PowerShell 脚本。在这一点上,您应该已经对如何为环境中的所有应用程序实现适当的应用控制解决方案有了充分的理解。
首先,您了解了如何签署您的代码,以及如何创建一个自签名脚本,供测试使用。掌握了这些知识后,您可以轻松地转移到企业环境中,您可能已经在使用企业签名或公共签名的证书。
接下来,我们深入研究了应用控制,并了解了现有的内建应用控制解决方案:SRP、AppLocker 和 WDAC。现在,您也应该熟悉如何规划在您的环境中进行允许列表配置。
然后,我们探索了 AppLocker 和 WDAC,并学习了如何审计 AppLocker 和 WDAC。我们还研究了如何配置 AppLocker 以避免可能的 PowerShell 降级攻击。
最后但同样重要的是,我们了解到,每当可能时,WDAC 是最安全的选项,其次是 AppLocker。然而,二者可以根据操作系统和使用场景在同一环境中结合使用。
然而,仅仅限制脚本和应用程序还不足以确保环境的安全性和强化。在下一章中,我们将探讨 Windows 恶意软件扫描接口(AMSI)如何保护您免受直接在控制台或内存中运行的恶意代码攻击。
进一步阅读
如果您想进一步探索本章中提到的一些话题,可以参考以下资源:
证书操作:
-
New-SelfSignedCertificate:
docs.microsoft.com/en-us/powershell/module/pki/new-selfsignedcertificate -
Set-AuthenticodeSignature:
docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-authenticodesignature -
Get-AuthenticodeSignature:
docs.microsoft.com/en-us/powershell/wwmodule/microsoft.powershell.security/get-authenticodesignature
CI/CD:
-
CI/CD:是什么,为什么,如何:
resources.github.com/ci-cd/ -
关于持续集成:
docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration
应用控制:
-
Windows 的应用程序控制:
docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/windows-defender-application-control -
使用智能安全图(ISG)授权可信应用:
learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/design/use-wdac-with-intelligent-security-graph -
启用基于虚拟化的代码完整性保护:
learn.microsoft.com/en-us/windows/security/hardware-security/enable-virtualization-based-protection-of-code-integrity -
ConfigCI 模块参考(ConfigCI):
docs.microsoft.com/en-us/powershell/module/configci -
了解 Windows Defender 应用程序控制(WDAC)策略规则和文件规则:
learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control/design/select-types-of-rules-to-create -
使用多个 Windows Defender 应用程序控制策略:
learn.microsoft.com/zh-cn/windows/security/application-security/application-control/windows-defender-application-control/design/deploy-multiple-wdac-policies -
使用签名策略来保护 Windows Defender 应用程序控制免受篡改:
learn.microsoft.com/zh-cn/windows/security/application-security/application-control/windows-defender-application-control/deployment/use-signed-policies-to-protect-wdac-against-tampering -
使用配置管理器管理 Windows Defender 应用程序控制:
learn.microsoft.com/zh-cn/mem/configmgr/protect/deploy-use/use-device-guard-with-configuration-manager -
Windows Defender 应用程序控制向导:
learn.microsoft.com/zh-cn/windows/security/application-security/application-control/windows-defender-application-control/design/wdac-wizard
AppLocker:
-
AppLocker 操作指南:
learn.microsoft.com/zh-cn/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/ee791916(v=ws.10)
你还可以在 GitHub 仓库中找到本章提到的所有链接,无需手动输入每个链接:第十一章 – github.com/PacktPublis…