-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Implement security channel message parsing
- Loading branch information
1 parent
1db5ac4
commit 7871461
Showing
68 changed files
with
983 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
package windows | ||
|
||
import ( | ||
"strings" | ||
) | ||
|
||
func parseSecurity(message string) (string, map[string]interface{}) { | ||
|
||
subject, details := message, map[string]interface{}{} | ||
|
||
mp := newMessageProcessor(message) | ||
|
||
// First line is expected to be the first return value | ||
l := mp.next() | ||
switch l.t { | ||
case valueType: | ||
subject = l.v | ||
case keyType: | ||
subject = l.k | ||
default: | ||
return message, nil | ||
} | ||
|
||
moreInfo := []string{} | ||
|
||
for mp.hasNext() { | ||
l = mp.next() | ||
switch l.t { | ||
case valueType: | ||
moreInfo = append(moreInfo, l.v) | ||
case keyType: | ||
if !mp.hasNextIndented(l.i + 1) { | ||
// standalone key/value pair with empty value | ||
details[l.k] = "-" | ||
continue | ||
} | ||
details[l.k] = mp.consumeSubsection(l.i + 1) | ||
case pairType: | ||
if !mp.hasNextIndented(l.i + 1) { | ||
// standalone key/value pair | ||
details[l.k] = l.v | ||
continue | ||
} | ||
// value was first in a list | ||
details[l.k] = append([]string{l.v}, mp.consumeSublist(l.i+1)...) | ||
} | ||
} | ||
|
||
if len(moreInfo) > 0 { | ||
details["Additional Context"] = moreInfo | ||
} | ||
|
||
return subject, details | ||
} | ||
|
||
func (mp *messageProcessor) consumeSubsection(depth int) map[string]interface{} { | ||
sub := map[string]interface{}{} | ||
for mp.hasNext() { | ||
l := mp.next() | ||
switch l.t { | ||
case emptyType: | ||
return sub | ||
case pairType: | ||
sub[l.k] = l.v | ||
case keyType: | ||
if !mp.hasNextIndented(depth + 1) { | ||
// standalone key/value pair with missing value | ||
sub[l.k] = "-" | ||
continue | ||
} | ||
sub[l.k] = mp.consumeSublist(depth + 1) | ||
} | ||
} | ||
return sub | ||
} | ||
|
||
func (mp *messageProcessor) consumeSublist(depth int) []string { | ||
sublist := []string{} | ||
for mp.hasNext() { | ||
if !mp.hasNextIndented(depth) { | ||
return sublist | ||
} | ||
l := mp.next() | ||
switch l.t { | ||
case valueType: | ||
sublist = append(sublist, l.v) | ||
case keyType: // not expected, but handle | ||
sublist = append(sublist, l.k) | ||
} | ||
} | ||
return sublist | ||
} | ||
|
||
type messageProcessor struct { | ||
lines []*parsedLine | ||
ptr int | ||
} | ||
|
||
type parsedLine struct { | ||
t lineType | ||
i int | ||
k string | ||
v string | ||
} | ||
|
||
type lineType int | ||
|
||
const ( | ||
emptyType lineType = iota | ||
keyType | ||
valueType | ||
pairType | ||
) | ||
|
||
func newMessageProcessor(message string) *messageProcessor { | ||
unparsedLines := strings.Split(strings.TrimSpace(message), "\n") | ||
parsedLines := make([]*parsedLine, len(unparsedLines)) | ||
for i, unparsedLine := range unparsedLines { | ||
parsedLines[i] = parse(unparsedLine) | ||
} | ||
return &messageProcessor{lines: parsedLines} | ||
} | ||
|
||
func parse(line string) *parsedLine { | ||
i := countIndent(line) | ||
l := strings.TrimSpace(line) | ||
if l == "" { | ||
return &parsedLine{t: emptyType, i: i} | ||
} | ||
|
||
if strings.Contains(l, ":\t") { | ||
k, v := parseKeyValue(l) | ||
return &parsedLine{t: pairType, i: i, k: k, v: v} | ||
} | ||
|
||
if strings.HasSuffix(l, ":") { | ||
return &parsedLine{t: keyType, i: i, k: l[:len(l)-1]} | ||
} | ||
|
||
return &parsedLine{t: valueType, i: i, v: l} | ||
} | ||
|
||
// return next line and increment position | ||
func (mp *messageProcessor) next() *parsedLine { | ||
defer mp.step() | ||
return mp.lines[mp.ptr] | ||
} | ||
|
||
// return next line but do not increment position | ||
func (mp *messageProcessor) peek() *parsedLine { | ||
return mp.lines[mp.ptr] | ||
} | ||
|
||
// just increment position | ||
func (mp *messageProcessor) step() { | ||
mp.ptr++ | ||
} | ||
|
||
func (mp *messageProcessor) hasNext() bool { | ||
return mp.ptr < len(mp.lines) | ||
} | ||
|
||
func (mp *messageProcessor) hasNextIndented(minDepth int) bool { | ||
if !mp.hasNext() || mp.ptr == 0 { | ||
return false | ||
} | ||
|
||
l := mp.peek() | ||
if l.t == emptyType { | ||
return false | ||
} | ||
|
||
return l.i >= minDepth | ||
} | ||
|
||
func countIndent(line string) int { | ||
i := 1 | ||
for pre := strings.Repeat("\t", i); strings.HasPrefix(line, pre); pre = strings.Repeat("\t", i) { | ||
i++ | ||
} | ||
return i - 1 | ||
} | ||
|
||
func parseKeyValue(line string) (string, string) { | ||
kv := strings.SplitN(line, ":\t", 2) | ||
return strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package windows | ||
|
||
import ( | ||
"encoding/json" | ||
"io/ioutil" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestParseSecurity(t *testing.T) { | ||
|
||
testCases := []string{ | ||
"account_name_changed", | ||
"audit_settings_changed", | ||
"audit_success", | ||
"credential_validate_attempt", | ||
"domain_policy_changed", | ||
"driver_started", | ||
"event_processing", | ||
"local_group_changed", | ||
"logon", | ||
"object_added", | ||
"per_user_audit_policy_table_created", | ||
"query_blank_password", | ||
"service_shutdown", | ||
"service_started", | ||
"special_logon", | ||
"time_change", | ||
"user_account_changed", | ||
"user_account_created", | ||
"user_account_enabled", | ||
"user_added_to_global_group", | ||
"user_password_reset_attempt", | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc, func(t *testing.T) { | ||
|
||
testDir := filepath.Join("testdata", "security", tc) | ||
messageBytes, err := ioutil.ReadFile(filepath.Join(testDir, "message.in")) | ||
require.NoError(t, err, "problem reading input file") | ||
|
||
message, details := parseSecurity(string(messageBytes)) | ||
|
||
// initTestResult(testDir, message, details) | ||
|
||
expectedMessageBytes, err := ioutil.ReadFile(filepath.Join(testDir, "message.out")) | ||
require.NoError(t, err, "problem reading expected message") | ||
expectedMessage := string(expectedMessageBytes) | ||
|
||
expectedDetailsBytes, err := ioutil.ReadFile(filepath.Join(testDir, "details.out")) | ||
require.NoError(t, err, "problem reading expected details") | ||
|
||
// This is a little silly, but if we rely on unmarshaling | ||
// then []string gets converted to []interface{} and the comparison fails | ||
detailBytes, err := json.Marshal(details) | ||
require.NoError(t, err, "problem processing details result") | ||
|
||
require.Equal(t, expectedMessage, message) | ||
require.JSONEq(t, string(expectedDetailsBytes), string(detailBytes)) | ||
}) | ||
} | ||
} | ||
|
||
// Use this to initialize test results from a WEL security message | ||
// make sure to validate manually! | ||
func initTestResult(testDir, message string, details map[string]interface{}) { | ||
ioutil.WriteFile(filepath.Join(testDir, "message.out"), []byte(message), 0644) | ||
bytes, _ := json.MarshalIndent(details, "", " ") | ||
ioutil.WriteFile(filepath.Join(testDir, "details.out"), bytes, 0644) | ||
} |
17 changes: 17 additions & 0 deletions
17
operator/builtin/input/windows/testdata/security/account_name_changed/details.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"Additional Information": { | ||
"Privileges": "-" | ||
}, | ||
"Subject": { | ||
"Account Domain": "WORKGROUP", | ||
"Account Name": "WIN-322E2C550UP$", | ||
"Logon ID": "0x3E7", | ||
"Security ID": "SYSTEM" | ||
}, | ||
"Target Account": { | ||
"Account Domain": "Builtin", | ||
"New Account Name": "Power Users", | ||
"Old Account Name": "Power Users", | ||
"Security ID": "BUILTIN\\Power Users" | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
operator/builtin/input/windows/testdata/security/account_name_changed/message.in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
The name of an account was changed: | ||
|
||
Subject: | ||
Security ID: SYSTEM | ||
Account Name: WIN-322E2C550UP$ | ||
Account Domain: WORKGROUP | ||
Logon ID: 0x3E7 | ||
|
||
Target Account: | ||
Security ID: BUILTIN\Power Users | ||
Account Domain: Builtin | ||
Old Account Name: Power Users | ||
New Account Name: Power Users | ||
|
||
Additional Information: | ||
Privileges: - |
1 change: 1 addition & 0 deletions
1
operator/builtin/input/windows/testdata/security/account_name_changed/message.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
The name of an account was changed |
22 changes: 22 additions & 0 deletions
22
operator/builtin/input/windows/testdata/security/audit_settings_changed/details.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"Auditing Settings": { | ||
"New Security Descriptor": "S:ARAI(AU;SAFA;DCLCRPCRSDWDWO;;;WD)", | ||
"Original Security Descriptor": "-" | ||
}, | ||
"Object": { | ||
"Handle ID": "0x72c", | ||
"Object Name": "C:\\Windows\\Temp\\winre\\ExtractedFromWim", | ||
"Object Server": "Security", | ||
"Object Type": "File" | ||
}, | ||
"Process Information": { | ||
"Process ID": "0x2ec", | ||
"Process Name": "C:\\Windows\\System32\\oobe\\Setup.exe" | ||
}, | ||
"Subject": { | ||
"Account Domain": "WORKGROUP", | ||
"Account Name": "WIN-PS00R22J635$", | ||
"Logon ID": "0x3E7", | ||
"Security ID": "SYSTEM" | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
operator/builtin/input/windows/testdata/security/audit_settings_changed/message.in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
Auditing settings on object were changed. | ||
|
||
Subject: | ||
Security ID: SYSTEM | ||
Account Name: WIN-PS00R22J635$ | ||
Account Domain: WORKGROUP | ||
Logon ID: 0x3E7 | ||
|
||
Object: | ||
Object Server: Security | ||
Object Type: File | ||
Object Name: C:\Windows\Temp\winre\ExtractedFromWim | ||
Handle ID: 0x72c | ||
|
||
Process Information: | ||
Process ID: 0x2ec | ||
Process Name: C:\Windows\System32\oobe\Setup.exe | ||
|
||
Auditing Settings: | ||
Original Security Descriptor: | ||
New Security Descriptor: S:ARAI(AU;SAFA;DCLCRPCRSDWDWO;;;WD) |
1 change: 1 addition & 0 deletions
1
operator/builtin/input/windows/testdata/security/audit_settings_changed/message.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Auditing settings on object were changed. |
5 changes: 5 additions & 0 deletions
5
operator/builtin/input/windows/testdata/security/audit_success/details.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"Additional Context": [ | ||
"This event is logged when LSASS.EXE starts and the auditing subsystem is initialized." | ||
] | ||
} |
3 changes: 3 additions & 0 deletions
3
operator/builtin/input/windows/testdata/security/audit_success/message.in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Windows is starting up. | ||
|
||
This event is logged when LSASS.EXE starts and the auditing subsystem is initialized. |
1 change: 1 addition & 0 deletions
1
operator/builtin/input/windows/testdata/security/audit_success/message.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Windows is starting up. |
6 changes: 6 additions & 0 deletions
6
operator/builtin/input/windows/testdata/security/credential_validate_attempt/details.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"Authentication Package": "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0", | ||
"Error Code": "0x0", | ||
"Logon Account": "Someone", | ||
"Source Workstation": "WIN-322E2C550UP" | ||
} |
6 changes: 6 additions & 0 deletions
6
operator/builtin/input/windows/testdata/security/credential_validate_attempt/message.in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
The computer attempted to validate the credentials for an account. | ||
|
||
Authentication Package: MICROSOFT_AUTHENTICATION_PACKAGE_V1_0 | ||
Logon Account: Someone | ||
Source Workstation: WIN-322E2C550UP | ||
Error Code: 0x0 |
1 change: 1 addition & 0 deletions
1
operator/builtin/input/windows/testdata/security/credential_validate_attempt/message.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
The computer attempted to validate the credentials for an account. |
Oops, something went wrong.