关于ETW的这点,他错了

admin 2024年5月6日16:31:27评论4 views字数 4957阅读16分31秒阅读模式

前言

2023年10月份,Maxime Meignanriskinsight发表了一篇名为A universal EDR bypass built in Windows 10[1] 的文章,其大致内容是作者发现了通过修改进程环境块(PEB)中的某几个字段,可以禁止进程产生特定的事件

当时看到这篇文章后感到非常兴奋,原因是我在2023年8月份的文章 ETW生产者和消费者模型3 中记录了同样的发现,相比作者可惜的是没有继续深挖如何对字段进行修改。秉持着收藏就等于会了的原则,随时我就把文章纳入收藏夹以待后续研究,结果一放就是半年 : (

现在想起来还得多亏了Legacyy在2024年4月末写的一篇名为ETW-ByeBye: Disabling ETW-TI Without PPL[2] 的文章 ( 差点吃灰 :)。

闲话少叙,这篇文章将包含如下几点内容:

  • • 概括如何禁止进程产生特定事件

  • • 如何使用 SealighterTI[3] 订阅Threat-Intelligence ETW Provider

  • • 阐述Leagacyy文章中的问题

  • • 编写代码思路

文末日志文件可在 https://github.com/jseclab/wechat_public/tree/main/etw/p4 查看

正文

概括

此技术的核心是在PEB中有如下几个字段可以启用/禁用事件写入,我们通过NtSetInformationProcess可设置此值。

EnableReadVmLogging:虚拟内存读事件

EnableWriteVmLogging:虚拟内存写事件

EnableProcessSuspendResumeLogging:进程挂起/恢复事件

EnableThreadSuspendResumeLogging:线程挂起/恢复事件

按照Maxime Meignan所述,这并不适应于所有系统,在win10的特定区间系统可用。

关于ETW的这点,他错了

SealighterTI

Threat-Intelligence ETW Provider通过事件提供了非常重要的威胁情报,包括上述提到的内存操作等,当然并不是什么“档次”的程序都可以随随便便订阅Threat-Intelligence ETW Provider的,通常只有PPL级别及其以上的才可以订阅,而SealighterTI结合了PPL的漏洞可以成功订阅Threat-Intelligence ETW Provider,这为对ETW感兴趣的研究人员提供了帮助。

PPL漏洞在Windows 10 v21H2 Build 19044.1826之后进行了修补,理论上SealighterTI在此之后就不能够使用了,作者也提到了另外的方法,可自行查看Note

使用步骤:

  • • 在Release页面下载SealighterTIsealighter_provider.man两个文件放在同一 文件夹内,虽然作者提供了debug版本,但是不建议下载。

  • • 打开sealighter_provider.man文件,替换所有的 !!SEALIGHTER_LOCATION!! 字段为SealighterTI全路径,比如 C:Program FilesSealighterTI.exe

  • • 以管理员运行cmd/powershell,执行 wevtutil im [sealigher_provider.man 全路径],比如 wevtutil im C:Program Filessealigher_provider.man

  • • 执行SealighterTI.exe -d

在停止记录之后,打开事件查看器,应当在应用程序和服务日志下生成Sealighter->Operational事件日志

当然我们需要有一个简单的测试程序帮助产生内存的读写事件,比如我采用的是每隔三秒钟对记事本进行内存写入操作

#include <windows.h>
#include <stdio.h>

int main()
{
    BYTE buffer[0x100] = { 0 };
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 4548);

    if (hProcess == NULL)
    {
        printf("error got handle , error code = %dn", GetLastError());
        Sleep(3 * 1000);
        return -1;
    }

    do {
        DWORD oldProtect = 0;

        if (VirtualProtectEx(hProcess, (LPVOID)0x7ff712c30000, 0x100, PAGE_READWRITE, &oldProtect))
        {
            if (WriteProcessMemory(hProcess, (LPVOID)0x7ff712c30000, buffer, 0x100, NULL)) printf("write memory successn");
            else printf("error code 2 = %dn", GetLastError());
        }
        else
        {
            printf("error code 1 = %dn", GetLastError());
        }

        Sleep(3 * 1000);
    } while (true);

    return 1;
}

Leagacyy文章中的问题

上述我们已经学会如何使用SealighterTI记录事件,可以帮助我们验证此技术的正确性,接下来我们看Leagacyy的文章,内容我们就不说了,直接看他的代码部分。

  • • 首先既然是禁用,上述中的几个字段理应设置为false,而非true

        ProcessLoggingInformation.EnableReadVmLogging = 1;
        ProcessLoggingInformation.EnableWriteVmLogging = 1;
        ProcessLoggingInformation.EnableProcessSuspendResumeLogging = 1;
        ProcessLoggingInformation.EnableThreadSuspendResumeLogging = 1;
  • • 使用NtSetInformationProcess时需指定设置的进程信息类型(为枚举值)以及对应的进程信息(通过特定的结构体来表示),比如这里的类型为ProcessEnableLogging,对应的承载进程信息结构体就是PROCESS_LOGGING_INFORMATIONLeagacyy 在文章中使用的PROCESS_LOGGING_INFORMATION结构体如下

typedef struct _PROCESS_LOGGING_INFORMATION
{
    ULONG Flags;
    ULONG EnableReadVmLogging;
    ULONG EnableWriteVmLogging;
    ULONG EnableProcessSuspendResumeLogging;
    ULONG EnableThreadSuspendResumeLogging;
    //ULONG EnableLocalExecProtectVmLogging;  // New in Win11
    //ULONG EnableRemoteExecProtectVmLogging; // New in Win11
    ULONG Reserved = 26;
} PROCESS_LOGGING_INFORMATION, * PPROCESS_LOGGING_INFORMATION;

而我在systeminformer中找到的PROCESS_LOGGING_INFOMATION却是个联合体,且大小只有四个字节

typedef union _PROCESS_LOGGING_INFORMATION
{
    ULONG Flags;
    struct
    {
        ULONG EnableReadVmLogging : 1;
        ULONG EnableWriteVmLogging : 1;
        ULONG EnableProcessSuspendResumeLogging : 1;
        ULONG EnableThreadSuspendResumeLogging : 1;
        ULONG EnableLocalExecProtectVmLogging : 1;
        ULONG EnableRemoteExecProtectVmLogging : 1;
        ULONG Reserved : 26;
    };
} PROCESS_LOGGING_INFORMATION, *PPROCESS_LOGGING_INFORMATION;

根据Maxime Meignan文章中NtSetInformationProcess伪代码可以看到当传入ProcessEnableLogging时会检查ProcessInformationLength的大小是否小于4

关于ETW的这点,他错了

  • • 第三个问题也是最为重要的问题,在调用NtSetInformationProcess时,第一个参数应当传入谁的句柄?

回答这个问题,我们应当使用windbg在PsIsProcessLoggingEnabled处下断点,并检查第一个参数也就是eprocess,查看其中的ImageFileName,事实证明当我使用测试程序不停的写入记事本程序时,PsIsProcessLoggingEnabled检查的实际上时记事本程序中字段开启有无,而非测试程序的,这一点和Maxime Meignan文章中的PsIsProcessLoggingEnabled伪代码相呼应。

关于ETW的这点,他错了

代码思路

  • • 提权,NtSetInformationProcess会检查调用进程是否有 SeDebugPrivilege or SeTcbPrivilege权限。

  • • 以PROCESS_SET_LIMITED_INFORMATION权限打开目标进程并获得句柄

  • • 动态获取NtSetInformationProcess函数地址

  • • 构造PROCESS_LOGGING_INFORMATION参数并调用NtSetInformationProcess

  • • Enjoy 关于ETW的这点,他错了

写在最后:通过上述步骤我成功复现了整个过程,我使用SealighterTI分别获得了禁用记事本内存操作的前后的所有事件,并导出到记事本上传至 github[4] ,有兴趣的可以查看。

testRW.txt为禁用前产生的事件,testRW-bye为禁用后产生的事件,3900为写入程序pid,4548为记事本程序pid,禁用后的内存读写事件未被记录

引用

[1]:https://www.riskinsight-wavestone.com/en/2023/10/a-universal-edr-bypass-built-in-windows-10/

[2]:https://www.legacyy.xyz/defenseevasion/windows/2024/04/24/disabling-etw-ti-without-ppl.html#building-a-poc

[3]:https://github.com/pathtofile/SealighterTI?tab=readme-ov-file

[4]:https://github.com/jseclab/wechat_public/tree/main/etw/p4

原文始发于微信公众号(无名之):关于ETW的这点,他错了

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月6日16:31:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   关于ETW的这点,他错了https://cn-sec.com/archives/2712061.html

发表评论

匿名网友 填写信息