Introduction

Windows OS uses a specific file format in order to store the logs generated by the different programs running on the system. One can usually find those logs at path C:\Windows\System32\winevt\Logs. According to the settings of your OS you can find a bunch of useful information that you may want to recover under some circumstances.

  • Login / logoffs (probably the most well known)
  • Execution of programs
  • Services installed / ran
  • Powershell Execution / scripts (according to the PS version)
  • Information about the handles
  • Some custom applications logs
  • ...

All these information can be very useful in the frame of incident response or forensics investigations. Under some circumstances, we may have to deal with corrupted disks or corrupted EVTX files. In such scenario, it is not easy to recover the EVTX files and extract the information inside. That is why we decided to write this small article in order to introduce our toolset and assess the efficiency/relevancy of Windows Event carving.

EVTX file-format in short

The EVTX file-format is quite straightforward. We can see it as being a four levels encapsulation file as depicted in the following image.

EVTX Fileformat

It is worth noting that every Chunk is independent from the others. A Chunk is always 64kB in size, in order to reduce the memory impact of the log collection on Windows OS. As a consequence, only one Chunk (per source) has to stay in memory and is committed to the corresponding EVTX file when it is full. One can notice that this design also implies that the Chunk structure is a great element for parallelisation.

Every Chunk contains cross-reference tables that the Events can use:

  1. A Template Reference table holding the BinXML Templates
  2. A String Reference table holding some strings shared between the Events

These cross-reference tables are used to optimize the size of the Chunks both in memory and on disk.

Due to this hard link between the Events and their corresponding Chunk we understand that our carving granularity cannot go lower than the Chunk Level. Indeed we would miss all the information shared in the cross-reference tables if we would like to carve at Event Level, which would result in incomplete Events.

Carving Pseudo-Algorithm

We describe here a simplified version of the carving algorithm we can use to recover events from raw data (file or disk image).

// Pseudo-algorithm in a Go like syntax (so it is probably not Go valid code !)

// Chunk Magic definition
ChunkMagic := "ElfChnk\x00"
// Allocate buffer to check Chunk Magic
buf := make([]byte, len(ChunkMagic))

// Reads bytes from data and set buf until EOF
for err := data.Read(buf); err != io.EOF; err = data.Read(buf) {
  data.Read(buf)
  // We can expect a chunk
  if string(buf) == ChunkMagic {
    // Parse Chunk Header
    header := ParseChunkHeader(data)
    // We validate the header to verify that it is not corrupted
    if header.Valid() {
      // We can parse the chunk
      chunk := ParseChunk(data)
      // We can now parse the Events in the chunk
      for event := range chunk.Events() {
        // Check the validity of the event header to prevent any corruption
        if event.Header.Valid() {
          // Process event (print, return ...)
        }
      }
    }
  }
}

Carving experiments

In order to carve EVTX events, we have developed our own tool based on our own EVTX parsing library. You can check out the code on Github

Pre-compiled binaries are available here

Experiment Scenario

  1. Dump the EVTX file(s) we plan to delete
  2. Stop the Event Log service to prevent any evtx to be generated after clear
  3. Delete the EVTX with whatever method
  4. Carve the disk image
  5. Measure the amount of events successfully recovered

Different deletion methods : Updated with NotPetya

  1. wevutil.exe
  2. Via Event Viewer
  3. Update: since the recent IT sec news gave us a nice example of real life EVTX deletion I decided to include a test assessing the amount of events we can recover after NotPetya ran. Since NotPetya is using the wevutil.exe binary, one cannot expect a significant difference in the results.

Experimental Settings

Method of carving: mounting vmdk file and carving device

Diffing method: hashing of events and count hashes in common

OS: Windows 10 running in a VM

> systeminfo
  Host Name:                 DESKTOP-5SUA567
  OS Name:                   Microsoft Windows 10 Pro
  OS Version:                10.0.14393 N/A Build 14393
  OS Manufacturer:           Microsoft Corporation
  OS Configuration:          Standalone Workstation
  OS Build Type:             Multiprocessor Free
  ...

Results

Deletion Method Event Source Waiting Time Del to Carve Total Events before deletion Total Events carved successfully % Recovered
wevutil.exe Sysmon-Operational < 5 min 47459 47279 99.6 %
event viewer Sysmon-Operational < 5 min 50134 48321 96.4 %

The NotPetya Scenario

In order not to spend too much time on this experiment, I decided to replay the commands issued by the well known malware wevtutil cl Setup & wevtutil cl System & wevtutil cl Security & wevtutil cl Application.

Deletion Method Event Source Waiting Time Del to Carve Total Events before deletion Total Events carved successfully % Recovered
wevutil.exe Security ~ 12h 2048 0 0 %
wevutil.exe Application ~ 12h 1092 0 0 %
wevutil.exe System ~ 12h 613 0 0 %
wevutil.exe Setup ~ 12h 9 0 0 %

Conclusion

From the previous results we can conclude that the amount of events we can recover successfully strongly depends on the waiting time between wiping and carving. It also shows that only clearing the Windows event logs with standard tools is enough to cover the traces of an attack. Windows event log carving is definitely a step to include into your forensic analysis since it is not very costly although you should not expect amazing results.

The poor recovering ratio after a long waiting time could be explained by the fact that in the default configuration, the evtx files have a fixed size. This means that write operations always occur at the same physical position on the disk and thus all past events are always overwritten with the new onces. It is worth noting that this behaviour could be different in function of the kind of hard drive used. If I remember correctly SSD (and flash memory in general) have an optimization mechanism that spreads the write operations accross all the cells to maximize their lifetime. This behaviour would prevent overwriting the old log entries.