pkg/generator/winlog/winlog.go (146 lines of code) (raw):
// Package winlog generates Windows Event Log XML records.
//
// Configuration:
//
// event_id: (number, optional) If provided, generated events using this ID.
// Must be one of the registered event IDs. See 'eventRandomizers'
// for the list of valid IDs. If not provided, the generator will
// randomly select from the available list for each record.
//
// - generator:
// type: winlog
// event_id: 4768
package winlog
import (
"encoding/json"
"encoding/xml"
"fmt"
"math/rand"
"sort"
"time"
"github.com/elastic/go-ucfg"
"github.com/elastic/spigot/pkg/generator"
"github.com/elastic/spigot/pkg/output/winlog"
)
const Name = "winlog"
type randomizerFunc func(g *Generator) Event
var (
eventRandomizers = map[int]randomizerFunc{
event4624: randomize4624,
event4634: randomize4634,
event4723: randomize4723,
event4741: randomize4741,
event4743: randomize4743,
event4768: randomize4768,
}
eventIDs []int // Populated at runtime based on 'eventRandomizers' keys.
)
// Event holds the random fields for a Windows Event Log record.
type Event struct {
XMLName xml.Name `xml:"http://schemas.microsoft.com/win/2004/08/events/event Event"`
Provider Provider `xml:"System>Provider"`
EventID EventID `xml:"System>EventID"`
Version uint8 `xml:"System>Version"`
Level uint8 `xml:"System>Level"`
Task uint16 `xml:"System>Task"`
Opcode uint8 `xml:"System>Opcode"`
Keywords HexUint64 `xml:"System>Keywords"`
TimeCreated TimeCreated `xml:"System>TimeCreated"`
RecordID uint64 `xml:"System>EventRecordID"`
Correlation Correlation `xml:"System>Correlation"`
Execution Execution `xml:"System>Execution"`
Channel string `xml:"System>Channel"`
Computer string `xml:"System>Computer"`
Security Security `xml:"System>Security"`
EventData EventData `xml:"EventData"`
}
func (e *Event) AsTemplate() winlog.EventTemplate {
messages := make([]string, len(e.EventData.Data))
for i, data := range e.EventData.Data {
messages[i] = data.Value
}
return winlog.EventTemplate{
EventType: uint16(e.Level),
EventID: e.EventID.ID,
Messages: messages,
}
}
// Provider identifies the provider that logged the event.
type Provider struct {
Name string `xml:"Name,attr,omitempty"`
GUID string `xml:"GUID,attr,omitempty"`
EventSourceName string `xml:"EventSourceName,attr,omitempty"`
}
// EventID is the identifier that the provider uses to identify a
// specific event type.
type EventID struct {
Qualifiers uint16 `xml:"Qualifiers,attr,omitempty"`
ID uint32 `xml:",chardata"`
}
// HexUint64 is a uint64. When marshaled, it will be in hexadecimal format.
type HexUint64 uint64
func (v HexUint64) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
return enc.EncodeElement(fmt.Sprintf("%#x", v), start)
}
// TimeCreated contains the system time of when the event was logged.
type TimeCreated struct {
SystemTime time.Time `xml:"SystemTime,attr"`
}
// Correlation contains activity identifiers that consumers can use to group
// related events together.
type Correlation struct {
ActivityID string `xml:"ActivityID,attr,omitempty"`
RelatedActivityID string `xml:"RelatedActivityID,attr,omitempty"`
}
// Execution contains information about the process and thread that logged the event.
type Execution struct {
ProcessID uint32 `xml:"ProcessID,attr"`
ThreadID uint32 `xml:"ThreadID,attr"`
// Only available for events logged to an event tracing log file (.etl file).
ProcessorID uint32 `xml:"ProcessorID,attr,omitempty"`
SessionID uint32 `xml:"SessionID,attr,omitempty"`
KernelTime uint32 `xml:"KernelTime,attr,omitempty"`
UserTime uint32 `xml:"UserTime,attr,omitempty"`
ProcessorTime uint32 `xml:"ProcessorTime,attr,omitempty"`
}
// EventData contains the event data.
type EventData struct {
Data []KeyValue `xml:",any"`
}
// KeyValue is a key value pair of strings.
type KeyValue struct {
Key string `xml:"Name,attr"`
Value string `xml:",chardata"`
}
// Security represents the Windows Security Identifier for an account.
type Security struct {
UserID string `xml:"UserID,attr,omitempty"`
}
// Generator provides a Windows Event XML record generator.
type Generator struct {
Event Event
eventID *int
staticTime *time.Time
render func(Event) ([]byte, error)
}
// Next produces the next Windows Event XML record.
func (g *Generator) Next() ([]byte, error) {
var eventID int
if g.eventID != nil {
eventID = *g.eventID
} else {
eventID = eventIDs[rand.Intn(len(eventIDs))]
}
fn, ok := eventRandomizers[eventID]
if !ok {
return nil, fmt.Errorf("event ID %d is not registered with this generator", eventID)
}
g.Event = fn(g)
return g.render(g.Event)
}
func (g *Generator) getTime() time.Time {
if g.staticTime != nil {
return *g.staticTime
}
return time.Now()
}
// New is the factory for Windows Event XML objects.
func New(cfg *ucfg.Config) (generator.Generator, error) {
c := defaultConfig()
if err := cfg.Unpack(&c); err != nil {
return nil, err
}
g := Generator{}
if c.EventID > 0 {
g.eventID = &c.EventID
}
if c.AsTemplate {
g.render = func(e Event) ([]byte, error) {
return json.Marshal(e.AsTemplate())
}
} else {
g.render = func(e Event) ([]byte, error) {
return xml.MarshalIndent(&g.Event, "", " ")
}
}
return &g, nil
}
func init() {
for k := range eventRandomizers {
eventIDs = append(eventIDs, k)
}
sort.Ints(eventIDs)
_ = generator.Register(Name, New)
}