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

Windows input fix #478

Merged
merged 3 commits into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
51 changes: 31 additions & 20 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"`
Comment on lines +37 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the issue description, it sounds like we might expect only one or the other of these. Is that right? If so, should we parse both here and only set whichever one is populated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be correct, only one of these would be populated, that being said I'm sure that could be done to only populate one of the fields. But I do have a question about that, would this mean getting rid of the RenderedLevel field of the EventXML struct, or simply removing that field from the output?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect that it only requires a change to the body of the log that is emitted.

Copy link
Contributor

@BinaryFissionGames BinaryFissionGames May 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, both may be populated in the XML. The RenderingInfo tag contains the "friendly" versions of these fields, for instance, System>Level may be 4, but RenderingInfo>Level would be Informational. In this case, both would be present on the XML returned from windows.

Only populating one field might make sense for the sake of removing redundancy, but I just want to clarify.

RenderedTask string `xml:"RenderingInfo>Task"`
Task string `xml:"System>Task"`
RenderedOpcode string `xml:"RenderingInfo>Opcode"`
Opcode string `xml:"System>Opcode"`
armstrmi marked this conversation as resolved.
Show resolved Hide resolved
RenderedKeywords []string `xml:"RenderingInfo>Keywords>Keyword"`
Keywords []string `xml:"System>Keywords"`
armstrmi marked this conversation as resolved.
Show resolved Hide resolved
EventData []string `xml:"EventData>Data"`
}

// parseTimestamp will parse the timestamp of the event.
Expand Down Expand Up @@ -76,15 +82,20 @@ func (e *EventXML) parseBody() map[string]interface{} {
"guid": e.Provider.GUID,
"event_source": e.Provider.EventSourceName,
},
"system_time": e.TimeCreated.SystemTime,
"computer": e.Computer,
"channel": e.Channel,
"record_id": e.RecordID,
"level": e.Level,
"message": message,
"task": e.Task,
"opcode": e.Opcode,
"keywords": e.Keywords,
"system_time": e.TimeCreated.SystemTime,
"computer": e.Computer,
"channel": e.Channel,
"record_id": e.RecordID,
"level": e.Level,
"rendered_level": e.RenderedLevel,
"message": message,
"task": e.Task,
"rendered_task": e.RenderedTask,
"opcode": e.Opcode,
"rendered_opcode": e.RenderedOpcode,
"keywords": e.Keywords,
"rendered_keywords": e.RenderedKeywords,
"event_data": e.EventData,
}
if len(details) > 0 {
body["details"] = details
Expand Down
144 changes: 127 additions & 17 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 @@ -75,14 +78,19 @@ 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{}{
Expand All @@ -95,16 +103,118 @@ func TestParseBody(t *testing.T) {
"guid": "guid",
"event_source": "event source",
},
"system_time": "2020-07-30T01:01:01.123456789Z",
"computer": "computer",
"channel": "application",
"record_id": uint64(1),
"level": "Information",
"message": "message",
"task": "task",
"opcode": "opcode",
"keywords": []string{"keyword"},
"system_time": "2020-07-30T01:01:01.123456789Z",
"computer": "computer",
"channel": "application",
"record_id": uint64(1),
"level": "Information",
"message": "message",
"task": "task",
"opcode": "opcode",
"keywords": []string{"keyword"},
"rendered_level": "rendered_level",
"rendered_task": "rendered_task",
"rendered_opcode": "rendered_opcode",
"rendered_keywords": []string{"RenderedKeywords"},
"event_data": []string{"this", "is", "some", "sample", "data"},
}

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

func TestParseBody2(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": "Information",
"message": "message",
"task": "task",
"opcode": "opcode",
"keywords": []string{"keyword"},
"rendered_level": "rendered_level",
"rendered_task": "rendered_task",
"rendered_opcode": "rendered_opcode",
"rendered_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)
}