导语:最近,Matt Graeber(@mattifestation)和我一直在Device Guard环境中挖掘绕过用户模式代码完整性(UMCI)的方法。
最近,Matt Graeber(@mattifestation)和我一直在Device Guard环境中挖掘绕过用户模式代码完整性(UMCI)的方法。我们挖到的许多CVE都已经公布,微软通过继续改进用于Device Guard和AppLocker的主要PowerShell策略实施机制——约束语言模式(CLM),在减轻PowerShell对UMCI的攻击面方面做了很不错的工作。以下缓解措施大大减少了攻击面,也就是CVE-2017-0218的修复结果。
绝大多数此类注入漏洞都会滥用微软的已签名的PowerShell脚本或包含运行未签名代码功能的模块。这个范围包括调用一个参数的Invoke-Expression到PowerShell的Add-Type cmdlet的自定义实现。微软签名的PowerShell代码是有针对性的,因为允许微软代码执行的AppLocker或Device Guard策略将以完整语言模式执行 – 即对可执行的代码没有限制。
为了充分理解修补程序,让我们来看看修补程序之前的行为。这个漏洞的关键点是攻击者可以使用微软签名过的PowerShell脚本中的函数来绕过UMCI。为了演示这一点,我们来看一下脚本“utils_SetupEnv.ps1”,它是C:Windowsdiagnostics目录中包含的Windows疑难解答包的一个组件。这个特殊的脚本有一个叫做“import-cs”的函数。这个函数只需要C#代码并调用Add-Type就可以了(注意:Add-Type在约束语言模式下是阻止调用的)。由于该脚本是微软签名的,因此将以完整语言模式执行,允许攻击者执行任意C#代码。
正如你在上图中看到的,我们导入了“utils_SetupEnv.ps1”,它暴露了“import-cs”函数给我们。使用这个函数,我们可以将我们自己的C#传递给系统进行执行,并绕过受限语言模式。上面的漏洞公布在了CVE-2017-0218并且已经修复。
为了应对上述漏洞,微软在PowerShell的受限语言模式下运行时加了一些额外的限制。第一个是你不能再通过Import-Module或其他方式导入PowerShell脚本(.PS1s)。如果你尝试在CLM中导入脚本,则会看到如下图所示的内容:
一种可能的解决方法是将PowerShell脚本(.PS1)重命名为模块文件(.PSM1)并以此方式导入。那么,这是第二个需要修复的地方。
微软对通过PowerShell模块(.PSM1)导入和使用的内容做出了限制。这是通过“ Export-ModuleMember ”完成的。如果你对Export-ModuleMember不熟悉,则会定义在导入模块后,哪些功能可以使用。在约束语言模式下,模块的功能必须通过Export-ModuleMember导出才能使用。这大大减少了在微软签名过的PowerShell模块中滥用函数调用的攻击面。一般来说,明确定义要向用户公开哪些模块的功能也是一个很好的做法。
如果我们将“utils_SetupEnv.ps1”重命名为“utils_SetupEnv.psm1”,并尝试导入它,它会显示导入成功。你会注意到我们之前使用的“import-cs”函数不被识别。这是因为“import-cs”不是通过Export-ModuleMember公开的。
我们来看一个有效的PowerShell模块文件,Export-ModuleMember定义将如下图所示:
这实质上意味着当导入模块时只能使用“Export-ODataEndpointP
roxy”。这严重限制了微软签名过的PowerShell脚本被滥用的可能性,这些脚本包含了可能被滥用然后运行未签名代码的功能,因为大部分功能都不会公开。同样,PowerShell团队正在缓慢而稳妥地缓解我们用来规避约束语言模式的许多旁绕过方式。
在review了这个修复之后,我发现并报告了Export-ModuleMember的一个方法,该方法被分配到了CVE-2017-8715,并在十月份的星期二补丁中发布。此绕过滥用了PowerShell模块清单(.PSD1)。在研究这些文件的影响时,我意识到你可以通过这些文件来配置模块行为,而且它们不受与许多其他PowerShell文件相同的签名要求的限制(可能因为PSD1文件不包含可执行文件码)。尽管如此,PSD1仍然可以签名。
如果我们回头看“utils_SetupEnv.ps1”脚本,“import-cs”函数将不再可用,因为该脚本中的任何函数都不会通过Export-ModuleMember公开。为了解决这个问题,我们可以将“utils_SetupEnv.ps1”重命名为“utils_SetupEnv.psm1”,这样我们就可以导入它。这样做后,我们可以删除“utils_SetupEnv.psm1”的一个相应的模块清单,然后我们导出精心构造的“import-cs”函数。这个模块清单看起来像这样:
正如你所看到的,我们已经将“import-cs”设置为一个函数,通过“FunctionsToExport”导出。这将像Export-ModuleMember那样导出函数。由于PowerShell模块清单文件不像其他PowerShell文件那样受限于相同的代码签名要求,因此我们可以简单地为我们想要滥用的微软签名过的脚本创建自己的文件。在删除了“utils_SetupEnv”PowerShell模块的上述清单后,尽管新引入了.PS1导入和导出模块成员的修复补丁,但是我们现在依旧可以使用“import-cs”函数执行任意C#代码。
如上所述,此绕过方式已发布在CVE-2017-8715。该修复方案涉及到PowerShell模块清单文件(.PSD1s)要与模块中的所有其他文件具有相同的代码签名的要求,即使某个模块已经加了签名并通过了Device Guard或AppLocker的策略,也要根据白名单规则判断签名,最终决定是否可以通过验证。这样做可以防止攻击者修改现有的清单或使用他们自己的清单文件。