最近几年,关于如何绕过应用程序白名单的研究非常火热,Casey Smith(@subtee)和Matt Graeber(@mattifestation)都有过这方面的研究,他们最新研究成果就是“应用程序白名单必须被锁定,以避免受信任的应用程序被攻击者实施代码注入”,不过他们的研究成果只是在Windows 7和8.1中可行,但在Windows 10的运行环境中这种办法却不可行,在Windows 10中激活Powershell约束语言模式(Powershell Constrained Language Mode)以及AppLocker的方法显然行不通。虽然Casey Smith关于绕过应用程序白名单的研究很多,但他的研究有个前提假设,就是利用被攻击者设备上的代码。本文就是在Casey Smith研究的基础上,通过很多嵌套技术和代码来实现如何绕过应用白名单和受限的 PowerShell。
HTA攻击
如果你之前没有听说过把HTML应用程序作为攻击向量或不了解Powershell的Empire工具,请先自补一下这部分内容。
启动Powershell Empire并创建一个监听器之后,会创建一个HTA stager,并简单地设置监听器名称和输出文件,
然后把它放在一个可以被攻击者访问的网络服务器上。HTA文件包含以下代码,
由于HTA文件是在浏览器沙箱外打开,因此允许ActiveX对象执行。它只是用base64编码的命令启动Powershell,而且它会使用另一个更大的Empire代理存储器并在内存中执行HTA文件,这时可以在被攻击者的浏览器上看到如下情形。
其次是,
单击运行后开始回调,Empire会在被攻击者的设备上启动一个新代理。
AppLocker和Powershell约束语言
本文是关于如何通过HTA文件获得Empire代理的研究,如果你尝试在计算机上运行一个恶意软件会得到以下提示。
如果你尝试在Powershell中使用.NET组件运行命令,那这个命令会被阻止
同样,如果你尝试启动与之前使用HTA相同的攻击,那同样会被阻止
由于受约束语言模式,我们从Powershell中都只能获得相同的错误结果。
无Powershell的Powershell
目前已经有一些关于运行Powershell命令而不使用Powershell.exe的研究。这个研究的想法是这样的,Powershell.exe真的只是.NET程序集System.Management.Automation的一个解释器,其实我们完全有可能编写自己的解释器来调用该程序集,只不过我们面临的问题是应用程序白名单的存在,因此我们需要以某种方式启动我们的自定义解释器。此外,这个解释器必须运行在一些进程空间,而且要把它注入到一个现有的进程中,而非新创建的进程中,必须保持运行时Empire代理在运行,其中包含一个名为ReflectivePick的模块。它是一个C ++应用程序,编译单个DLL并从System.Management.Automation调用自定义的运行空间,实际上允许执行Powershell命令。
为了开始我们的测试,我们要用到一个简单的命令编译ReflectivePick DLL,以便在运行空间中执行测试,如下图所示。
然后从白名单的文件夹中通过使用rundll32运行ReflectivePick DLL,并得到以下结果,
这时,Powershell命令已执行,即使AppLocker将Powershell.exe锁定到约束语言,运行空间的语言模式还是全语言。我们可以把解码的命令记录到了一个文件,以便能够调试它,完整的命令如下图,
从命令行运行更新的DLL,在文本文件中显示解码的Empire stager
启动Empire代理
到目前为止,我们正在通过rundll32.exe创建一个新进程,并将DLL加载到其中,但这不是一个可行的方法,因为DLL不在白名单中,此外,我们正在创建一个新的过程。为了避免以上这两个问题,我们可以使用Powershell脚本Invoke-ReflectivePEInjection将ReflectivePick DLL加载到另一个进程中。这当然会在创建启用“约束语言模式”时启动Powershell脚本。Invoke-ReflectivePEInjection对我们的这个进程提供了两个参数,DLL作为字节数组和要注入的PID,想注入ReflectivePick DLL到explorer进程,我们首先要找到PID。
然后到字节数组中,得到ReflectivePick DLL的内容
要把Invoke-ReflectivePEInjection脚本作为一个函数编写,因此我们首先要导入模块,确保将其放置在白名单文件夹中,以避免现在的约束语言。然后使用PID和DLL调用它
我们注意到,调试文本文件是使用Empire stager创建的,如下图所示,我们成功地从explorer进程中运行Empire代理
把从DLL获取的PID和字节的命令嵌入到Powershell脚本中,以及通过在脚本文件的末尾添加以下内容来调用该函数
然后我们只需运行没有任何参数的Powershell脚本文件
这时,我们便会得到Empire代理回调
不过,现在ReflectivePick DLL仍然是磁盘上的外部文件,所以要把它嵌入到Powershell脚本中,就要通过将DLL的字节编码为base64来实现
然后将编码文件的内容复制到Powershell脚本中并分配变量
而不是从磁盘获取文件的字节,我们通过base64解码变量的内容来得到它们
这样,我们就再一次收到Empire代理
从InstallUtil.exe调用Powershell
不过目前为止,我们还没有绕过白名单和受限的Powershell,因为我们现在使用Powershell加载DLL到内存中,所调用Powershell和约束语言模式会阻止这个目的的实现。前不久,Casey Smith曾发布了一种使用InstallUtil.exe绕过AppLocker的方法以及用于创建Powershell运行空间的概念验证代码。
我们可以修改其中的代码并执行了一个预定义命令,它的工作原理如下图所示,
把它编译到Bypass.exe EXE中,可以很明显的看到被AppLocker阻止
然后运行InstallUtil.exe并使用Casey Smith描述的命令行参数来执行卸载
从上图中我们可以看到,该命令已被执行,并且自定义的Powershell运行空间并没有启用约束语言模式。此时,我们将测试命令更改为整个Invoke-ReflectivePEInjection脚本以及我们之前添加的嵌入式DLL和启动命令,不过,此时,Powershell会由于分行问题被干扰。 Invoke-ReflectivePEInjection是用新行创建的,但是将它嵌入到C#项目中需要新建一行,为此我们首先对整个文件进行base64编码。
然后将其与base64解码程序一起嵌入到EXE中
我们还将解码的Powershell命令写入test5.txt文件,以确保它可以正常工作。对更新的代码运行InstallUtil.exe可以得到一下以下结果
Invoke-ReflectivePEInjection脚本被解码并保留其新行,此外,Empire stager也被写入其调试文件。我们可以看到,Empire代理已成功启动
调用InstallUtil.exe
到目前为止,我们设法将Powershell约束语言模式的旁路转换为EXE文件的AppLocker旁路。虽然我们也成功地执行过EXE,但我们仍然需要一些方法来调用InstallUtil.exe并将EXE下载到磁盘。为了实现这一个目标,我们将使用Regsvr32.exe,这是另一个AppLocker旁路。
Regsvr32.exe可以用来执行scriptlet,它可以包含任意的JavaScript。但一开始我们没有注意到这一点,仍然有EXE在磁盘中从Regsvr32.exe运行的脚本执行InstallUtil.exe来看,所使用的scriptlet是从Casey Smith的概念证明中修改的
如下图所示运行它
这给了我们一个Empire回调
现在你可能想知道为什么要使用Regsvr32.exe启动InstallUtil.exe?因为到目前为止并没有真正获得任何能够达到目的工具,但Regsvr32.exe却可以用来把EXE下载到磁盘,此外scriptlet文件也可以存储在web服务器上,如下图所示
下载文件
要通过Regsvr32.exe的下载进行测试,我们就要用base64编码一些虚拟文本
然后,我们使用Casey Smith发现的另一种已被广泛使用的certutil.exe解码和写入磁盘的方法。 把base64编码文本放在BEGIN CERTIFICATE和END CERTIFICATE标签中,这是为了方便向certutil.exe提供正确的格式。然后我们将base64编码的文本写入文件,并使用certutil.exe解码,如下图所示,
然后开始执行
并且文件的内容被清楚地解码。现在是时候为InstallUtil.exe的EXE一点微调和嵌入了。因此,我们在另一台计算机上使用certutil.exe对其进行编码
为了允许base64 blob同时覆盖多行,我们为每一行添加一个反斜线
在测试的时候,我们还发现不能在一个scriptlet中嵌入整个编码的EXE。所以,我们不得不把它分成4部分插入到单独的scriptlet。这四个scriptlet中的每一个都简单地采用了嵌入的base64代码,并将其写入一个文件,如下图所示
如下图所示,显示正在写入的文件
然后本文作者创建了第五个scriptlet文件,并把磁盘上的前四个文件组合到一个文本文件中,并继续调用certutil.exe来解码它,并将EXE写入磁盘
运行所有的scriptlet,如下图所示
发生Empire代理回调
要压缩这个scriptlet文件,就必须通过刚刚的那四个scriptlet文件
运行时,会再次发生Empire代理回调
返回HTA
现在我们终于实现了单一的命令,我们可以使用这个命令创建我们的Empire。要启动它,我们可以将该命令嵌入HTA文件
攻击此文件的链接是以我们通常的方式发送的钓鱼邮件,用户会通过浏览器接收
尽管AppLocker和Powershell约束语言模式被启用,但运行时还是创建了我们期望的Empire
结论
总而言之,本文中的方法提供了一个来自Web服务器的HTA,它调用Regsvr32.exe来执行五个脚本,这五个脚本会下载一个嵌入base64编码的EXE,然后对其进行解码并将它写入磁盘。最后执行InstallUtil.exe绕过AppLocker,并依次执行EXE卸载。 其中,EXE包含一个base64编码的Powershell脚本,它在EXE创建的自定义Powershell运行空间中会进行解码和执行。 Powershell脚本包含一个嵌入的base64编码的DLL,通过Powershell脚本将其解码并反射加载到explorer进程中。反射加载的DLL包含嵌入式base64编码的Powershell脚本,该脚本会在浏览器运行时,在自定义的Powershell运行空间内进行解码和执行。
不过在执行这种攻击时,以下四个二进制文件需要被AppLocker列入白名单:
MSHTA.EXE
REGSVR32.EXE
CERTUTIL.EXE
INSTALLUTIL.EXE
如果使用默认AppLocker规则或所有Microsoft签名的二进制文件是受信任的,这四个文件都将是白名单。虽然攻击确实绕过了AppLocker和Powershell约束语言模式,但还有AMSI,它不会绕过ScriptBlock Logging,因此可以进行最终结果的检测,如下图所示