From 666ff1c30fe624e9fcd9a108b20fceb82331f5fa Mon Sep 17 00:00:00 2001 From: Andrew Kroh Date: Thu, 27 Apr 2017 16:29:17 -0400 Subject: [PATCH] Update aucoalesce to normalize events --- aucoalesce/coalesce.go | 497 +++++++++++- aucoalesce/coalesce_test.go | 143 +++- aucoalesce/event_type.go | 141 ++++ aucoalesce/id_lookup.go | 119 +++ aucoalesce/id_lookup_test.go | 32 + aucoalesce/mknormalize_data.go | 106 +++ aucoalesce/normalizations.yaml | 735 ++++++++++++++++++ aucoalesce/normalize.go | 115 +++ aucoalesce/normalize_test.go | 54 ++ aucoalesce/testdata/execve.log | 6 - aucoalesce/testdata/execve.log.golden | 72 -- .../testdata/random-internet.json.golden | 41 + aucoalesce/testdata/random-internet.yaml | 4 + .../testdata/rhel-7-linux-3.10.0.json.golden | 506 ++++++++++++ aucoalesce/testdata/rhel-7-linux-3.10.0.yaml | 40 + aucoalesce/testdata/sockaddr.log | 4 - aucoalesce/testdata/sockaddr.log.golden | 55 -- .../ubuntu-16.10-linux-4.8.0.json.golden | 609 +++++++++++++++ .../testdata/ubuntu-16.10-linux-4.8.0.yaml | 65 ++ .../ubuntu-17.04-linux-4.10.0.json.golden | 515 ++++++++++++ .../testdata/ubuntu-17.04-linux-4.10.0.yaml | 49 ++ aucoalesce/znormalize_data.go | 40 + 22 files changed, 3734 insertions(+), 214 deletions(-) create mode 100644 aucoalesce/event_type.go create mode 100644 aucoalesce/id_lookup.go create mode 100644 aucoalesce/id_lookup_test.go create mode 100644 aucoalesce/mknormalize_data.go create mode 100644 aucoalesce/normalizations.yaml create mode 100644 aucoalesce/normalize.go create mode 100644 aucoalesce/normalize_test.go delete mode 100644 aucoalesce/testdata/execve.log delete mode 100644 aucoalesce/testdata/execve.log.golden create mode 100644 aucoalesce/testdata/random-internet.json.golden create mode 100644 aucoalesce/testdata/random-internet.yaml create mode 100644 aucoalesce/testdata/rhel-7-linux-3.10.0.json.golden create mode 100644 aucoalesce/testdata/rhel-7-linux-3.10.0.yaml delete mode 100644 aucoalesce/testdata/sockaddr.log delete mode 100644 aucoalesce/testdata/sockaddr.log.golden create mode 100644 aucoalesce/testdata/ubuntu-16.10-linux-4.8.0.json.golden create mode 100644 aucoalesce/testdata/ubuntu-16.10-linux-4.8.0.yaml create mode 100644 aucoalesce/testdata/ubuntu-17.04-linux-4.10.0.json.golden create mode 100644 aucoalesce/testdata/ubuntu-17.04-linux-4.10.0.yaml create mode 100644 aucoalesce/znormalize_data.go diff --git a/aucoalesce/coalesce.go b/aucoalesce/coalesce.go index b71232c..dabf930 100644 --- a/aucoalesce/coalesce.go +++ b/aucoalesce/coalesce.go @@ -12,87 +12,498 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package aucoalesce provides functions to coalesce related audit messages into -// a single event. +// Package aucoalesce provides functions to coalesce compound audit messages +// into a single event and normalize all message types with some common fields. package aucoalesce import ( + "os" + "strconv" "strings" - - "github.com/pkg/errors" + "time" "github.com/elastic/go-libaudit/auparse" + "github.com/pkg/errors" ) +// modeBlockDevice is the file mode bit representing block devices. This OS +// package does not have a constant defined for this. +const modeBlockDevice = 060000 + +type Event struct { + Timestamp time.Time `json:"@timestamp" yaml:"timestamp"` + Sequence uint32 `json:"sequence" yaml:"sequence"` + Category AuditEventType `json:"category" yaml:"category"` + Type auparse.AuditMessageType `json:"record_type" yaml:"type"` + Result string `json:"result,omitempty" yaml"result,omitempty"` + Session string `json:"session" yaml:"session"` + Subject Subject `json:"actor" yaml:"actor"` + Action string `json:"action,omitempty" yaml:"action,omitempty"` + Object Object `json:"thing,omitempty" yaml:"thing,omitempty"` + How string `json:"how,omitempty" yaml:"how,omitempty"` + Key string `json:"key,omitempty" yaml:"key,omitempty"` + + Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"` + Paths []map[string]string `json:"paths,omitempty" yaml:"paths,omitempty"` + Socket map[string]string `json:"socket,omitempty" yaml:"socket,omitempty"` + + Warnings []error `json:"-" yaml:"-"` +} + +type Subject struct { + Primary string `json:"primary,omitempty" yaml:"primary,omitempty"` + Secondary string `json:"secondary,omitempty" yaml:"secondary,omitempty"` + Attributes map[string]string `json:"attrs,omitempty" yaml:"attrs,omitempty"` // Other identifying data like euid, suid, fsuid, gid, egid, sgid, fsgid. + SELinux map[string]string `json:"selinux,omitempty" yaml:"selinux,omitempty"` // SELinux labels. +} + +type Object struct { + Primary string `json:"primary,omitempty" yaml:"primary,omitempty"` + Secondary string `json:"secondary,omitempty" yaml:"secondary,omitempty"` + What string `json:"what,omitempty" yaml:"what,omitempty"` + SELinux map[string]string `json:"selinux,omitempty" yaml:"selinux,omitempty"` +} + // CoalesceMessages combines the given messages into a single event. It assumes // that all the messages in the slice have the same timestamp and sequence -// number. An error is returned is msgs is empty or nil. -func CoalesceMessages(msgs []*auparse.AuditMessage) (map[string]interface{}, error) { - if len(msgs) == 0 { +// number. An error is returned is msgs is empty or nil or only contains and EOE +// (end-of-event) message. +func CoalesceMessages(msgs []*auparse.AuditMessage) (*Event, error) { + msgs = filterEOE(msgs) + + var event *Event + var err error + switch len(msgs) { + case 0: return nil, errors.New("messages is empty") + case 1: + event, err = normalizeSimple(msgs[0]) + default: + event, err = normalizeCompound(msgs) } - event := map[string]interface{}{ - "@timestamp": msgs[0].Timestamp, - "sequence": msgs[0].Sequence, + if event != nil { + applyNormalization(event) } + return event, err +} - for _, msg := range msgs { - data, _ := msg.Data() - if len(data) == 0 { +// filterEOE returns a slice (backed by the given msgs slice) that does not +// contain EOE (end-of-event) messages. EOE messages are sentinel messages used +// to signal the completion of an event, but they carry no data. +func filterEOE(msgs []*auparse.AuditMessage) []*auparse.AuditMessage { + if len(msgs) > 0 && msgs[len(msgs)-1].RecordType == auparse.AUDIT_EOE { + return msgs[:len(msgs)-1] + } + return msgs +} + +func normalizeSimple(msg *auparse.AuditMessage) (*Event, error) { + return newEvent(msg, nil), nil +} + +func normalizeCompound(msgs []*auparse.AuditMessage) (*Event, error) { + var special, syscall *auparse.AuditMessage + for i, msg := range msgs { + if i == 0 && msg.RecordType != auparse.AUDIT_SYSCALL { + special = msg continue } + if msg.RecordType == auparse.AUDIT_SYSCALL { + syscall = msg + break + } + } + if syscall == nil { + // All compound records have syscall messages. + return nil, errors.New("missing syscall message in compound event") + } + + event := newEvent(special, syscall) + for _, msg := range msgs { switch msg.RecordType { - default: - addRecord(msg, event) + case auparse.AUDIT_SYSCALL: + delete(event.Data, "items") case auparse.AUDIT_PATH: addPathRecord(msg, event) - case auparse.AUDIT_CWD: - addCWDRecord(msg, event) - case auparse.AUDIT_SYSCALL: - rename("syscall", "name", data) - delete(data, "items") - addRecord(msg, event) - case auparse.AUDIT_EOE: - // EOE (end-of-event) is just an empty sentinel message. + case auparse.AUDIT_SOCKADDR: + data, _ := msg.Data() + event.Socket = data + default: + addFieldsToEventData(msg, event) } } return event, nil } -func addRecord(msg *auparse.AuditMessage, event map[string]interface{}) { - recordType := strings.ToLower(msg.RecordType.String()) - data, _ := msg.Data() - event[recordType] = data +func newEvent(msg *auparse.AuditMessage, syscall *auparse.AuditMessage) *Event { + if msg == nil { + msg = syscall + } + event := &Event{ + Timestamp: msg.Timestamp, + Sequence: msg.Sequence, + Category: GetAuditEventType(msg.RecordType), + Type: msg.RecordType, + Data: make(map[string]string, 10), + } + + if syscall != nil { + msg = syscall + } + + data, err := msg.Data() + if err != nil { + event.Warnings = append(event.Warnings, err) + return event + } + + if result, found := data["result"]; found { + event.Result = result + delete(data, "result") + } else { + event.Result = "unknown" + } + + if ses, found := data["ses"]; found { + event.Session = ses + delete(data, "ses") + } + + if auid, found := data["auid"]; found { + event.Subject.Primary = auid + } + + if uid, found := data["uid"]; found { + event.Subject.Secondary = uid + } + + if key, found := data["key"]; found { + event.Key = key + delete(data, "key") + } + + for k, v := range data { + if strings.HasSuffix(k, "uid") || strings.HasSuffix(k, "gid") { + addSubjectAttribute(k, v, event) + } else if strings.HasPrefix(k, "subj_") { + addSubjectSELinuxLabel(k[5:], v, event) + } else { + event.Data[k] = v + } + } + + return event +} + +func addSubjectAttribute(key, value string, event *Event) { + if event.Subject.Attributes == nil { + event.Subject.Attributes = map[string]string{} + } + + event.Subject.Attributes[key] = value } -func addPathRecord(msg *auparse.AuditMessage, event map[string]interface{}) { - paths, ok := event["path"].([]map[string]string) - if !ok { - paths = make([]map[string]string, 0, 1) +func addSubjectSELinuxLabel(key, value string, event *Event) { + if event.Subject.SELinux == nil { + event.Subject.SELinux = map[string]string{} } - data, _ := msg.Data() - paths = append(paths, data) - event["path"] = paths + event.Subject.SELinux[key] = value } -func addCWDRecord(msg *auparse.AuditMessage, event map[string]interface{}) { - data, _ := msg.Data() - cwd, found := data["cwd"] - if !found { +func addObjectSELinuxLabel(key, value string, event *Event) { + if event.Object.SELinux == nil { + event.Object.SELinux = map[string]string{} + } + + event.Object.SELinux[key] = value +} + +func addPathRecord(path *auparse.AuditMessage, event *Event) { + data, err := path.Data() + if err != nil { + event.Warnings = append(event.Warnings, errors.Wrap(err, + "failed to parse PATH message")) return } - event["cwd"] = cwd + event.Paths = append(event.Paths, data) +} + +func addFieldsToEventData(msg *auparse.AuditMessage, event *Event) { + data, err := msg.Data() + if err != nil { + event.Warnings = append(event.Warnings, + errors.Wrap(err, "failed to parse message")) + return + } + + for k, v := range data { + if _, found := event.Data[k]; found { + event.Warnings = append(event.Warnings, errors.Errorf( + "duplicate key (%v) from %v message", k, msg.RecordType)) + continue + } + event.Data[k] = v + } +} + +func applyNormalization(event *Event) { + setHowDefaults(event) + + var norm *Normalization + if event.Type == auparse.AUDIT_SYSCALL { + syscall := event.Data["syscall"] + norm = syscallNorms[syscall] + } else { + norm = recordTypeNorms[event.Type.String()] + } + if norm == nil { + event.Warnings = append(event.Warnings, errors.New("no normalization found for event")) + return + } + + event.Action = norm.Action + + switch norm.Object.What { + case "file", "filesystem": + event.Object.What = norm.Object.What + setFileObject(event, norm.Object.PathIndex) + case "socket": + event.Object.What = norm.Object.What + setSocketObject(event) + default: + event.Object.What = norm.Object.What + } + + if len(norm.Subject.PrimaryFieldName.Values) > 0 { + var err error + for _, subjKey := range norm.Subject.PrimaryFieldName.Values { + if err = setSubjectPrimary(subjKey, event); err == nil { + break + } + } + if err != nil { + event.Warnings = append(event.Warnings, errors.Errorf("failed to set subject primary using keys=%v because they were not found", norm.Subject.PrimaryFieldName.Values)) + } + } + + if len(norm.Subject.SecondaryFieldName.Values) > 0 { + var err error + for _, subjKey := range norm.Subject.SecondaryFieldName.Values { + if err = setSubjectSecondary(subjKey, event); err == nil { + break + } + } + if err != nil { + event.Warnings = append(event.Warnings, errors.Errorf("failed to set subject secondary using keys=%v because they were not found", norm.Subject.SecondaryFieldName.Values)) + } + } + + if len(norm.Object.PrimaryFieldName.Values) > 0 { + var err error + for _, objKey := range norm.Object.PrimaryFieldName.Values { + if err = setObjectPrimary(objKey, event); err == nil { + break + } + } + if err != nil { + event.Warnings = append(event.Warnings, errors.Errorf("failed to set object primary using keys=%v because they were not found", norm.Object.PrimaryFieldName.Values)) + } + } + + if len(norm.Object.SecondaryFieldName.Values) > 0 { + var err error + for _, objKey := range norm.Object.SecondaryFieldName.Values { + if err = setObjectSecondary(objKey, event); err == nil { + break + } + } + if err != nil { + event.Warnings = append(event.Warnings, errors.Errorf("failed to set object secondary using keys=%v because they were not found", norm.Object.SecondaryFieldName.Values)) + } + } + + if len(norm.How.Values) > 0 { + var err error + for _, howKey := range norm.How.Values { + if err = setHow(howKey, event); err == nil { + break + } + } + if err != nil { + event.Warnings = append(event.Warnings, errors.Errorf("failed to set how using keys=%v because they were not found", norm.How.Values)) + } + } +} + +func getValue(key string, event *Event) (string, bool) { + value, found := event.Data[key] + if !found { + value, found = event.Subject.Attributes[key] + } + return value, found +} + +func setHow(key string, event *Event) error { + value, found := getValue(key, event) + if !found { + return errors.Errorf("failed to set how value: key '%v' not found", key) + } + + event.How = value + return nil +} + +func setSubjectPrimary(key string, event *Event) error { + value, found := getValue(key, event) + if !found { + return errors.Errorf("failed to set subject primary value: key '%v' not found", key) + } + + event.Subject.Primary = value + return nil +} + +func setSubjectSecondary(key string, event *Event) error { + value, found := getValue(key, event) + if !found { + return errors.Errorf("failed to set subject secondary value: key '%v' not found", key) + } + + event.Subject.Secondary = value + return nil +} + +func setObjectPrimary(key string, event *Event) error { + value, found := getValue(key, event) + if !found { + return errors.Errorf("failed to set object primary value: key '%v' not found", key) + } + + event.Object.Primary = value + return nil +} + +func setObjectSecondary(key string, event *Event) error { + value, found := getValue(key, event) + if !found { + return errors.Errorf("failed to set object secondary value: key '%v' not found", key) + } + + event.Object.Secondary = value + return nil } -func rename(old, new string, event map[string]string) { - value, found := event[old] +func setFileObject(event *Event, pathIndexHint int) error { + if len(event.Paths) == 0 { + return errors.New("path message not found") + } + + var pathIndex int + if len(event.Paths) > pathIndexHint { + pathIndex = pathIndexHint + } + + path := event.Paths[pathIndex] + for _, p := range event.Paths[pathIndex:] { + // Skip over PARENT and UNKNOWN types in case the path index was wrong. + if nametype := p["nametype"]; nametype != "PARENT" && nametype != "UNKNOWN" { + path = p + break + } + } + + value, found := path["name"] + if found { + event.Object.Primary = value + } + + value, found = path["inode"] if found { - delete(event, old) - event[new] = value + event.Object.Secondary = value + } + + value, found = path["mode"] + if found { + mode, err := strconv.ParseUint(value, 8, 64) + if err != nil { + return errors.Wrap(err, "failed to parse file mode") + } + + m := os.FileMode(mode) + switch { + case m.IsRegular(): + event.Object.What = "file" + case m.IsDir(): + event.Object.What = "directory" + case m&os.ModeCharDevice != 0: + event.Object.What = "character-device" + case m&modeBlockDevice != 0: + event.Object.What = "block-device" + case m&os.ModeNamedPipe != 0: + event.Object.What = "named-pipe" + case m&os.ModeSymlink != 0: + event.Object.What = "symlink" + case m&os.ModeSocket != 0: + event.Object.What = "socket" + } + } + + for k, v := range path { + if strings.HasPrefix(k, "obj_") { + addObjectSELinuxLabel(k[4:], v, event) + } + } + + return nil +} + +func setSocketObject(event *Event) error { + value, found := event.Socket["addr"] + if found { + event.Object.Primary = value + } else { + value, found = event.Socket["path"] + if found { + event.Object.Primary = value + } + } + + value, found = event.Socket["port"] + if found { + event.Object.Secondary = value + } + return nil +} + +func setHowDefaults(event *Event) { + exe, found := event.Data["exe"] + if !found { + // Fallback to comm. + exe, found = event.Data["comm"] + if !found { + return + } + } + event.How = exe + + switch { + case strings.HasPrefix(exe, "/usr/bin/python"), + strings.HasPrefix(exe, "/usr/bin/sh"), + strings.HasPrefix(exe, "/usr/bin/bash"), + strings.HasPrefix(exe, "/usr/bin/perl"): + default: + return + } + + // It's probably some kind of interpreted script so use "comm". + comm, found := event.Data["comm"] + if !found { + return } + event.How = comm } diff --git a/aucoalesce/coalesce_test.go b/aucoalesce/coalesce_test.go index 251ab02..228d282 100644 --- a/aucoalesce/coalesce_test.go +++ b/aucoalesce/coalesce_test.go @@ -21,81 +21,152 @@ import ( "io/ioutil" "os" "path/filepath" + "sort" + "strings" "testing" - "github.com/elastic/go-libaudit/auparse" "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" + + "github.com/elastic/go-libaudit/auparse" ) var update = flag.Bool("update", false, "update .golden files") func TestCoalesceMessages(t *testing.T) { - files, err := filepath.Glob("testdata/*.log") + testFiles, err := filepath.Glob("testdata/*.yaml") if err != nil { - t.Fatal("glob failed", err) + t.Fatal("glob", err) } - for _, name := range files { - testCoalesce(t, name) + for _, file := range testFiles { + t.Run(file, func(t *testing.T) { + testCoalesceEvent(t, file) + }) } } -func testCoalesce(t testing.TB, file string) { - msgs := readMessages(t, file) +type testEvent struct { + name string + messages []*auparse.AuditMessage +} - event, err := CoalesceMessages(msgs) - if err != nil { - t.Fatal(err) +type testEventOutput struct { + TestName string `json:"test_name"` + Event *Event `json:"event"` + Warnings []string `json:"warnings,omitempty"` +} + +func newTestEventOutput(testName string, event *Event) testEventOutput { + var errs []string + for _, err := range event.Warnings { + errs = append(errs, err.Error()) + } + return testEventOutput{testName, event, errs} +} + +func testCoalesceEvent(t *testing.T, file string) { + testEvents := readEventsFromYAML(t, file) + + var events []testEventOutput + for _, te := range testEvents { + event, err := CoalesceMessages(te.messages) + if err != nil { + t.Fatal(err) + } + + events = append(events, newTestEventOutput(te.name, event)) } // Update golden files on -update. if *update { - if err = writeGoldenFile(file, event); err != nil { + if err := writeGoldenFile(file, events); err != nil { t.Fatal(err) } } - // Compare events to golden events. - goldenEvent, err := readGoldenFile(file + ".golden") + goldenEvents, err := readGoldenFile(file) if err != nil { t.Fatal(err) } - assert.EqualValues(t, goldenEvent, normalizeEvent(t, event), "file: %v", file) + // Compare events to golden events. + for i, observed := range events { + if i >= len(goldenEvents) { + t.Errorf("golden file has fewer events that there are test cases (run with -update): file=%v", file) + continue + } + expected := goldenEvents[i] + + t.Run(testEvents[i].name, func(t *testing.T) { + assert.EqualValues(t, expected, normalizeEvent(t, observed), "file=%v test_case=%v", file, testEvents[i].name) + }) + } } -func readMessages(t testing.TB, name string) []*auparse.AuditMessage { - f, err := os.Open(name) +func readEventsFromYAML(t testing.TB, name string) []testEvent { + file, err := ioutil.ReadFile(name) if err != nil { t.Fatal(err) } - defer f.Close() - var msgs []*auparse.AuditMessage + var data map[string]interface{} + if err := yaml.Unmarshal(file, &data); err != nil { + t.Fatal(err) + } - // Read logs and parse events. - s := bufio.NewScanner(bufio.NewReader(f)) - for s.Scan() { - line := s.Text() - msg, err := auparse.ParseLogLine(line) - if err != nil { - t.Fatal("invalid message:", line) + tests, ok := data["tests"] + if !ok { + t.Fatal("failed to find 'tests' in yaml") + } + + cases, ok := tests.(map[interface{}]interface{}) + if !ok { + t.Fatalf("unexpected type %T for 'tests'", tests) + } + + // Create test cases from YAML file. + var testEvents []testEvent + for name, messages := range cases { + var msgs []*auparse.AuditMessage + + s := bufio.NewScanner(strings.NewReader(messages.(string))) + for s.Scan() { + line := s.Text() + msg, err := auparse.ParseLogLine(line) + if err != nil { + t.Fatal("invalid message:", line) + } + + msgs = append(msgs, msg) } - msgs = append(msgs, msg) + testEvents = append(testEvents, testEvent{ + name: name.(string), + messages: msgs, + }) } - return msgs + // Sort the test cases by their key to ensure ordering. + sort.Slice(testEvents, func(i, j int) bool { + return testEvents[i].name < testEvents[j].name + }) + + return testEvents } -func writeGoldenFile(sourceName string, event map[string]interface{}) error { - f, err := os.Create(sourceName + ".golden") +func writeGoldenFile(name string, events []testEventOutput) error { + if strings.HasSuffix(name, ".yaml") { + name = name[:len(name)-len(".yaml")] + } + + f, err := os.Create(name + ".json.golden") if err != nil { return err } defer f.Close() - b, err := json.MarshalIndent(event, "", " ") + b, err := json.MarshalIndent(events, "", " ") if err != nil { return err } @@ -107,13 +178,17 @@ func writeGoldenFile(sourceName string, event map[string]interface{}) error { return nil } -func readGoldenFile(name string) (map[string]interface{}, error) { - data, err := ioutil.ReadFile(name) +func readGoldenFile(name string) ([]map[string]interface{}, error) { + if strings.HasSuffix(name, ".yaml") { + name = name[:len(name)-len(".yaml")] + } + + data, err := ioutil.ReadFile(name + ".json.golden") if err != nil { return nil, err } - var out map[string]interface{} + var out []map[string]interface{} if err := json.Unmarshal(data, &out); err != nil { return nil, err } @@ -121,7 +196,7 @@ func readGoldenFile(name string) (map[string]interface{}, error) { return out, nil } -func normalizeEvent(t testing.TB, event map[string]interface{}) map[string]interface{} { +func normalizeEvent(t testing.TB, event testEventOutput) map[string]interface{} { b, err := json.Marshal(event) if err != nil { t.Fatal(err) diff --git a/aucoalesce/event_type.go b/aucoalesce/event_type.go new file mode 100644 index 0000000..3019b3f --- /dev/null +++ b/aucoalesce/event_type.go @@ -0,0 +1,141 @@ +// Copyright 2017 Elasticsearch Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aucoalesce + +import ( + . "github.com/elastic/go-libaudit/auparse" +) + +// AuditEventType is a categorization of a simple or compound audit event. +type AuditEventType uint16 + +const ( + EventTypeUnknown AuditEventType = iota + EventTypeUserspace + EventTypeSystemServices + EventTypeConfig + EventTypeTTY + EventTypeUserAccount + EventTypeUserLogin + EventTypeAuditDaemon + EventTypeMACDecision + EventTypeAnomoly + EventTypeIntegrity + EventTypeAnomolyResponse + EventTypeMAC + EventTypeCrypto + EventTypeVirt + EventTypeAuditRule + EventTypeDACDecision + EventTypeGroupChange +) + +var auditEventTypeNames = map[AuditEventType]string{ + EventTypeUnknown: "unknown", + EventTypeUserspace: "user-space", + EventTypeSystemServices: "system-services", + EventTypeConfig: "configuration", + EventTypeTTY: "TTY", + EventTypeUserAccount: "user-account", + EventTypeUserLogin: "user-login", + EventTypeAuditDaemon: "audit-daemon", + EventTypeMACDecision: "mac-decision", + EventTypeAnomoly: "anomoly", + EventTypeIntegrity: "integrity", + EventTypeAnomolyResponse: "anomaly-response", + EventTypeMAC: "mac", + EventTypeCrypto: "crypto", + EventTypeVirt: "virt", + EventTypeAuditRule: "audit-rule", + EventTypeDACDecision: "dac-decision", + EventTypeGroupChange: "group-change", +} + +func (t AuditEventType) String() string { + name, found := auditEventTypeNames[t] + if found { + return name + } + return auditEventTypeNames[EventTypeUnknown] +} + +func (t AuditEventType) MarshalText() (text []byte, err error) { + return []byte(t.String()), nil +} + +func GetAuditEventType(t AuditMessageType) AuditEventType { + // Ported from: https://github.com/linux-audit/audit-userspace/blob/v2.7.5/auparse/normalize.c#L681 + switch { + case t >= AUDIT_USER_AUTH && t <= AUDIT_USER_END, + t >= AUDIT_USER_CHAUTHTOK && t <= AUDIT_CRED_REFR, + t >= AUDIT_USER_LOGIN && t <= AUDIT_USER_LOGOUT, + t == AUDIT_GRP_AUTH: + return EventTypeUserLogin + case t >= AUDIT_ADD_USER && t <= AUDIT_DEL_GROUP, + t >= AUDIT_GRP_MGMT && t <= AUDIT_GRP_CHAUTHTOK, + t >= AUDIT_ACCT_LOCK && t <= AUDIT_ACCT_UNLOCK: + return EventTypeUserAccount + case t == AUDIT_KERNEL, + t >= AUDIT_SYSTEM_BOOT && t <= AUDIT_SERVICE_STOP: + return EventTypeSystemServices + case t == AUDIT_USYS_CONFIG, + t == AUDIT_CONFIG_CHANGE, + t == AUDIT_NETFILTER_CFG, + t >= AUDIT_FEATURE_CHANGE && t <= AUDIT_REPLACE: + return EventTypeConfig + case t == AUDIT_SECCOMP: + return EventTypeDACDecision + case t >= AUDIT_CHGRP_ID && t <= AUDIT_TRUSTED_APP, + t == AUDIT_USER_CMD, + t == AUDIT_CHUSER_ID: + return EventTypeUserspace + case t == AUDIT_USER_TTY, t == AUDIT_TTY: + return EventTypeTTY + case t >= AUDIT_DAEMON_START && t <= AUDIT_LAST_DAEMON: + return EventTypeAuditDaemon + case t == AUDIT_USER_SELINUX_ERR, + t == AUDIT_USER_AVC, + t >= AUDIT_APPARMOR_ALLOWED && t <= AUDIT_APPARMOR_DENIED, + t == AUDIT_APPARMOR_ERROR, + t >= AUDIT_AVC && t <= AUDIT_AVC_PATH: + return EventTypeMACDecision + case t >= AUDIT_INTEGRITY_DATA && t <= AUDIT_INTEGRITY_LAST_MSG, + t == AUDIT_ANOM_RBAC_INTEGRITY_FAIL: + return EventTypeIntegrity + case t >= AUDIT_ANOM_PROMISCUOUS && t <= AUDIT_LAST_KERN_ANOM_MSG, + t >= AUDIT_ANOM_LOGIN_FAILURES && t <= AUDIT_ANOM_RBAC_FAIL, + t >= AUDIT_ANOM_CRYPTO_FAIL && t <= AUDIT_LAST_ANOM_MSG: + return EventTypeAnomoly + case t >= AUDIT_RESP_ANOMALY && t <= AUDIT_LAST_ANOM_RESP: + return EventTypeAnomolyResponse + case t >= AUDIT_MAC_POLICY_LOAD && t <= AUDIT_LAST_SELINUX, + t >= AUDIT_AA && t <= AUDIT_APPARMOR_AUDIT, + t >= AUDIT_APPARMOR_HINT && t <= AUDIT_APPARMOR_STATUS, + t >= AUDIT_USER_ROLE_CHANGE && t <= AUDIT_LAST_USER_LSPP_MSG: + return EventTypeMAC + case t >= AUDIT_FIRST_KERN_CRYPTO_MSG && t <= AUDIT_LAST_KERN_CRYPTO_MSG, + t >= AUDIT_CRYPTO_TEST_USER && t <= AUDIT_LAST_CRYPTO_MSG: + return EventTypeCrypto + case t >= AUDIT_VIRT_CONTROL && t <= AUDIT_LAST_VIRT_MSG: + return EventTypeVirt + case t >= AUDIT_SYSCALL && t <= AUDIT_SOCKETCALL, + t >= AUDIT_SOCKADDR && t <= AUDIT_MQ_GETSETATTR, + t >= AUDIT_FD_PAIR && t <= AUDIT_OBJ_PID, + t >= AUDIT_BPRM_FCAPS && t <= AUDIT_NETFILTER_PKT: + return EventTypeAuditRule + default: + return EventTypeUnknown + } +} diff --git a/aucoalesce/id_lookup.go b/aucoalesce/id_lookup.go new file mode 100644 index 0000000..439d521 --- /dev/null +++ b/aucoalesce/id_lookup.go @@ -0,0 +1,119 @@ +package aucoalesce + +import ( + "math" + "os/user" + "strings" + "time" +) + +const cacheTimeout = 0 + +var ( + userLookup = NewUserCache() + groupLookup = NewGroupCache() +) + +type stringItem struct { + timeout time.Time + value string +} + +func (i *stringItem) isExpired() bool { + return time.Now().After(i.timeout) +} + +// UserCache is a cache of UID to username. +type UserCache map[string]stringItem + +// NewUserCache returns a new UserCache. +func NewUserCache() UserCache { + return map[string]stringItem{ + "0": {timeout: time.Unix(math.MaxInt64, 0), value: "root"}, + } +} + +// LookupUID looks up a UID and returns the username associated with it. If +// no username could be found an empty string is returned. The value will be +// cached for a minute. This requires cgo on Linux. +func (c UserCache) LookupUID(uid string) string { + if uid == "" || uid == "unset" { + return "" + } + + if item, found := c[uid]; found && !item.isExpired() { + return item.value + } + + // Cache the value (even on error). + user, err := user.LookupId(uid) + if err != nil { + c[uid] = stringItem{timeout: time.Now().Add(cacheTimeout), value: ""} + return "" + } + + c[uid] = stringItem{timeout: time.Now().Add(cacheTimeout), value: user.Username} + return user.Username +} + +// GroupCache is a cache of GID to group name. +type GroupCache map[string]stringItem + +// NewGroupCache returns a new GroupCache. +func NewGroupCache() GroupCache { + return map[string]stringItem{ + "0": {timeout: time.Unix(math.MaxInt64, 0), value: "root"}, + } +} + +// LookupGID looks up a GID and returns the group associated with it. If +// no group could be found an empty string is returned. The value will be +// cached for a minute. This requires cgo on Linux. +func (c GroupCache) LookupGID(gid string) string { + if gid == "" || gid == "unset" { + return "" + } + + if item, found := c[gid]; found && !item.isExpired() { + return item.value + } + + // Cache the value (even on error). + group, err := user.LookupGroupId(gid) + if err != nil { + c[gid] = stringItem{timeout: time.Now().Add(cacheTimeout), value: ""} + return "" + } + + c[gid] = stringItem{timeout: time.Now().Add(cacheTimeout), value: group.Name} + return group.Name +} + +// ResolveIDs translates all uid and gid values to their associated names. +// This requires cgo on Linux. +func ResolveIDs(event *Event) { + if v := userLookup.LookupUID(event.Subject.Primary); v != "" { + event.Subject.Primary = v + } + if v := userLookup.LookupUID(event.Subject.Secondary); v != "" { + event.Subject.Secondary = v + } + + processMap := func(m map[string]string) { + for key, id := range m { + if strings.HasSuffix(key, "uid") { + if v := userLookup.LookupUID(id); v != "" { + m[key] = v + } + } else if strings.HasSuffix(key, "gid") { + if v := groupLookup.LookupGID(id); v != "" { + m[key] = v + } + } + } + } + processMap(event.Subject.Attributes) + for _, path := range event.Paths { + processMap(path) + } +} diff --git a/aucoalesce/id_lookup_test.go b/aucoalesce/id_lookup_test.go new file mode 100644 index 0000000..ec06244 --- /dev/null +++ b/aucoalesce/id_lookup_test.go @@ -0,0 +1,32 @@ +package aucoalesce + +import ( + "os" + "strconv" + "testing" +) + +func TestUIDLookup(t *testing.T) { + uid := os.Getuid() + user := userLookup.LookupUID(strconv.Itoa(uid)) + gid := os.Getgid() + group := groupLookup.LookupGID(strconv.Itoa(gid)) + + t.Log(user, group) +} + +func TestResolveIDs(t *testing.T) { + auid := strconv.Itoa(os.Getuid()) + event := &Event{ + Subject: Subject{ + Primary: auid, + Secondary: "0", + }, + Data: map[string]string{ + "auid": auid, + "gid": strconv.Itoa(os.Getgid()), + }, + } + ResolveIDs(event) + t.Logf("%+v", event) +} diff --git a/aucoalesce/mknormalize_data.go b/aucoalesce/mknormalize_data.go new file mode 100644 index 0000000..92cb9dd --- /dev/null +++ b/aucoalesce/mknormalize_data.go @@ -0,0 +1,106 @@ +// +build ignore + +package main + +import ( + "bytes" + "encoding/base64" + "flag" + "fmt" + "go/format" + "io/ioutil" + "os" + "text/template" +) + +var tpl = template.Must(template.New("normalizations").Parse(` +// mknormalize_data.go +// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT + +// Copyright 2017 Elasticsearch Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aucoalesce + +import ( + "encoding/base64" + "fmt" +) + +var assets map[string][]byte + +func asset(key string) ([]byte, error) { + if assets == nil { + assets = map[string][]byte{} + + var value []byte + {{- range $asset := .Assets }} + value, _ = base64.StdEncoding.DecodeString("{{ $asset.Data }}") + assets["{{ $asset.Name }}"] = value{{ end }} + } + + if value, found := assets[key]; found { + return value, nil + } + return nil, fmt.Errorf("asset not found for key=%v", key) +} +`)) + +type asset struct { + Name string + Data string +} + +var assets []asset + +func addAsset(key, file string) error { + data, err := ioutil.ReadFile(file) + if err != nil { + return err + } + + assets = append(assets, asset{ + Name: key, + Data: base64.StdEncoding.EncodeToString(data), + }) + return nil +} + +type templateVars struct { + Assets []asset +} + +func main() { + flag.Parse() + + args := flag.Args() + if len(args)%2 != 0 { + fmt.Fprintln(os.Stderr, "error: expected pairs of arguments (a key and a filename)") + os.Exit(1) + } + + for i := 0; i < len(args); i += 2 { + addAsset(args[i], args[i+1]) + } + + var buf bytes.Buffer + tpl.Execute(&buf, templateVars{ + Assets: assets, + }) + bs, err := format.Source(buf.Bytes()) + if err != nil { + panic(err) + } + os.Stdout.Write(bs) +} diff --git a/aucoalesce/normalizations.yaml b/aucoalesce/normalizations.yaml new file mode 100644 index 0000000..72de1fe --- /dev/null +++ b/aucoalesce/normalizations.yaml @@ -0,0 +1,735 @@ +--- +# Macros declares some YAML anchors that can be referenced for some common +# object type normalizations like user-session, socket, or process. +macros: +- &defaults + subject: + primary: auid + secondary: uid + how: [exe, comm] + +- ¯o-user-session + subject: + primary: auid + secondary: [acct, id, uid] + object: + primary: terminal + secondary: [addr, hostname] + what: user-session + how: [exe, terminal] + +- ¯o-socket + <<: *defaults + object: + primary: [addr, path] + secondary: port + what: socket + +- ¯o-process + <<: *defaults + object: + primary: [cmd, exe, comm] + secondary: pid + what: process + how: terminal + +# Normalizations is a list of declarations specifying how to normalize the data +# contained in an event. The normalization can be applied based on the syscall +# name (e.g. connect, open) or based on the record type (e.g. USER_LOGIN). +# No two normalizations can apply to the same syscall or record type. This +# will result in a failure at load time. +# +# Each normalization should specify: +# action - what happened +# actor - who did this or who triggered the event +# object - what was the "thing" involved in the action (e.g. process, socket) +# how - how was the action performed (e.g. exe or terminal) +normalizations: +- + action: opened-file + object: + what: file + syscalls: + - creat + - fallocate + - truncate + - ftruncate + - open + - openat + - readlink + - readlinkat +- + action: changed-file-attributes-of + object: + what: file + syscalls: + - setxattr + - fsetxattr + - lsetxattr + - removexattr + - fremovexattr + - lremovexattr +- + action: changed-file-permissions-of + object: + what: file + syscalls: + - chmod + - fchmod + - fchmodat +- + action: changed-file-ownership-of + object: + what: file + syscalls: + - chown + - fchown + - fchownat + - lchown +- + action: loaded-kernel-module + object: + what: file + primary: name + record_types: + - KERN_MODULE + syscalls: + - finit_module + - init_module +- + action: unloaded-kernel-module + object: + what: file + syscalls: + - delete_module +- + action: created-directory + object: + what: file + path_index: 1 + syscalls: + - mkdir + - mkdirat +- + action: mounted + object: + what: filesystem + path_index: 1 + syscalls: + - mount +- + action: renamed + object: + what: file + path_index: 2 + syscalls: + - rename + - renameat + - renameat2 +- + action: checked-metadata-of + object: + what: file + syscalls: + - access + - faccessat + - newfstatat + - stat + - fstat + - lstat + - stat64 + - getxattr + - lgetxattr + - fgetxattr +- + action: checked-filesystem-metadata-of + object: + what: filesystem + syscalls: + - statfs + - fstatfs +- + action: symlinked + object: + what: file + syscalls: + - symlink + - symlinkat +- + action: unmounted + object: + what: filesystem + syscalls: + - umount2 +- + action: deleted + object: + what: file + syscalls: + - rmdir + - unlink + - unlinkat +- + action: changed-timestamp-of + object: + what: file + syscalls: + - utime + - utimes + - futimesat + - futimens + - utimensat +- + action: executed + object: + what: file + syscalls: + - execve + - execveat +- + action: listen-for-connections + object: + what: socket + syscalls: + - listen +- + action: accepted-connection-from + object: + what: socket + syscalls: + - accept + - accept4 +- + action: bound-socket + object: + what: socket + syscalls: + - bind +- + action: connected-to + object: + what: socket + syscalls: + - connect +- + action: received-from + object: + what: socket + syscalls: + - recvfrom + - recvmsg +- + action: sent-to + object: + what: socket + syscalls: + - sendto + - sendmsg +- + action: killed-pid + object: + what: process + syscalls: + - kill + - tkill + - tgkill +- + action: changed-identity-of + object: + what: process + how: syscall + syscalls: + - setuid + - seteuid + - setfsuid + - setreuid + - setresuid + - setgid + - setegid + - setfsgid + - setregid + - setresgid +- + action: changed-system-time + object: + what: system + syscalls: + - settimeofday + - clock_settime + - stime + - adjtimex +- + action: make-device + object: + what: file + syscalls: + - mknod + - mknodat +- + action: changed-system-name + object: + what: system + syscalls: + - sethostname + - setdomainname +- + action: allocated-memory + object: + what: memory + syscalls: + - mmap + - brk +- + action: adjusted-scheduling-policy-of + object: + what: process + how: syscall + syscalls: + - sched_setparam + - sched_setscheduler + - sched_setattr +- + action: caused-mac-policy-error + object: + what: system + record_types: SELINUX_ERR +- + action: loaded-firewall-rule-to + object: + primary: table + what: firewall + record_types: NETFILTER_CFG +- + # Could be entered or exited based on prom field. + action: changed-promiscuous-mode-on-device + object: + primary: dev + what: network-device + record_types: ANOM_PROMISCUOUS +- + action: locked-account + record_types: ACCT_LOCK +- + action: unlocked-account + record_types: ACCT_UNLOCK +- + action: added-group-account-to + object: + primary: [id, acct] + what: account + record_types: ADD_GROUP +- + action: added-user-account + object: + primary: [id, acct] + what: account + record_types: ADD_USER +- + action: crashed-program + object: + primary: [comm, exe] + secondary: pid + what: process + how: sig + record_types: ANOM_ABEND +- + action: attempted-execution-of-forbidden-program + object: + primary: cmd + what: process + how: terminal + record_types: ANOM_EXEC +- + action: used-suspcious-link + record_types: ANOM_LINK +- + <<: *macro-user-session + action: failed-log-in-too-many-times-to + record_types: ANOM_LOGIN_FAILURES +- + <<: *macro-user-session + action: attempted-log-in-from-unusual-place-to + record_types: ANOM_LOGIN_LOCATION +- + <<: *macro-user-session + action: opened-too-many-sessions-to + record_types: ANOM_LOGIN_SESSIONS +- + <<: *macro-user-session + action: attempted-log-in-during-unusual-hour-to + record_types: ANOM_LOGIN_TIME +- + action: tested-file-system-integrity-of + object: + primary: hostname + what: filesystem + record_types: ANOM_RBAC_INTEGRITY_FAIL +- + action: violated-selinux-policy + subject: + primary: scontext + object: + primary: tcontext + record_types: AVC +- + action: changed-group + record_types: CHGRP_ID +- + action: changed-user-id + record_types: CHUSER_ID +- + action: changed-audit-configuration + object: + primary: [op, key, audit_enabled, audit_pid, audit_backlog_limit, audit_failure] + what: audit-config + record_types: CONFIG_CHANGE +- + <<: *macro-user-session + action: acquired-credentials + record_types: CRED_ACQ +- + <<: *macro-user-session + action: disposed-credentials + record_types: CRED_DISP +- + <<: *macro-user-session + action: refreshed-credentials + record_types: CRED_REFR +- + <<: *macro-user-session + action: negotiated-crypto-key + object: + primary: fp + secondary: [addr, hostname] + what: user-session + record_types: CRYPTO_KEY_USER +- + action: crypto-officer-logged-in + record_types: CRYPTO_LOGIN +- + action: crypto-officer-logged-out + record_types: CRYPTO_LOGOUT +- + <<: *macro-user-session + action: started-crypto-session + object: + primary: addr + secondary: [rport] + record_types: CRYPTO_SESSION +- + action: access-result + record_types: DAC_CHECK +- + action: aborted-auditd-startup + object: + what: service + record_types: DAEMON_ABORT +- + action: remote-audit-connected + object: + what: service + record_types: DAEMON_ACCEPT +- + action: remote-audit-disconnected + object: + what: service + record_types: DAEMON_CLOSE +- + action: changed-auditd-configuration + object: + what: service + record_types: DAEMON_CONFIG +- + action: shutdown-audit + object: + what: service + record_types: DAEMON_END +- + action: audit-error + object: + what: service + record_types: DAEMON_ERR +- + action: reconfigured-auditd + object: + what: service + record_types: DAEMON_RECONFIG +- + action: resumed-audit-logging + object: + what: service + record_types: DAEMON_RESUME +- + action: rotated-audit-logs + object: + what: service + record_types: DAEMON_ROTATE +- + action: started-audit + object: + what: service + record_types: DAEMON_START +- + action: deleted-group-account-from + object: + primary: [id, acct] + what: account + record_types: DEL_GROUP +- + action: deleted-user-account + object: + primary: [id, acct] + what: account + record_types: DEL_USER +- + action: changed-audit-feature + object: + primary: feature + what: system + record_types: FEATURE_CHANGE +- + action: relabeled-filesystem + record_types: FS_RELABEL +- + action: authenticated-to-group + record_types: GRP_AUTH +- + <<: *macro-user-session + action: changed-group-password + object: + primary: acct + what: user-session + record_types: GRP_CHAUTHTOK +- + action: modified-group-account + object: + primary: [id, acct] + what: account + record_types: GRP_MGMT +- + action: initialized-audit-subsystem + record_types: KERNEL +- + action: modified-level-of + object: + primary: printer + what: printer + record_types: LABEL_LEVEL_CHANGE +- + action: overrode-label-of + object: + what: mac-config + record_types: LABEL_OVERRIDE +- + object: + what: mac-config + record_types: + - AUDIT_DEV_ALLOC + - AUDIT_DEV_DEALLOC + - AUDIT_FS_RELABEL + - AUDIT_USER_MAC_POLICY_LOAD + - AUDIT_USER_MAC_CONFIG_CHANGE +- + action: changed-login-id-to + subject: + primary: [old_auid, old-auid] + secondary: uid + object: + primary: auid + what: user-session + record_types: LOGIN +- + action: mac-permission + record_types: MAC_CHECK +- + action: changed-selinux-boolean + object: + primary: bool + what: mac-config + record_types: MAC_CONFIG_CHANGE +- + action: loaded-selinux-policy + object: + what: mac-config + record_types: MAC_POLICY_LOAD +- + action: changed-selinux-enforcement + object: + primary: enforcing + what: mac-config + record_types: MAC_STATUS +- + action: assigned-user-role-to + object: + primary: [id, acct] + what: account + record_types: ROLE_ASSIGN +- + action: modified-role + record_types: ROLE_MODIFY +- + action: removed-use-role-from + object: + primary: [id, acct] + what: account + record_types: ROLE_REMOVE +- + action: violated-seccomp-policy + object: + primary: syscall + what: process + record_types: SECCOMP +- + action: started-service + object: + primary: unit + what: service + record_types: SERVICE_START +- + action: stopped-service + object: + primary: unit + what: service + record_types: SERVICE_STOP +- + action: booted-system + object: + what: system + record_types: SYSTEM_BOOT +- + action: changed-to-runlevel + object: + primary: new-level + what: system + record_types: SYSTEM_RUNLEVEL +- + action: shutdown-system + object: + what: system + record_types: SYSTEM_SHUTDOWN +- + action: sent-test + record_types: TEST +- + action: unknown + record_types: TRUSTED_APP +- + action: sent-message + object: + primary: addr + record_types: USER +- + <<: *macro-user-session + action: was-authorized + record_types: USER_ACCT +- + <<: *macro-user-session + action: authenticated + record_types: USER_AUTH +- + action: access-permission + record_types: USER_AVC +- + <<: *macro-user-session + action: changed-password + record_types: USER_CHAUTHTOK +- + action: ran-command + object: + primary: cmd + what: process + record_types: USER_CMD + description: > + These messages are from user-space apps, like sudo, that log commands + being run by a user. The uid contained in these messages is user's UID at + the time the command was run. It is not the "target" UID used to run the + command, which is normally root. +- + <<: *macro-user-session + action: ended-session + record_types: USER_END +- + <<: *macro-user-session + action: error + record_types: USER_ERR +- + <<: *macro-user-session + action: logged-in + record_types: USER_LOGIN +- + <<: *macro-user-session + action: logged-out + record_types: USER_LOGOUT +- + action: changed-mac-configuration + record_types: USER_MAC_CONFIG_CHANGE +- + action: loaded-mac-policy + record_types: USER_MAC_POLICY_LOAD +- + <<: *macro-user-session + action: modified-user-account + record_types: USER_MGMT +- + <<: *macro-user-session + action: changed-role-to + object: + primary: selected-context + what: user-session + record_types: USER_ROLE_CHANGE +- + action: access-error + record_types: USER_SELINUX_ERR +- + <<: *macro-user-session + action: started-session + record_types: USER_START +- + action: changed-configuration + object: + primary: op + what: system + record_types: USYS_CONFIG +- + action: issued-vm-control + object: + primary: op + secondary: vm + what: virtual-machine + record_types: VIRT_CONTROL +- + action: created-vm-image + record_types: VIRT_CREATE +- + action: deleted-vm-image + record_types: VIRT_DESTROY +- + action: checked-integrity-of + record_types: VIRT_INTEGRITY_CHECK +- + action: assigned-vm-id + object: + primary: vm + what: virtual-machine + record_types: VIRT_MACHINE_ID +- + action: migrated-vm-from + record_types: VIRT_MIGRATE_IN +- + action: migrated-vm-to + record_types: VIRT_MIGRATE_OUT +- + action: assigned-vm-resource + object: + primary: resrc + secondary: vm + what: virtual-machine + record_types: VIRT_RESOURCE +- action: typed + object: + primary: data + what: keystrokes + how: [comm, exe] + record_types: + - TTY + - USER_TTY diff --git a/aucoalesce/normalize.go b/aucoalesce/normalize.go new file mode 100644 index 0000000..5c335e8 --- /dev/null +++ b/aucoalesce/normalize.go @@ -0,0 +1,115 @@ +// Copyright 2017 Elasticsearch Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aucoalesce + +import ( + "fmt" + + "github.com/pkg/errors" + "gopkg.in/yaml.v2" +) + +//go:generate sh -c "go run mknormalize_data.go normalizationData normalizations.yaml > znormalize_data.go" + +var ( + syscallNorms map[string]*Normalization + recordTypeNorms map[string]*Normalization +) + +func init() { + data, err := asset("normalizationData") + if err != nil { + panic("normalizationData not found in assets") + } + + syscallNorms, recordTypeNorms, err = LoadNormalizationConfig(data) + if err != nil { + panic(errors.Wrap(err, "failed to parse built in normalization mappings")) + } +} + +// Strings is a custom type to enable YAML values that can be either a string +// or a list of strings. +type Strings struct { + Values []string +} + +func (s *Strings) UnmarshalYAML(unmarshal func(interface{}) error) error { + var singleValue string + if err := unmarshal(&singleValue); err == nil { + s.Values = append(s.Values, singleValue) + return nil + } + + return unmarshal(&s.Values) +} + +type NormalizationConfig struct { + Default Normalization `yaml:"default"` + Normalizations []Normalization +} + +type Normalization struct { + Subject SubjectMapping `yaml:"subject"` + Action string `yaml:"action"` + Object ObjectMapping `yaml:"object"` + How Strings `yaml:"how"` + RecordTypes Strings `yaml:"record_types"` + Syscalls Strings `yaml:"syscalls"` +} + +type SubjectMapping struct { + PrimaryFieldName Strings `yaml:"primary"` + SecondaryFieldName Strings `yaml:"secondary"` +} + +type ObjectMapping struct { + PrimaryFieldName Strings `yaml:"primary"` + SecondaryFieldName Strings `yaml:"secondary"` + What string `yaml:"what"` + PathIndex int `yaml:"path_index"` +} + +type HowMapping struct { + FieldName string `yaml:"field"` +} + +func LoadNormalizationConfig(b []byte) (syscalls map[string]*Normalization, recordTypes map[string]*Normalization, err error) { + c := &NormalizationConfig{} + if err := yaml.Unmarshal(b, c); err != nil { + return nil, nil, err + } + + syscalls = map[string]*Normalization{} + recordTypes = map[string]*Normalization{} + + for i := range c.Normalizations { + norm := c.Normalizations[i] + for _, syscall := range norm.Syscalls.Values { + if _, found := syscalls[syscall]; found { + return nil, nil, fmt.Errorf("duplication mappings for sycall %v", syscall) + } + syscalls[syscall] = &norm + } + for _, recordType := range norm.RecordTypes.Values { + if _, found := recordTypes[recordType]; found { + return nil, nil, fmt.Errorf("duplication mappings for record_type %v", recordType) + } + recordTypes[recordType] = &norm + } + } + + return syscalls, recordTypes, nil +} diff --git a/aucoalesce/normalize_test.go b/aucoalesce/normalize_test.go new file mode 100644 index 0000000..4032a5a --- /dev/null +++ b/aucoalesce/normalize_test.go @@ -0,0 +1,54 @@ +// Copyright 2017 Elasticsearch Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aucoalesce + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" +) + +func TestNormInit(t *testing.T) { + assert.NotEmpty(t, syscallNorms) + assert.NotEmpty(t, recordTypeNorms) +} + +func TestLoadNormalizationConfig(t *testing.T) { + b, err := ioutil.ReadFile("normalizations.yaml") + if err != nil { + t.Fatal(err) + } + + if _, _, err := LoadNormalizationConfig(b); err != nil { + t.Fatal(err) + } +} + +var stringsYAML = ` +--- +plain_string: plain string +list_strings: [x, y, z] +` + +func TestStrings_UnmarshalYAML(t *testing.T) { + var data map[string]Strings + if err := yaml.Unmarshal([]byte(stringsYAML), &data); err != nil { + t.Fatal(err) + } + assert.Equal(t, []string{"plain string"}, data["plain_string"].Values) + assert.Equal(t, []string{"x", "y", "z"}, data["list_strings"].Values) +} diff --git a/aucoalesce/testdata/execve.log b/aucoalesce/testdata/execve.log deleted file mode 100644 index b2506a6..0000000 --- a/aucoalesce/testdata/execve.log +++ /dev/null @@ -1,6 +0,0 @@ -type=SYSCALL msg=audit(1492037291.036:59): arch=c000003e syscall=59 success=yes exit=0 a0=1522170 a1=1506120 a2=14faeb0 a3=7ffcc4582df0 items=2 ppid=12041 pid=13393 auid=1000 uid=1000 gid=1001 euid=1000 suid=1000 fsuid=1000 egid=1001 sgid=1001 fsgid=1001 tty=pts1 ses=802 comm="grep" exe="/usr/bin/grep" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="user_commands" -type=EXECVE msg=audit(1492037291.036:59): argc=3 a0="grep" a1="--color=auto" a2="mapping" -type=CWD msg=audit(1492037291.036:59): cwd="/home/andrew_kroh" -type=PATH msg=audit(1492037291.036:59): item=0 name="/usr/bin/grep" inode=2512 dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:bin_t:s0 objtype=NORMAL -type=PATH msg=audit(1492037291.036:59): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=19161168 dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0 objtype=NORMAL -type=EOE msg=audit(1492037291.036:59) diff --git a/aucoalesce/testdata/execve.log.golden b/aucoalesce/testdata/execve.log.golden deleted file mode 100644 index 8da8c21..0000000 --- a/aucoalesce/testdata/execve.log.golden +++ /dev/null @@ -1,72 +0,0 @@ -{ - "@timestamp": "2017-04-12T22:48:11.036Z", - "cwd": "/home/andrew_kroh", - "execve": { - "argc": "3", - "cmdline": "\"grep\" \"--color=auto\" \"mapping\"" - }, - "path": [ - { - "dev": "08:01", - "inode": "2512", - "item": "0", - "mode": "0100755", - "name": "/usr/bin/grep", - "obj_domain": "bin_t", - "obj_level": "s0", - "obj_role": "object_r", - "obj_user": "system_u", - "objtype": "NORMAL", - "ogid": "0", - "ouid": "0", - "rdev": "00:00" - }, - { - "dev": "08:01", - "inode": "19161168", - "item": "1", - "mode": "0100755", - "name": "/lib64/ld-linux-x86-64.so.2", - "obj_domain": "ld_so_t", - "obj_level": "s0", - "obj_role": "object_r", - "obj_user": "system_u", - "objtype": "NORMAL", - "ogid": "0", - "ouid": "0", - "rdev": "00:00" - } - ], - "sequence": 59, - "syscall": { - "a0": "1522170", - "a1": "1506120", - "a2": "14faeb0", - "a3": "7ffcc4582df0", - "arch": "x86_64", - "auid": "1000", - "comm": "grep", - "egid": "1001", - "euid": "1000", - "exe": "/usr/bin/grep", - "exit": "0", - "fsgid": "1001", - "fsuid": "1000", - "gid": "1001", - "key": "user_commands", - "name": "execve", - "pid": "13393", - "ppid": "12041", - "ses": "802", - "sgid": "1001", - "subj_category": "c0.c1023", - "subj_domain": "unconfined_t", - "subj_level": "s0-s0", - "subj_role": "unconfined_r", - "subj_user": "unconfined_u", - "success": "yes", - "suid": "1000", - "tty": "pts1", - "uid": "1000" - } -} diff --git a/aucoalesce/testdata/random-internet.json.golden b/aucoalesce/testdata/random-internet.json.golden new file mode 100644 index 0000000..5e2faee --- /dev/null +++ b/aucoalesce/testdata/random-internet.json.golden @@ -0,0 +1,41 @@ +[ + { + "test_name": "ANOM_ABEND SIGSEGV seg fault", + "event": { + "@timestamp": "2015-02-06T15:03:14.398Z", + "sequence": 911150, + "category": "anomoly", + "record_type": "anom_abend", + "result": "unknown", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "48", + "attrs": { + "auid": "unset", + "gid": "48", + "uid": "48" + }, + "selinux": { + "domain": "httpd_t", + "level": "s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "httpd", + "secondary": "31242", + "what": "process" + }, + "action": "crashed-program", + "how": "11", + "data": { + "comm": "httpd", + "pid": "31242", + "reason": "memory violation", + "sig": "11" + } + } + } +] diff --git a/aucoalesce/testdata/random-internet.yaml b/aucoalesce/testdata/random-internet.yaml new file mode 100644 index 0000000..d86b910 --- /dev/null +++ b/aucoalesce/testdata/random-internet.yaml @@ -0,0 +1,4 @@ +--- +tests: + ANOM_ABEND SIGSEGV seg fault: | + type=ANOM_ABEND msg=audit(1423234994.398:911150): auid=4294967295 uid=48 gid=48 ses=4294967295 subj=system_u:system_r:httpd_t:s0 pid=31242 comm="httpd" reason="memory violation" sig=11 diff --git a/aucoalesce/testdata/rhel-7-linux-3.10.0.json.golden b/aucoalesce/testdata/rhel-7-linux-3.10.0.json.golden new file mode 100644 index 0000000..1ee4c46 --- /dev/null +++ b/aucoalesce/testdata/rhel-7-linux-3.10.0.json.golden @@ -0,0 +1,506 @@ +[ + { + "test_name": "CONFIG_CHANGE add rule", + "event": { + "@timestamp": "2017-04-21T04:37:47.018Z", + "sequence": 1209, + "category": "configuration", + "record_type": "config_change", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "attrs": { + "auid": "unset" + }, + "selinux": { + "domain": "unconfined_service_t", + "level": "s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "add_rule", + "what": "audit-config" + }, + "action": "changed-audit-configuration", + "key": "pam", + "data": { + "list": "4", + "op": "add_rule" + } + } + }, + { + "test_name": "CONFIG_CHANGE backlog limit", + "event": { + "@timestamp": "2017-04-21T05:49:55.844Z", + "sequence": 15406, + "category": "configuration", + "record_type": "config_change", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "attrs": { + "auid": "unset" + }, + "selinux": { + "domain": "unconfined_service_t", + "level": "s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "64", + "what": "audit-config" + }, + "action": "changed-audit-configuration", + "data": { + "audit_backlog_limit": "64", + "old": "8192" + } + } + }, + { + "test_name": "CRYPTO_KEY_USER", + "event": { + "@timestamp": "2016-12-07T02:17:21.497Z", + "sequence": 404, + "category": "crypto", + "record_type": "crypto_key_user", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "suid": "0", + "uid": "0" + }, + "selinux": { + "category": "c0.c1023", + "domain": "sshd_t", + "level": "s0-s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "6d:a3:7f:ed:de:4a:79:f2:aa:49:ec:d1:75:36:97:a3", + "secondary": "96.241.146.97", + "what": "user-session" + }, + "action": "negotiated-crypto-key", + "how": "/usr/sbin/sshd", + "data": { + "addr": "96.241.146.97", + "exe": "/usr/sbin/sshd", + "fp": "6d:a3:7f:ed:de:4a:79:f2:aa:49:ec:d1:75:36:97:a3", + "kind": "server", + "op": "destroy", + "pid": "1299", + "spid": "1299" + } + } + }, + { + "test_name": "CRYPTO_SESSION", + "event": { + "@timestamp": "2016-12-07T02:17:21.515Z", + "sequence": 406, + "category": "crypto", + "record_type": "crypto_session", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "suid": "74", + "uid": "0" + }, + "selinux": { + "category": "c0.c1023", + "domain": "sshd_t", + "level": "s0-s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "96.241.146.97", + "secondary": "63927", + "what": "user-session" + }, + "action": "started-crypto-session", + "how": "/usr/sbin/sshd", + "data": { + "addr": "96.241.146.97", + "cipher": "chacha20-poly1305@openssh.com", + "direction": "from-server", + "exe": "/usr/sbin/sshd", + "ksize": "512", + "laddr": "10.142.0.2", + "lport": "22", + "op": "start", + "pfs": "curve25519-sha256@libssh.org", + "pid": "1298", + "rport": "63927", + "spid": "1299" + } + } + }, + { + "test_name": "LOGIN success", + "event": { + "@timestamp": "2016-12-07T02:17:23.057Z", + "sequence": 414, + "category": "unknown", + "record_type": "login", + "result": "success", + "session": "1", + "actor": { + "primary": "4294967295", + "secondary": "0", + "attrs": { + "auid": "1000", + "old-auid": "4294967295", + "uid": "0" + }, + "selinux": { + "category": "c0.c1023", + "domain": "sshd_t", + "level": "s0-s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "1000", + "what": "user-session" + }, + "action": "changed-login-id-to", + "data": { + "old-ses": "4294967295", + "pid": "1298" + } + } + }, + { + "test_name": "USER_LOGIN", + "event": { + "@timestamp": "2017-04-24T15:00:15.752Z", + "sequence": 42120, + "category": "user-login", + "record_type": "user_login", + "result": "fail", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "root", + "attrs": { + "auid": "unset", + "uid": "0" + }, + "selinux": { + "category": "c0.c1023", + "domain": "sshd_t", + "level": "s0-s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "ssh", + "secondary": "46.160.144.250", + "what": "user-session" + }, + "action": "logged-in", + "how": "/usr/sbin/sshd", + "data": { + "acct": "root", + "addr": "46.160.144.250", + "exe": "/usr/sbin/sshd", + "op": "login", + "pid": "18981", + "terminal": "ssh" + } + } + }, + { + "test_name": "USER_LOGOUT", + "event": { + "@timestamp": "2017-04-26T03:56:45.243Z", + "sequence": 73336, + "category": "user-login", + "record_type": "user_logout", + "result": "success", + "session": "132", + "actor": { + "primary": "1000", + "secondary": "1000", + "attrs": { + "auid": "1000", + "uid": "0" + }, + "selinux": { + "category": "c0.c1023", + "domain": "sshd_t", + "level": "s0-s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "/dev/pts/1", + "what": "user-session" + }, + "action": "logged-out", + "how": "/usr/sbin/sshd", + "data": { + "exe": "/usr/sbin/sshd", + "id": "1000", + "op": "login", + "pid": "2370", + "terminal": "/dev/pts/1" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "changed-system-time", + "event": { + "@timestamp": "2017-04-21T18:15:41.391Z", + "sequence": 20246, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "38", + "attrs": { + "auid": "unset", + "egid": "38", + "euid": "38", + "fsgid": "38", + "fsuid": "38", + "gid": "38", + "sgid": "38", + "suid": "38", + "uid": "38" + }, + "selinux": { + "domain": "ntpd_t", + "level": "s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "what": "system" + }, + "action": "changed-system-time", + "how": "/usr/sbin/ntpd", + "key": "time-change", + "data": { + "a0": "7f71508da920", + "a1": "1", + "a2": "0", + "a3": "7f715258624c", + "arch": "x86_64", + "comm": "ntpd", + "exe": "/usr/sbin/ntpd", + "exit": "0", + "items": "0", + "pid": "1075", + "ppid": "1", + "syscall": "adjtimex", + "tty": "(none)" + } + } + }, + { + "test_name": "make-device", + "event": { + "@timestamp": "2017-04-21T18:53:19.05Z", + "sequence": 20294, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "egid": "0", + "euid": "0", + "fsgid": "0", + "fsuid": "0", + "gid": "0", + "sgid": "0", + "suid": "0", + "uid": "0" + }, + "selinux": { + "domain": "systemd_logind_t", + "level": "s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "/run/systemd/sessions/", + "secondary": "11378", + "what": "file", + "selinux": { + "domain": "systemd_logind_sessions_t", + "level": "s0", + "role": "object_r", + "user": "system_u" + } + }, + "action": "make-device", + "how": "/usr/lib/systemd/systemd-logind;58f98c85 (deleted)", + "key": "specialfiles", + "data": { + "a0": "7ff61dde1960", + "a1": "1180", + "a2": "0", + "a3": "2", + "arch": "x86_64", + "comm": "systemd-logind", + "cwd": "/", + "exe": "/usr/lib/systemd/systemd-logind;58f98c85 (deleted)", + "exit": "0", + "pid": "326", + "ppid": "1", + "syscall": "mknod", + "tty": "(none)" + }, + "paths": [ + { + "dev": "00:13", + "inode": "11378", + "item": "0", + "mode": "040755", + "name": "/run/systemd/sessions/", + "obj_domain": "systemd_logind_sessions_t", + "obj_level": "s0", + "obj_role": "object_r", + "obj_user": "system_u", + "objtype": "PARENT", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + }, + { + "dev": "00:13", + "inode": "98040", + "item": "1", + "mode": "010600", + "name": "/run/systemd/sessions/23.ref", + "obj_domain": "systemd_logind_sessions_t", + "obj_level": "s0", + "obj_role": "object_r", + "obj_user": "system_u", + "objtype": "CREATE", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + } + ] + } + }, + { + "test_name": "mount syscall", + "event": { + "@timestamp": "2017-04-25T14:01:01.69Z", + "sequence": 48922, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "egid": "0", + "euid": "0", + "fsgid": "0", + "fsuid": "0", + "gid": "0", + "sgid": "0", + "suid": "0", + "uid": "0" + }, + "selinux": { + "domain": "systemd_logind_t", + "level": "s0", + "role": "system_r", + "user": "system_u" + } + }, + "thing": { + "primary": "/run/user/0", + "secondary": "454267", + "what": "file", + "selinux": { + "domain": "user_tmp_t", + "level": "s0", + "role": "object_r", + "user": "system_u" + } + }, + "action": "mounted", + "how": "/usr/lib/systemd/systemd-logind;58f98c85 (deleted)", + "key": "mount", + "data": { + "a0": "7ff61c0a7270", + "a1": "7ff61dddf470", + "a2": "7ff61c0a7270", + "a3": "6", + "arch": "x86_64", + "comm": "systemd-logind", + "cwd": "/", + "exe": "/usr/lib/systemd/systemd-logind;58f98c85 (deleted)", + "exit": "0", + "pid": "326", + "ppid": "1", + "syscall": "mount", + "tty": "(none)" + }, + "paths": [ + { + "item": "0", + "name": "/run/user/0", + "objtype": "UNKNOWN" + }, + { + "dev": "00:13", + "inode": "454267", + "item": "1", + "mode": "040700", + "name": "/run/user/0", + "obj_domain": "user_tmp_t", + "obj_level": "s0", + "obj_role": "object_r", + "obj_user": "system_u", + "objtype": "NORMAL", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + } + ] + } + } +] diff --git a/aucoalesce/testdata/rhel-7-linux-3.10.0.yaml b/aucoalesce/testdata/rhel-7-linux-3.10.0.yaml new file mode 100644 index 0000000..0137a08 --- /dev/null +++ b/aucoalesce/testdata/rhel-7-linux-3.10.0.yaml @@ -0,0 +1,40 @@ +--- +tests: + changed-system-time: | + type=SYSCALL msg=audit(1492798541.391:20246): arch=c000003e syscall=159 success=yes exit=0 a0=7f71508da920 a1=1 a2=0 a3=7f715258624c items=0 ppid=1 pid=1075 auid=4294967295 uid=38 gid=38 euid=38 suid=38 fsuid=38 egid=38 sgid=38 fsgid=38 tty=(none) ses=4294967295 comm="ntpd" exe="/usr/sbin/ntpd" subj=system_u:system_r:ntpd_t:s0 key="time-change" + type=EOE msg=audit(1492798541.391:20246): + + make-device: | + type=SYSCALL msg=audit(1492800799.050:20294): arch=c000003e syscall=133 success=yes exit=0 a0=7ff61dde1960 a1=1180 a2=0 a3=2 items=2 ppid=1 pid=326 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="systemd-logind" exe=2F7573722F6C69622F73797374656D642F73797374656D642D6C6F67696E643B3538663938633835202864656C6574656429 subj=system_u:system_r:systemd_logind_t:s0 key="specialfiles" + type=CWD msg=audit(1492800799.050:20294): cwd="/" + type=PATH msg=audit(1492800799.050:20294): item=0 name="/run/systemd/sessions/" inode=11378 dev=00:13 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:systemd_logind_sessions_t:s0 objtype=PARENT + type=PATH msg=audit(1492800799.050:20294): item=1 name="/run/systemd/sessions/23.ref" inode=98040 dev=00:13 mode=010600 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:systemd_logind_sessions_t:s0 objtype=CREATE + type=EOE msg=audit(1492800799.050:20294): + + CONFIG_CHANGE backlog limit: | + type=CONFIG_CHANGE msg=audit(1492753795.844:15406): audit_backlog_limit=64 old=8192 auid=4294967295 ses=4294967295 subj=system_u:system_r:unconfined_service_t:s0 res=1 + + CONFIG_CHANGE add rule: | + type=CONFIG_CHANGE msg=audit(1492749467.018:1209): auid=4294967295 ses=4294967295 subj=system_u:system_r:unconfined_service_t:s0 op="add_rule" key="pam" list=4 res=1 + + LOGIN success: | + type=LOGIN msg=audit(1481077043.057:414): pid=1298 uid=0 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 old-auid=4294967295 auid=1000 old-ses=4294967295 ses=1 res=1 + + USER_LOGIN: | + type=USER_LOGIN msg=audit(1493046015.752:42120): pid=18981 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=login acct="root" exe="/usr/sbin/sshd" hostname=? addr=46.160.144.250 terminal=ssh res=failed' + + USER_LOGOUT: | + type=USER_LOGOUT msg=audit(1493179005.243:73336): pid=2370 uid=0 auid=1000 ses=132 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=login id=1000 exe="/usr/sbin/sshd" hostname=? addr=? terminal=/dev/pts/1 res=success' + + CRYPTO_KEY_USER: | + type=CRYPTO_KEY_USER msg=audit(1481077041.497:404): pid=1299 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=destroy kind=server fp=6d:a3:7f:ed:de:4a:79:f2:aa:49:ec:d1:75:36:97:a3 direction=? spid=1299 suid=0 exe="/usr/sbin/sshd" hostname=? addr=96.241.146.97 terminal=? res=success' + + CRYPTO_SESSION: | + type=CRYPTO_SESSION msg=audit(1481077041.515:406): pid=1298 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=start direction=from-server cipher=chacha20-poly1305@openssh.com ksize=512 mac= pfs=curve25519-sha256@libssh.org spid=1299 suid=74 rport=63927 laddr=10.142.0.2 lport=22 exe="/usr/sbin/sshd" hostname=? addr=96.241.146.97 terminal=? res=success' + + mount syscall: | + type=SYSCALL msg=audit(1493128861.690:48922): arch=c000003e syscall=165 success=yes exit=0 a0=7ff61c0a7270 a1=7ff61dddf470 a2=7ff61c0a7270 a3=6 items=2 ppid=1 pid=326 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="systemd-logind" exe=2F7573722F6C69622F73797374656D642F73797374656D642D6C6F67696E643B3538663938633835202864656C6574656429 subj=system_u:system_r:systemd_logind_t:s0 key="mount" + type=CWD msg=audit(1493128861.690:48922): cwd="/" + type=PATH msg=audit(1493128861.690:48922): item=0 name="/run/user/0" objtype=UNKNOWN + type=PATH msg=audit(1493128861.690:48922): item=1 name="/run/user/0" inode=454267 dev=00:13 mode=040700 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:user_tmp_t:s0 objtype=NORMAL + type=EOE msg=audit(1493128861.690:48922): \ No newline at end of file diff --git a/aucoalesce/testdata/sockaddr.log b/aucoalesce/testdata/sockaddr.log deleted file mode 100644 index 6df7c0c..0000000 --- a/aucoalesce/testdata/sockaddr.log +++ /dev/null @@ -1,4 +0,0 @@ -type=SYSCALL msg=audit(1492027062.361:1316151): arch=c000003e syscall=46 success=yes exit=10 a0=14 a1=7ffe911f2610 a2=4000 a3=ffffffffffffffa9 items=1 ppid=1 pid=385 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="systemd-logind" exe="/usr/lib/systemd/systemd-logind" subj=system_u:system_r:systemd_logind_t:s0 key=(null) -type=SOCKADDR msg=audit(1492027062.361:1316151): saddr=01002F72756E2F73797374656D642F6E6F74696679 -type=CWD msg=audit(1492027062.361:1316151): cwd="/" -type=PATH msg=audit(1492027062.361:1316151): item=0 name="/run/systemd/notify" inode=6504 dev=00:13 mode=0140777 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:init_var_run_t:s0 objtype=NORMAL diff --git a/aucoalesce/testdata/sockaddr.log.golden b/aucoalesce/testdata/sockaddr.log.golden deleted file mode 100644 index 1a06b8d..0000000 --- a/aucoalesce/testdata/sockaddr.log.golden +++ /dev/null @@ -1,55 +0,0 @@ -{ - "@timestamp": "2017-04-12T19:57:42.361Z", - "cwd": "/", - "path": [ - { - "dev": "00:13", - "inode": "6504", - "item": "0", - "mode": "0140777", - "name": "/run/systemd/notify", - "obj_domain": "init_var_run_t", - "obj_level": "s0", - "obj_role": "object_r", - "obj_user": "system_u", - "objtype": "NORMAL", - "ogid": "0", - "ouid": "0", - "rdev": "00:00" - } - ], - "sequence": 1316151, - "sockaddr": { - "address_family": "unix", - "path": "/run/systemd/notify" - }, - "syscall": { - "a0": "14", - "a1": "7ffe911f2610", - "a2": "4000", - "a3": "ffffffffffffffa9", - "arch": "x86_64", - "auid": "unset", - "comm": "systemd-logind", - "egid": "0", - "euid": "0", - "exe": "/usr/lib/systemd/systemd-logind", - "exit": "10", - "fsgid": "0", - "fsuid": "0", - "gid": "0", - "name": "sendmsg", - "pid": "385", - "ppid": "1", - "ses": "4294967295", - "sgid": "0", - "subj_domain": "systemd_logind_t", - "subj_level": "s0", - "subj_role": "system_r", - "subj_user": "system_u", - "success": "yes", - "suid": "0", - "tty": "(none)", - "uid": "0" - } -} diff --git a/aucoalesce/testdata/ubuntu-16.10-linux-4.8.0.json.golden b/aucoalesce/testdata/ubuntu-16.10-linux-4.8.0.json.golden new file mode 100644 index 0000000..09c533c --- /dev/null +++ b/aucoalesce/testdata/ubuntu-16.10-linux-4.8.0.json.golden @@ -0,0 +1,609 @@ +[ + { + "test_name": "ANOM_PROMISCUOUS", + "event": { + "@timestamp": "2017-04-21T00:32:22.981Z", + "sequence": 753, + "category": "anomoly", + "record_type": "anom_promiscuous", + "result": "success", + "session": "1", + "actor": { + "primary": "1001", + "secondary": "0", + "attrs": { + "auid": "1001", + "egid": "0", + "euid": "0", + "fsgid": "0", + "fsuid": "0", + "gid": "0", + "sgid": "0", + "suid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "ens4", + "what": "network-device" + }, + "action": "changed-promiscuous-mode-on-device", + "how": "/sbin/ifconfig", + "data": { + "a0": "4", + "a1": "8914", + "a2": "7ffdaff944b0", + "a3": "0", + "arch": "x86_64", + "auid": "1001", + "comm": "ifconfig", + "dev": "ens4", + "exe": "/sbin/ifconfig", + "exit": "0", + "gid": "0", + "old_prom": "256", + "pid": "1926", + "ppid": "1852", + "proctitle": "ifconfig", + "prom": "0", + "ses": "1", + "syscall": "ioctl", + "tty": "pts0", + "uid": "0" + } + } + }, + { + "test_name": "CONFIG_CHANGE remove rule", + "event": { + "@timestamp": "2017-04-20T23:57:50.795Z", + "sequence": 12517, + "category": "configuration", + "record_type": "config_change", + "result": "success", + "session": "67", + "actor": { + "primary": "1001", + "attrs": { + "auid": "1001" + } + }, + "thing": { + "primary": "remove_rule", + "what": "audit-config" + }, + "action": "changed-audit-configuration", + "key": "container-create", + "data": { + "list": "4", + "op": "remove_rule" + } + } + }, + { + "test_name": "CONFIG_CHANGE update rules", + "event": { + "@timestamp": "2017-04-21T03:01:04.836Z", + "sequence": 8068, + "category": "configuration", + "record_type": "config_change", + "result": "success", + "session": "6", + "actor": { + "primary": "1001", + "attrs": { + "auid": "1001" + } + }, + "thing": { + "primary": "updated_rules", + "what": "audit-config" + }, + "action": "changed-audit-configuration", + "key": "auth", + "data": { + "list": "4", + "op": "updated_rules", + "path": "/etc/gshadow" + } + } + }, + { + "test_name": "EXECVE", + "event": { + "@timestamp": "2017-04-21T05:28:42.985Z", + "sequence": 8972, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "11", + "actor": { + "primary": "1001", + "secondary": "1001", + "attrs": { + "auid": "1001", + "egid": "1002", + "euid": "1001", + "fsgid": "1002", + "fsuid": "1001", + "gid": "1002", + "sgid": "1002", + "suid": "1001", + "uid": "1001" + } + }, + "thing": { + "primary": "/bin/uname", + "secondary": "155", + "what": "file" + }, + "action": "executed", + "how": "/bin/uname", + "key": "user_commands", + "data": { + "a0": "10812c8", + "a1": "1070208", + "a2": "1152008", + "a3": "59a", + "arch": "x86_64", + "argc": "2", + "cmdline": "\"uname\" \"-a\"", + "comm": "uname", + "cwd": "/home/andrew_kroh", + "exe": "/bin/uname", + "exit": "0", + "pid": "10043", + "ppid": "10027", + "proctitle": "uname", + "syscall": "execve", + "tty": "pts0" + }, + "paths": [ + { + "dev": "08:01", + "inode": "155", + "item": "0", + "mode": "0100755", + "name": "/bin/uname", + "nametype": "NORMAL", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + }, + { + "dev": "08:01", + "inode": "1923", + "item": "1", + "mode": "0100755", + "name": "/lib64/ld-linux-x86-64.so.2", + "nametype": "NORMAL", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + } + ] + } + }, + { + "test_name": "NETFILTER_CFG", + "event": { + "@timestamp": "2017-04-20T00:35:20.473Z", + "sequence": 4678, + "category": "configuration", + "record_type": "netfilter_cfg", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "egid": "0", + "euid": "0", + "fsgid": "0", + "fsuid": "0", + "gid": "0", + "sgid": "0", + "suid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "filter", + "what": "firewall" + }, + "action": "loaded-firewall-rule-to", + "how": "/sbin/xtables-multi", + "data": { + "a0": "4", + "a1": "0", + "a2": "40", + "a3": "562bf7914100", + "arch": "x86_64", + "comm": "iptables", + "entries": "7", + "exe": "/sbin/xtables-multi", + "exit": "0", + "family": "2", + "pid": "9709", + "ppid": "9708", + "proctitle": "/sbin/iptables", + "syscall": "setsockopt", + "table": "filter", + "tty": "(none)" + } + } + }, + { + "test_name": "SERVICE_START", + "event": { + "@timestamp": "2017-04-19T18:19:50.183Z", + "sequence": 4083, + "category": "system-services", + "record_type": "service_start", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "uid": "0" + } + }, + "thing": { + "primary": "rsyslog", + "what": "service" + }, + "action": "started-service", + "how": "/lib/systemd/systemd", + "data": { + "comm": "systemd", + "exe": "/lib/systemd/systemd", + "pid": "1", + "unit": "rsyslog" + } + } + }, + { + "test_name": "USER_END", + "event": { + "@timestamp": "2017-04-21T05:17:01.295Z", + "sequence": 8784, + "category": "user-login", + "record_type": "user_end", + "result": "success", + "session": "10", + "actor": { + "primary": "0", + "secondary": "root", + "attrs": { + "auid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "cron", + "what": "user-session" + }, + "action": "ended-session", + "how": "/usr/sbin/cron", + "data": { + "acct": "root", + "exe": "/usr/sbin/cron", + "op": "PAM:session_close", + "pid": "9945", + "terminal": "cron" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "USER_LOGIN failed ssh", + "event": { + "@timestamp": "2017-04-22T21:25:01.818Z", + "sequence": 19955, + "category": "user-login", + "record_type": "user_login", + "result": "fail", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "(invalid user)", + "attrs": { + "auid": "unset", + "uid": "0" + } + }, + "thing": { + "primary": "sshd", + "secondary": "179.38.151.221", + "what": "user-session" + }, + "action": "logged-in", + "how": "/usr/sbin/sshd", + "data": { + "acct": "(invalid user)", + "addr": "179.38.151.221", + "exe": "/usr/sbin/sshd", + "op": "login", + "pid": "12635", + "terminal": "sshd" + } + } + }, + { + "test_name": "USER_LOGIN success", + "event": { + "@timestamp": "2017-04-21T21:39:57.778Z", + "sequence": 12651, + "category": "user-login", + "record_type": "user_login", + "result": "success", + "session": "36", + "actor": { + "primary": "1001", + "secondary": "1001", + "attrs": { + "auid": "1001", + "uid": "0" + } + }, + "thing": { + "primary": "/dev/pts/1", + "secondary": "72.83.230.100", + "what": "user-session" + }, + "action": "logged-in", + "how": "/usr/sbin/sshd", + "data": { + "addr": "72.83.230.100", + "exe": "/usr/sbin/sshd", + "hostname": "72.83.230.100", + "id": "1001", + "op": "login", + "pid": "11396", + "terminal": "/dev/pts/1" + } + } + }, + { + "test_name": "USER_START", + "event": { + "@timestamp": "2017-04-21T05:28:41.165Z", + "sequence": 8955, + "category": "user-login", + "record_type": "user_start", + "result": "success", + "session": "11", + "actor": { + "primary": "1001", + "secondary": "andrew_kroh", + "attrs": { + "auid": "1001", + "uid": "0" + } + }, + "thing": { + "primary": "ssh", + "secondary": "72.83.230.100", + "what": "user-session" + }, + "action": "started-session", + "how": "/usr/sbin/sshd", + "data": { + "acct": "andrew_kroh", + "addr": "72.83.230.100", + "exe": "/usr/sbin/sshd", + "hostname": "72.83.230.100", + "op": "PAM:session_open", + "pid": "9950", + "terminal": "ssh" + } + } + }, + { + "test_name": "accept syscall", + "event": { + "@timestamp": "2017-04-21T05:28:40.441Z", + "sequence": 8832, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "egid": "0", + "euid": "0", + "fsgid": "0", + "fsuid": "0", + "gid": "0", + "sgid": "0", + "suid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "72.83.230.100", + "secondary": "58140", + "what": "socket" + }, + "action": "accepted-connection-from", + "how": "/usr/sbin/sshd", + "key": "net", + "data": { + "a0": "3", + "a1": "7ffd0dc80040", + "a2": "7ffd0dc7ffd0", + "a3": "0", + "arch": "x86_64", + "comm": "sshd", + "exe": "/usr/sbin/sshd", + "exit": "5", + "pid": "1663", + "ppid": "1", + "proctitle": "(sshd)", + "syscall": "accept", + "tty": "(none)" + }, + "socket": { + "addr": "72.83.230.100", + "family": "ipv4", + "port": "58140" + } + } + }, + { + "test_name": "changed-system-time", + "event": { + "@timestamp": "2017-04-21T14:09:35.673Z", + "sequence": 11516, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "112", + "attrs": { + "auid": "unset", + "egid": "116", + "euid": "112", + "fsgid": "116", + "fsuid": "112", + "gid": "116", + "sgid": "116", + "suid": "112", + "uid": "112" + } + }, + "thing": { + "what": "system" + }, + "action": "changed-system-time", + "how": "/usr/sbin/ntpd", + "key": "time-change", + "data": { + "a0": "5614c63c1160", + "a1": "2001", + "a2": "5614c63c1160", + "a3": "0", + "arch": "x86_64", + "comm": "ntpd", + "exe": "/usr/sbin/ntpd", + "exit": "0", + "pid": "1596", + "ppid": "1", + "proctitle": "/usr/sbin/ntpd", + "syscall": "adjtimex", + "tty": "(none)" + } + } + }, + { + "test_name": "connect syscall", + "event": { + "@timestamp": "2017-04-21T05:38:27.096Z", + "sequence": 9004, + "category": "audit-rule", + "record_type": "syscall", + "result": "fail", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "egid": "0", + "euid": "0", + "fsgid": "0", + "fsuid": "0", + "gid": "0", + "sgid": "0", + "suid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "169.254.169.254", + "secondary": "80", + "what": "socket" + }, + "action": "connected-to", + "how": "google_ip_forwa", + "key": "net", + "data": { + "a0": "5", + "a1": "7ffc12ac3ab0", + "a2": "10", + "a3": "4", + "arch": "x86_64", + "comm": "google_ip_forwa", + "exe": "/usr/bin/python3.5", + "exit": "-115", + "pid": "1648", + "ppid": "1", + "proctitle": "(g_daemon)", + "syscall": "connect", + "tty": "(none)" + }, + "socket": { + "addr": "169.254.169.254", + "family": "ipv4", + "port": "80" + } + } + }, + { + "test_name": "listen syscall", + "event": { + "@timestamp": "2017-04-25T12:26:38.373Z", + "sequence": 25922, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "140", + "actor": { + "primary": "1001", + "secondary": "1001", + "attrs": { + "auid": "1001", + "egid": "1002", + "euid": "1001", + "fsgid": "1002", + "fsuid": "1001", + "gid": "1002", + "sgid": "1002", + "suid": "1001", + "uid": "1001" + } + }, + "thing": { + "what": "socket" + }, + "action": "listen-for-connections", + "how": "/lib/systemd/systemd", + "key": "net", + "data": { + "a0": "e", + "a1": "80", + "a2": "20", + "a3": "7ffe900ae940", + "arch": "x86_64", + "comm": "systemd", + "exe": "/lib/systemd/systemd", + "exit": "0", + "pid": "23492", + "ppid": "1", + "proctitle": "(systemd)", + "syscall": "listen", + "tty": "(none)" + } + } + } +] diff --git a/aucoalesce/testdata/ubuntu-16.10-linux-4.8.0.yaml b/aucoalesce/testdata/ubuntu-16.10-linux-4.8.0.yaml new file mode 100644 index 0000000..58c60f0 --- /dev/null +++ b/aucoalesce/testdata/ubuntu-16.10-linux-4.8.0.yaml @@ -0,0 +1,65 @@ +--- +tests: + ANOM_PROMISCUOUS: | + type=ANOM_PROMISCUOUS msg=audit(1492734742.981:753): dev=ens4 prom=0 old_prom=256 auid=1001 uid=0 gid=0 ses=1 + type=SYSCALL msg=audit(1492734742.981:753): arch=c000003e syscall=16 success=yes exit=0 a0=4 a1=8914 a2=7ffdaff944b0 a3=0 items=0 ppid=1852 pid=1926 auid=1001 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="ifconfig" exe="/sbin/ifconfig" key=(null) + type=PROCTITLE msg=audit(1492734742.981:753): proctitle=6966636F6E66696700656E7334002D70726F6D697363 + type=EOE msg=audit(1492734742.981:753): + + EXECVE: | + type=SYSCALL msg=audit(1492752522.985:8972): arch=c000003e syscall=59 success=yes exit=0 a0=10812c8 a1=1070208 a2=1152008 a3=59a items=2 ppid=10027 pid=10043 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=pts0 ses=11 comm="uname" exe="/bin/uname" key="key=user_commands" + type=EXECVE msg=audit(1492752522.985:8972): argc=2 a0="uname" a1="-a" + type=CWD msg=audit(1492752522.985:8972): cwd="/home/andrew_kroh" + type=PATH msg=audit(1492752522.985:8972): item=0 name="/bin/uname" inode=155 dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL + type=PATH msg=audit(1492752522.985:8972): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=1923 dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL + type=PROCTITLE msg=audit(1492752522.985:8972): proctitle=756E616D65002D61 + type=EOE msg=audit(1492752522.985:8972): + + NETFILTER_CFG: | + type=NETFILTER_CFG msg=audit(1492648520.473:4678): table=filter family=2 entries=7 + type=SYSCALL msg=audit(1492648520.473:4678): arch=c000003e syscall=54 success=yes exit=0 a0=4 a1=0 a2=40 a3=562bf7914100 items=0 ppid=9708 pid=9709 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="iptables" exe="/sbin/xtables-multi" key=(null) + type=PROCTITLE msg=audit(1492648520.473:4678): proctitle=2F7362696E2F69707461626C6573002D77002D49007373686775617264002D730034352E37362E3134352E313532002D6A0044524F50 + type=EOE msg=audit(1492648520.473:4678): + + accept syscall: | + type=SYSCALL msg=audit(1492752520.441:8832): arch=c000003e syscall=43 success=yes exit=5 a0=3 a1=7ffd0dc80040 a2=7ffd0dc7ffd0 a3=0 items=0 ppid=1 pid=1663 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="sshd" exe="/usr/sbin/sshd" key="key=net" + type=SOCKADDR msg=audit(1492752520.441:8832): saddr=0200E31C4853E6640000000000000000 + type=PROCTITLE msg=audit(1492752520.441:8832): proctitle="(sshd)" + type=EOE msg=audit(1492752520.441:8832): + + connect syscall: | + type=SYSCALL msg=audit(1492753107.096:9004): arch=c000003e syscall=42 success=no exit=-115 a0=5 a1=7ffc12ac3ab0 a2=10 a3=4 items=0 ppid=1 pid=1648 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="google_ip_forwa" exe="/usr/bin/python3.5" key="key=net" + type=SOCKADDR msg=audit(1492753107.096:9004): saddr=02000050A9FEA9FE0000000000000000 + type=PROCTITLE msg=audit(1492753107.096:9004): proctitle="(g_daemon)" + type=EOE msg=audit(1492753107.096:9004): + + USER_START: | + type=USER_START msg=audit(1492752521.165:8955): pid=9950 uid=0 auid=1001 ses=11 msg='op=PAM:session_open acct="andrew_kroh" exe="/usr/sbin/sshd" hostname=72.83.230.100 addr=72.83.230.100 terminal=ssh res=success' + + USER_END: | + type=USER_END msg=audit(1492751821.295:8784): pid=9945 uid=0 auid=0 ses=10 msg='op=PAM:session_close acct="root" exe="/usr/sbin/cron" hostname=? addr=? terminal=cron res=success' + + SERVICE_START: | + type=SERVICE_START msg=audit(1492625990.183:4083): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=rsyslog comm="systemd" exe="/lib/systemd/systemd" hostname=? addr=? terminal=? res=success + + changed-system-time: | + type=SYSCALL msg=audit(1492783775.673:11516): arch=c000003e syscall=159 success=yes exit=0 a0=5614c63c1160 a1=2001 a2=5614c63c1160 a3=0 items=0 ppid=1 pid=1596 auid=4294967295 uid=112 gid=116 euid=112 suid=112 fsuid=112 egid=116 sgid=116 fsgid=116 tty=(none) ses=4294967295 comm="ntpd" exe="/usr/sbin/ntpd" key="key=time-change" + type=PROCTITLE msg=audit(1492783775.673:11516): proctitle=2F7573722F7362696E2F6E747064002D70002F7661722F72756E2F6E7470642E706964002D67002D63002F7661722F6C69622F6E74702F6E74702E636F6E662E64686370002D75003131323A313136 + type=EOE msg=audit(1492783775.673:11516): + + CONFIG_CHANGE update rules: | + type=CONFIG_CHANGE msg=audit(1492743664.836:8068): auid=1001 ses=6 op="updated_rules" path="/etc/gshadow" key="auth" list=4 res=1 + + CONFIG_CHANGE remove rule: | + type=CONFIG_CHANGE msg=audit(1492732670.795:12517): auid=1001 ses=67 op="remove_rule" key="key=container-create" list=4 res=1 + + USER_LOGIN failed ssh: | + type=USER_LOGIN msg=audit(1492896301.818:19955): pid=12635 uid=0 auid=4294967295 ses=4294967295 msg='op=login acct=28696E76616C6964207573657229 exe="/usr/sbin/sshd" hostname=? addr=179.38.151.221 terminal=sshd res=failed' + + USER_LOGIN success: | + type=USER_LOGIN msg=audit(1492810797.778:12651): pid=11396 uid=0 auid=1001 ses=36 msg='op=login id=1001 exe="/usr/sbin/sshd" hostname=72.83.230.100 addr=72.83.230.100 terminal=/dev/pts/1 res=success' + + listen syscall: | + type=SYSCALL msg=audit(1493123198.373:25922): arch=c000003e syscall=50 success=yes exit=0 a0=e a1=80 a2=20 a3=7ffe900ae940 items=0 ppid=1 pid=23492 auid=1001 uid=1001 gid=1002 euid=1001 suid=1001 fsuid=1001 egid=1002 sgid=1002 fsgid=1002 tty=(none) ses=140 comm="systemd" exe="/lib/systemd/systemd" key="key=net" + type=PROCTITLE msg=audit(1493123198.373:25922): proctitle="(systemd)" + type=EOE msg=audit(1493123198.373:25922): \ No newline at end of file diff --git a/aucoalesce/testdata/ubuntu-17.04-linux-4.10.0.json.golden b/aucoalesce/testdata/ubuntu-17.04-linux-4.10.0.json.golden new file mode 100644 index 0000000..e2c89b3 --- /dev/null +++ b/aucoalesce/testdata/ubuntu-17.04-linux-4.10.0.json.golden @@ -0,0 +1,515 @@ +[ + { + "test_name": "CRED_ACQ", + "event": { + "@timestamp": "2017-04-26T15:17:01.115Z", + "sequence": 21416, + "category": "user-login", + "record_type": "cred_acq", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "root", + "attrs": { + "auid": "unset", + "uid": "0" + } + }, + "thing": { + "primary": "cron", + "what": "user-session" + }, + "action": "acquired-credentials", + "how": "/usr/sbin/cron", + "data": { + "acct": "root", + "exe": "/usr/sbin/cron", + "op": "PAM:setcred", + "pid": "10665", + "terminal": "cron" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "CRED_DISP", + "event": { + "@timestamp": "2017-04-26T14:17:01.101Z", + "sequence": 21264, + "category": "user-login", + "record_type": "cred_disp", + "result": "success", + "session": "38", + "actor": { + "primary": "0", + "secondary": "root", + "attrs": { + "auid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "cron", + "what": "user-session" + }, + "action": "disposed-credentials", + "how": "/usr/sbin/cron", + "data": { + "acct": "root", + "exe": "/usr/sbin/cron", + "op": "PAM:setcred", + "pid": "10631", + "terminal": "cron" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "USER_ACCT", + "event": { + "@timestamp": "2017-04-26T15:17:01.115Z", + "sequence": 21415, + "category": "user-login", + "record_type": "user_acct", + "result": "success", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "root", + "attrs": { + "auid": "unset", + "uid": "0" + } + }, + "thing": { + "primary": "cron", + "what": "user-session" + }, + "action": "was-authorized", + "how": "/usr/sbin/cron", + "data": { + "acct": "root", + "exe": "/usr/sbin/cron", + "op": "PAM:accounting", + "pid": "10665", + "terminal": "cron" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "USER_AUTH", + "event": { + "@timestamp": "2017-04-25T23:24:12.324Z", + "sequence": 18669, + "category": "user-login", + "record_type": "user_auth", + "result": "success", + "session": "1", + "actor": { + "primary": "1001", + "secondary": "root", + "attrs": { + "auid": "1001", + "uid": "0" + } + }, + "thing": { + "primary": "/dev/pts/0", + "what": "user-session" + }, + "action": "authenticated", + "how": "/bin/su", + "data": { + "acct": "root", + "exe": "/bin/su", + "op": "PAM:authentication", + "pid": "9730", + "terminal": "/dev/pts/0" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "USER_CHAUTHTOK failed", + "event": { + "@timestamp": "2017-04-26T16:40:50.928Z", + "sequence": 21878, + "category": "user-login", + "record_type": "user_chauthtok", + "result": "fail", + "session": "41", + "actor": { + "primary": "1001", + "secondary": "akroh", + "attrs": { + "auid": "1001", + "uid": "1002" + } + }, + "thing": { + "primary": "pts/0", + "what": "user-session" + }, + "action": "changed-password", + "how": "/usr/bin/passwd", + "data": { + "acct": "akroh", + "exe": "/usr/bin/passwd", + "op": "PAM:chauthtok", + "pid": "10829", + "terminal": "pts/0" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "USER_CMD", + "event": { + "@timestamp": "2017-04-25T23:24:12.304Z", + "sequence": 18662, + "category": "user-space", + "record_type": "user_cmd", + "result": "success", + "session": "1", + "actor": { + "primary": "1001", + "secondary": "1001", + "attrs": { + "auid": "1001", + "uid": "1001" + } + }, + "thing": { + "primary": "su", + "what": "process" + }, + "action": "ran-command", + "data": { + "cmd": "su", + "cwd": "/home/andrew_kroh", + "pid": "9729", + "terminal": "pts/0" + } + } + }, + { + "test_name": "USER_END", + "event": { + "@timestamp": "2017-04-26T14:17:01.105Z", + "sequence": 21265, + "category": "user-login", + "record_type": "user_end", + "result": "success", + "session": "38", + "actor": { + "primary": "0", + "secondary": "root", + "attrs": { + "auid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "cron", + "what": "user-session" + }, + "action": "ended-session", + "how": "/usr/sbin/cron", + "data": { + "acct": "root", + "exe": "/usr/sbin/cron", + "op": "PAM:session_close", + "pid": "10631", + "terminal": "cron" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "USER_ERR", + "event": { + "@timestamp": "2017-04-26T15:16:59.739Z", + "sequence": 21413, + "category": "user-login", + "record_type": "user_err", + "result": "fail", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "0", + "attrs": { + "auid": "unset", + "uid": "0" + } + }, + "thing": { + "primary": "ssh", + "secondary": "185.56.82.22", + "what": "user-session" + }, + "action": "error", + "how": "/usr/sbin/sshd", + "data": { + "addr": "185.56.82.22", + "exe": "/usr/sbin/sshd", + "hostname": "185.56.82.22", + "op": "PAM:bad_ident", + "pid": "10663", + "terminal": "ssh" + } + } + }, + { + "test_name": "USER_LOGIN", + "event": { + "@timestamp": "2017-04-26T14:14:10.975Z", + "sequence": 21203, + "category": "user-login", + "record_type": "user_login", + "result": "fail", + "session": "unset", + "actor": { + "primary": "unset", + "secondary": "(invalid user)", + "attrs": { + "auid": "unset", + "uid": "0" + } + }, + "thing": { + "primary": "sshd", + "secondary": "31.207.47.36", + "what": "user-session" + }, + "action": "logged-in", + "how": "/usr/sbin/sshd", + "data": { + "acct": "(invalid user)", + "addr": "31.207.47.36", + "exe": "/usr/sbin/sshd", + "op": "login", + "pid": "10617", + "terminal": "sshd" + } + } + }, + { + "test_name": "USER_START", + "event": { + "@timestamp": "2017-04-26T15:17:01.115Z", + "sequence": 21419, + "category": "user-login", + "record_type": "user_start", + "result": "success", + "session": "39", + "actor": { + "primary": "0", + "secondary": "root", + "attrs": { + "auid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "cron", + "what": "user-session" + }, + "action": "started-session", + "how": "/usr/sbin/cron", + "data": { + "acct": "root", + "exe": "/usr/sbin/cron", + "op": "PAM:session_open", + "pid": "10665", + "terminal": "cron" + } + }, + "warnings": [ + "failed to set object secondary using keys=[addr hostname] because they were not found" + ] + }, + { + "test_name": "rename syscall", + "event": { + "@timestamp": "2017-04-25T13:05:24.089Z", + "sequence": 126, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "5", + "actor": { + "primary": "1001", + "secondary": "0", + "attrs": { + "auid": "1001", + "egid": "0", + "euid": "0", + "fsgid": "0", + "fsuid": "0", + "gid": "0", + "sgid": "0", + "suid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "/etc/audit/rules.d/audit.rules", + "secondary": "271112", + "what": "file" + }, + "action": "renamed", + "how": "/usr/bin/vim.basic", + "key": "auditconfig", + "data": { + "a0": "55942f993060", + "a1": "55942fb79090", + "a2": "fffffffffffffeb0", + "a3": "55942fb79090", + "arch": "x86_64", + "comm": "vim", + "cwd": "/home/andrew_kroh", + "exe": "/usr/bin/vim.basic", + "exit": "0", + "pid": "3231", + "ppid": "3207", + "proctitle": "vim", + "syscall": "rename", + "tty": "pts1" + }, + "paths": [ + { + "dev": "08:01", + "inode": "271071", + "item": "0", + "mode": "040750", + "name": "/etc/audit/rules.d/", + "nametype": "PARENT", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + }, + { + "dev": "08:01", + "inode": "271071", + "item": "1", + "mode": "040750", + "name": "/etc/audit/rules.d/", + "nametype": "PARENT", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + }, + { + "dev": "08:01", + "inode": "271112", + "item": "2", + "mode": "0100640", + "name": "/etc/audit/rules.d/audit.rules", + "nametype": "DELETE", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + }, + { + "dev": "08:01", + "inode": "271112", + "item": "3", + "mode": "0100640", + "name": "/etc/audit/rules.d/audit.rules~", + "nametype": "CREATE", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + } + ] + } + }, + { + "test_name": "unlink syscall", + "event": { + "@timestamp": "2017-04-25T14:09:15.852Z", + "sequence": 624, + "category": "audit-rule", + "record_type": "syscall", + "result": "success", + "session": "5", + "actor": { + "primary": "1001", + "secondary": "0", + "attrs": { + "auid": "1001", + "egid": "0", + "euid": "0", + "fsgid": "0", + "fsuid": "0", + "gid": "0", + "sgid": "0", + "suid": "0", + "uid": "0" + } + }, + "thing": { + "primary": "/etc/audit/rules.d/.audit.rules.swp", + "secondary": "271044", + "what": "file" + }, + "action": "deleted", + "how": "/usr/bin/vim.basic", + "key": "auditconfig", + "data": { + "a0": "55faa178f800", + "a1": "1", + "a2": "1", + "a3": "7ffd21b026d0", + "arch": "x86_64", + "comm": "vim", + "cwd": "/home/andrew_kroh", + "exe": "/usr/bin/vim.basic", + "exit": "0", + "pid": "3346", + "ppid": "3309", + "proctitle": "vim", + "syscall": "unlink", + "tty": "pts1" + }, + "paths": [ + { + "dev": "08:01", + "inode": "271071", + "item": "0", + "mode": "040750", + "name": "/etc/audit/rules.d/", + "nametype": "PARENT", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + }, + { + "dev": "08:01", + "inode": "271044", + "item": "1", + "mode": "0100640", + "name": "/etc/audit/rules.d/.audit.rules.swp", + "nametype": "DELETE", + "ogid": "0", + "ouid": "0", + "rdev": "00:00" + } + ] + } + } +] diff --git a/aucoalesce/testdata/ubuntu-17.04-linux-4.10.0.yaml b/aucoalesce/testdata/ubuntu-17.04-linux-4.10.0.yaml new file mode 100644 index 0000000..0fa879b --- /dev/null +++ b/aucoalesce/testdata/ubuntu-17.04-linux-4.10.0.yaml @@ -0,0 +1,49 @@ +--- +tests: + unlink syscall: | + type=SYSCALL msg=audit(1493129355.852:624): arch=c000003e syscall=87 success=yes exit=0 a0=55faa178f800 a1=1 a2=1 a3=7ffd21b026d0 items=2 ppid=3309 pid=3346 auid=1001 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=5 comm="vim" exe="/usr/bin/vim.basic" key="auditconfig" + type=CWD msg=audit(1493129355.852:624): cwd="/home/andrew_kroh" + type=PATH msg=audit(1493129355.852:624): item=0 name="/etc/audit/rules.d/" inode=271071 dev=08:01 mode=040750 ouid=0 ogid=0 rdev=00:00 nametype=PARENT + type=PATH msg=audit(1493129355.852:624): item=1 name="/etc/audit/rules.d/.audit.rules.swp" inode=271044 dev=08:01 mode=0100640 ouid=0 ogid=0 rdev=00:00 nametype=DELETE + type=PROCTITLE msg=audit(1493129355.852:624): proctitle=76696D002F6574632F61756469742F72756C65732E642F61756469742E72756C6573 + type=EOE msg=audit(1493129355.852:624): + + rename syscall: | + type=SYSCALL msg=audit(1493125524.089:126): arch=c000003e syscall=82 success=yes exit=0 a0=55942f993060 a1=55942fb79090 a2=fffffffffffffeb0 a3=55942fb79090 items=4 ppid=3207 pid=3231 auid=1001 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=5 comm="vim" exe="/usr/bin/vim.basic" key="auditconfig" + type=CWD msg=audit(1493125524.089:126): cwd="/home/andrew_kroh" + type=PATH msg=audit(1493125524.089:126): item=0 name="/etc/audit/rules.d/" inode=271071 dev=08:01 mode=040750 ouid=0 ogid=0 rdev=00:00 nametype=PARENT + type=PATH msg=audit(1493125524.089:126): item=1 name="/etc/audit/rules.d/" inode=271071 dev=08:01 mode=040750 ouid=0 ogid=0 rdev=00:00 nametype=PARENT + type=PATH msg=audit(1493125524.089:126): item=2 name="/etc/audit/rules.d/audit.rules" inode=271112 dev=08:01 mode=0100640 ouid=0 ogid=0 rdev=00:00 nametype=DELETE + type=PATH msg=audit(1493125524.089:126): item=3 name="/etc/audit/rules.d/audit.rules~" inode=271112 dev=08:01 mode=0100640 ouid=0 ogid=0 rdev=00:00 nametype=CREATE + type=PROCTITLE msg=audit(1493125524.089:126): proctitle=76696D002F6574632F61756469742F72756C65732E642F61756469742E72756C6573 + type=EOE msg=audit(1493125524.089:126): + + USER_CMD: | + type=USER_CMD msg=audit(1493162652.304:18662): pid=9729 uid=1001 auid=1001 ses=1 msg='cwd="/home/andrew_kroh" cmd="su" terminal=pts/0 res=success' + + USER_ACCT: | + type=USER_ACCT msg=audit(1493219821.115:21415): pid=10665 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:accounting acct="root" exe="/usr/sbin/cron" hostname=? addr=? terminal=cron res=success' + + USER_AUTH: | + type=USER_AUTH msg=audit(1493162652.324:18669): pid=9730 uid=0 auid=1001 ses=1 msg='op=PAM:authentication acct="root" exe="/bin/su" hostname=? addr=? terminal=/dev/pts/0 res=success' + + USER_START: | + type=USER_START msg=audit(1493219821.115:21419): pid=10665 uid=0 auid=0 ses=39 msg='op=PAM:session_open acct="root" exe="/usr/sbin/cron" hostname=? addr=? terminal=cron res=success' + + CRED_ACQ: | + type=CRED_ACQ msg=audit(1493219821.115:21416): pid=10665 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:setcred acct="root" exe="/usr/sbin/cron" hostname=? addr=? terminal=cron res=success' + + USER_ERR: | + type=USER_ERR msg=audit(1493219819.739:21413): pid=10663 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:bad_ident acct="?" exe="/usr/sbin/sshd" hostname=185.56.82.22 addr=185.56.82.22 terminal=ssh res=failed' + + USER_END: | + type=USER_END msg=audit(1493216221.105:21265): pid=10631 uid=0 auid=0 ses=38 msg='op=PAM:session_close acct="root" exe="/usr/sbin/cron" hostname=? addr=? terminal=cron res=success' + + CRED_DISP: | + type=CRED_DISP msg=audit(1493216221.101:21264): pid=10631 uid=0 auid=0 ses=38 msg='op=PAM:setcred acct="root" exe="/usr/sbin/cron" hostname=? addr=? terminal=cron res=success' + + USER_LOGIN: | + type=USER_LOGIN msg=audit(1493216050.975:21203): pid=10617 uid=0 auid=4294967295 ses=4294967295 msg='op=login acct=28696E76616C6964207573657229 exe="/usr/sbin/sshd" hostname=? addr=31.207.47.36 terminal=sshd res=failed' + + USER_CHAUTHTOK failed: | + type=USER_CHAUTHTOK msg=audit(1493224850.928:21878): pid=10829 uid=1002 auid=1001 ses=41 msg='op=PAM:chauthtok acct="akroh" exe="/usr/bin/passwd" hostname=? addr=? terminal=pts/0 res=failed' diff --git a/aucoalesce/znormalize_data.go b/aucoalesce/znormalize_data.go new file mode 100644 index 0000000..0276788 --- /dev/null +++ b/aucoalesce/znormalize_data.go @@ -0,0 +1,40 @@ +// mknormalize_data.go +// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT + +// Copyright 2017 Elasticsearch Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aucoalesce + +import ( + "encoding/base64" + "fmt" +) + +var assets map[string][]byte + +func asset(key string) ([]byte, error) { + if assets == nil { + assets = map[string][]byte{} + + var value []byte + value, _ = base64.StdEncoding.DecodeString("LS0tCiMgTWFjcm9zIGRlY2xhcmVzIHNvbWUgWUFNTCBhbmNob3JzIHRoYXQgY2FuIGJlIHJlZmVyZW5jZWQgZm9yIHNvbWUgY29tbW9uCiMgb2JqZWN0IHR5cGUgbm9ybWFsaXphdGlvbnMgbGlrZSB1c2VyLXNlc3Npb24sIHNvY2tldCwgb3IgcHJvY2Vzcy4KbWFjcm9zOgotICZkZWZhdWx0cwogIHN1YmplY3Q6CiAgICBwcmltYXJ5OiBhdWlkCiAgICBzZWNvbmRhcnk6IHVpZAogIGhvdzogW2V4ZSwgY29tbV0KCi0gJm1hY3JvLXVzZXItc2Vzc2lvbgogIHN1YmplY3Q6CiAgICBwcmltYXJ5OiBhdWlkCiAgICBzZWNvbmRhcnk6IFthY2N0LCBpZCwgdWlkXQogIG9iamVjdDoKICAgIHByaW1hcnk6IHRlcm1pbmFsCiAgICBzZWNvbmRhcnk6IFthZGRyLCBob3N0bmFtZV0KICAgIHdoYXQ6IHVzZXItc2Vzc2lvbgogIGhvdzogW2V4ZSwgdGVybWluYWxdCgotICZtYWNyby1zb2NrZXQKICA8PDogKmRlZmF1bHRzCiAgb2JqZWN0OgogICAgcHJpbWFyeTogW2FkZHIsIHBhdGhdCiAgICBzZWNvbmRhcnk6IHBvcnQKICAgIHdoYXQ6IHNvY2tldAoKLSAmbWFjcm8tcHJvY2VzcwogIDw8OiAqZGVmYXVsdHMKICBvYmplY3Q6CiAgICBwcmltYXJ5OiBbY21kLCBleGUsIGNvbW1dCiAgICBzZWNvbmRhcnk6IHBpZAogICAgd2hhdDogcHJvY2VzcwogIGhvdzogdGVybWluYWwKCiMgTm9ybWFsaXphdGlvbnMgaXMgYSBsaXN0IG9mIGRlY2xhcmF0aW9ucyBzcGVjaWZ5aW5nIGhvdyB0byBub3JtYWxpemUgdGhlIGRhdGEKIyBjb250YWluZWQgaW4gYW4gZXZlbnQuIFRoZSBub3JtYWxpemF0aW9uIGNhbiBiZSBhcHBsaWVkIGJhc2VkIG9uIHRoZSBzeXNjYWxsCiMgbmFtZSAoZS5nLiBjb25uZWN0LCBvcGVuKSBvciBiYXNlZCBvbiB0aGUgcmVjb3JkIHR5cGUgKGUuZy4gVVNFUl9MT0dJTikuCiMgTm8gdHdvIG5vcm1hbGl6YXRpb25zIGNhbiBhcHBseSB0byB0aGUgc2FtZSBzeXNjYWxsIG9yIHJlY29yZCB0eXBlLiBUaGlzCiMgd2lsbCByZXN1bHQgaW4gYSBmYWlsdXJlIGF0IGxvYWQgdGltZS4KIwojIEVhY2ggbm9ybWFsaXphdGlvbiBzaG91bGQgc3BlY2lmeToKIyAgIGFjdGlvbiAtIHdoYXQgaGFwcGVuZWQKIyAgIGFjdG9yICAtIHdobyBkaWQgdGhpcyBvciB3aG8gdHJpZ2dlcmVkIHRoZSBldmVudAojICAgb2JqZWN0IC0gd2hhdCB3YXMgdGhlICJ0aGluZyIgaW52b2x2ZWQgaW4gdGhlIGFjdGlvbiAoZS5nLiBwcm9jZXNzLCBzb2NrZXQpCiMgICBob3cgICAgLSBob3cgd2FzIHRoZSBhY3Rpb24gcGVyZm9ybWVkIChlLmcuIGV4ZSBvciB0ZXJtaW5hbCkKbm9ybWFsaXphdGlvbnM6Ci0KICBhY3Rpb246IG9wZW5lZC1maWxlCiAgb2JqZWN0OgogICAgd2hhdDogZmlsZQogIHN5c2NhbGxzOgogIC0gY3JlYXQKICAtIGZhbGxvY2F0ZQogIC0gdHJ1bmNhdGUKICAtIGZ0cnVuY2F0ZQogIC0gb3BlbgogIC0gb3BlbmF0CiAgLSByZWFkbGluawogIC0gcmVhZGxpbmthdAotCiAgYWN0aW9uOiBjaGFuZ2VkLWZpbGUtYXR0cmlidXRlcy1vZgogIG9iamVjdDoKICAgIHdoYXQ6IGZpbGUKICBzeXNjYWxsczoKICAtIHNldHhhdHRyCiAgLSBmc2V0eGF0dHIKICAtIGxzZXR4YXR0cgogIC0gcmVtb3ZleGF0dHIKICAtIGZyZW1vdmV4YXR0cgogIC0gbHJlbW92ZXhhdHRyCi0KICBhY3Rpb246IGNoYW5nZWQtZmlsZS1wZXJtaXNzaW9ucy1vZgogIG9iamVjdDoKICAgIHdoYXQ6IGZpbGUKICBzeXNjYWxsczoKICAtIGNobW9kCiAgLSBmY2htb2QKICAtIGZjaG1vZGF0Ci0KICBhY3Rpb246IGNoYW5nZWQtZmlsZS1vd25lcnNoaXAtb2YKICBvYmplY3Q6CiAgICB3aGF0OiBmaWxlCiAgc3lzY2FsbHM6CiAgLSBjaG93bgogIC0gZmNob3duCiAgLSBmY2hvd25hdAogIC0gbGNob3duCi0KICBhY3Rpb246IGxvYWRlZC1rZXJuZWwtbW9kdWxlCiAgb2JqZWN0OgogICAgd2hhdDogZmlsZQogICAgcHJpbWFyeTogbmFtZQogIHJlY29yZF90eXBlczoKICAtIEtFUk5fTU9EVUxFCiAgc3lzY2FsbHM6CiAgLSBmaW5pdF9tb2R1bGUKICAtIGluaXRfbW9kdWxlCi0KICBhY3Rpb246IHVubG9hZGVkLWtlcm5lbC1tb2R1bGUKICBvYmplY3Q6CiAgICB3aGF0OiBmaWxlCiAgc3lzY2FsbHM6CiAgLSBkZWxldGVfbW9kdWxlCi0KICBhY3Rpb246IGNyZWF0ZWQtZGlyZWN0b3J5CiAgb2JqZWN0OgogICAgd2hhdDogZmlsZQogICAgcGF0aF9pbmRleDogMQogIHN5c2NhbGxzOgogIC0gbWtkaXIKICAtIG1rZGlyYXQKLQogIGFjdGlvbjogbW91bnRlZAogIG9iamVjdDoKICAgIHdoYXQ6IGZpbGVzeXN0ZW0KICAgIHBhdGhfaW5kZXg6IDEKICBzeXNjYWxsczoKICAtIG1vdW50Ci0KICBhY3Rpb246IHJlbmFtZWQKICBvYmplY3Q6CiAgICB3aGF0OiBmaWxlCiAgICBwYXRoX2luZGV4OiAyCiAgc3lzY2FsbHM6CiAgLSByZW5hbWUKICAtIHJlbmFtZWF0CiAgLSByZW5hbWVhdDIKLQogIGFjdGlvbjogY2hlY2tlZC1tZXRhZGF0YS1vZgogIG9iamVjdDoKICAgIHdoYXQ6IGZpbGUKICBzeXNjYWxsczoKICAtIGFjY2VzcwogIC0gZmFjY2Vzc2F0CiAgLSBuZXdmc3RhdGF0CiAgLSBzdGF0CiAgLSBmc3RhdAogIC0gbHN0YXQKICAtIHN0YXQ2NAogIC0gZ2V0eGF0dHIKICAtIGxnZXR4YXR0cgogIC0gZmdldHhhdHRyCi0KICBhY3Rpb246IGNoZWNrZWQtZmlsZXN5c3RlbS1tZXRhZGF0YS1vZgogIG9iamVjdDoKICAgIHdoYXQ6IGZpbGVzeXN0ZW0KICBzeXNjYWxsczoKICAtIHN0YXRmcwogIC0gZnN0YXRmcwotCiAgYWN0aW9uOiBzeW1saW5rZWQKICBvYmplY3Q6CiAgICB3aGF0OiBmaWxlCiAgc3lzY2FsbHM6CiAgLSBzeW1saW5rCiAgLSBzeW1saW5rYXQKLQogIGFjdGlvbjogdW5tb3VudGVkCiAgb2JqZWN0OgogICAgd2hhdDogZmlsZXN5c3RlbQogIHN5c2NhbGxzOgogIC0gdW1vdW50MgotCiAgYWN0aW9uOiBkZWxldGVkCiAgb2JqZWN0OgogICAgd2hhdDogZmlsZQogIHN5c2NhbGxzOgogIC0gcm1kaXIKICAtIHVubGluawogIC0gdW5saW5rYXQKLQogIGFjdGlvbjogY2hhbmdlZC10aW1lc3RhbXAtb2YKICBvYmplY3Q6CiAgICB3aGF0OiBmaWxlCiAgc3lzY2FsbHM6CiAgLSB1dGltZQogIC0gdXRpbWVzCiAgLSBmdXRpbWVzYXQKICAtIGZ1dGltZW5zCiAgLSB1dGltZW5zYXQKLQogIGFjdGlvbjogZXhlY3V0ZWQKICBvYmplY3Q6CiAgICB3aGF0OiBmaWxlCiAgc3lzY2FsbHM6CiAgLSBleGVjdmUKICAtIGV4ZWN2ZWF0Ci0KICBhY3Rpb246IGxpc3Rlbi1mb3ItY29ubmVjdGlvbnMKICBvYmplY3Q6CiAgICB3aGF0OiBzb2NrZXQKICBzeXNjYWxsczoKICAtIGxpc3RlbgotCiAgYWN0aW9uOiBhY2NlcHRlZC1jb25uZWN0aW9uLWZyb20KICBvYmplY3Q6CiAgICB3aGF0OiBzb2NrZXQKICBzeXNjYWxsczoKICAtIGFjY2VwdAogIC0gYWNjZXB0NAotCiAgYWN0aW9uOiBib3VuZC1zb2NrZXQKICBvYmplY3Q6CiAgICB3aGF0OiBzb2NrZXQKICBzeXNjYWxsczoKICAtIGJpbmQKLQogIGFjdGlvbjogY29ubmVjdGVkLXRvCiAgb2JqZWN0OgogICAgd2hhdDogc29ja2V0CiAgc3lzY2FsbHM6CiAgLSBjb25uZWN0Ci0KICBhY3Rpb246IHJlY2VpdmVkLWZyb20KICBvYmplY3Q6CiAgICB3aGF0OiBzb2NrZXQKICBzeXNjYWxsczoKICAtIHJlY3Zmcm9tCiAgLSByZWN2bXNnCi0KICBhY3Rpb246IHNlbnQtdG8KICBvYmplY3Q6CiAgICB3aGF0OiBzb2NrZXQKICBzeXNjYWxsczoKICAtIHNlbmR0bwogIC0gc2VuZG1zZwotCiAgYWN0aW9uOiBraWxsZWQtcGlkCiAgb2JqZWN0OgogICAgd2hhdDogcHJvY2VzcwogIHN5c2NhbGxzOgogIC0ga2lsbAogIC0gdGtpbGwKICAtIHRna2lsbAotCiAgYWN0aW9uOiBjaGFuZ2VkLWlkZW50aXR5LW9mCiAgb2JqZWN0OgogICAgd2hhdDogcHJvY2VzcwogIGhvdzogc3lzY2FsbAogIHN5c2NhbGxzOgogIC0gc2V0dWlkCiAgLSBzZXRldWlkCiAgLSBzZXRmc3VpZAogIC0gc2V0cmV1aWQKICAtIHNldHJlc3VpZAogIC0gc2V0Z2lkCiAgLSBzZXRlZ2lkCiAgLSBzZXRmc2dpZAogIC0gc2V0cmVnaWQKICAtIHNldHJlc2dpZAotCiAgYWN0aW9uOiBjaGFuZ2VkLXN5c3RlbS10aW1lCiAgb2JqZWN0OgogICAgd2hhdDogc3lzdGVtCiAgc3lzY2FsbHM6CiAgLSBzZXR0aW1lb2ZkYXkKICAtIGNsb2NrX3NldHRpbWUKICAtIHN0aW1lCiAgLSBhZGp0aW1leAotCiAgYWN0aW9uOiBtYWtlLWRldmljZQogIG9iamVjdDoKICAgIHdoYXQ6IGZpbGUKICBzeXNjYWxsczoKICAtIG1rbm9kCiAgLSBta25vZGF0Ci0KICBhY3Rpb246IGNoYW5nZWQtc3lzdGVtLW5hbWUKICBvYmplY3Q6CiAgICB3aGF0OiBzeXN0ZW0KICBzeXNjYWxsczoKICAtIHNldGhvc3RuYW1lCiAgLSBzZXRkb21haW5uYW1lCi0KICBhY3Rpb246IGFsbG9jYXRlZC1tZW1vcnkKICBvYmplY3Q6CiAgICB3aGF0OiBtZW1vcnkKICBzeXNjYWxsczoKICAtIG1tYXAKICAtIGJyawotCiAgYWN0aW9uOiBhZGp1c3RlZC1zY2hlZHVsaW5nLXBvbGljeS1vZgogIG9iamVjdDoKICAgIHdoYXQ6IHByb2Nlc3MKICBob3c6IHN5c2NhbGwKICBzeXNjYWxsczoKICAtIHNjaGVkX3NldHBhcmFtCiAgLSBzY2hlZF9zZXRzY2hlZHVsZXIKICAtIHNjaGVkX3NldGF0dHIKLQogIGFjdGlvbjogY2F1c2VkLW1hYy1wb2xpY3ktZXJyb3IKICBvYmplY3Q6CiAgICB3aGF0OiBzeXN0ZW0KICByZWNvcmRfdHlwZXM6IFNFTElOVVhfRVJSCi0KICBhY3Rpb246IGxvYWRlZC1maXJld2FsbC1ydWxlLXRvCiAgb2JqZWN0OgogICAgcHJpbWFyeTogdGFibGUKICAgIHdoYXQ6IGZpcmV3YWxsCiAgcmVjb3JkX3R5cGVzOiBORVRGSUxURVJfQ0ZHCi0KICAjIENvdWxkIGJlIGVudGVyZWQgb3IgZXhpdGVkIGJhc2VkIG9uIHByb20gZmllbGQuCiAgYWN0aW9uOiBjaGFuZ2VkLXByb21pc2N1b3VzLW1vZGUtb24tZGV2aWNlCiAgb2JqZWN0OgogICAgcHJpbWFyeTogZGV2CiAgICB3aGF0OiBuZXR3b3JrLWRldmljZQogIHJlY29yZF90eXBlczogQU5PTV9QUk9NSVNDVU9VUwotCiAgYWN0aW9uOiBsb2NrZWQtYWNjb3VudAogIHJlY29yZF90eXBlczogQUNDVF9MT0NLCi0KICBhY3Rpb246IHVubG9ja2VkLWFjY291bnQKICByZWNvcmRfdHlwZXM6IEFDQ1RfVU5MT0NLCi0KICBhY3Rpb246IGFkZGVkLWdyb3VwLWFjY291bnQtdG8KICBvYmplY3Q6CiAgICBwcmltYXJ5OiBbaWQsIGFjY3RdCiAgICB3aGF0OiBhY2NvdW50CiAgcmVjb3JkX3R5cGVzOiBBRERfR1JPVVAKLQogIGFjdGlvbjogYWRkZWQtdXNlci1hY2NvdW50CiAgb2JqZWN0OgogICAgcHJpbWFyeTogW2lkLCBhY2N0XQogICAgd2hhdDogYWNjb3VudAogIHJlY29yZF90eXBlczogQUREX1VTRVIKLQogIGFjdGlvbjogY3Jhc2hlZC1wcm9ncmFtCiAgb2JqZWN0OgogICAgcHJpbWFyeTogW2NvbW0sIGV4ZV0KICAgIHNlY29uZGFyeTogcGlkCiAgICB3aGF0OiBwcm9jZXNzCiAgaG93OiBzaWcKICByZWNvcmRfdHlwZXM6IEFOT01fQUJFTkQKLQogIGFjdGlvbjogYXR0ZW1wdGVkLWV4ZWN1dGlvbi1vZi1mb3JiaWRkZW4tcHJvZ3JhbQogIG9iamVjdDoKICAgIHByaW1hcnk6IGNtZAogICAgd2hhdDogcHJvY2VzcwogIGhvdzogdGVybWluYWwKICByZWNvcmRfdHlwZXM6IEFOT01fRVhFQwotCiAgYWN0aW9uOiB1c2VkLXN1c3BjaW91cy1saW5rCiAgcmVjb3JkX3R5cGVzOiBBTk9NX0xJTksKLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiBmYWlsZWQtbG9nLWluLXRvby1tYW55LXRpbWVzLXRvCiAgcmVjb3JkX3R5cGVzOiBBTk9NX0xPR0lOX0ZBSUxVUkVTCi0KICA8PDogKm1hY3JvLXVzZXItc2Vzc2lvbgogIGFjdGlvbjogYXR0ZW1wdGVkLWxvZy1pbi1mcm9tLXVudXN1YWwtcGxhY2UtdG8KICByZWNvcmRfdHlwZXM6IEFOT01fTE9HSU5fTE9DQVRJT04KLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiBvcGVuZWQtdG9vLW1hbnktc2Vzc2lvbnMtdG8KICByZWNvcmRfdHlwZXM6IEFOT01fTE9HSU5fU0VTU0lPTlMKLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiBhdHRlbXB0ZWQtbG9nLWluLWR1cmluZy11bnVzdWFsLWhvdXItdG8KICByZWNvcmRfdHlwZXM6IEFOT01fTE9HSU5fVElNRQotCiAgYWN0aW9uOiB0ZXN0ZWQtZmlsZS1zeXN0ZW0taW50ZWdyaXR5LW9mCiAgb2JqZWN0OgogICAgcHJpbWFyeTogaG9zdG5hbWUKICAgIHdoYXQ6IGZpbGVzeXN0ZW0KICByZWNvcmRfdHlwZXM6IEFOT01fUkJBQ19JTlRFR1JJVFlfRkFJTAotCiAgYWN0aW9uOiB2aW9sYXRlZC1zZWxpbnV4LXBvbGljeQogIHN1YmplY3Q6CiAgICBwcmltYXJ5OiBzY29udGV4dAogIG9iamVjdDoKICAgIHByaW1hcnk6IHRjb250ZXh0CiAgcmVjb3JkX3R5cGVzOiBBVkMKLQogIGFjdGlvbjogY2hhbmdlZC1ncm91cAogIHJlY29yZF90eXBlczogQ0hHUlBfSUQKLQogIGFjdGlvbjogY2hhbmdlZC11c2VyLWlkCiAgcmVjb3JkX3R5cGVzOiBDSFVTRVJfSUQKLQogIGFjdGlvbjogY2hhbmdlZC1hdWRpdC1jb25maWd1cmF0aW9uCiAgb2JqZWN0OgogICAgcHJpbWFyeTogW29wLCBrZXksIGF1ZGl0X2VuYWJsZWQsIGF1ZGl0X3BpZCwgYXVkaXRfYmFja2xvZ19saW1pdCwgYXVkaXRfZmFpbHVyZV0KICAgIHdoYXQ6IGF1ZGl0LWNvbmZpZwogIHJlY29yZF90eXBlczogQ09ORklHX0NIQU5HRQotCiAgPDw6ICptYWNyby11c2VyLXNlc3Npb24KICBhY3Rpb246IGFjcXVpcmVkLWNyZWRlbnRpYWxzCiAgcmVjb3JkX3R5cGVzOiBDUkVEX0FDUQotCiAgPDw6ICptYWNyby11c2VyLXNlc3Npb24KICBhY3Rpb246IGRpc3Bvc2VkLWNyZWRlbnRpYWxzCiAgcmVjb3JkX3R5cGVzOiBDUkVEX0RJU1AKLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiByZWZyZXNoZWQtY3JlZGVudGlhbHMKICByZWNvcmRfdHlwZXM6IENSRURfUkVGUgotCiAgPDw6ICptYWNyby11c2VyLXNlc3Npb24KICBhY3Rpb246IG5lZ290aWF0ZWQtY3J5cHRvLWtleQogIG9iamVjdDoKICAgIHByaW1hcnk6IGZwCiAgICBzZWNvbmRhcnk6IFthZGRyLCBob3N0bmFtZV0KICAgIHdoYXQ6IHVzZXItc2Vzc2lvbgogIHJlY29yZF90eXBlczogQ1JZUFRPX0tFWV9VU0VSCi0KICBhY3Rpb246IGNyeXB0by1vZmZpY2VyLWxvZ2dlZC1pbgogIHJlY29yZF90eXBlczogQ1JZUFRPX0xPR0lOCi0KICBhY3Rpb246IGNyeXB0by1vZmZpY2VyLWxvZ2dlZC1vdXQKICByZWNvcmRfdHlwZXM6IENSWVBUT19MT0dPVVQKLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiBzdGFydGVkLWNyeXB0by1zZXNzaW9uCiAgb2JqZWN0OgogICAgcHJpbWFyeTogYWRkcgogICAgc2Vjb25kYXJ5OiBbcnBvcnRdCiAgcmVjb3JkX3R5cGVzOiBDUllQVE9fU0VTU0lPTgotCiAgYWN0aW9uOiBhY2Nlc3MtcmVzdWx0CiAgcmVjb3JkX3R5cGVzOiBEQUNfQ0hFQ0sKLQogIGFjdGlvbjogYWJvcnRlZC1hdWRpdGQtc3RhcnR1cAogIG9iamVjdDoKICAgIHdoYXQ6IHNlcnZpY2UKICByZWNvcmRfdHlwZXM6IERBRU1PTl9BQk9SVAotCiAgYWN0aW9uOiByZW1vdGUtYXVkaXQtY29ubmVjdGVkCiAgb2JqZWN0OgogICAgd2hhdDogc2VydmljZQogIHJlY29yZF90eXBlczogREFFTU9OX0FDQ0VQVAotCiAgYWN0aW9uOiByZW1vdGUtYXVkaXQtZGlzY29ubmVjdGVkCiAgb2JqZWN0OgogICAgd2hhdDogc2VydmljZQogIHJlY29yZF90eXBlczogREFFTU9OX0NMT1NFCi0KICBhY3Rpb246IGNoYW5nZWQtYXVkaXRkLWNvbmZpZ3VyYXRpb24KICBvYmplY3Q6CiAgICB3aGF0OiBzZXJ2aWNlCiAgcmVjb3JkX3R5cGVzOiBEQUVNT05fQ09ORklHCi0KICBhY3Rpb246IHNodXRkb3duLWF1ZGl0CiAgb2JqZWN0OgogICAgd2hhdDogc2VydmljZQogIHJlY29yZF90eXBlczogREFFTU9OX0VORAotCiAgYWN0aW9uOiBhdWRpdC1lcnJvcgogIG9iamVjdDoKICAgIHdoYXQ6IHNlcnZpY2UKICByZWNvcmRfdHlwZXM6IERBRU1PTl9FUlIKLQogIGFjdGlvbjogcmVjb25maWd1cmVkLWF1ZGl0ZAogIG9iamVjdDoKICAgIHdoYXQ6IHNlcnZpY2UKICByZWNvcmRfdHlwZXM6IERBRU1PTl9SRUNPTkZJRwotCiAgYWN0aW9uOiByZXN1bWVkLWF1ZGl0LWxvZ2dpbmcKICBvYmplY3Q6CiAgICB3aGF0OiBzZXJ2aWNlCiAgcmVjb3JkX3R5cGVzOiBEQUVNT05fUkVTVU1FCi0KICBhY3Rpb246IHJvdGF0ZWQtYXVkaXQtbG9ncwogIG9iamVjdDoKICAgIHdoYXQ6IHNlcnZpY2UKICByZWNvcmRfdHlwZXM6IERBRU1PTl9ST1RBVEUKLQogIGFjdGlvbjogc3RhcnRlZC1hdWRpdAogIG9iamVjdDoKICAgIHdoYXQ6IHNlcnZpY2UKICByZWNvcmRfdHlwZXM6IERBRU1PTl9TVEFSVAotCiAgYWN0aW9uOiBkZWxldGVkLWdyb3VwLWFjY291bnQtZnJvbQogIG9iamVjdDoKICAgIHByaW1hcnk6IFtpZCwgYWNjdF0KICAgIHdoYXQ6IGFjY291bnQKICByZWNvcmRfdHlwZXM6IERFTF9HUk9VUAotCiAgYWN0aW9uOiBkZWxldGVkLXVzZXItYWNjb3VudAogIG9iamVjdDoKICAgIHByaW1hcnk6IFtpZCwgYWNjdF0KICAgIHdoYXQ6IGFjY291bnQKICByZWNvcmRfdHlwZXM6IERFTF9VU0VSCi0KICBhY3Rpb246IGNoYW5nZWQtYXVkaXQtZmVhdHVyZQogIG9iamVjdDoKICAgIHByaW1hcnk6IGZlYXR1cmUKICAgIHdoYXQ6IHN5c3RlbQogIHJlY29yZF90eXBlczogRkVBVFVSRV9DSEFOR0UKLQogIGFjdGlvbjogcmVsYWJlbGVkLWZpbGVzeXN0ZW0KICByZWNvcmRfdHlwZXM6IEZTX1JFTEFCRUwKLQogIGFjdGlvbjogYXV0aGVudGljYXRlZC10by1ncm91cAogIHJlY29yZF90eXBlczogR1JQX0FVVEgKLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiBjaGFuZ2VkLWdyb3VwLXBhc3N3b3JkCiAgb2JqZWN0OgogICAgcHJpbWFyeTogYWNjdAogICAgd2hhdDogdXNlci1zZXNzaW9uCiAgcmVjb3JkX3R5cGVzOiBHUlBfQ0hBVVRIVE9LCi0KICBhY3Rpb246IG1vZGlmaWVkLWdyb3VwLWFjY291bnQKICBvYmplY3Q6CiAgICBwcmltYXJ5OiBbaWQsIGFjY3RdCiAgICB3aGF0OiBhY2NvdW50CiAgcmVjb3JkX3R5cGVzOiBHUlBfTUdNVAotCiAgYWN0aW9uOiBpbml0aWFsaXplZC1hdWRpdC1zdWJzeXN0ZW0KICByZWNvcmRfdHlwZXM6IEtFUk5FTAotCiAgYWN0aW9uOiBtb2RpZmllZC1sZXZlbC1vZgogIG9iamVjdDoKICAgIHByaW1hcnk6IHByaW50ZXIKICAgIHdoYXQ6IHByaW50ZXIKICByZWNvcmRfdHlwZXM6IExBQkVMX0xFVkVMX0NIQU5HRQotCiAgYWN0aW9uOiBvdmVycm9kZS1sYWJlbC1vZgogIG9iamVjdDoKICAgIHdoYXQ6IG1hYy1jb25maWcKICByZWNvcmRfdHlwZXM6IExBQkVMX09WRVJSSURFCi0KICBvYmplY3Q6CiAgICB3aGF0OiBtYWMtY29uZmlnCiAgcmVjb3JkX3R5cGVzOgogIC0gQVVESVRfREVWX0FMTE9DCiAgLSBBVURJVF9ERVZfREVBTExPQwogIC0gQVVESVRfRlNfUkVMQUJFTAogIC0gQVVESVRfVVNFUl9NQUNfUE9MSUNZX0xPQUQKICAtIEFVRElUX1VTRVJfTUFDX0NPTkZJR19DSEFOR0UKLQogIGFjdGlvbjogY2hhbmdlZC1sb2dpbi1pZC10bwogIHN1YmplY3Q6CiAgICBwcmltYXJ5OiBbb2xkX2F1aWQsIG9sZC1hdWlkXQogICAgc2Vjb25kYXJ5OiB1aWQKICBvYmplY3Q6CiAgICBwcmltYXJ5OiBhdWlkCiAgICB3aGF0OiB1c2VyLXNlc3Npb24KICByZWNvcmRfdHlwZXM6IExPR0lOCi0KICBhY3Rpb246IG1hYy1wZXJtaXNzaW9uCiAgcmVjb3JkX3R5cGVzOiBNQUNfQ0hFQ0sKLQogIGFjdGlvbjogY2hhbmdlZC1zZWxpbnV4LWJvb2xlYW4KICBvYmplY3Q6CiAgICBwcmltYXJ5OiBib29sCiAgICB3aGF0OiBtYWMtY29uZmlnCiAgcmVjb3JkX3R5cGVzOiBNQUNfQ09ORklHX0NIQU5HRQotCiAgYWN0aW9uOiBsb2FkZWQtc2VsaW51eC1wb2xpY3kKICBvYmplY3Q6CiAgICB3aGF0OiBtYWMtY29uZmlnCiAgcmVjb3JkX3R5cGVzOiBNQUNfUE9MSUNZX0xPQUQKLQogIGFjdGlvbjogY2hhbmdlZC1zZWxpbnV4LWVuZm9yY2VtZW50CiAgb2JqZWN0OgogICAgcHJpbWFyeTogZW5mb3JjaW5nCiAgICB3aGF0OiBtYWMtY29uZmlnCiAgcmVjb3JkX3R5cGVzOiBNQUNfU1RBVFVTCi0KICBhY3Rpb246IGFzc2lnbmVkLXVzZXItcm9sZS10bwogIG9iamVjdDoKICAgIHByaW1hcnk6IFtpZCwgYWNjdF0KICAgIHdoYXQ6IGFjY291bnQKICByZWNvcmRfdHlwZXM6IFJPTEVfQVNTSUdOCi0KICBhY3Rpb246IG1vZGlmaWVkLXJvbGUKICByZWNvcmRfdHlwZXM6IFJPTEVfTU9ESUZZCi0KICBhY3Rpb246IHJlbW92ZWQtdXNlLXJvbGUtZnJvbQogIG9iamVjdDoKICAgIHByaW1hcnk6IFtpZCwgYWNjdF0KICAgIHdoYXQ6IGFjY291bnQKICByZWNvcmRfdHlwZXM6IFJPTEVfUkVNT1ZFCi0KICBhY3Rpb246IHZpb2xhdGVkLXNlY2NvbXAtcG9saWN5CiAgb2JqZWN0OgogICAgcHJpbWFyeTogc3lzY2FsbAogICAgd2hhdDogcHJvY2VzcwogIHJlY29yZF90eXBlczogU0VDQ09NUAotCiAgYWN0aW9uOiBzdGFydGVkLXNlcnZpY2UKICBvYmplY3Q6CiAgICBwcmltYXJ5OiB1bml0CiAgICB3aGF0OiBzZXJ2aWNlCiAgcmVjb3JkX3R5cGVzOiBTRVJWSUNFX1NUQVJUCi0KICBhY3Rpb246IHN0b3BwZWQtc2VydmljZQogIG9iamVjdDoKICAgIHByaW1hcnk6IHVuaXQKICAgIHdoYXQ6IHNlcnZpY2UKICByZWNvcmRfdHlwZXM6IFNFUlZJQ0VfU1RPUAotCiAgYWN0aW9uOiBib290ZWQtc3lzdGVtCiAgb2JqZWN0OgogICAgd2hhdDogc3lzdGVtCiAgcmVjb3JkX3R5cGVzOiBTWVNURU1fQk9PVAotCiAgYWN0aW9uOiBjaGFuZ2VkLXRvLXJ1bmxldmVsCiAgb2JqZWN0OgogICAgcHJpbWFyeTogbmV3LWxldmVsCiAgICB3aGF0OiBzeXN0ZW0KICByZWNvcmRfdHlwZXM6IFNZU1RFTV9SVU5MRVZFTAotCiAgYWN0aW9uOiBzaHV0ZG93bi1zeXN0ZW0KICBvYmplY3Q6CiAgICB3aGF0OiBzeXN0ZW0KICByZWNvcmRfdHlwZXM6IFNZU1RFTV9TSFVURE9XTgotCiAgYWN0aW9uOiBzZW50LXRlc3QKICByZWNvcmRfdHlwZXM6IFRFU1QKLQogIGFjdGlvbjogdW5rbm93bgogIHJlY29yZF90eXBlczogVFJVU1RFRF9BUFAKLQogIGFjdGlvbjogc2VudC1tZXNzYWdlCiAgb2JqZWN0OgogICAgcHJpbWFyeTogYWRkcgogIHJlY29yZF90eXBlczogVVNFUgotCiAgPDw6ICptYWNyby11c2VyLXNlc3Npb24KICBhY3Rpb246IHdhcy1hdXRob3JpemVkCiAgcmVjb3JkX3R5cGVzOiBVU0VSX0FDQ1QKLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiBhdXRoZW50aWNhdGVkCiAgcmVjb3JkX3R5cGVzOiBVU0VSX0FVVEgKLQogIGFjdGlvbjogYWNjZXNzLXBlcm1pc3Npb24KICByZWNvcmRfdHlwZXM6IFVTRVJfQVZDCi0KICA8PDogKm1hY3JvLXVzZXItc2Vzc2lvbgogIGFjdGlvbjogY2hhbmdlZC1wYXNzd29yZAogIHJlY29yZF90eXBlczogVVNFUl9DSEFVVEhUT0sKLQogIGFjdGlvbjogcmFuLWNvbW1hbmQKICBvYmplY3Q6CiAgICBwcmltYXJ5OiBjbWQKICAgIHdoYXQ6IHByb2Nlc3MKICByZWNvcmRfdHlwZXM6IFVTRVJfQ01ECiAgZGVzY3JpcHRpb246ID4KICAgIFRoZXNlIG1lc3NhZ2VzIGFyZSBmcm9tIHVzZXItc3BhY2UgYXBwcywgbGlrZSBzdWRvLCB0aGF0IGxvZyBjb21tYW5kcwogICAgYmVpbmcgcnVuIGJ5IGEgdXNlci4gVGhlIHVpZCBjb250YWluZWQgaW4gdGhlc2UgbWVzc2FnZXMgaXMgdXNlcidzIFVJRCBhdAogICAgdGhlIHRpbWUgdGhlIGNvbW1hbmQgd2FzIHJ1bi4gSXQgaXMgbm90IHRoZSAidGFyZ2V0IiBVSUQgdXNlZCB0byBydW4gdGhlCiAgICBjb21tYW5kLCB3aGljaCBpcyBub3JtYWxseSByb290LgotCiAgPDw6ICptYWNyby11c2VyLXNlc3Npb24KICBhY3Rpb246IGVuZGVkLXNlc3Npb24KICByZWNvcmRfdHlwZXM6IFVTRVJfRU5ECi0KICA8PDogKm1hY3JvLXVzZXItc2Vzc2lvbgogIGFjdGlvbjogZXJyb3IKICByZWNvcmRfdHlwZXM6IFVTRVJfRVJSCi0KICA8PDogKm1hY3JvLXVzZXItc2Vzc2lvbgogIGFjdGlvbjogbG9nZ2VkLWluCiAgcmVjb3JkX3R5cGVzOiBVU0VSX0xPR0lOCi0KICA8PDogKm1hY3JvLXVzZXItc2Vzc2lvbgogIGFjdGlvbjogbG9nZ2VkLW91dAogIHJlY29yZF90eXBlczogVVNFUl9MT0dPVVQKLQogIGFjdGlvbjogY2hhbmdlZC1tYWMtY29uZmlndXJhdGlvbgogIHJlY29yZF90eXBlczogVVNFUl9NQUNfQ09ORklHX0NIQU5HRQotCiAgYWN0aW9uOiBsb2FkZWQtbWFjLXBvbGljeQogIHJlY29yZF90eXBlczogVVNFUl9NQUNfUE9MSUNZX0xPQUQKLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiBtb2RpZmllZC11c2VyLWFjY291bnQKICByZWNvcmRfdHlwZXM6IFVTRVJfTUdNVAotCiAgPDw6ICptYWNyby11c2VyLXNlc3Npb24KICBhY3Rpb246IGNoYW5nZWQtcm9sZS10bwogIG9iamVjdDoKICAgIHByaW1hcnk6IHNlbGVjdGVkLWNvbnRleHQKICAgIHdoYXQ6IHVzZXItc2Vzc2lvbgogIHJlY29yZF90eXBlczogVVNFUl9ST0xFX0NIQU5HRQotCiAgYWN0aW9uOiBhY2Nlc3MtZXJyb3IKICByZWNvcmRfdHlwZXM6IFVTRVJfU0VMSU5VWF9FUlIKLQogIDw8OiAqbWFjcm8tdXNlci1zZXNzaW9uCiAgYWN0aW9uOiBzdGFydGVkLXNlc3Npb24KICByZWNvcmRfdHlwZXM6IFVTRVJfU1RBUlQKLQogIGFjdGlvbjogY2hhbmdlZC1jb25maWd1cmF0aW9uCiAgb2JqZWN0OgogICAgcHJpbWFyeTogb3AKICAgIHdoYXQ6IHN5c3RlbQogIHJlY29yZF90eXBlczogVVNZU19DT05GSUcKLQogIGFjdGlvbjogaXNzdWVkLXZtLWNvbnRyb2wKICBvYmplY3Q6CiAgICBwcmltYXJ5OiBvcAogICAgc2Vjb25kYXJ5OiB2bQogICAgd2hhdDogdmlydHVhbC1tYWNoaW5lCiAgcmVjb3JkX3R5cGVzOiBWSVJUX0NPTlRST0wKLQogIGFjdGlvbjogY3JlYXRlZC12bS1pbWFnZQogIHJlY29yZF90eXBlczogVklSVF9DUkVBVEUKLQogIGFjdGlvbjogZGVsZXRlZC12bS1pbWFnZQogIHJlY29yZF90eXBlczogVklSVF9ERVNUUk9ZCi0KICBhY3Rpb246IGNoZWNrZWQtaW50ZWdyaXR5LW9mCiAgcmVjb3JkX3R5cGVzOiBWSVJUX0lOVEVHUklUWV9DSEVDSwotCiAgYWN0aW9uOiBhc3NpZ25lZC12bS1pZAogIG9iamVjdDoKICAgIHByaW1hcnk6IHZtCiAgICB3aGF0OiB2aXJ0dWFsLW1hY2hpbmUKICByZWNvcmRfdHlwZXM6IFZJUlRfTUFDSElORV9JRAotCiAgYWN0aW9uOiBtaWdyYXRlZC12bS1mcm9tCiAgcmVjb3JkX3R5cGVzOiBWSVJUX01JR1JBVEVfSU4KLQogIGFjdGlvbjogbWlncmF0ZWQtdm0tdG8KICByZWNvcmRfdHlwZXM6IFZJUlRfTUlHUkFURV9PVVQKLQogIGFjdGlvbjogYXNzaWduZWQtdm0tcmVzb3VyY2UKICBvYmplY3Q6CiAgICBwcmltYXJ5OiByZXNyYwogICAgc2Vjb25kYXJ5OiB2bQogICAgd2hhdDogdmlydHVhbC1tYWNoaW5lCiAgcmVjb3JkX3R5cGVzOiBWSVJUX1JFU09VUkNFCi0gYWN0aW9uOiB0eXBlZAogIG9iamVjdDoKICAgIHByaW1hcnk6IGRhdGEKICAgIHdoYXQ6IGtleXN0cm9rZXMKICBob3c6IFtjb21tLCBleGVdCiAgcmVjb3JkX3R5cGVzOgogIC0gVFRZCiAgLSBVU0VSX1RUWQo=") + assets["normalizationData"] = value + } + + if value, found := assets[key]; found { + return value, nil + } + return nil, fmt.Errorf("asset not found for key=%v", key) +}