导语:mavinject.exe是一个合法的Windows组件,它可能被恶意滥用,而不仅仅局限于DLL注入。
一、前言
一直以来,攻击者都滥用mavinject.exe进行DLL注入。我第一次是从这个tweet中听说mavinject,后来当Casey Smith开始在tweet上发表实际滥用案例时,我的兴趣再度被激发。然而,我一度失去了兴趣,因为mavinject不允许执行任意未签名的代码(强制执行应用程序白名单)。最近,我写了一些脚本,用于识别与通常恶意软件使用相同API(CreateRemoteThread,VirtualAllocEx等)的已签名应用程序,mavinject.exe脱颖而出(因为它使用这些API中的每一个)。这重新激起了我对mavinject的兴趣,尽管我无法完全滥用mavinject来实现任意代码执行,但我希望这篇文章能够对其他人的进一步研究有一定的参考价值。除此之外,我想提供一些基本的mavinject检测建议。
在我扫描的可疑API中,mavinject使用了恶意软件通常使用的与注入相关的函数:
· VirtualProtectEx
· CreateRemoteThread
· VirtualAllocEx
· WriteProcessMemory
尽管mavinject.exe不是恶意软件,但我想调查它是否可被恶意滥用,而不仅仅局限于DLL注入。
二、背景知识
Mavinject是一个合法的Windows组件,可以在任何正在运行的进程中执行任意代码注入。由于这是Windows上的一个常见组件,因此可以利用它来执行living-off-the-land攻击。
可在系统中多个不同的位置上找到Mavinject:
"C:\Program Files\Common Files\microsoft shared\ClickToRun\MavInject32.exe"
该应用程序是Microsoft Application Virtualization(App-V)的一部分。其文件描述为:
FileDescription: Microsoft Application Virtualization Injector
常见的使用方式为:
mavinject <PID> /INJECTRUNNING
使用此命令行运行的可执行文件查询以下注册表项:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AppV\Subsystem
其相应的值是:
ValueName: Modules - ValueData: C:\Windows\System32\AppVEntSubsystems32.dllValueName: Modules64 - ValueData: C:\Windows\System32\AppVEntSubsystems64.dll
根据目标进程体系结构(32位或64位),它会注入其中一个DLL。
经过进一步分析,通过以下方式滥用相同的机制,可以在任意运行的进程中注入dll:
MavInject.exe <PID> /INJECTRUNNING <PATH DLL>
三、mavinject执行DLL注入
通常滥用mavinject的方式如下所示:
mavinject.exe PROCESSID /INJECTRUNNING Path\To\Payload.dll
当用于DLL注入时,mavinject执行以下操作:
1.调用OpenProcess获取目标进程的句柄。它请求以下访问:0x10043A(SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD)。从检测的角度来看,对于那些熟悉Sysmon的人来说,构建ProcessAccess规则很合理,但请注意请求的访问与GrantedAccess字段并不是一定匹配。此外,我不了解此进程访问的唯一性,但通过让Sysmon持续捕获ProcessAccess事件,就可以很容易的发现。
2.调用VirtualAllocEx和WriteProcessMemory将DLL路径写入目标进程。该字符串将用作LoadLibraryW的参数。
3.调用CreateRemoteThread获取目标进程,使用在步骤#2中写入的路径为参数调用LoadLibraryW。
这是一个很熟悉的过程,因为这种注入技术已经存在并且被广泛使用(documented)。
四、mavinject执行Import Descriptor注入
在IDA中逆向mavinject,发现命令行参数/HMODULE=0x非常显眼,因为在任何地方都没有记录。最终我发现它使用Detours UpdateImports32/64函数的一个变体预先导入了一个导入表(IMAGE_IMPORT_DESCRIPTOR结构)以及所选择的DLL名称和序号。/HMODULE= 0参数使用方法如下所示:
mavinject.exe 4964 /HMODULE=0x013C0000 foo.dll 4
在本例中,32位的mavinject注入一个导入表,它将foo.dll中序号为4的函数“导出”为32位进程(PID 4964),并将其导入基址为0x013C0000(powershell.exe基地址)的模块中。值得一提的是是,foo.dll没有导出一个序号为4的函数。这只是一个虚构的例子,强调了可以注入任意字符串和序号。注入导入表添加后,可以使用WinDbg来验证:
0:009> !dh -i 013C0000 _IMAGE_IMPORT_DESCRIPTOR 04860000 foo.dll 048600D0 Import Address Table 048600C8 Import Name Table 0 time date stamp 0 Index of first forwarder reference 80000004 Ordinal 4
在上面的输出中,80000004中的8表示IMAGE_ORDINAL_FLAG32,它告诉Windows Loader通过序号而不是名称导入函数。有关导入表的更多信息,请阅读这篇文章this amazing article。
我发现这个功能非常有趣,因为理想情况下,能够以某种方式重定向导入地址表(IAT)。在实践中,我无法实现这一目标,我不相信使用mavinject自己可以用来实现任意导入表钩子。可能存在一些滥用混合导入表或者其他AppV相关DLL的注入,比如AppVEntSubsystems [32 | 64] .dll,但我没有深入研究。
但是,我确实发现了一个有趣的bug,即mavinject如何将IMAGE_ORDINAL_FLAG32用于命令行提供的序号。正常情况下,IMAGE_ORDINAL_FLAG32应该“与”(即掩码)序号,而不是“加”。mavinject在命令行接受一个DWORD值作为序号。然后代码将IMAGE_ORDINAL_FLAG32(0x8000000)加到指定的值中,这就会导致溢出。如果发生溢出,那么读取导入表的代码将按名称而不是序号来导入。为了突出显示溢出,使用导入表导入This program cannot be run in DOS mode(用于突出显示该bug的伪造“导入”)——PE头的偏移0x4E(0x80000000 + 0x4E == 2147483726 ,这将导致溢出并返回到0x4E):
mavinject.exe 4964 /HMODULE=0x013C0000 foobar.dll 2147483726在执行导入表格添加时,WinDbg确认导入列表的溢出导致的冲突:
0:009> !dh -i 013C0000 _IMAGE_IMPORT_DESCRIPTOR 04870000 foobar.dll 048700F8 Import Address Table 048700F0 Import Name Table 0 time date stamp 0 Index of first forwarder reference 0000004E 6854 is program cannot be run in DOS mode.
我还没有找到一种有效的方式来滥用这一bug,但我认为它很有趣。此外,UpdateImports32/64函数的一个显著副作用是将导入表模块的PE校验和设置为零。这是值得注意的,因为Cobalt Strike Beacon等恶意软件和工具可以清除/更新/修改PE校验和。
另一个mavinject.exe支持的命令行如下:
mavinject.exe PROCESSID DLL_FULL_PATH_OR_FILENAME
该选项类似于/HMODULE =0x,但是它将指定DLL中序号#1的导出导入到主进程模块。一个副作用是此方法从Microsoft Detours库中调用DetourCopyPayloadToProcess,并将主模块中PE头保存在内存的.detours节中。This article解释了.detours部分的用途。不过,似乎没有办法只使用mavinject从自定义钩子函数引入.detourssection。
最后,我还是无法将导入表注入作为有趣的(除了任意数据注入之外的)利用方法。尽管如此,我还在研究这一功能,希望它能激励一些人。为识别使用Detours库的已签名代码(因为库静态链接到代码中),需要获取所有模块的符号,然后在PDB文件中搜索Detours functions。
五、mavinject滥用检测建议
· 捕获命令行日志,查找“INJECTRUNNING”。攻击者可以重命名可滥用的应用程序来逃避检测,因此不要将检测仅限于“mavinject.exe”。mavinject在执行DLL注入时需要使用“INJECTRUNNING”,因此这是很好的DLL注入检测的基础。
· 通常,要检测mavinject.exe,请不要忽略攻击者会重命名它。应当根据Version Info资源中的属性,而不是Description或OrginalFileName来构建检测。但是,攻击者可以修改这些字段,但如果这样做的话签名将失效。
· 以下是一组用于检测mavinject使用的Sysmon规则示例:
<ProcessCreate onmatch="include"> <!-- Catch mavinject DLL injection --> <CommandLine condition="contains">INJECTRUNNING</CommandLine> <!-- Catch mavinject regardless of its filename and command line usage --> <!-- Note: an attacker can modify this field in the binary. It will render its signature invalid but it will also evade this rule. --> <Description condition="is">Microsoft Application Virtualization Injector</Description> </ProcessCreate> <CreateRemoteThread onmatch="include"> <!-- Catch mavinject DLL injection or any other DLL injection where LoadLibraryW was called. May be FP prone. --> <StartFunction condition="is">LoadLibraryW</StartFunction> </CreateRemoteThread>
六、总结
在撰写本文时,我希望能达到以下任一目的:
· 如果阅读本文前也对/HMODULE=0x命令行开关感兴趣,现在你已经无需自己去逆向此功能。
· 受到启发,可以利用mavinject和AppV函数调查Detours滥用行为,目前我对此一无所知,但我相信将来会有大量的滥用。
· 希望考虑一下写博客来介绍你的研究成果和方法,即便最终没有成功,也没有关系,毕竟,失败会产生灵感,直至最后的胜利。