Universally Evading Sysmon and ETW

栏目: IT技术 · 发布时间: 4年前

内容简介:TheThere's been some great research into this by

The source code and latest release are both available.

Sysmon and windows event log are both extremely powerful tools in a defender's arsenal. Their very flexible configurations give them a great insight into the activity on endpoints, making the process of detecting attackers a lot easier. It's for this reason that I'm going to lead you through my journey in defeating them ;)

There's been some great research into this by xpn and matterpreter . Their solutions are both good but don't quite reach my needs of a fully universal bypass. Metterpreter's method of unloading the driver does technically, but unloading the driver feels like a dirty way of doing it. Especially due to the number of very telling events triggered from it.

In order to be able to figure out how to bypass it, it's vital to first understand how it works. This post by @dotslashroot gives a really good insight into this and I really recommend you read it before carrying on.

We now understand that ETW (Event Tracing for Windows) is responsible for handling the reporting of the events caught in the kernel drivers' callbacks, but how does sysmon's user mode process actually report it?

Firing up Ghidra and throwing in sysmon64.exe , we can see that it uses the ReportEventW Windows API call to report the event.

Universally Evading Sysmon and ETW

Now that we know this, it would be possible to just hook this call and filter/block events from there... but what's the point in that? We would still need admin privs to do that and I think we could put them to better use.

Going deeper down the call chain and looking at ReportEventW in ADVAPI32.dll we can see that its essentially a wrapper around EtwEventWriteTransfer which is defined in NTDLL.dll.

Universally Evading Sysmon and ETW

By examining EtwEventWriteTransfer we can see it calls the kernel function NtTraceEvent which is defined inside ntoskrnl.exe.

Universally Evading Sysmon and ETW

We now know that this function will be called by any user mode process that wants to report an event, Awesome! Here's a quick diagram to visualize this process.

Universally Evading Sysmon and ETW

Now that we know what kernel function it is that we want to target let's focus on testing to see if this will actually work. To do this I'm going to be using WinDBG kernel debugging, more information on that can be found here .

I'll start by setting a breakpoint at nt!NtTraceEvent then once this breakpoint is hit I will then patch the very start of the function with a ret . This will force the function to return straight away, before any of the event reporting code is run.

Universally Evading Sysmon and ETW

And it worked! If you look below you will see that I'm able to launch a powershell prompt without any sysmon events being triggered.

Universally Evading Sysmon and ETW

So now we have a working PoC its time to start writing code. The code we want to write will need to hook NtTraceEvent and give us the choice if we want to report the event or not. Since the function we are targeting is a kernel function we will need to have our hooking code running inside kernel space as well. There are two main problems we are going to encounter when we try to do this.

Luckily there are two super cool projects already around for the purpose of defeating them, KDU by @hFireF0x and InfinityHook . I won't go into detail about how they both work as there's a lot of information at their respective links about that, But I'm happy because this saved me a lot of time as I don't need to write my own bypasses.

I'll start by writing the code to run in the kernel, a link to it all can be found here . Right at the start of the DriverEntry we are going to need to locate the export of both NtTraceEvent and IoCreateDriver . The reason we need to find IoCreateDriver is because of KDU. It will load our driver by loading and exploiting a signed driver and then bootstrap ours into kernel space, this method of loading our driver will mean that both the DriverObject and RegistryPath passed to DriverEntry will be incorrect. But because we need to be able to communicate with our user mode process (so we know when to report and block events) we will need to create a valid DriverObject . We can do this by calling IoCreateDriver and giving it the address of our DriverInitialize routine, our DriverInitialize will then be called and passed a valid DriverObject which can then finally be used to create an IOCTL, letting us speak to user mode. This code snippet is below.

NTSTATUS DriverEntry(
	_In_ PDRIVER_OBJECT DriverObject,
	_In_ PUNICODE_STRING RegistryPath)
{
	NTSTATUS        status;
	UNICODE_STRING  drvName;

	UNREFERENCED_PARAMETER(DriverObject);
	UNREFERENCED_PARAMETER(RegistryPath);

	DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, "[+] infinityhook: Loaded.\r\n");

	OriginalNtTraceEvent = (NtTraceEvent_t)MmGetSystemRoutineAddress(&StringNtTraceEvent);
	OriginalIoCreateDriver = (IoCreateDriver_t)MmGetSystemRoutineAddress(&StringIoCreateDriver);

	if (!OriginalIoCreateDriver)
	{
		DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, "[-] infinityhook: Failed to locate export: %wZ.\n", StringIoCreateDriver);
		return STATUS_ENTRYPOINT_NOT_FOUND;
	}

	if (!OriginalNtTraceEvent)
	{
		DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, "[-] infinityhook: Failed to locate export: %wZ.\n", StringNtTraceEvent);
		return STATUS_ENTRYPOINT_NOT_FOUND;
	}

	RtlInitUnicodeString(&drvName, L"\\Driver\\ghostinthelogs");
	status = OriginalIoCreateDriver(&drvName, &DriverInitialize);

	DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, "[+] Called OriginalIoCreateDriver status: 0x%X\n", status);

	NTSTATUS Status = IfhInitialize(SyscallStub);
	if (!NT_SUCCESS(Status))
	{
		DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, "[-] infinityhook: Failed to initialize with status: 0x%lx.\n", Status);
	}

	return Status;
}

Once we have located our exports and got a valid DriverObject we can now use InfinityHook to initialize our NtTraceEvent hook. The function IfhInitialize does this. I call IfhInitialize and pass it a pointer to my callback. This callback will be hit every time a syscall is made. The callback is given a pointer to the address of the function about to be called. Having access to this pointer means we can change it to point to the address of our hooked function. The callback code is shown below.

void __fastcall SyscallStub(
	_In_ unsigned int SystemCallIndex,
	_Inout_ void** SystemCallFunction)
{
	UNREFERENCED_PARAMETER(SystemCallIndex);

	if (*SystemCallFunction == OriginalNtTraceEvent)
	{
		*SystemCallFunction = DetourNtTraceEvent;
	}
}

This code will redirect every call to NtTraceEvent to our DetourNtTraceEvent . The code for DetourNtTraceEvent is shown below.

NTSTATUS DetourNtTraceEvent(
	_In_ PHANDLE TraceHandle,
	_In_ ULONG Flags,
	_In_ ULONG FieldSize,
	_In_ PVOID Fields)
{

	if (HOOK_STATUS == 0)
	{
		return OriginalNtTraceEvent(TraceHandle, Flags, FieldSize, Fields);
	}

	return STATUS_SUCCESS;
}

This code is very simple. It'll check to see if HOOK_STATUS (set by the user mode process via an IOCTL) is 0, if it is then it will carry out a call to NtTraceEvent , therefore reporting the event. If HOOK_STATUS is nonzero it will just return STATUS_SUCCESS signifying that the event was reported successfully, which of course it wasn't. It would be cool if someone could figure out how to parse the Fields parameter so it would be possible to apply a filter to the events being reported, if you reach out to me I'll give you all the info I've got about it and show you how far I've got with it as well, we might be able to work it out ;)

Because I want to keep this all as a single executable, I will be embedding this driver inside of the executable, so when it needs to be used it'll be unpacked and then KDU will load it to the kernel.

I won't go into detail about the rest of the code as its mostly KDU and interacting with the driver from user mode, but if you're interested you can find it here .

So does it work?

Yep :) Well on everything I've tested it on, if you find something its doesn't work on or any general bugs let me know and I'll try to fix them. Also, I'm not a programmer so my code is going to be far from perfect but feel free to make any pull requests with any cool features you can think of!

Here's some examples of it running and its various features.

Loading the driver and setting the hook

Universally Evading Sysmon and ETW

Enabling the hook (disabling all logging)

Universally Evading Sysmon and ETW

Getting the status of the hook

Universally Evading Sysmon and ETW

Disabling the hook (enabling all logging)

Universally Evading Sysmon and ETW

If you still reading then thanks for sticking around, you can get updates about new projects and any other stuff I'm up to on my twitter .


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

scikit learn机器学习

scikit learn机器学习

黄永昌 / 机械工业出版社 / 2018-3-1 / CNY 59.00

本书通过通俗易懂的语言、丰富的图示和生动的实例,拨开了笼罩在机器学习上方复杂的数学“乌云”,让读者以较低的代价和门槛轻松入门机器学习。本书共分为11章,主要介绍了在Python环境下学习scikit-learn机器学习框架的相关知识。本书涵盖的主要内容有机器学习概述、Python机器学习软件包、机器学习理论基础、k-近邻算法、线性回归算法、逻辑回归算法、决策树、支持向量机、朴素贝叶斯算法、PCA ......一起来看看 《scikit learn机器学习》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具