Monitoring File mods through ETW and Velociraptor

In my last blog, I went over writing an ETW provider and how we can stream the events back to a Velociraptor server. This week I wanted to go over what you can do using the built-in ETW providers, and essentially setting up your own streaming EDR with Velociraptor and the built-in providers.

Windows has over a thousand built-in providers: If you’re willing to open the flood gate, you’ll be able to see everything on your network. But how do we refine the events we capture so we’re not DOSing our network/host/server/log storage?

This week I’ll be focusing on process creation, module loads and file modifications.


Getting Started

Before we get too carried away, how do we actually query our providers?

Logman is a built-in tool that can be used for querying providers and creating Event Tracing Sessions. There’s a few core commands that you should be comfortable with when using Logman.

Query all Sessions

logman query -ets

Query all Providers

logman query providers

Query a specific provider

logman query providers Microsoft-Windows-Kernel-Process

Create a Session

logman create start “Process Logging” -p “Microsoft-Windows-Kernel-Process” (process,image) -ets

When we query a specific provider, we get given a list of important details about the provider. This includes:

  • Provider GUID: This is how you reference the provider 99% of the time.

  • Keywords: These are a bitfield for the event types. You can provide the hexadecimal value of the events you want to capture to filter out unwanted events.

  • Log Levels: Similar to keywords, you can filter based on level to ensure you only get the events you’re after.

  • PID: This is all the current processes utilising this provider.

Once we know what Providers we want to capture and their keywords, we can use Velociraptor to create an Event Tracing Session and start capturing the logs.

Using the VQL plugin watch_etw, we just need to provide a GUID and Velociraptor will start capturing the data.

In this example, I provide the GUID for Microsoft-Windows-Kernel-Process, as well as the keyword 0x50. Looking at the image above, you can see that 0x50 includes the keywords for Process and Image events.

This an example for how we can do process monitoring using ETW and Velociraptor. This will tell us every time a process starts or stops, and every time a module loads or unloads. While this is extremely useful for blue teams, it doesn’t really detail anything that Sysmon can’t currently do. So, in the next section we’ll go through ETW manifests to get some more interesting data, specifically around file modifications. To locate the manifest of an ETW provider, I’ve been using this repo on github: https://github.com/repnz/etw-providers-docs


File Monitoring

The knowledge of what files an actor is accessing on a network is a huge advantage in DFIR, while also being extremely beneficial for Machine Learning and detecting abnormal process interactions. The Microsoft-Windows-Kernel-File provider provides Kernel logging on files that are being created, opened, renamed and deleted.

One of the difficulties of working with Kernel providers, is that quite often the fields returned are not useful without Kernel context. Kernel-File is a great example of that, with half of the event templates returning a Kernel Object address rather than a filename. While a Kernel Object holds a huge amount of potential, it is useless without a way to look up the address and I don’t particularly want to install a Kernel driver just for that. Because of this, the first thing I did with Kernel-File was remove all the templates that do not have a filename.

Example of templates with file paths.

So, with the restriction of requiring a file path, I excluded all event templates without one. This left us with five different event types:

  • NameCreate

  • Create

  • DirEnum

  • DeletePath

When we look at the events that utilise these event templates, we’re given the following list:

List of viable events to capture.

Once you’ve read through that list, you might ask “Why are there two create events?”. This was a question I had as well, so I dug a bit further. It ends up Event ID 12: Create has a pretty poor named, but it is linked to the WinAPI function: NtCreateFile. This is interesting for a couple of reasons, but we’ll start with the “CreateDisposition” argument.

CreateDisposition lets you declare how you want to interact with the specified file, specifically whether you want to create, open or overwrite it. This means that this Create event might actually be a file being opened, rather than created. When a file is actually created, event ID 30 is sent instead of event ID 12. This means we can use event ID to monitor what files a process is interacting with.

I started by capturing this Provider through Velociraptor using the VQL on the left. This limited us to only the event IDs that we care about to minimize the flood gates, while renaming the fields into a more OSSEM appropriate standard (gotta love that common data model).

I also excluded all events which referenced Velociraptor or Microsoft-Windows-System-Events, just due to the sheer amount of traffic these two filenames were generating.

Filtering for event ID 12, I got the below results. These is no CreateDisposition, butt here is three bitfields:

  • CreateOptions

  • CreateAttributes

  • FileShareAccess

CreateOptions

CreateOptions took my immediate attention due to the large value in each field. I immediately assumed that this would be some sort of bitfield. Looking at the MSDN documentation, CreateOptions is an argument for the function and it provides a list of valid options. Looking at the options though, there was no values for the bitfield, and there was not enough options to make sense of the create options bitfield.

To try and solve the bitfield issue, I opened up visual studio, started typing one of the options, then opened the definition. This lead me to the kernel header “wdm.h”, and there it was! The bitfield details and a nice little comment confirming it!

I restructured these definitions into a bitfield within a Jupyter notebook, so I can do some pre-ingestion clean up and change the bitfield into the string values. My class ended up looking like this.

A python one liner can then be used to convert the bitfield to an array of strings.

CreateAttributes

CreateAttributes was a bit of a confusing one at first. These wasn’t a direct link to its contents and an argument within NtCreateFile. Digging through the kernel header, “wdm.h”, I was able to find the definitions again. This ended up being linked to the “FileAttributes” argument and provided a bunch of additional context on the file. Similar to CreateOptions, I was able to import a bitfield and use a python one liner to convert it into a string array.

Share Access

Saving the easiest one for last, I was able to directly link up Share Access to the NtCreateFile argument ShareAccess. That was pretty straight forward, but where do we find the bitfield? Similar to the other two options, I was able to find the reference with wdm.h. I created the following struct for my notebook:

Using the same one liner as the other two, I can quickly convert the share options.


Wrap Up

Using ETW and Velociraptor can give you in-depth streaming data about your network, especially if you don’t have an existing EDR. This can be a wealth of information for machine learning or detecting intrusions within a network, although you will need to be able to store a wealth of data.

Once you’ve converted the data into something more readable, you’ll get events like this for ingestion:

After Christmas, I’ll go into a few other areas that I’ve been monitoring, including:

  • Registry,

  • SMB,

  • Named Pipes

If there’s an area of particular interest, let me know!

Previous
Previous

Cobalt Strike DFIR: Listening to the Pipes

Next
Next

W3WProtect: Kernel ETW and Velociraptor