0xrawsec / golang-evtx

GNU General Public License v3.0
158 stars 27 forks source link

Live-monitoring seems not to be working #22

Open pH-T opened 4 years ago

pH-T commented 4 years ago

Hi!

Based on evtxmon I tried to come up with a minimal monitoring tool myself:

package main

import (
    "log"

    "github.com/0xrawsec/golang-evtx/evtx"
)

func main() {
    ef, err := evtx.OpenDirty(`C:\Windows\System32\winevt\Logs\Microsoft-Windows-Sysmon%4Operational.evtx`)
    if err != nil {
        log.Fatal(err)
    }

    stop := make(chan bool, 1)
    for e := range ef.MonitorEvents(stop) {
        log.Println(string(evtx.ToJSON(e)))
    }

}

Although Sysmon is running ("Event Viewer" shows all/new events) I dont get any output. If I add ef.SetMonitorExisting(true) some old events (it seems always the same old events are dumped?) are shown but new ones are still missing. Using evtxmon directly (changed writer.Write(evtx.ToJSON(e)) to log.Println(string(evtx.ToJSON(e)))) resulted in the same issue...

Did I make a mistake?

steve-offutt commented 4 years ago

While I don't see the same behavior as above I do observe the duplicate events that seem to be mentioned. Here is a modified version of what @pH-T posted where just the EventRecordID of each event (which should be unique) is logged for C:\Windows\System32\winevt\Logs\Security.evtx.

package main

import (
    "flag"
    "fmt"
    "log"

    "github.com/0xrawsec/golang-evtx/evtx"
)

func main() {
    efile := flag.String("file", "", "evtxfile to monitor")
    flag.Parse()
    fmt.Println(*efile)

    if *efile == "" {
        log.Fatal("file arg required")
    }
    ef, err := evtx.OpenDirty(*efile)
    if err != nil {
        log.Fatal(err)
    }

    stop := make(chan bool, 1)
    for e := range ef.MonitorEvents(stop) {
        log.Println(e.EventRecordID())
    }
}

The output shows duplicate events every time a new record is written to Security.evtx.

2020/10/29 14:14:36 151682
2020/10/29 14:14:36 151683
2020/10/29 14:14:36 151684
2020/10/29 14:14:36 151685
2020/10/29 14:14:36 151686
2020/10/29 14:14:36 151687
2020/10/29 14:14:36 151688
2020/10/29 14:14:36 151689
2020/10/29 14:14:36 151690
2020/10/29 14:14:36 151691
2020/10/29 14:14:36 151692
2020/10/29 14:14:36 151693
2020/10/29 14:14:36 151694
2020/10/29 14:14:36 151695
2020/10/29 14:14:36 151696
2020/10/29 14:14:36 151697
2020/10/29 14:24:30 151682
2020/10/29 14:24:30 151683
2020/10/29 14:24:30 151684
2020/10/29 14:24:30 151685
2020/10/29 14:24:30 151686
2020/10/29 14:24:30 151687
2020/10/29 14:24:30 151688
2020/10/29 14:24:30 151689
2020/10/29 14:24:30 151690
2020/10/29 14:24:30 151691
2020/10/29 14:24:30 151692
2020/10/29 14:24:30 151693
2020/10/29 14:24:30 151694
2020/10/29 14:24:30 151695
2020/10/29 14:24:30 151696
2020/10/29 14:24:30 151697
2020/10/29 14:24:30 151698      <------------------NEW EVENT

Not sure if it's related but wanted to definitely point out the duplicate events.

qjerome commented 4 years ago

Hi guys,

This tool is a bit outdated and since then I came up with a better solution for live monitoring. Check this out, you can monitor directly to Windows event channels: https://github.com/0xrawsec/golang-win32/blob/master/win32/wevtapi/helpers.go I would recommend you guys use a PullEventProvider to listen to the channels you want. I actually need to fix evtxmon to use that method too, however I don't have much time to do it now.

Cheers,

pathtofile commented 2 years ago

fwiw I used @qjerome 's idea to subscribe to sysmon events and it worked well, so I'll be using that instead of this library. Code roughly looks like:

import (
    "fmt"
    "sync"
    "time"

    "github.com/0xrawsec/golang-win32/win32/wevtapi"
)

func GetEvents() {
    fmt.Println("Getting events")

    SysmonChannel := "Microsoft-Windows-Sysmon/Operational"
    wg := sync.WaitGroup{}
    ep := wevtapi.NewPullEventProvider()

    wg.Add(1)
    go func() {
        for e := range ep.FetchEvents([]string{SysmonChannel}, wevtapi.EvtSubscribeToFutureEvents) {
            j := e.ToJSONEvent()
            channel := j.Event.System.Channel
            switch channel {
            case SysmonChannel:
                if j.Event.System.EventID == "1" {
                    event := j.Event.EventData
                    fmt.Printf("Event: %s\n", event["Image"])
                }
            }
        }
        wg.Done()
    }()

    fmt.Println("Sleeping")
    time.Sleep(5 * time.Second)

    // Stopping EventProvider
    ep.Stop()
    wg.Wait()
}