透过Autoruns看持久化绕过姿势的分享

本文已在丁牛网安实验室FreeBuf专栏 DigApis安全 中首发!引用转发请注明 “原文来自:m0nst3r@DigApis安全”字样,谢谢!

[TOC]

概要

在网络攻防的对抗中,对于攻击者而言,对目标系统的权限维持(也称持久化)非常重要;对于防御者来说,发现网络中的这些点也非常重要。

本文主要内容来自Kyle和Chris在DerbyCon 7中的分享,主要展示了一些半公开和尚未公开的技术,用于绕过Autoruns这个最常用的持久化枚举检查工具。

哪儿的问题?

Windows系统可能有成百上千种方法去加载/调用一些库或可执行程序,有时是在启动时,有时是在用户登陆时,也有时是当一个程序执行时。我们称这些点为ASEPs(Auto Start Entry Points),例如Skype,Skype一般会设置成“开机启动”,这样可以省去每次开机都要打开Skype的麻烦,Skype会告诉Windows系统,我是一个合法的程序,请每次开机的时候启动我。但攻击者也会从中受益,因为攻击者可以把恶意代码设置为一个服务,并设置为“开机启动”。

作为防御方,我们可能会想到一些自动检查这些ASEPs的工具,而且我们有MSDN可以查。但是有很多东西是无法MSDN文档中找到的,收集这些自启动点也是非常困难的。另外,攻击者一般会使用一些间接的方法来扰乱安全排查软件的视线。

Sysinternals Autoruns

Sysinternals Autoruns 是一款 由Mark Russinovich开发和维护的软件,它可以检查到的ASEP也是最多的,如:

  • Run Keys,运行键
  • Services
  • Schedualed Tasks
  • Providers
  • Drivers
  • WMI

这款工具不是专门为安全人员设计开发的,它能简单枚举出计算机中的自启动的位置,但是需要用户去确定这个自启动程序的合法性。即使如此,它也常常被当作一个安全工具来使用,因为作者还集成了VirusTotal来检测自启动位置上的恶意软件,所以恶意软件的制作者们也一直在寻找可以躲过Autoruns检查的方法。

4个半公开的绕过方法

Nested Commands (命令嵌套)

Nested Commands 是一种将多条命令集合成一条命令的机制。
之所以要这样做,是因为我们不想让Autoruns软件检测出我们运行的恶意代码,这些命令会让Autoruns或防御者认为我们的命令是在运行一个具有合法签名的程序。这是一个绕过的基础知识。随着安全人员和攻击者越来越多的关注这些绕过方式,相信在将来还会出现更加复杂的方式。

怎么隐藏

当我们说隐藏的时候,我们究竟指的是什么呢?
来看下面的图:
15.png.jpg

这是一张Autoruns的截图。Autoruns可以告诉机器上所有的自启动项,注册表中哪些是开机启动的,哪些是登陆时启动的,哪些是作为服务启动的,甚至还有哪些是作为驱动来启动的,以及一些计划任务和Winsock Prividers。
从图中可以看出,在我们没有使用隐藏技术的时候,当我们开启了Autoruns的过滤功能后,我们安装的自启动项就暴露在眼前了,包括我们启动项所在位置,执行的命令以及加载的DLL信息。

我们要做的是利用Autoruns的两个功能,这两个功能本来是要帮助安全人员在检查自启动程序时缩小排查范围的,但是可以利用这两个功能来达到隐藏的目的:

  • 隐藏Microsoft条目:这个功能可以把具有Microsoft签名的条目隐藏。
  • 隐藏Windows条目:这个功能可以把具有Windows证书签名的条目隐藏。

这两个功能可以帮助安全人员把注意力集中在第三方安装的自启动项中,一般情况下,这些启动项有比较大的概率是恶意的。

在介绍隐藏技术之前,首先来了解一下基本的背景知识:

  • Process Exit Codes
    每个运行的进程/程序都会有一个返回码(Process Exit Code),根据这个返回码可以判断程序的运行结果是成功或失败。如果返回码是0,则表示成功;若为返回码为非0的数值,则表示失败。

  • 逻辑操作符
    逻辑操作符的作用是根据其他程序的失败或成功来执行命令的批处理语法。
    例如:foo.exe && bar.exe
    在批处理脚本中,我们有如下三种操作符可用:

    • & [block]:执行完前一个命令后,立刻执行后面的命令,不管前面的命令是否成功执行。
    • && [if success]:当且仅当前面的命令执行成功,才执行后面的命令。
    • !! [if not success]:当且仅当前面的命令执行失败,才执行后面的命令。

利用方法

  1. 选一个合法的自启动项:
    比如 :C:\Windows\system32\VBoxTray.exe
  2. 将命令修改为如下格式:
    cmd.exe /c start C:\Windows\system32\VBoxTray.exe & evil.exe

通过这样设置以后,程序启动的流程就变成了如下的样子:
19.png

cmd.exe会在VBoxTray.exe执行完成后,马上启动另一个进程执行我们的evil.exe。相当于我们用一条命令运行了两个程序。值得注意的是,我们这里用的是&而不是&&,因为VBoxTray不会退出。

Autoruns会检测到什么结果呢?看下图:

20.png

在版本<13.80的Autoruns里面,我们修改的启动项会以VBoxTray名字显示,而且图标也是正常的,发布者显示来自Oracle,包括执行的文件(Image Path)都显示正常,唯一能发现我们更改的地方是详细信息里面。作为防御者,在看到正常的启动项时,估计很少有人看详细信息。
这样,我们就达到了某种程度的成功。

但是这样就安全了吗?呵呵…

22.png

我们看到,在版本>=13.80的Autoruns里面,执行文件就显示成了cmd.exe,我们显然已经不在VBoxTray的保护下面了。

这样的变化提示防御者,单纯使用Autoruns并不能够帮你排除所有的恶意启动项,我们还需要加入自己的分析。

Shell32.dll Indirection (间接调用Shell32.dll)

简单的说,这个技术是结合rundll32.dllshell32.dll来执行程序,以便能够欺骗Autoruns。

Shell32.dll是一个Microsoft签名的程序,它提供了explorer.exe的功能,比如”找开“,”运行程序“等,我们可以使用IDA打开这个DLL然后查看导出表。
对攻击者而言,这个DLL还有非常多的有用的函数可用,可以用来加载别的DLL文件或者执行一个程序,比如ShellExec_RunDLLControl_RunDLLDllInstall等等。

利用方法

我们通过如下的方法,可以启动一个程序:
rundll32.exe shell32.dll,ShellExec_RunDLL calc.exe

这条语种的执行流程如下:

30.png

如果我们通过这种方式来设置我们的启动项的话,在Autoruns里面会是什么样子呢?

  • Autoruns < 13.80 不启用MS过滤
    31.png
  • Autoruns < 13.80 启用MS过滤
    32.png

我们看到,在不启用过滤时,Autoruns将其识别为shell32.dll,但是,当防御者打开”过滤Microsoft签名的程序“时,被安装在机器上的自启动项便不见了。

  • Autoruns >= 13.80 启用MS过滤
    33.png

但是,在高版本的Autoruns中,即使我们启用了过滤,我们的启动项依然会被显示出来,即rundll32.exe
一些正常的程序也会使用rundll32.exe来进行自启动,比如打印机驱动。所以即使我们的启动项被显示出来了,但是这里还是需要一些安全知识背景才能确定这个启动项是不是恶意的。

DLL Hijacking (DLL劫持)

DLL Hijacking,或DLL劫持,是一种利用Windows加载动态链接库时的Search Order(搜索顺序)来加载/执行恶意代码的技术手段。
在Autoruns中,如果利用这种技术手段设置启动项的话,Autoruns只会显示可执行程序的信息,它并不关心这个程序加载的是哪个DLL。所以,Autoruns在遇到DLL劫持的技术时,是帮不了防御者的忙的。

那什么是搜索顺序呢?

  • Search Order:
    程序通过LoadLibrary()函数来请求Windows系统去加载一个DLL到内存中,而Windows会遵循一个已定义好的搜索方法去查找被请求的DLL,具体顺序如下:
    • 程序运行目录
    • 系统system32目录
    • 系统system目录
    • Windows目录(C:\Windows)
    • 当前目录
    • PATH环境变量中的目录列表

Windows会根据搜索顺序一个一个的查找被请求加载的DLL,只要找到一个DLL的名字与被请求的DLL名字一致,Windows就会停止继续查找,并去加载它,不管它是不是恶意的DLL。

所以我们只需将恶意的DLL一个合适的目录中,并且保证这个目录在搜索顺序中比放置合法DLL的目录靠上,我们的恶意DLL就会被加载。

木马Dridex的做法

木马Dridex就是一个使用一种叫作AtomBombing的技术对DLL进行劫持的变种,而使用Autoruns检查的时候,Autoruns只会将可执行程序显示出来。

  1. Dridex木马会利用DLL劫持技术将自己隐藏在一个有合法签名的可执行程序下面,它获取可执行程序的哈希值,直到找到一个符合的,然后将这个程序复制到用户目录下的AppData\Roaming文件夹中。
  2. 从程序的导入表中随机选取一个DLL,并且复制到包含正常可执行程序的目录中,将恶意代码注入到DLL中,让恶意代码在DLL加载时执行。
  3. 在注册表中新建一个键,并指向合法的可执行程序,并且设置为当用户登陆时运行。

用Autoruns来检查感染Dridex木马的机器时,是这样的:
44.jpg

可以看到,Autoruns只识别出了合法的程序,并且这个启动项并没有什么异常!

SyncAppvPublishingService

SyncAppvPublishingService是PowerShell的提供App Virtualization Publishing功能的一个命令。这个功能是做什么的,可自行百度,但不懂也没关系。
有意思的是,这个命令自带了2个VBS文件和1个EXE文件。这个是helpers,可以帮助我们在无需PowerShell命令行中执行PowerShell命令。比如我们想从命令行或一个脚本中来运行PowerShell命令。它就是将获取我们在命令行中的参数进行格式化,并将其传递给PowerShell模块来执行。

48.jpg
49.jpg
50.jpg

如图所示,它用g_cmdArgs来接收命令行参数,然后传给syncCmd进行简单的拼接,然后调用PowerShell模块执行。所以这里就有一个命令注入的漏洞。SyncAppvPublishingService.exe与这个helper是一样的漏洞。

利用方法

我们可以通过如下方法启动一个计算器,执行流程如下:
52.png

Autoruns的检测结果:
53.png

可以看到,我们的启动项变为了Microsoft签名的,所以当防御者打开过滤的时候,我们的启动项就会被隐藏起来。

4个未公开的绕过方法

Service DLL Bug

首先认识一下两种ServiceStandalone Servicesss service

Standalone Service

iPod Service 是随iTunes安装的Service类型的自启动项,用来管理硬件的一个Service,当它启动时,会运行一个自己的进程。当系统启动时,会调用iPodService.exe。这就是一个典型的Standalone Service的运行方式。来看下这样的Service在注册表中的样子:

56.png

在Autoruns中的,这个Service是一个由Apple Inc签名的合法启动项:

57.png

Shared Service

DcomLaunch是Shared Service的一个很好的例子。它是微软自带的一个Service启动项,启动的是非常常见的svchost.exe程序,当它启动时,它会加载rpcss.dll
在注册表中是这样的:
59.png

对于绕过非常重要的键是Parameters键,它用来指定它当启动时要加载的DLL文件,这是就是这个rpcss.dll,如下图:
60.png

在Autoruns里面的检测结果是一个Microsoft签名的Service:
61.png

如果我们的iPod Service里面手工添加一个Parameters键,会是什么样呢?
63.png

64.png

当我们进行如上修改后,在Autoruns中,会被显示为一个Microsoft签名的合法启动项。

利用方法

经过上面的演示,估计大家都知道如何隐藏自己的启动项了。
添加一个启动项,类型为Standalone Service,然后指定启动时运行的程序。
65.png

然后新建一个Parameters键,然后随便挑一个合法的微软DLL,写进去。
66.png

在Autoruns中就会被当作一个Microsoft签名的合法启动项了:
67.png

Extension Search Order Bug (扩展名的搜索顺序利用漏洞)

搜索路径这里不再展开,直奔主题:比如我们要运行计算器,一般我们会输入calc.exe,这里程序会去搜索路径中去找这个程序。但是如果我们只输入calc,也就是不带.exe后缀,会好发生什么呢?
73.png

为什么这样呢?
74.png

当我们不指定扩展名时,Windows会根据默认的扩展名的搜索顺序在搜索目录中进行查找,但不幸的是,它会选查找.com扩展的文件,然后才是.exe扩展的文件。

利用方法

找一个自启动的Windows签名的启动项:
76.png

它在Autoruns检测结果如下:
77.png

我们把注册表中的键值进行一下修改,把程序扩展名删掉:
78.png

然后,将我们的恶意程序复制到相应目录下,并将扩展名改为.com
79.png

当机器重启时,我们的程序就会自动运行:
80.png

在Autoruns中检测,会发现它并没有什么异常,因为Autoruns并不检测扩展名,而是直接解析.exe文件:
81.png

SIP Hijacking (SIP劫持)

工具

PoCSubjectInterfacePackage

利用方法

84.png

我们将一个合法程序的电子授权证书偷过来,然后添加到自己的恶意程序中,那么在Autoruns中就会显示为Microsoft验证过的启动项:
85.png

.INF Scriptlets

提到这种技术的时候,我们一般会想到Casey给出的一个使用regsvr32.exe的例子:
88.png

我们使用这个合法的Microsoft可执行程序来静默注册或卸载一个二进制程序或对象文件。上面这个例子中,我们告诉Windows我们想要卸载scrobj.dll,当卸载这个dll时,会给我们机会来提交或下载一个脚本文件,这个脚本文件是XML格式的。这使得我们能利利用一个合法的程序调用一个合法的dll去下载我们的payload。这种方法自从公开之后就变得不好用了,因为各种防护开始针对这种方法时行封堵。比如在Autoruns当中,会显示出regsvr32.exe
90.png

那么我们就没有办法了吗?当然不是。

在MSDN中有一个INF UnregisterDlls命令:
92.png

我们新建一个inf文件,使用合适的程序去调用它,那么它就会跟我们上文中提到的相似,程序会像regsvr32一样,调用scrobj.dll去下载我们指定的脚本文件。如果通过社会工程学的攻击方法,可诱导用户右击并安装我们指定的程序,如下图。
93.png

利用方法

利用rundll32.exe去调用setupapi.dll,然后指定我们新建的inf文件,就可以达到我们的目的,执行流程如下:
94.png

安装完成全,Autoruns的检测结果如下:
95.png

很不幸的是,被新版本的Autoruns检测出来了。

这里,我们的绕过方法是使用InfDefaultInstall.exe。这是一个本地签名的微软程序:
96.png

这个可执行程序一样会去加载你的inf文件,下载并执行你指定的脚本文件

结语

持久化越来越已成为攻击者所关注的事,希望通过这篇文章的分析,能够提高防御者的视野。毕竟,攻击者的招数不止这些!