Skip to content

Commit 74a755b

Browse files
committed
chore(alertsenders): Adapt to use shared eventlog code
Presently, both eventlog output and eventlog sender profit from the common codebase. In the future, we'll modularize the rest of the eventlog operations and make all conumsers use the shared code.
1 parent 2f66468 commit 74a755b

File tree

9 files changed

+44
-80
lines changed

9 files changed

+44
-80
lines changed

make.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ goto :EOF
8686
:mc
8787
:: Generate eventlog message compiler input file
8888
go generate github.com/rabbitstack/fibratus/pkg/outputs/eventlog
89-
windmc -r pkg/outputs/eventlog/mc pkg/outputs/eventlog/mc/fibratus.mc
89+
windmc -c -r pkg/outputs/eventlog/mc pkg/outputs/eventlog/mc/fibratus.mc
9090
windres -O coff -r -fo pkg/outputs/eventlog/mc/fibratus.res pkg/outputs/eventlog/mc/fibratus.rc
9191
:: Link the resulting resource object
9292
gcc pkg/outputs/eventlog/mc/fibratus.res -o pkg/outputs/eventlog/mc/fibratus.dll -s -shared "-Wl,--subsystem,windows"

pkg/alertsender/alert.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,19 @@ type Alert struct {
104104
func (a Alert) String(verbose bool) string {
105105
if verbose {
106106
var b strings.Builder
107+
if len(a.Events) > 1 {
108+
b.WriteString("System events involved in this alert:\n\n")
109+
} else {
110+
b.WriteString("System event involved in this alert:\n\n")
111+
}
107112
for n, evt := range a.Events {
108-
b.WriteString(fmt.Sprintf("Event #%d:\n", n+1))
109-
b.WriteString(evt.String())
113+
b.WriteString(fmt.Sprintf("\tEvent #%d:\n", n+1))
114+
b.WriteString(strings.TrimSuffix(evt.StringShort(), "\t"))
110115
}
111116
if a.Text == "" {
112-
return fmt.Sprintf("%s\n\n%s", a.Title, b.String())
117+
return fmt.Sprintf("%s\n\nSeverity: %s\n\n%s", a.Title, a.Severity, b.String())
113118
}
114-
return fmt.Sprintf("%s\n\n%s\n\n%s", a.Title, a.Text, b.String())
119+
return fmt.Sprintf("%s\n\n%s\n\nSeverity: %s\n\n%s", a.Title, a.Text, a.Severity, b.String())
115120
}
116121

117122
if a.Text == "" {

pkg/alertsender/alert_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func TestAlertString(t *testing.T) {
6262
},
6363
}}),
6464
true,
65-
"Credential discovery via VaultCmd.exe\n\nSuspicious vault enumeration via VaultCmd tool\n\nEvent #1:\n\n\t\tSeq: 0\n\t\tPid: 1023\n\t\tTid: 0\n\t\tType: CreateProcess\n\t\tCPU: 0\n\t\tName: CreateProcess\n\t\tCategory: process\n\t\tDescription: \n\t\tHost: ,\n\t\tTimestamp: 0001-01-01 00:00:00 +0000 UTC,\n\t\tKparams: cmdline➜ C:\\Windows\\system32\\svchost-fake.exe -k RPCSS, name➜ svchost-fake.exe,\n\t\tMetadata: ,\n\t \n\t\tPid: 0\n\t\tPpid: 345\n\t\tName: svchost.exe\n\t\tCmdline: C:\\Windows\\System32\\svchost.exe\n\t\tExe: \n\t\tCwd: \n\t\tSID: S-1-5-18\n\t\tUsername: SYSTEM\n\t\tDomain: NT AUTHORITY\n\t\tArgs: []\n\t\tSession ID: 0\n\t\tEnvs: map[]\n\t\t\n\t",
65+
"Credential discovery via VaultCmd.exe\n\nSuspicious vault enumeration via VaultCmd tool\n\nSeverity: low\n\nSystem event involved in this alert:\n\n\tEvent #1:\n\n\t\tSeq: 0\n\t\tPid: 1023\n\t\tTid: 0\n\t\tName: CreateProcess\n\t\tCategory: process\n\t\tHost: \n\t\tTimestamp: 0001-01-01 00:00:00 +0000 UTC\n\t\tParameters: cmdline➜ C:\\Windows\\system32\\svchost-fake.exe -k RPCSS, name➜ svchost-fake.exe\n \n\t\tPid: 0\n\t\tPpid: 345\n\t\tName: svchost.exe\n\t\tCmdline: C:\\Windows\\System32\\svchost.exe\n\t\tExe: \n\t\tCwd: \n\t\tSID: S-1-5-18\n\t\tUsername: SYSTEM\n\t\tDomain: NT AUTHORITY\n\t\tArgs: []\n\t\tSession ID: 0\n\t\tAncestors: \n\t\n",
6666
},
6767
{
6868
NewAlertWithEvents("Credential discovery via VaultCmd.exe", "", nil, Normal, []*kevent.Kevent{{
@@ -83,7 +83,7 @@ func TestAlertString(t *testing.T) {
8383
},
8484
}}),
8585
true,
86-
"Credential discovery via VaultCmd.exe\n\nEvent #1:\n\n\t\tSeq: 0\n\t\tPid: 1023\n\t\tTid: 0\n\t\tType: CreateProcess\n\t\tCPU: 0\n\t\tName: CreateProcess\n\t\tCategory: process\n\t\tDescription: \n\t\tHost: ,\n\t\tTimestamp: 0001-01-01 00:00:00 +0000 UTC,\n\t\tKparams: cmdline➜ C:\\Windows\\system32\\svchost-fake.exe -k RPCSS, name➜ svchost-fake.exe,\n\t\tMetadata: ,\n\t \n\t\tPid: 0\n\t\tPpid: 345\n\t\tName: svchost.exe\n\t\tCmdline: C:\\Windows\\System32\\svchost.exe\n\t\tExe: \n\t\tCwd: \n\t\tSID: S-1-5-18\n\t\tUsername: SYSTEM\n\t\tDomain: NT AUTHORITY\n\t\tArgs: []\n\t\tSession ID: 0\n\t\tEnvs: map[]\n\t\t\n\t",
86+
"Credential discovery via VaultCmd.exe\n\nSeverity: low\n\nSystem event involved in this alert:\n\n\tEvent #1:\n\n\t\tSeq: 0\n\t\tPid: 1023\n\t\tTid: 0\n\t\tName: CreateProcess\n\t\tCategory: process\n\t\tHost: \n\t\tTimestamp: 0001-01-01 00:00:00 +0000 UTC\n\t\tParameters: cmdline➜ C:\\Windows\\system32\\svchost-fake.exe -k RPCSS, name➜ svchost-fake.exe\n \n\t\tPid: 0\n\t\tPpid: 345\n\t\tName: svchost.exe\n\t\tCmdline: C:\\Windows\\System32\\svchost.exe\n\t\tExe: \n\t\tCwd: \n\t\tSID: S-1-5-18\n\t\tUsername: SYSTEM\n\t\tDomain: NT AUTHORITY\n\t\tArgs: []\n\t\tSession ID: 0\n\t\tAncestors: \n\t\n",
8787
},
8888
}
8989

pkg/alertsender/eventlog/eventlog.go

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,12 @@ import (
2222
"errors"
2323
"fmt"
2424
"github.com/rabbitstack/fibratus/pkg/alertsender"
25-
"github.com/rabbitstack/fibratus/pkg/kevent/ktypes"
2625
evlog "github.com/rabbitstack/fibratus/pkg/util/eventlog"
2726
"golang.org/x/sys/windows"
2827
"hash/crc32"
2928
"strings"
3029
)
3130

32-
const (
33-
// source represents the event source that generates the alerts
34-
source = "Fibratus"
35-
// levels designates the supported eventlog levels
36-
levels = uint32(evlog.Info | evlog.Warn | evlog.Erro)
37-
// msgFile specifies the location of the eventlog message DLL
38-
msgFile = "%ProgramFiles%\\Fibratus\\fibratus.dll"
39-
// keyName represents the registry key under which the eventlog source is registered
40-
keyName = `SYSTEM\CurrentControlSet\Services\EventLog`
41-
)
42-
4331
const minIDChars = 12
4432

4533
type eventlog struct {
@@ -56,14 +44,14 @@ func makeSender(config alertsender.Config) (alertsender.Sender, error) {
5644
if !ok {
5745
return nil, alertsender.ErrInvalidConfig(alertsender.Eventlog)
5846
}
59-
sourceName, err := windows.UTF16PtrFromString(source)
47+
sourceName, err := windows.UTF16PtrFromString(evlog.Source)
6048
if err != nil {
6149
return nil, fmt.Errorf("could not convert source name: %v", err)
6250
}
6351

64-
err = evlog.Install(source, msgFile, keyName, false, levels, uint32(len(ktypes.Categories())))
52+
err = evlog.Install(evlog.Levels)
6553
if err != nil {
66-
if !errors.Is(err, evlog.ErrKeyExists{}) {
54+
if !errors.Is(err, evlog.ErrKeyExists) {
6755
return nil, err
6856
}
6957
}
@@ -77,24 +65,11 @@ func makeSender(config alertsender.Config) (alertsender.Sender, error) {
7765

7866
// Send logs the alert to the eventlog.
7967
func (s *eventlog) Send(alert alertsender.Alert) error {
80-
var etype uint16
81-
switch alert.Severity {
82-
case alertsender.Normal:
83-
etype = windows.EVENTLOG_INFORMATION_TYPE
84-
case alertsender.Medium:
85-
etype = windows.EVENTLOG_WARNING_TYPE
86-
case alertsender.High, alertsender.Critical:
87-
etype = windows.EVENTLOG_ERROR_TYPE
88-
default:
89-
etype = windows.EVENTLOG_INFORMATION_TYPE
90-
}
91-
92-
var eventID uint32
93-
68+
var code uint16
9469
// despite the event id is 4-byte long
9570
// we can only use 2 bytes to store the
96-
// event identifier. Calculate the hash
97-
// of the event id from alert identifier
71+
// event code. Calculate the hash
72+
// of the event code from alert identifier
9873
// but keeping in mind collisions are
9974
// possible since we're mapping a larger
10075
// space to a smaller one
@@ -105,8 +80,7 @@ func (s *eventlog) Send(alert alertsender.Alert) error {
10580
id := strings.Replace(alert.ID, "-", "", -1)
10681
h := crc32.ChecksumIEEE([]byte(id[:minIDChars]))
10782
// take the lower 16 bits of the CRC32 hash
108-
eid := uint16(h & 0xFFFF)
109-
eventID = uint32(eid)
83+
code = uint16(h & 0xFFFF)
11084
}
11185

11286
msg := alert.String(s.config.Verbose)
@@ -119,7 +93,10 @@ func (s *eventlog) Send(alert alertsender.Alert) error {
11993
return fmt.Errorf("could not convert eventlog message to UTF16: %v: %s", err, msg)
12094
}
12195

122-
return windows.ReportEvent(s.log, etype, 0, eventID, uintptr(0), 1, 0, &m, nil)
96+
return windows.ReportEvent(s.log, windows.EVENTLOG_INFORMATION_TYPE, 0,
97+
evlog.EventID(windows.EVENTLOG_INFORMATION_TYPE, code),
98+
uintptr(0),
99+
1, 0, &m, nil)
123100
}
124101

125102
// Shutdown deregisters the event source.

pkg/outputs/eventlog/api.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,12 @@ package eventlog
2525
import (
2626
"bytes"
2727
"errors"
28-
"github.com/rabbitstack/fibratus/pkg/kevent/ktypes"
2928
"github.com/rabbitstack/fibratus/pkg/util/eventlog"
3029
"syscall"
3130

3231
"golang.org/x/sys/windows"
3332
)
3433

35-
const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application`
36-
37-
var categoryCount = len(ktypes.Categories())
38-
3934
// Eventlog provides access to the system log.
4035
type Eventlog struct {
4136
Handle windows.Handle

pkg/outputs/eventlog/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func (c Config) parseTemplate() (*template.Template, error) {
5555
// AddFlags registers persistent flags.
5656
func AddFlags(flags *pflag.FlagSet) {
5757
flags.String(tmpl, "", "Go template for rendering the eventlog message")
58-
flags.String(level, "info", "Specifies the eventlog level")
58+
flags.String(level, "info", "Specifies the eventlog level. Deprecated")
5959
flags.String(remoteHost, "", "Address of the remote eventlog intake")
6060
flags.Bool(enabled, false, "Indicates if the eventlog output is enabled")
6161
}

pkg/outputs/eventlog/eventlog.go

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ package eventlog
2323
import (
2424
"errors"
2525
"github.com/rabbitstack/fibratus/pkg/util/eventlog"
26+
"golang.org/x/sys/windows"
2627
"text/template"
2728

2829
"github.com/rabbitstack/fibratus/pkg/kevent/ktypes"
@@ -32,13 +33,6 @@ import (
3233
)
3334

3435
const (
35-
// source under which eventlog events are reported
36-
source = "Fibratus"
37-
// levels designates the supported eventlog levels
38-
levels = uint32(eventlog.Info | eventlog.Warn | eventlog.Erro)
39-
// msgFile specifies the location of the eventlog message DLL
40-
msgFile = "%ProgramFiles%\\Fibratus\\fibratus.dll"
41-
4236
// categoryOffset specifies the start of the event id number space
4337
categoryOffset = 25
4438
)
@@ -64,10 +58,10 @@ func initEventlog(config outputs.Config) (outputs.OutputGroup, error) {
6458
if !ok {
6559
return outputs.Fail(outputs.ErrInvalidConfig(outputs.Eventlog, config.Output))
6660
}
67-
err := eventlog.Install(source, msgFile, addKeyName, false, levels, uint32(categoryCount))
61+
err := eventlog.Install(eventlog.Levels)
6862
if err != nil {
6963
// ignore error if the key already exists
70-
if !errors.Is(err, eventlog.ErrKeyExists{}) {
64+
if !errors.Is(err, eventlog.ErrKeyExists) {
7165
return outputs.Fail(err)
7266
}
7367
}
@@ -89,9 +83,9 @@ func (e *evtlog) Connect() error {
8983
err error
9084
)
9185
if e.config.RemoteHost != "" {
92-
evl, err = OpenRemote(e.config.RemoteHost, source)
86+
evl, err = OpenRemote(e.config.RemoteHost, eventlog.Source)
9387
} else {
94-
evl, err = Open(source)
88+
evl, err = Open(eventlog.Source)
9589
}
9690
if err != nil {
9791
return err
@@ -121,30 +115,18 @@ func (e *evtlog) publish(kevt *kevent.Kevent) error {
121115
if err != nil {
122116
return err
123117
}
124-
eid := e.eventID(kevt)
125-
if eid == 0 {
118+
categoryID := e.categoryID(kevt)
119+
eventID := eventlog.EventID(windows.EVENTLOG_INFORMATION_TYPE, uint16(e.eventCode(kevt)))
120+
if eventID == 0 {
126121
return ErrUnknownEventID
127122
}
128-
err = e.log(eid, e.categoryID(kevt), buf)
123+
err = e.evtlog.Info(eventID, categoryID, buf)
129124
if err != nil {
130125
return err
131126
}
132127
return nil
133128
}
134129

135-
func (e *evtlog) log(eventID uint32, categoryID uint16, buf []byte) error {
136-
switch eventlog.LevelFromString(e.config.Level) {
137-
case eventlog.Info:
138-
return e.evtlog.Info(eventID, categoryID, buf)
139-
case eventlog.Warn:
140-
return e.evtlog.Warning(eventID, categoryID, buf)
141-
case eventlog.Erro:
142-
return e.evtlog.Error(eventID, categoryID, buf)
143-
default:
144-
panic("unknown eventlog level")
145-
}
146-
}
147-
148130
// categoryID maps category name to eventlog identifier.
149131
func (e *evtlog) categoryID(kevt *kevent.Kevent) uint16 {
150132
for i, cat := range e.cats {
@@ -155,8 +137,8 @@ func (e *evtlog) categoryID(kevt *kevent.Kevent) uint16 {
155137
return 0
156138
}
157139

158-
// eventID returns the event ID from the event type.
159-
func (e *evtlog) eventID(kevt *kevent.Kevent) uint32 {
140+
// eventCode returns the event ID from the event type.
141+
func (e *evtlog) eventCode(kevt *kevent.Kevent) uint32 {
160142
for i, evt := range e.events {
161143
if evt.Name == kevt.Name {
162144
return uint32(i + categoryOffset)

pkg/outputs/eventlog/eventlog_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package eventlog
2020

2121
import (
2222
"errors"
23+
"github.com/rabbitstack/fibratus/pkg/util/eventlog"
2324
"github.com/rabbitstack/fibratus/pkg/util/va"
2425
"golang.org/x/sys/windows"
2526
"testing"
@@ -46,8 +47,8 @@ func TestEvtlogPublish(t *testing.T) {
4647
events: ktypes.GetKtypesMetaIndexed(),
4748
cats: ktypes.Categories(),
4849
}
49-
err = Install(source, msgFile, false, levels)
50-
if err != nil && !errors.Is(err, ErrKeyExists) {
50+
err = eventlog.Install(eventlog.Levels)
51+
if err != nil && !errors.Is(err, eventlog.ErrKeyExists) {
5152
require.NoError(t, err)
5253
}
5354
require.NoError(t, el.Connect())

pkg/outputs/eventlog/mc/gen.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ package main
2020

2121
import (
2222
"bytes"
23-
"errors"
23+
"fmt"
2424
"github.com/Masterminds/sprig/v3"
2525
"github.com/rabbitstack/fibratus/pkg/kevent/ktypes"
2626
"io"
@@ -55,7 +55,7 @@ func (s *Source) Generate(w io.Writer) error {
5555
t := template.Must(template.New("main").Funcs(funcmap).Parse(srcTemplate))
5656
err := t.Execute(w, s)
5757
if err != nil {
58-
return errors.New("failed to execute template: " + err.Error())
58+
return fmt.Errorf("failed to execute template: %v", err)
5959
}
6060
return nil
6161
}
@@ -79,6 +79,10 @@ func main() {
7979

8080
const srcTemplate = `
8181
;// Code generated by 'go generate'; DO NOT EDIT.
82+
MessageIdTypedef=DWORD
83+
84+
LanguageNames=(English=0x409:MSG00409)
85+
8286
;//************** Event categories ************
8387
{{- range $i, $cat := .Categories }}
8488
MessageId={{ add1 $i }}

0 commit comments

Comments
 (0)