Skip to content
This repository has been archived by the owner on May 25, 2022. It is now read-only.

Commit

Permalink
Windows input fix (#478)
Browse files Browse the repository at this point in the history
* initial commit

* added separate fields for RenderingInfo and EventData

* changed xml.go to only populate output with necessary fields
  • Loading branch information
armstrmi authored May 4, 2022
1 parent b6b247e commit c912ec5
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 37 deletions.
2 changes: 1 addition & 1 deletion operator/input/windows/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func (e *EventLogInput) sendEvent(ctx context.Context, eventXML EventXML) {
}

entry.Timestamp = eventXML.parseTimestamp()
entry.Severity = eventXML.parseSeverity()
entry.Severity = eventXML.parseRenderedSeverity()
e.Write(ctx, entry)
}

Expand Down
22 changes: 22 additions & 0 deletions operator/input/windows/testdata/xmlSample.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Security-SPP" Guid="{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}" EventSourceName="Software Protection Platform Service" />
<EventID Qualifiers="16384">16384</EventID>
<Version>0</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2022-04-22T10:20:52.3778625Z" />
<EventRecordID>23401</EventRecordID>
<Correlation />
<Execution ProcessID="0" ThreadID="0" />
<Channel>Application</Channel>
<Computer>computer</Computer>
<Security />
</System>
<EventData>
<Data>2022-04-28T19:48:52Z</Data>
<Data>RulesEngine</Data>
</EventData>
</Event>
82 changes: 64 additions & 18 deletions operator/input/windows/xml.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build windows
// +build windows

package windows
Expand All @@ -26,17 +27,22 @@ import (

// EventXML is the rendered xml of an event.
type EventXML struct {
EventID EventID `xml:"System>EventID"`
Provider Provider `xml:"System>Provider"`
Computer string `xml:"System>Computer"`
Channel string `xml:"System>Channel"`
RecordID uint64 `xml:"System>EventRecordID"`
TimeCreated TimeCreated `xml:"System>TimeCreated"`
Message string `xml:"RenderingInfo>Message"`
Level string `xml:"RenderingInfo>Level"`
Task string `xml:"RenderingInfo>Task"`
Opcode string `xml:"RenderingInfo>Opcode"`
Keywords []string `xml:"RenderingInfo>Keywords>Keyword"`
EventID EventID `xml:"System>EventID"`
Provider Provider `xml:"System>Provider"`
Computer string `xml:"System>Computer"`
Channel string `xml:"System>Channel"`
RecordID uint64 `xml:"System>EventRecordID"`
TimeCreated TimeCreated `xml:"System>TimeCreated"`
Message string `xml:"RenderingInfo>Message"`
RenderedLevel string `xml:"RenderingInfo>Level"`
Level string `xml:"System>Level"`
RenderedTask string `xml:"RenderingInfo>Task"`
Task string `xml:"System>Task"`
RenderedOpcode string `xml:"RenderingInfo>Opcode"`
Opcode string `xml:"System>Opcode"`
RenderedKeywords []string `xml:"RenderingInfo>Keywords>Keyword"`
Keywords []string `xml:"System>Keywords"`
EventData []string `xml:"EventData>Data"`
}

// parseTimestamp will parse the timestamp of the event.
Expand All @@ -47,9 +53,11 @@ func (e *EventXML) parseTimestamp() time.Time {
return time.Now()
}

// parseSeverity will parse the severity of the event.
func (e *EventXML) parseSeverity() entry.Severity {
switch e.Level {
// parseRenderedSeverity will parse the severity of the event.
func (e *EventXML) parseRenderedSeverity() entry.Severity {
switch e.RenderedLevel {
case "":
return e.parseSeverity()
case "Critical":
return entry.Fatal
case "Error":
Expand All @@ -63,9 +71,46 @@ func (e *EventXML) parseSeverity() entry.Severity {
}
}

// parseSeverity will parse the severity of the event when RenderingInfo is not populated
func (e *EventXML) parseSeverity() entry.Severity {
switch e.Level {
case "1":
return entry.Fatal
case "2":
return entry.Error
case "3":
return entry.Warn
case "4":
return entry.Info
default:
return entry.Default
}
}

// parseBody will parse a body from the event.
func (e *EventXML) parseBody() map[string]interface{} {
message, details := e.parseMessage()

level := e.RenderedLevel
if level == "" {
level = e.Level
}

task := e.RenderedTask
if task == "" {
task = e.Task
}

opcode := e.RenderedOpcode
if opcode == "" {
opcode = e.Opcode
}

keywords := e.RenderedKeywords
if keywords == nil {
keywords = e.Keywords
}

body := map[string]interface{}{
"event_id": map[string]interface{}{
"qualifiers": e.EventID.Qualifiers,
Expand All @@ -80,11 +125,12 @@ func (e *EventXML) parseBody() map[string]interface{} {
"computer": e.Computer,
"channel": e.Channel,
"record_id": e.RecordID,
"level": e.Level,
"level": level,
"message": message,
"task": e.Task,
"opcode": e.Opcode,
"keywords": e.Keywords,
"task": task,
"opcode": opcode,
"keywords": keywords,
"event_data": e.EventData,
}
if len(details) > 0 {
body["details"] = details
Expand Down
198 changes: 180 additions & 18 deletions operator/input/windows/xml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build windows
// +build windows

package windows

import (
"io/ioutil"
"path/filepath"
"testing"
"time"

Expand Down Expand Up @@ -49,16 +52,26 @@ func TestParseInvalidTimestamp(t *testing.T) {
}

func TestParseSeverity(t *testing.T) {
xmlCritical := EventXML{Level: "Critical"}
xmlError := EventXML{Level: "Error"}
xmlWarning := EventXML{Level: "Warning"}
xmlInformation := EventXML{Level: "Information"}
xmlUnknown := EventXML{Level: "Unknown"}
require.Equal(t, entry.Fatal, xmlCritical.parseSeverity())
require.Equal(t, entry.Error, xmlError.parseSeverity())
require.Equal(t, entry.Warn, xmlWarning.parseSeverity())
require.Equal(t, entry.Info, xmlInformation.parseSeverity())
require.Equal(t, entry.Default, xmlUnknown.parseSeverity())
xmlRenderedCritical := EventXML{RenderedLevel: "Critical"}
xmlRenderedError := EventXML{RenderedLevel: "Error"}
xmlRenderedWarning := EventXML{RenderedLevel: "Warning"}
xmlRenderedInformation := EventXML{RenderedLevel: "Information"}
xmlRenderedUnknown := EventXML{RenderedLevel: "Unknown"}
xmlCritical := EventXML{Level: "1"}
xmlError := EventXML{Level: "2"}
xmlWarning := EventXML{Level: "3"}
xmlInformation := EventXML{Level: "4"}
xmlUnknown := EventXML{Level: "0"}
require.Equal(t, entry.Fatal, xmlRenderedCritical.parseRenderedSeverity())
require.Equal(t, entry.Error, xmlRenderedError.parseRenderedSeverity())
require.Equal(t, entry.Warn, xmlRenderedWarning.parseRenderedSeverity())
require.Equal(t, entry.Info, xmlRenderedInformation.parseRenderedSeverity())
require.Equal(t, entry.Default, xmlRenderedUnknown.parseRenderedSeverity())
require.Equal(t, entry.Fatal, xmlCritical.parseRenderedSeverity())
require.Equal(t, entry.Error, xmlError.parseRenderedSeverity())
require.Equal(t, entry.Warn, xmlWarning.parseRenderedSeverity())
require.Equal(t, entry.Info, xmlInformation.parseRenderedSeverity())
require.Equal(t, entry.Default, xmlUnknown.parseRenderedSeverity())
}

func TestParseBody(t *testing.T) {
Expand All @@ -75,14 +88,69 @@ func TestParseBody(t *testing.T) {
TimeCreated: TimeCreated{
SystemTime: "2020-07-30T01:01:01.123456789Z",
},
Computer: "computer",
Channel: "application",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
Computer: "computer",
Channel: "application",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []string{"this", "is", "some", "sample", "data"},
RenderedLevel: "rendered_level",
RenderedTask: "rendered_task",
RenderedOpcode: "rendered_opcode",
RenderedKeywords: []string{"RenderedKeywords"},
}

expected := map[string]interface{}{
"event_id": map[string]interface{}{
"id": uint32(1),
"qualifiers": uint16(2),
},
"provider": map[string]interface{}{
"name": "provider",
"guid": "guid",
"event_source": "event source",
},
"system_time": "2020-07-30T01:01:01.123456789Z",
"computer": "computer",
"channel": "application",
"record_id": uint64(1),
"level": "rendered_level",
"message": "message",
"task": "rendered_task",
"opcode": "rendered_opcode",
"keywords": []string{"RenderedKeywords"},
"event_data": []string{"this", "is", "some", "sample", "data"},
}

require.Equal(t, expected, xml.parseBody())
}

func TestParseNoRendered(t *testing.T) {
xml := EventXML{
EventID: EventID{
ID: 1,
Qualifiers: 2,
},
Provider: Provider{
Name: "provider",
GUID: "guid",
EventSourceName: "event source",
},
TimeCreated: TimeCreated{
SystemTime: "2020-07-30T01:01:01.123456789Z",
},
Computer: "computer",
Channel: "application",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []string{"this", "is", "some", "sample", "data"},
}

expected := map[string]interface{}{
Expand All @@ -104,7 +172,101 @@ func TestParseBody(t *testing.T) {
"task": "task",
"opcode": "opcode",
"keywords": []string{"keyword"},
"event_data": []string{"this", "is", "some", "sample", "data"},
}

require.Equal(t, expected, xml.parseBody())
}

func TestParseBodySecurity(t *testing.T) {
xml := EventXML{
EventID: EventID{
ID: 1,
Qualifiers: 2,
},
Provider: Provider{
Name: "provider",
GUID: "guid",
EventSourceName: "event source",
},
TimeCreated: TimeCreated{
SystemTime: "2020-07-30T01:01:01.123456789Z",
},
Computer: "computer",
Channel: "Security",
RecordID: 1,
Level: "Information",
Message: "message",
Task: "task",
Opcode: "opcode",
Keywords: []string{"keyword"},
EventData: []string{"this", "is", "some", "sample", "data"},
RenderedLevel: "rendered_level",
RenderedTask: "rendered_task",
RenderedOpcode: "rendered_opcode",
RenderedKeywords: []string{"RenderedKeywords"},
}

expected := map[string]interface{}{
"event_id": map[string]interface{}{
"id": uint32(1),
"qualifiers": uint16(2),
},
"provider": map[string]interface{}{
"name": "provider",
"guid": "guid",
"event_source": "event source",
},
"system_time": "2020-07-30T01:01:01.123456789Z",
"computer": "computer",
"channel": "Security",
"record_id": uint64(1),
"level": "rendered_level",
"message": "message",
"task": "rendered_task",
"opcode": "rendered_opcode",
"keywords": []string{"RenderedKeywords"},
"event_data": []string{"this", "is", "some", "sample", "data"},
}

require.Equal(t, expected, xml.parseBody())
}

func TestInvalidUnmarshal(t *testing.T) {
_, err := unmarshalEventXML([]byte("Test \n Invalid \t Unmarshal"))
require.Error(t, err)

}
func TestUnmarshal(t *testing.T) {
data, err := ioutil.ReadFile(filepath.Join("testdata", "xmlSample.xml"))
require.NoError(t, err)

event, err := unmarshalEventXML(data)
require.NoError(t, err)

xml := EventXML{
EventID: EventID{
ID: 16384,
Qualifiers: 16384,
},
Provider: Provider{
Name: "Microsoft-Windows-Security-SPP",
GUID: "{E23B33B0-C8C9-472C-A5F9-F2BDFEA0F156}",
EventSourceName: "Software Protection Platform Service",
},
TimeCreated: TimeCreated{
SystemTime: "2022-04-22T10:20:52.3778625Z",
},
Computer: "computer",
Channel: "Application",
RecordID: 23401,
Level: "4",
Message: "",
Task: "0",
Opcode: "0",
EventData: []string{"2022-04-28T19:48:52Z", "RulesEngine"},
Keywords: []string{"0x80000000000000"},
}

require.Equal(t, xml, event)
}

0 comments on commit c912ec5

Please sign in to comment.