From 47de17dede702b698be52945324c4a0dec62e294 Mon Sep 17 00:00:00 2001 From: Ricardo Valdes Date: Wed, 23 Sep 2026 09:33:50 -0400 Subject: [PATCH 1/5] fix(o365): derive action results from final workload outcomes --- filters/office365/o365.yml | 150 ++++- .../alerts/o365_action_result_rules_test.go | 348 ++++++++++ plugins/alerts/o365_action_result_test.go | 111 ++++ .../alerts/testdata/o365_action_result.json | 595 ++++++++++++++++++ ...365_potential_password_spraying_attack.yml | 4 +- rules/office365/dlp_policy_violations.yml | 4 +- .../information_barriers_violations.yml | 4 +- rules/office365/insider_risk_indicators.yml | 4 +- ...ible_succesfull_password_guessing_o365.yml | 6 +- rules/office365/safe_links_click_patterns.yml | 4 +- 10 files changed, 1195 insertions(+), 35 deletions(-) create mode 100644 plugins/alerts/o365_action_result_rules_test.go create mode 100644 plugins/alerts/o365_action_result_test.go create mode 100644 plugins/alerts/testdata/o365_action_result.json diff --git a/filters/office365/o365.yml b/filters/office365/o365.yml index e638ee143..395ebbc82 100755 --- a/filters/office365/o365.yml +++ b/filters/office365/o365.yml @@ -1,4 +1,4 @@ -# Microsoft 365 filter, version 1.2.3 +# Microsoft 365 filter, version 1.3.0 pipeline: - dataTypes: @@ -73,18 +73,125 @@ pipeline: from: - log.DestFolder.Path to: log.destFolderPath + # ResultStatus is workload-specific. Preserve it and derive only established + # operation outcomes; partial, pending and unknown results remain unset. + - delete: + fields: + - actionResult + - add: + function: string + params: + key: actionResult + value: success + where: >- + !oneOf("log.RecordType", [1, 15, 41, 188, 189, 190, 191, 192, 193, 194, 231, 386, 387, 401, 402]) && + oneOf("log.ResultStatus", ["Succeeded", "Success", "Successful"]) && + !equals("action", "UserLoginFailed") + # ExchangeAdmin uses string True/False; these are not universal outcome codes. + - add: + function: string + params: + key: actionResult + value: success + where: equals("log.RecordType", 1) && equals("log.ResultStatus", "True") + # STS HTTP success and UserLoggedIn alone do not prove completed authentication. + # Require an explicit zero result code and reject contradictory/unknown errors. + # ErrorNumber is the corresponding field in observed STS audit records. + - add: + function: string + params: + key: actionResult + value: success + where: >- + equals("log.RecordType", 15) && + (equals("log.ErrorCode", 0) || equals("log.ErrorNumber", 0)) && + (!exists("log.ErrorCode") || equals("log.ErrorCode", 0)) && + (!exists("log.ErrorNumber") || equals("log.ErrorNumber", 0)) && + (!exists("log.LogonError") || regexMatch("log.LogonError", "^$")) && + (!exists("log.ResultStatus") || oneOf("log.ResultStatus", ["Succeeded", "Success", "Successful"])) && + !equals("action", "UserLoginFailed") + # Planner defines its own result enum. Audit records also emit its member names. + - add: + function: string + params: + key: actionResult + value: success + where: >- + oneOf("log.RecordType", [188, 189, 190, 191, 192, 193, 194, 231, 386, 387, 401, 402]) && + (equals("log.ResultStatus", 1) || equals("log.ResultStatus", "Success")) + # Safe Links reports the navigation decision separately from event processing. + # Values 4/5 mean the user overrode the page and navigated; 3 remains pending. - add: function: string params: key: actionResult value: success - where: oneOf("log.ResultStatus", ["Succeeded", "Success", "Successful", "True"]) && !equals("action", "UserLoginFailed") + where: equals("log.RecordType", 41) && oneOf("log.URLClickAction", [4, 5]) + - add: + function: string + params: + key: actionResult + value: failure + where: >- + !oneOf("log.RecordType", [41, 188, 189, 190, 191, 192, 193, 194, 231, 386, 387, 401, 402]) && + (oneOf("log.ResultStatus", ["Failure", "Failed"]) || + (equals("log.RecordType", 1) && equals("log.ResultStatus", "False"))) + - add: + function: string + params: + key: actionResult + value: failure + where: >- + equals("log.RecordType", 15) && + (greaterThan("log.ErrorCode", 0) || regexMatch("log.LogonError", "(?s)^.+$")) - add: function: string params: key: actionResult - value: failed - where: oneOf("log.ResultStatus", ["Failure", "Failed"]) + value: failure + where: >- + oneOf("log.RecordType", [188, 189, 190, 191, 192, 193, 194, 231, 386, 387, 401, 402]) && + (equals("log.ResultStatus", 2) || equals("log.ResultStatus", "Failure")) + - add: + function: string + params: + key: actionResult + value: denied + where: >- + !oneOf("log.RecordType", [41, 188, 189, 190, 191, 192, 193, 194, 231, 386, 387, 401, 402]) && + equals("log.ResultStatus", "Blocked") + - add: + function: string + params: + key: actionResult + value: denied + where: >- + oneOf("log.RecordType", [188, 189, 190, 191, 192, 193, 194, 231, 386, 387, 401, 402]) && + (equals("log.ResultStatus", 3) || equals("log.ResultStatus", "AuthorizationFailure")) + # These exact operation names describe prevented user access, not successful + # administrative changes to a blocking policy. + - add: + function: string + params: + key: actionResult + value: denied + where: >- + oneOf("action", ["SharingInvitationBlocked", "UnmanagedSyncClientBlocked", "URLNavigationBlocked", "AccessRequestDenied"]) || + (equals("log.RecordType", 41) && equals("log.URLClickAction", 2)) + # KmsiInterrupt is the expected "Keep me signed in" prompt, not a final result. + - delete: + fields: + - actionResult + where: >- + equals("log.RecordType", 15) && + (equals("log.ErrorCode", 50140) || equals("log.ErrorNumber", 50140)) + # A failed login wins even when its HTTP request or audit operation succeeded. + - add: + function: string + params: + key: actionResult + value: failure + where: equals("action", "UserLoginFailed") - dynamic: plugin: com.utmstack.geolocation params: @@ -141,24 +248,23 @@ pipeline: - log.ItemName to: target.filename where: equals("log.Workload", "OneDrive") || equals("log.Workload", "SharePoint") - - add: - function: string - params: - key: actionResult - value: success - where: equals("log.ResultStatus", "PartiallySucceeded") - - add: - function: string - params: - key: actionResult - value: blocked - where: equals("log.ResultStatus", "Blocked") - - add: - function: string - params: - key: actionResult - value: failed - where: equals("action", "UserLoginFailed") + # Safe Links supplies the clicking user's IP and destination URL under its own + # documented fields. Copy them so vendor-specific queries retain the originals. + - grok: + source: log.UserIp + patterns: + - fieldName: origin.ip + pattern: (?s:.*) + where: >- + equals("log.RecordType", 41) && + (inCIDR("log.UserIp", "0.0.0.0/0") || inCIDR("log.UserIp", "::/0")) && + !inCIDR("log.UserIp", "0.0.0.0/32") && !inCIDR("log.UserIp", "::/128") + - grok: + source: log.URL + patterns: + - fieldName: target.url + pattern: (?s:.*) + where: equals("log.RecordType", 41) && regexMatch("log.URL", "(?s)^.+$") - delete: fields: - log.AppAccessContext diff --git a/plugins/alerts/o365_action_result_rules_test.go b/plugins/alerts/o365_action_result_rules_test.go new file mode 100644 index 000000000..78da5d1e7 --- /dev/null +++ b/plugins/alerts/o365_action_result_rules_test.go @@ -0,0 +1,348 @@ +package main + +// These tests use the pinned SDK CEL and history implementation. Raw normalization +// uses the explicit offline filter model in o365ActionResultNormalize, not a live +// EventProcessor. The history transport is a loopback mock, not customer storage. +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "reflect" + "strings" + "testing" + "time" + + sdkos "github.com/threatwinds/go-sdk/os" + "github.com/threatwinds/go-sdk/plugins" + "github.com/threatwinds/go-sdk/utils" + "github.com/tidwall/gjson" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/structpb" +) + +var o365OutcomeRuleFiles = []string{ + "possible_succesfull_password_guessing_o365", + "credential_access_microsoft_365_potential_password_spraying_attack", + "dlp_policy_violations", "safe_links_click_patterns", "insider_risk_indicators", "information_barriers_violations", +} + +func o365OutcomeRule(t *testing.T, name string) *plugins.Rule { + t.Helper() + b, err := utils.ReadPbYaml("../../rules/office365/" + name + ".yml") + if err != nil { + t.Fatal(err) + } + r := new(plugins.Rule) + if err = protojson.Unmarshal(b, r); err != nil { + t.Fatal(err) + } + r.Normalize() + return r +} + +func o365OutcomeRaw(t *testing.T, name string) string { + t.Helper() + event := map[string]any{"Workload": "Exchange", "ClientIP": "198.51.100.10", "UserId": "reviewer@example.test", "ResultStatus": "Blocked"} + switch name { + case "possible_succesfull_password_guessing_o365", "credential_access_microsoft_365_potential_password_spraying_attack": + event["Operation"] = "UserLoginFailed" + event["Workload"] = "AzureActiveDirectory" + event["RecordType"] = 15 + event["ResultStatus"] = "Succeeded" + case "dlp_policy_violations": + event["Operation"] = "DLPRuleMatch" + case "safe_links_click_patterns": + event["Operation"] = "ClickedSafeLink" + case "insider_risk_indicators": + event["Operation"] = "PolicyEvaluation" + event["PolicyName"] = "InsiderRiskPolicy" + case "information_barriers_violations": + event["Operation"] = "PolicyEvaluation" + event["PolicyType"] = "InformationBarrier" + default: + t.Fatal("unknown case", name) + } + b, err := json.Marshal(event) + if err != nil { + t.Fatal(err) + } + return string(b) +} + +func o365OutcomeSet(t *testing.T, event, path string, value any) string { + t.Helper() + var m map[string]any + if err := json.Unmarshal([]byte(event), &m); err != nil { + t.Fatal(err) + } + keys := strings.Split(path, ".") + node := m + for _, key := range keys[:len(keys)-1] { + next, ok := node[key].(map[string]any) + if !ok { + next = map[string]any{} + node[key] = next + } + node = next + } + key := keys[len(keys)-1] + if value == nil { + delete(node, key) + } else { + node[key] = value + } + b, err := json.Marshal(m) + if err != nil { + t.Fatal(err) + } + return string(b) +} + +func o365OutcomeAssert(t *testing.T, cache *plugins.CELCache, r *plugins.Rule, event string, want bool) { + t.Helper() + got, err := cache.Eval(r.Where, event) + if err != nil || got != want { + t.Fatalf("predicate got %v want %v: %v", got, want, err) + } +} + +func TestO365ActionResultRuleCompatibility(t *testing.T) { + cache := plugins.NewCELCache("o365-outcome-rules") + for _, name := range o365OutcomeRuleFiles { + t.Run(name, func(t *testing.T) { + r := o365OutcomeRule(t, name) + event := o365ActionResultNormalize(t, o365OutcomeRaw(t, name)) + o365OutcomeAssert(t, cache, r, event, true) + if gaps := fixtureHistoryPlaceholders(r.Correlation, event); len(gaps) != 0 { + t.Fatal(gaps) + } + failureRule := strings.Contains(name, "password_") + // Exercise extraction and normalization for a negative record as well + // as the positive raw fixture before testing legacy stored outcomes. + negativeRaw := o365OutcomeSet(t, o365OutcomeRaw(t, name), "ResultStatus", "Succeeded") + if failureRule { + negativeRaw = o365OutcomeSet(t, negativeRaw, "Operation", "UserLoggedIn") + negativeRaw = o365OutcomeSet(t, negativeRaw, "ErrorNumber", 0) + } + if name == "dlp_policy_violations" { + negativeRaw = o365OutcomeSet(t, negativeRaw, "ResultStatus", "Failed") + } + o365OutcomeAssert(t, cache, r, o365ActionResultNormalize(t, negativeRaw), false) + for _, outcome := range []string{"success", "failure", "failed", "denied", "blocked", "unknown", ""} { + want := outcome == "denied" || outcome == "blocked" + if failureRule { + want = outcome == "failure" || outcome == "failed" + } + if name == "dlp_policy_violations" { + want = outcome != "failure" && outcome != "failed" + } + t.Run(outcome, func(t *testing.T) { + o365OutcomeAssert(t, cache, r, o365OutcomeSet(t, event, "actionResult", outcome), want) + }) + } + // Preserve DLP's existing unknown-outcome detection scope; absence is not + // described as success. Other migrated outcome branches need an outcome. + o365OutcomeAssert(t, cache, r, o365OutcomeSet(t, event, "actionResult", nil), name == "dlp_policy_violations") + unrelated := o365OutcomeSet(t, event, "action", "UnrelatedOperation") + unrelated = o365OutcomeSet(t, unrelated, "log.PolicyName", nil) + unrelated = o365OutcomeSet(t, unrelated, "log.PolicyType", nil) + o365OutcomeAssert(t, cache, r, unrelated, false) + if failureRule || name == "safe_links_click_patterns" { + o365OutcomeAssert(t, cache, r, o365OutcomeSet(t, event, "origin.ip", nil), name == "safe_links_click_patterns") + } + if name == "possible_succesfull_password_guessing_o365" || name == "safe_links_click_patterns" { + o365OutcomeAssert(t, cache, r, o365OutcomeSet(t, event, "origin.user", nil), false) + } + }) + } +} + +func TestO365ActionResultPreservesIndependentBranches(t *testing.T) { + cache := plugins.NewCELCache("o365-independent-branches") + for _, tc := range []struct { + name, event string + want bool + }{ + {"insider_risk_indicators", `{"action":"InsiderRiskAlert","actionResult":"failure"}`, true}, + {"insider_risk_indicators", `{"log":{"RiskLevel":"High","AlertSource":"InsiderRiskManagement"}}`, true}, + {"insider_risk_indicators", `{"log":{"RiskLevel":"Low","AlertSource":"InsiderRiskManagement"}}`, false}, + {"information_barriers_violations", `{"action":"InformationBarrierPolicyViolation","origin":{"user":"reviewer@example.test"}}`, true}, + {"information_barriers_violations", `{"action":"CommunicationBlocked","log":{"ViolationType":"InformationBarrier"},"origin":{"user":"reviewer@example.test"}}`, true}, + {"information_barriers_violations", `{"action":"CommunicationBlocked","log":{"ViolationType":"Other"},"origin":{"user":"reviewer@example.test"}}`, false}, + } { + t.Run(tc.name+fmt.Sprint(tc.want), func(t *testing.T) { o365OutcomeAssert(t, cache, o365OutcomeRule(t, tc.name), tc.event, tc.want) }) + } +} + +func TestO365ActionResultSDKHistory(t *testing.T) { + // Isolate the SDK's process-global OpenSearch connection and field mapper. + if os.Getenv("UTM_O365_OUTCOME_HISTORY_CHILD") != "1" { + c := exec.Command(os.Args[0], "-test.run=^TestO365ActionResultSDKHistory$") + c.Env = append(os.Environ(), "UTM_O365_OUTCOME_HISTORY_CHILD=1") + if b, err := c.CombinedOutput(); err != nil { + t.Fatalf("isolated history: %v\n%s", err, b) + } + return + } + var history []string + var expectedTerms map[string]string + var window time.Duration + queries := 0 + mapping := map[string]any{"properties": map[string]any{ + "@timestamp": map[string]any{"type": "date"}, "action": map[string]any{"type": "keyword"}, + "origin": map[string]any{"properties": map[string]any{"user": map[string]any{"type": "keyword"}, "ip": map[string]any{"type": "ip"}}}, + "log": map[string]any{"properties": map[string]any{"PolicyType": map[string]any{"type": "keyword"}}}, + }} + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + if strings.HasSuffix(r.URL.Path, "/_mapping") { + _ = json.NewEncoder(w).Encode(map[string]any{"v11-log-o365-test": map[string]any{"mappings": mapping}}) + return + } + if r.URL.Path != "/v11-log-o365-*/_search" { + t.Errorf("unexpected request %s", r.URL.Path) + http.Error(w, "bad request", 400) + return + } + queries++ + b, err := io.ReadAll(r.Body) + if err != nil { + t.Error(err) + return + } + q := string(b) + terms := map[string]string{} + cutoff := time.Time{} + clauses := append(gjson.Get(q, "query.bool.filter").Array(), gjson.Get(q, "query.bool.must").Array()...) + if gjson.Get(q, "query.bool.must_not").Exists() { + t.Error("unexpected negative history clauses") + } + for _, clause := range clauses { + if term := clause.Get("term"); term.Exists() { + for field, value := range term.Map() { + terms[strings.TrimSuffix(field, ".keyword")] = value.Get("value").String() + } + } else if span := clause.Get("range"); span.Exists() { + cutoff, err = time.Parse(time.RFC3339Nano, span.Get("@timestamp.gte").String()) + if err != nil { + t.Error(err) + } + } else { + t.Errorf("unsupported history clause %s", clause.Raw) + } + } + if !reflect.DeepEqual(terms, expectedTerms) { + t.Errorf("history scope got %v want %v", terms, expectedTerms) + } + if delta := time.Since(cutoff) - window; delta < -2*time.Second || delta > 2*time.Second { + t.Errorf("wrong cutoff %v", delta) + } + hits := []map[string]any{} + for _, doc := range history { + match := true + for field, value := range terms { + if gjson.Get(doc, field).String() != value { + match = false + } + } + stamp, err := time.Parse(time.RFC3339Nano, gjson.Get(doc, "@timestamp").String()) + if err != nil || stamp.Before(cutoff) { + match = false + } + if match { + hits = append(hits, map[string]any{"_id": fmt.Sprint(len(hits)), "_index": "v11-log-o365-test", "_source": map[string]any{}}) + } + } + _ = json.NewEncoder(w).Encode(map[string]any{"took": 1, "hits": map[string]any{"total": map[string]any{"value": len(hits), "relation": "eq"}, "hits": hits}}) + })) + defer server.Close() + if err := sdkos.Connect([]string{server.URL}, "", ""); err != nil { + t.Fatal(err) + } + cache := plugins.NewCELCache("o365-history") + for _, tc := range []struct { + name, within string + count uint64 + terms map[string]string + }{ + {"possible_succesfull_password_guessing_o365", "1m", 10, map[string]string{"action": "UserLoginFailed", "origin.user": "reviewer@example.test", "origin.ip": "198.51.100.10"}}, + {"credential_access_microsoft_365_potential_password_spraying_attack", "60s", 5, map[string]string{"origin.ip": "198.51.100.10"}}, + {"safe_links_click_patterns", "30m", 5, map[string]string{"origin.user": "reviewer@example.test", "action": "ClickedSafeLink"}}, + {"information_barriers_violations", "12h", 3, map[string]string{"origin.user": "reviewer@example.test", "log.PolicyType": "InformationBarrier"}}, + } { + t.Run(tc.name, func(t *testing.T) { + r := o365OutcomeRule(t, tc.name) + if len(r.Correlation) != 1 { + t.Fatal("unexpected history count") + } + search := r.Correlation[0] + if search.Count != tc.count || search.Within != tc.within { + t.Fatal("history threshold/window changed") + } + expectedTerms = tc.terms + window, _ = time.ParseDuration(tc.within) + event := o365ActionResultNormalize(t, o365OutcomeRaw(t, tc.name)) + o365OutcomeAssert(t, cache, r, event, true) + if tc.name == "possible_succesfull_password_guessing_o365" { + if gjson.Get(event, "log.clientIP").Exists() { + t.Fatal("test needs normalized IP without obsolete alias") + } + old := proto.Clone(search).(*plugins.SearchRequest) + for _, e := range old.With { + if e.Field == "origin.ip" { + e.Value = structpb.NewStringValue("{{.log.clientIP}}") + } + } + before := queries + if _, _, err := old.Execute(&event); err == nil { + t.Fatal("obsolete placeholder unexpectedly resolved") + } + if queries != before { + t.Fatal("unresolved placeholder issued query") + } + } + prior := o365OutcomeSet(t, event, "@timestamp", time.Now().Add(-window/2).UTC().Format(time.RFC3339Nano)) + history = nil + for i := uint64(0); i < tc.count-1; i++ { + history = append(history, prior) + } + if yes, _, err := search.Execute(&event); err != nil || yes { + t.Fatalf("below threshold: %v %v", yes, err) + } + history = append(history, prior) + if yes, _, err := search.Execute(&event); err != nil || !yes { + t.Fatalf("at threshold: %v %v", yes, err) + } + expired := o365OutcomeSet(t, prior, "@timestamp", time.Now().Add(-window-time.Minute).UTC().Format(time.RFC3339Nano)) + history[len(history)-1] = expired + if yes, _, err := search.Execute(&event); err != nil || yes { + t.Fatalf("expired history counted: %v %v", yes, err) + } + for field := range expectedTerms { + history[len(history)-1] = o365OutcomeSet(t, prior, field, "different-value") + if yes, _, err := search.Execute(&event); err != nil || yes { + t.Fatalf("different %s counted: %v %v", field, yes, err) + } + } + for _, expression := range search.With { + value := expression.Value.GetStringValue() + if strings.HasPrefix(value, "{{.") { + field := strings.TrimSuffix(strings.TrimPrefix(value, "{{."), "}}") + missing := o365OutcomeSet(t, event, field, nil) + before := queries + if _, _, err := search.Execute(&missing); err == nil { + t.Fatalf("missing %s accepted", field) + } + if queries != before { + t.Fatal("unresolved placeholder issued query") + } + } + } + }) + } +} diff --git a/plugins/alerts/o365_action_result_test.go b/plugins/alerts/o365_action_result_test.go new file mode 100644 index 000000000..bbc15d0fd --- /dev/null +++ b/plugins/alerts/o365_action_result_test.go @@ -0,0 +1,111 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/threatwinds/go-sdk/plugins" + "github.com/threatwinds/go-sdk/utils" + "github.com/tidwall/gjson" + "google.golang.org/protobuf/encoding/protojson" +) + +// o365ActionResultNormalize runs fabricated raw JSON through the committed +// extraction/normalization model. Only external geolocation is omitted; it does +// not produce actionResult. This does not execute the closed EventProcessor, +// threat-intelligence membership, or alert creation. +func o365ActionResultNormalize(t *testing.T, raw string) string { + t.Helper() + b, err := utils.ReadPbYaml("../../filters/office365/o365.yml") + if err != nil { + t.Fatal(err) + } + cfg := new(plugins.Config) + if err = protojson.Unmarshal(b, cfg); err != nil { + t.Fatal(err) + } + for _, stage := range cfg.Pipeline { + steps := stage.Steps[:0] + for _, step := range stage.Steps { + if step.Dynamic != nil { + if step.Dynamic.Plugin != "com.utmstack.geolocation" { + t.Fatalf("unmodeled dynamic producer: %s", step.Dynamic.Plugin) + } + continue + } + steps = append(steps, step) + } + stage.Steps = steps + } + root := t.TempDir() + if err = os.Mkdir(filepath.Join(root, "filters"), 0700); err != nil { + t.Fatal(err) + } + b, err = protojson.Marshal(cfg) + if err != nil { + t.Fatal(err) + } + if err = os.WriteFile(filepath.Join(root, "filters", "o365.yml"), b, 0600); err != nil { + t.Fatal(err) + } + out, issues, err := normalize(root, Fixture{Filter: "o365.yml", Raw: &raw, DataType: "o365", DataSource: "synthetic-collector"}, plugins.NewCELCache("o365-raw-outcome")) + if err != nil || len(issues) != 0 { + t.Fatalf("raw extraction model: %v; CEL issues: %v", err, issues) + } + return out +} + +func TestO365ActionResult(t *testing.T) { + b, err := os.ReadFile("testdata/o365_action_result.json") + if err != nil { + t.Fatal(err) + } + var cases []struct { + Name string `json:"name"` + Raw string `json:"raw"` + Result string `json:"result"` + Preserve map[string]any `json:"preserve"` + Expected map[string]any `json:"expected"` + Absent []string `json:"absent"` + IP *bool `json:"ipEligible"` + } + if err = json.Unmarshal(b, &cases); err != nil || len(cases) == 0 { + t.Fatalf("cases: %v", err) + } + cache := plugins.NewCELCache("o365-result-predicates") + for _, tc := range cases { + t.Run(tc.Name, func(t *testing.T) { + out := o365ActionResultNormalize(t, tc.Raw) + got := gjson.Get(out, "actionResult") + if got.String() != tc.Result || (tc.Result == "" && got.Exists()) { + t.Fatalf("actionResult = %s, want %q", got.Raw, tc.Result) + } + for _, result := range []string{"success", "failure", "denied"} { + match, err := cache.Eval(`equals("actionResult","`+result+`") && inCIDR("origin.ip","0.0.0.0/0")`, out) + want := tc.Result == result && (tc.IP == nil || *tc.IP) + if err != nil || match != want { + t.Errorf("SDK %s-and-IP predicate = %v, %v", result, match, err) + } + } + for path, want := range tc.Preserve { + got := gjson.Get(out, path) + if !got.Exists() || !reflect.DeepEqual(got.Value(), want) { + t.Errorf("vendor field %s = %v, want %v", path, got.Value(), want) + } + } + for path, want := range tc.Expected { + if got := gjson.Get(out, path); !got.Exists() || !reflect.DeepEqual(got.Value(), want) { + t.Errorf("standard field %s = %v, want %v", path, got.Value(), want) + } + } + for _, path := range tc.Absent { + if gjson.Get(out, path).Exists() { + t.Errorf("unexpected field %s", path) + } + } + }) + } +} diff --git a/plugins/alerts/testdata/o365_action_result.json b/plugins/alerts/testdata/o365_action_result.json new file mode 100644 index 000000000..4fc43acdb --- /dev/null +++ b/plugins/alerts/testdata/o365_action_result.json @@ -0,0 +1,595 @@ +[ + { + "name": "completed-Success", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\"}", + "result": "success", + "preserve": { + "log.ResultStatus": "Success" + } + }, + { + "name": "completed-Succeeded", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Succeeded\"}", + "result": "success", + "preserve": { + "log.ResultStatus": "Succeeded" + } + }, + { + "name": "completed-Successful", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Successful\"}", + "result": "success", + "preserve": { + "log.ResultStatus": "Successful" + } + }, + { + "name": "failed-Failure", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Failure\"}", + "result": "failure", + "preserve": { + "log.ResultStatus": "Failure" + } + }, + { + "name": "failed-Failed", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Failed\"}", + "result": "failure", + "preserve": { + "log.ResultStatus": "Failed" + } + }, + { + "name": "blocked-status", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Blocked\"}", + "result": "denied", + "preserve": { + "log.ResultStatus": "Blocked" + } + }, + { + "name": "unresolved-PartiallySucceeded", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"PartiallySucceeded\"}", + "result": "", + "preserve": { + "log.ResultStatus": "PartiallySucceeded" + } + }, + { + "name": "unresolved-Pending", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Pending\"}", + "result": "", + "preserve": { + "log.ResultStatus": "Pending" + } + }, + { + "name": "unresolved-InProgress", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"InProgress\"}", + "result": "", + "preserve": { + "log.ResultStatus": "InProgress" + } + }, + { + "name": "unresolved-FutureVendorStatus", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"FutureVendorStatus\"}", + "result": "", + "preserve": { + "log.ResultStatus": "FutureVendorStatus" + } + }, + { + "name": "unresolved-", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"\"}", + "result": "", + "preserve": { + "log.ResultStatus": "" + } + }, + { + "name": "unresolved-None", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":null}", + "result": "", + "preserve": { + "log.ResultStatus": null + } + }, + { + "name": "missing-outcome", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\"}", + "result": "", + "preserve": {} + }, + { + "name": "non-exchange-boolean-True", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"True\"}", + "result": "", + "preserve": { + "log.ResultStatus": "True" + } + }, + { + "name": "non-exchange-boolean-False", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"False\"}", + "result": "", + "preserve": { + "log.ResultStatus": "False" + } + }, + { + "name": "exchange-true", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"True\"}", + "result": "success", + "preserve": { + "log.ResultStatus": "True" + } + }, + { + "name": "exchange-false", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"False\"}", + "result": "failure", + "preserve": { + "log.ResultStatus": "False" + } + }, + { + "name": "failed-login-HTTP-success", + "raw": "{\"Operation\":\"UserLoginFailed\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorCode\":\"50126\",\"LogonError\":\"InvalidUserNameOrPassword\"}", + "result": "failure", + "preserve": { + "log.ResultStatus": "Success", + "log.ErrorCode": "50126", + "log.LogonError": "InvalidUserNameOrPassword" + } + }, + { + "name": "failed-login-contradictory-zero", + "raw": "{\"Operation\":\"UserLoginFailed\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorCode\":\"0\"}", + "result": "failure", + "preserve": { + "log.ResultStatus": "Success", + "log.ErrorCode": "0" + } + }, + { + "name": "sts-HTTP-only", + "raw": "{\"Operation\":\"PasswordLogonInitialAuthUsingPassword\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Succeeded\"}", + "result": "", + "preserve": { + "log.ResultStatus": "Succeeded" + } + }, + { + "name": "sts-nonzero-error", + "raw": "{\"Operation\":\"PasswordLogonInitialAuthUsingPassword\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Succeeded\",\"ErrorCode\":\"50076\"}", + "result": "failure", + "preserve": { + "log.ResultStatus": "Succeeded", + "log.ErrorCode": "50076" + } + }, + { + "name": "sts-logon-error", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Succeeded\",\"LogonError\":\"AuthenticationFailed\"}", + "result": "failure", + "preserve": { + "log.ResultStatus": "Succeeded", + "log.LogonError": "AuthenticationFailed" + } + }, + { + "name": "sts-success", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorCode\":\"0\"}", + "result": "success", + "preserve": { + "log.ResultStatus": "Success", + "log.ErrorCode": "0" + } + }, + { + "name": "sts-zero-success", + "raw": "{\"Operation\":\"PasswordLogonInitialAuthUsingPassword\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Succeeded\",\"ErrorCode\":\"0\"}", + "result": "success", + "preserve": { + "log.ResultStatus": "Succeeded", + "log.ErrorCode": "0" + } + }, + { + "name": "sts-unknown-error-code", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorCode\":\"unrecognized\"}", + "result": "", + "preserve": { + "log.ResultStatus": "Success", + "log.ErrorCode": "unrecognized" + } + }, + { + "name": "sts-null-error-code", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorCode\":null}", + "result": "", + "preserve": { + "log.ResultStatus": "Success", + "log.ErrorCode": null + } + }, + { + "name": "prevented-URLNavigationBlocked", + "raw": "{\"Operation\":\"URLNavigationBlocked\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\"}", + "result": "denied", + "preserve": { + "log.ResultStatus": "Success" + } + }, + { + "name": "prevented-SharingInvitationBlocked", + "raw": "{\"Operation\":\"SharingInvitationBlocked\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\"}", + "result": "denied", + "preserve": { + "log.ResultStatus": "Success" + } + }, + { + "name": "prevented-UnmanagedSyncClientBlocked", + "raw": "{\"Operation\":\"UnmanagedSyncClientBlocked\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\"}", + "result": "denied", + "preserve": { + "log.ResultStatus": "Success" + } + }, + { + "name": "prevented-AccessRequestDenied", + "raw": "{\"Operation\":\"AccessRequestDenied\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\"}", + "result": "denied", + "preserve": { + "log.ResultStatus": "Success" + } + }, + { + "name": "safe-links-2", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"Workload\":\"ThreatIntelligence\",\"RecordType\":41,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"URLClickAction\":2}", + "result": "denied", + "preserve": { + "log.ResultStatus": "Success", + "log.URLClickAction": 2 + } + }, + { + "name": "safe-links-3", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"Workload\":\"ThreatIntelligence\",\"RecordType\":41,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"URLClickAction\":3}", + "result": "", + "preserve": { + "log.ResultStatus": "Success", + "log.URLClickAction": 3 + } + }, + { + "name": "safe-links-4", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"Workload\":\"ThreatIntelligence\",\"RecordType\":41,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"URLClickAction\":4}", + "result": "success", + "preserve": { + "log.ResultStatus": "Success", + "log.URLClickAction": 4 + } + }, + { + "name": "safe-links-5", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"Workload\":\"ThreatIntelligence\",\"RecordType\":41,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"URLClickAction\":5}", + "result": "success", + "preserve": { + "log.ResultStatus": "Success", + "log.URLClickAction": 5 + } + }, + { + "name": "safe-links-999", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"Workload\":\"ThreatIntelligence\",\"RecordType\":41,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"URLClickAction\":999}", + "result": "", + "preserve": { + "log.ResultStatus": "Success", + "log.URLClickAction": 999 + } + }, + { + "name": "safe-links-no-click-action", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"Workload\":\"SharePoint\",\"RecordType\":41,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\"}", + "result": "", + "preserve": { + "log.ResultStatus": "Success" + } + }, + { + "name": "planner-1", + "raw": "{\"Operation\":\"TaskModified\",\"Workload\":\"MicrosoftPlanner\",\"RecordType\":188,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":1}", + "result": "success", + "preserve": { + "log.ResultStatus": 1 + } + }, + { + "name": "planner-2", + "raw": "{\"Operation\":\"TaskModified\",\"Workload\":\"MicrosoftPlanner\",\"RecordType\":188,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":2}", + "result": "failure", + "preserve": { + "log.ResultStatus": 2 + } + }, + { + "name": "planner-3", + "raw": "{\"Operation\":\"TaskModified\",\"Workload\":\"MicrosoftPlanner\",\"RecordType\":188,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":3}", + "result": "denied", + "preserve": { + "log.ResultStatus": 3 + } + }, + { + "name": "planner-0", + "raw": "{\"Operation\":\"TaskModified\",\"Workload\":\"MicrosoftPlanner\",\"RecordType\":188,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":0}", + "result": "", + "preserve": { + "log.ResultStatus": 0 + } + }, + { + "name": "planner-4", + "raw": "{\"Operation\":\"TaskModified\",\"Workload\":\"MicrosoftPlanner\",\"RecordType\":188,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":4}", + "result": "", + "preserve": { + "log.ResultStatus": 4 + } + }, + { + "name": "non-planner-numeric-1", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":1}", + "result": "", + "preserve": { + "log.ResultStatus": 1 + } + }, + { + "name": "non-planner-numeric-2", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":2}", + "result": "", + "preserve": { + "log.ResultStatus": 2 + } + }, + { + "name": "non-planner-numeric-3", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":3}", + "result": "", + "preserve": { + "log.ResultStatus": 3 + } + }, + { + "name": "sts-unresolved-Pending", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Pending\",\"ErrorCode\":\"0\"}", + "result": "", + "preserve": { + "log.ResultStatus": "Pending", + "log.ErrorCode": "0" + } + }, + { + "name": "sts-unresolved-InProgress", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"InProgress\",\"ErrorCode\":\"0\"}", + "result": "", + "preserve": { + "log.ResultStatus": "InProgress", + "log.ErrorCode": "0" + } + }, + { + "name": "sts-unresolved-FutureOutcome", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"FutureOutcome\",\"ErrorCode\":\"0\"}", + "result": "", + "preserve": { + "log.ResultStatus": "FutureOutcome", + "log.ErrorCode": "0" + } + }, + { + "name": "sts-unresolved-None", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":null,\"ErrorCode\":\"0\"}", + "result": "", + "preserve": { + "log.ResultStatus": null, + "log.ErrorCode": "0" + } + }, + { + "name": "sts-observed-zero", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorNumber\":\"0\"}", + "result": "success", + "preserve": { + "log.ErrorNumber": "0", + "log.ResultStatus": "Success" + } + }, + { + "name": "sts-observed-kmsi-interrupt", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorNumber\":\"50140\",\"ExtendedProperties\":[{\"Name\":\"ResultStatusDetail\",\"Value\":\"Success\"},{\"Name\":\"RequestType\",\"Value\":\"Login:login\"}]}", + "result": "", + "preserve": { + "log.ErrorNumber": "50140", + "log.ExtendedProperties": [ + { + "Name": "ResultStatusDetail", + "Value": "Success" + }, + { + "Name": "RequestType", + "Value": "Login:login" + } + ], + "log.ResultStatus": "Success" + } + }, + { + "name": "sts-documented-kmsi-interrupt", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorCode\":\"50140\"}", + "result": "", + "preserve": { + "log.ErrorCode": "50140", + "log.ResultStatus": "Success" + } + }, + { + "name": "sts-conflicting-code-aliases", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorNumber\":\"50140\",\"ErrorCode\":\"0\"}", + "result": "", + "preserve": { + "log.ErrorNumber": "50140", + "log.ErrorCode": "0", + "log.ResultStatus": "Success" + } + }, + { + "name": "sts-unknown-error-number", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorNumber\":\"new-code\"}", + "result": "", + "preserve": { + "log.ErrorNumber": "new-code", + "log.ResultStatus": "Success" + } + }, + { + "name": "sts-null-error-number", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorNumber\":null}", + "result": "", + "preserve": { + "log.ErrorNumber": null, + "log.ResultStatus": "Success" + } + }, + { + "name": "sts-logon-error-with-zero-number", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorNumber\":\"0\",\"LogonError\":\"FlowTokenExpired\"}", + "result": "failure", + "preserve": { + "log.ErrorNumber": "0", + "log.LogonError": "FlowTokenExpired", + "log.ResultStatus": "Success" + } + }, + { + "name": "sts-negative-unknown-code", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\",\"ErrorNumber\":\"999999\"}", + "result": "", + "preserve": { + "log.ErrorNumber": "999999", + "log.ResultStatus": "Success" + } + }, + { + "name": "planner-string-enum-Success", + "raw": "{\"Operation\":\"PlanRead\",\"Workload\":\"Planner\",\"RecordType\":188,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\"}", + "result": "success", + "preserve": { + "log.ResultStatus": "Success" + } + }, + { + "name": "planner-string-enum-Failure", + "raw": "{\"Operation\":\"PlanRead\",\"Workload\":\"Planner\",\"RecordType\":188,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Failure\"}", + "result": "failure", + "preserve": { + "log.ResultStatus": "Failure" + } + }, + { + "name": "planner-string-enum-AuthorizationFailure", + "raw": "{\"Operation\":\"PlanRead\",\"Workload\":\"Planner\",\"RecordType\":188,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"AuthorizationFailure\"}", + "result": "denied", + "preserve": { + "log.ResultStatus": "AuthorizationFailure" + } + }, + { + "name": "wrong-result-type-array", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":[\"Success\"]}", + "result": "", + "preserve": { + "log.ResultStatus": [ + "Success" + ] + } + }, + { + "name": "wrong-result-type-object", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":{\"value\":\"Success\"}}", + "result": "", + "preserve": { + "log.ResultStatus": { + "value": "Success" + } + } + }, + { + "name": "wrong-result-type-boolean", + "raw": "{\"Operation\":\"FileDownloaded\",\"Workload\":\"SharePoint\",\"RecordType\":6,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":true}", + "result": "", + "preserve": { + "log.ResultStatus": true + } + }, + { + "name": "safe-links-native-shape-allowed", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"RecordType\":41,\"UserId\":\"analyst@example.invalid\",\"UserIp\":\"192.0.2.20\",\"URL\":\"https://example.invalid/path\",\"URLClickAction\":4,\"ResultStatus\":\"Success\"}", + "result": "success", + "preserve": { + "log.UserIp": "192.0.2.20", + "log.URL": "https://example.invalid/path", + "log.URLClickAction": 4 + }, + "expected": { + "target.url": "https://example.invalid/path", + "origin.ip": "192.0.2.20" + }, + "absent": [], + "ipEligible": true + }, + { + "name": "safe-links-native-shape-blocked", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"RecordType\":41,\"UserId\":\"analyst@example.invalid\",\"UserIp\":\"192.0.2.20\",\"URL\":\"https://example.invalid/path\",\"URLClickAction\":2,\"ResultStatus\":\"Success\"}", + "result": "denied", + "preserve": { + "log.UserIp": "192.0.2.20", + "log.URL": "https://example.invalid/path", + "log.URLClickAction": 2 + }, + "expected": { + "target.url": "https://example.invalid/path", + "origin.ip": "192.0.2.20" + }, + "absent": [], + "ipEligible": true + }, + { + "name": "safe-links-native-shape-invalid-ip", + "raw": "{\"Operation\":\"ClickedSafeLink\",\"RecordType\":41,\"UserId\":\"analyst@example.invalid\",\"UserIp\":\"not-an-ip\",\"URL\":\"https://example.invalid/path\",\"URLClickAction\":4,\"ResultStatus\":\"Success\"}", + "result": "success", + "preserve": { + "log.UserIp": "not-an-ip", + "log.URL": "https://example.invalid/path", + "log.URLClickAction": 4 + }, + "expected": { + "target.url": "https://example.invalid/path" + }, + "absent": [ + "origin.ip" + ], + "ipEligible": false + }, + { + "name": "sts-login-label-without-final-code", + "raw": "{\"Operation\":\"UserLoggedIn\",\"Workload\":\"AzureActiveDirectory\",\"RecordType\":15,\"ClientIP\":\"192.0.2.10\",\"UserId\":\"analyst@example.invalid\",\"ResultStatus\":\"Success\"}", + "result": "", + "preserve": { + "log.ResultStatus": "Success" + } + } +] diff --git a/rules/office365/credential_access_microsoft_365_potential_password_spraying_attack.yml b/rules/office365/credential_access_microsoft_365_potential_password_spraying_attack.yml index 3e8e7f493..2a6664372 100644 --- a/rules/office365/credential_access_microsoft_365_potential_password_spraying_attack.yml +++ b/rules/office365/credential_access_microsoft_365_potential_password_spraying_attack.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.3 +# Rule version v1.0.4 dataTypes: - "o365" @@ -16,7 +16,7 @@ references: description: "Credential Access consists of techniques for stealing credentials like account names and passwords. Techniques used to get credentials include keylogging or credential dumping. Using legitimate credentials can give adversaries access to systems, make them harder to detect, and provide the opportunity to create more accounts to help achieve their goals.
Identifies a high number (25) of failed Microsoft 365 user authentication attempts from a single IP address within 30 minutes, which could be indicative of a password spraying attack. An adversary may attempt a password spraying attack to obtain unauthorized access to user accounts." where: | - oneOf("log.Workload", ["Exchange", "AzureActiveDirectory"]) && oneOf("action", ["UserLoginFailed", "PasswordLogonInitialAuthUsingPassword"]) && oneOf("actionResult", ["failed"]) && exists("origin.ip") + oneOf("log.Workload", ["Exchange", "AzureActiveDirectory"]) && oneOf("action", ["UserLoginFailed", "PasswordLogonInitialAuthUsingPassword"]) && oneOf("actionResult", ["failure", "failed"]) && exists("origin.ip") afterEvents: - indexPattern: v11-log-o365-* with: diff --git a/rules/office365/dlp_policy_violations.yml b/rules/office365/dlp_policy_violations.yml index c6ec30033..1047e6457 100644 --- a/rules/office365/dlp_policy_violations.yml +++ b/rules/office365/dlp_policy_violations.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - o365 @@ -41,7 +41,7 @@ where: | equals("log.Workload", "Teams") || equals("log.Workload", "SecurityComplianceCenter") ) && - !equals("actionResult", "failed") + !oneOf("actionResult", ["failure", "failed"]) groupBy: - lastEvent.log.PolicyId - lastEvent.log.SensitiveInfoTypeData diff --git a/rules/office365/information_barriers_violations.yml b/rules/office365/information_barriers_violations.yml index ef3b66437..2301d1c36 100644 --- a/rules/office365/information_barriers_violations.yml +++ b/rules/office365/information_barriers_violations.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - o365 @@ -24,7 +24,7 @@ description: | 5. Provide additional training to users if violations appear to be due to lack of awareness 6. Consider implementing additional technical controls to prevent future violations where: | - equals("action", "InformationBarrierPolicyViolation") || (equals("log.PolicyType", "InformationBarrier") && equals("actionResult", "blocked")) || (equals("log.ViolationType", "InformationBarrier") && equals("action", "CommunicationBlocked")) + equals("action", "InformationBarrierPolicyViolation") || (equals("log.PolicyType", "InformationBarrier") && oneOf("actionResult", ["denied", "blocked"])) || (equals("log.ViolationType", "InformationBarrier") && equals("action", "CommunicationBlocked")) afterEvents: - indexPattern: v11-log-o365-* with: diff --git a/rules/office365/insider_risk_indicators.yml b/rules/office365/insider_risk_indicators.yml index 608a7f5c2..fbacd7aec 100644 --- a/rules/office365/insider_risk_indicators.yml +++ b/rules/office365/insider_risk_indicators.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - o365 @@ -26,7 +26,7 @@ description: | 7. Consider implementing additional monitoring or access restrictions if suspicious activity is confirmed 8. Escalate to security team and HR if malicious intent is suspected where: | - equals("action", "InsiderRiskAlert") || (contains("log.PolicyName", "InsiderRisk") && equals("actionResult", "blocked")) || (oneOf("log.RiskLevel", ["High", "Critical"]) && equals("log.AlertSource", "InsiderRiskManagement")) + equals("action", "InsiderRiskAlert") || (contains("log.PolicyName", "InsiderRisk") && oneOf("actionResult", ["denied", "blocked"])) || (oneOf("log.RiskLevel", ["High", "Critical"]) && equals("log.AlertSource", "InsiderRiskManagement")) groupBy: - lastEvent.log.PolicyName - lastEvent.log.RiskLevel diff --git a/rules/office365/possible_succesfull_password_guessing_o365.yml b/rules/office365/possible_succesfull_password_guessing_o365.yml index 1c17e8b10..d8f95b26a 100644 --- a/rules/office365/possible_succesfull_password_guessing_o365.yml +++ b/rules/office365/possible_succesfull_password_guessing_o365.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - o365 @@ -21,7 +21,7 @@ references: - "https://attack.mitre.org/tactics/TA0006" - "https://attack.mitre.org/techniques/T1110/001/" where: | - oneOf("log.Workload", ["Exchange","AzureActiveDirectory"]) && equals("action", "UserLoginFailed") && oneOf("actionResult", ["failed"]) && exists("origin.user") && exists("origin.ip") + oneOf("log.Workload", ["Exchange","AzureActiveDirectory"]) && equals("action", "UserLoginFailed") && oneOf("actionResult", ["failure", "failed"]) && exists("origin.user") && exists("origin.ip") afterEvents: - indexPattern: v11-log-o365-* with: @@ -33,7 +33,7 @@ afterEvents: value: "{{.origin.user}}" - field: origin.ip operator: filter_term - value: "{{.log.clientIP}}" + value: "{{.origin.ip}}" within: 1m count: 10 groupBy: diff --git a/rules/office365/safe_links_click_patterns.yml b/rules/office365/safe_links_click_patterns.yml index 5ee89a314..6421ff26e 100644 --- a/rules/office365/safe_links_click_patterns.yml +++ b/rules/office365/safe_links_click_patterns.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - o365 @@ -24,7 +24,7 @@ description: | 5. Implement additional security awareness training for the affected user 6. Consider blocking the malicious domains at the network level where: | - equals("action", "ClickedSafeLink") && equals("actionResult", "blocked") && exists("origin.user") + equals("action", "ClickedSafeLink") && oneOf("actionResult", ["denied", "blocked"]) && exists("origin.user") afterEvents: - indexPattern: v11-log-o365-* with: From 20a9f321bddba99e606c8c75254d8242e9f42816 Mon Sep 17 00:00:00 2001 From: Ricardo Valdes Date: Wed, 23 Sep 2026 11:19:20 -0400 Subject: [PATCH 2/5] feat(o365): add grouped administrator awareness rules --- filters/office365/o365.yml | 40 +- plugins/alerts/o365_awareness_test.go | 105 + plugins/alerts/testdata/o365_awareness.json | 2959 +++++++++++++++++ .../awareness_calendar_delegation.yml | 31 + rules/office365/awareness_mail_connectors.yml | 31 + .../awareness_mailbox_client_access.yml | 31 + .../awareness_mailbox_folder_permissions.yml | 32 + ...ollection_microsoft_365_new_inbox_rule.yml | 45 +- rules/office365/mail_forwarding_rules.yml | 52 +- .../mailbox_auto_forwarding_set_mailbox.yml | 40 +- rules/office365/mailbox_delegation_abuse.yml | 55 +- rules/office365/suspicious_inbox_rules.yml | 31 - 12 files changed, 3328 insertions(+), 124 deletions(-) create mode 100644 plugins/alerts/o365_awareness_test.go create mode 100644 plugins/alerts/testdata/o365_awareness.json create mode 100644 rules/office365/awareness_calendar_delegation.yml create mode 100644 rules/office365/awareness_mail_connectors.yml create mode 100644 rules/office365/awareness_mailbox_client_access.yml create mode 100644 rules/office365/awareness_mailbox_folder_permissions.yml delete mode 100644 rules/office365/suspicious_inbox_rules.yml diff --git a/filters/office365/o365.yml b/filters/office365/o365.yml index 395ebbc82..b4b823fde 100755 --- a/filters/office365/o365.yml +++ b/filters/office365/o365.yml @@ -1,4 +1,4 @@ -# Microsoft 365 filter, version 1.3.0 +# Microsoft 365 filter, version 1.4.0 pipeline: - dataTypes: @@ -8,6 +8,44 @@ pipeline: source: raw - drop: where: oneOf("log.Operation", ['AINotesUpdate', 'AcceptedSharingLinkOnFolder', 'AccessRequestUpdated', 'AccessedOdataLink', 'AddCommentToIncident.', 'AddFormCoauthor', 'AddRemediatedData', 'AddTagsToIncident', 'AdminThreadMuted', 'AdminThreadUnmuted', 'AlertExcelDownloaded', 'AlertNotificationsRecipientAdded', 'AllowShareFormForCopy', 'AppPublishedToCatalog', 'AppUpdatedInCatalog', 'AppUpgraded', 'ApplyRecordLabel', 'ApproveDisposal', 'AssignUserToIncident', 'AuditSearchCancelled', 'AuditSearchCompleted', 'AuditSearchCreated', 'AuditSearchExportJobCompleted', 'AuditSearchExportJobCreated', 'AuditSearchExportResultsDownloaded', 'BackupItemAdded', 'BackupItemRemoved', 'BackupItemRestoreCompleted', 'BackupItemRestoreTriggered', 'BackupPolicyActivated', 'BackupPolicyPaused', 'BotAddedToTeam', 'BreakEnded', 'BurnJob', 'CanceledQuery', 'CaseUpdated', 'ChannelAdded', 'ChannelOwnerResponded', 'ChatRetrieved', 'ChatUpdated', 'ClassificationAdded', 'ClassificationDefinitionCreated', 'ClientViewSignaled', 'ClockedIn', 'ClockedOut', 'CloseConversation', 'CollectionCreated', 'CollectionHardDeleted', 'CollectionRenamed', 'CollectionSoftDeleted', 'CollectionUpdated', 'ComplianceManagerAutomationChange', 'ComplianceSettingChanged', 'ConnectToExcelWorkbook', 'ConnectorAdded', 'CopilotInteraction', 'Copy', 'Create', 'CreateComment', 'CreateCopilotPlugin', 'CreateCopilotPromptBook', 'CreateForm', 'CreateResponse', 'CreateTag', 'CreateUpdateRequest', 'CreateWorkingSet', 'CreateWorkingSetSearch', 'DataExport', 'DataShareCreated', 'DataShareDeleted', 'DeleteCopilotPlugin', 'DeleteCopilotPromptBook', 'DeleteSummaryLink', 'DeleteTag', 'DeleteWorkingSetSearch', 'DeletedResult', 'DisableCopilotPlugin', 'DisableCopilotPromptBook', 'DisallowShareFormForCopy', 'DocumentSensitivityMismatchDetected', 'DomainControllerCoverageExcelDownloaded', 'DownloadCopyOfLakeData', 'DownloadDocument', 'DownloadedReport', 'DraftRestoreTaskCreated', 'DraftRestoreTaskDeleted', 'DraftRestoreTaskEdited', 'EditUpdateRequest', 'EnableCopilotPlugin', 'EnableCopilotPromptBook', 'EntityCreated', 'ErrorRemediationJob', 'ExchangeDataProactivelyPreserved', 'ExecutedQuery', 'ExportForm', 'ExportJob', 'ExtendRetention', 'FailedValidation', 'FileCheckOutDiscarded', 'FileCheckedIn', 'FileCheckedOut', 'FileCopied', 'FileDeletedFirstStageRecycleBin', 'FileDeletedSecondStageRecycleBin', 'FileModifiedExtended', 'FileRecycled', 'FileRestored', 'FileSyncDownloadedFull', 'FileSyncUploadedFull', 'FileUpdateDescription', 'FileUploaded', 'FileVersionRecycled', 'FileVersionsAllMinorsRecycled', 'FileVersionsAllRecycled', 'FileVisited', 'FolderCopied', 'FolderCreated', 'FolderDeletedFirstStageRecycleBin', 'FolderDeletedSecondStageRecycleBin', 'FolderRecycled', 'FolderRestored', 'FolderSharingLinkShared', 'GenerateCopyOfLakeData', 'GetAllRestoreArtifactsInTask', 'GetBackupItem', 'GetRestoreTaskDetails', 'GetSummaryLink', 'GlossaryTermAssigned', 'GlossaryTermCreated', 'HoldRemoved', 'HoldUpdated', 'HubSiteJoined', 'HubSiteOrphanHubDeleted', 'HubSiteRegistered', 'InformationBarriersInsightsReportCompleted', 'InformationBarriersInsightsReportOneDriveSectionQueried', 'InformationBarriersInsightsReportSchedule', 'InformationBarriersInsightsReportSharePointSectionQueried', 'InviteSent', 'InviteeResponded', 'LabelContentExplorerAccessedItem', 'LegacyWorkflowEnabledSet', 'LinkedEntityCreated', 'ListAllBackupItemsInPolicies', 'ListAllBackupItemsInTenant', 'ListAllBackupItemsInWorkload', 'ListAllBackupPolicies', 'ListAllRestorePoints', 'ListAllRestoreTasks', 'ListColumnCreated', 'ListColumnUpdated', 'ListContentTypeCreated', 'ListContentTypeDeleted', 'ListContentTypeUpdated', 'ListCreated', 'ListForms', 'ListItemCreated', 'ListItemRecycled', 'ListItemRestored', 'LiveNotesUpdate', 'LockRecord', 'LogsCollection', 'ManagedSyncClientAllowed', 'MarkedMessageChanged', 'MeetingDetail', 'MeetingParticipantDetail', 'MessageCreatedHasLink', 'MessageCreatedNotification', 'MessageCreation', 'MessageDeleted', 'MessageDeletedNotification', 'MessageEditedHasLink', 'MessageHostedContentsListed', 'MessageRead', 'MessageUpdated', 'MessageUpdatedNotification', 'MonitoringAlertNotificationRecipientAdded', 'MonitoringAlertUpdated', 'MoveForm', 'MovedFormIntoCollection', 'MovedFormOutofCollection', 'NewAdaptiveScope', 'NewBackupPolicyCreated', 'NewComplianceTag', 'NewRetentionCompliancePolicy', 'NewsFeedEnabledSet', 'OffShiftDialogAccepted', 'OfficeOnDemandSet', 'OpenConversation', 'OpenShiftAdded', 'PagePrefetched', 'PageViewed', 'PageViewedExtended', 'PeopleResultsScopeSet', 'PerformedCardAction', 'PlanCopied', 'PlanListRead', 'PreviewForm', 'PreviewItemDownloaded', 'PreviewItemListed', 'PreviewModeEnabledSet', 'PreviewWorkingSetSearch', 'ProInvitation', 'ProjectCreated', 'ProjectListAccessed', 'PulseCancel', 'PulseCreate', 'PulseCreateDraft', 'PulseDeleteDraft', 'PulseExtendDeadline', 'PulseInvite', 'PulseShareResults', 'PulseSubmit', 'QuarantinePreview', 'QuarantineReleaseRequest', 'QuarantineReleaseRequestDeny', 'QuarantineViewHeader', 'RecordDelete', 'RelabelItem', 'RemediationActionAdded', 'RemediationActionUpdated', 'RemoveAdaptiveScope', 'RemoveComplianceTag', 'RemoveCuratedTopic', 'RemoveFormCoauthor', 'RemoveTagsFromIncident', 'RemovedSearchExported', 'RemovedSearchPreviewed', 'RemovedSearchResultsPurged', 'RemovedSearchResultsSentToZoom', 'ReportDownloaded', 'RequestAdded', 'RequestRespondedTo', 'RestoreTaskActivated', 'RestoreTaskCompleted', 'RoadmapAccessed', 'RoadmapCreated', 'RoadmapItemAccessed', 'RoadmapItemCreated', 'RunAntiVirusScan', 'ScheduleGroupAdded', 'ScheduleShared', 'SearchPermissionUpdated', 'SearchQueryPerformed', 'SearchRemoved', 'SearchReport', 'SearchReportRemoved', 'SearchResultsSentToZoom', 'SearchStopped', 'SearchUpdated', 'SearchViewed', 'Send', 'SensitivityLabelApplied', 'SensitivityLabelChanged', 'SensorActivationMethodConfigurationUpdated', 'SensorCreated', 'SensorDeploymentAccessKeyReceived', 'SensorDeploymentAccessKeyUpdated', 'SetAdvancedFeatures', 'SetRestrictiveRetentionUI', 'SharePointDataProactivelyPreserved', 'SharingInvitationRevoked', 'SharingInvitationUpdated', 'ShiftAdded', 'SiteAdminChangeRequest', 'SiteCollectionCreated', 'SiteCollectionQuotaModified', 'SiteColumnCreated', 'SiteColumnDeleted', 'SiteColumnUpdated', 'SiteContentTypeCreated', 'SiteContentTypeDeleted', 'SiteContentTypeUpdated', 'SoftDeleteSettingsUpdated', 'SubTaskCreated', 'SubmitResponse', 'SubmitUpdate', 'SubscribedToMessages', 'SupervisionRuleMatch', 'SupervisoryReviewTag', 'TabAdded', 'TabUpdated', 'TagFiles', 'TagJob', 'TaggingConfigurationUpdated', 'TaskAccessed', 'TaskAssigned', 'TaskCompleted', 'TaskCreated', 'TaskListCreated', 'TaskListRead', 'TaskRead', 'TeamCreated', 'ThreadAccessFailure', 'ThreadViewed', 'TimeClockEntryAdded', 'TimeOffAdded', 'UnlockRecord', 'Update', 'UpdateCopilotPlugin', 'UpdateCopilotPromptBook', 'UpdateCopilotSettings', 'UpdateIncidentStatus', 'UpdateResponse', 'UpdateTag', 'UpdateUsageReportsPrivacySetting', 'UpdateWorkingSetSearch', 'UpdatedPolicyConfigPriority', 'UploadedOrgData', 'UsagePolicyAcceptance', 'ViewBackupPolicyDetails', 'ViewDocument', 'ViewForm', 'ViewResponse', 'ViewResponses', 'ViewRuntimeForm', 'ViewUpdate', 'ViewedExplore', 'ViewedSearchExported', 'ViewedSearchPreviewed', 'WorkforceIntegrationAdded', 'WorkspaceCreated', 'updateddeviceconfiguration']) + # Capture documented Name/Value parameter identities before the legacy string + # cast loses their structure. These flags mean a setting was supplied, including + # clearing it; they do not establish an enabled setting or an external recipient. + # Never trust markers supplied by the input record. + - delete: + fields: + - log.o365InboxForwardingChange + - log.o365MailboxForwardingChange + - log.o365SendOnBehalfChange + - add: + function: string + params: + key: log.o365InboxForwardingChange + value: "true" + where: >- + equals("log.Workload", "Exchange") && + oneOf("log.Operation", ["New-InboxRule", "Set-InboxRule"]) && + (exists("log.Parameters.#(Name==ForwardTo).Name") || + exists("log.Parameters.#(Name==ForwardAsAttachmentTo).Name") || + exists("log.Parameters.#(Name==RedirectTo).Name")) + - add: + function: string + params: + key: log.o365MailboxForwardingChange + value: "true" + where: >- + equals("log.Workload", "Exchange") && equals("log.Operation", "Set-Mailbox") && + (exists("log.Parameters.#(Name==ForwardingAddress).Name") || + exists("log.Parameters.#(Name==ForwardingSmtpAddress).Name") || + exists("log.Parameters.#(Name==DeliverToMailboxAndForward).Name")) + - add: + function: string + params: + key: log.o365SendOnBehalfChange + value: "true" + where: >- + equals("log.Workload", "Exchange") && equals("log.Operation", "Set-Mailbox") && + exists("log.Parameters.#(Name==GrantSendOnBehalfTo).Name") - cast: fields: - log.Parameters diff --git a/plugins/alerts/o365_awareness_test.go b/plugins/alerts/o365_awareness_test.go new file mode 100644 index 000000000..0a6073a5e --- /dev/null +++ b/plugins/alerts/o365_awareness_test.go @@ -0,0 +1,105 @@ +package main + +import ( + "encoding/json" + "os" + "reflect" + "strings" + "testing" + + "github.com/threatwinds/go-sdk/plugins" + "github.com/tidwall/gjson" +) + +// These fabricated raw records exercise the complete checked-in O365 filter +// model and the pinned SDK CEL. The EventProcessor playground separately runs +// the real parser; neither test claims customer alert indexing or notifications. +func TestO365AwarenessRawPredicatesAndGrouping(t *testing.T) { + var cases []struct { + Name string `json:"name"` + Raw string `json:"raw"` + Rule string `json:"rule"` + Match bool `json:"match"` + Expected map[string]any `json:"expected"` + Absent []string `json:"absent"` + } + b, err := os.ReadFile("testdata/o365_awareness.json") + if err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(b, &cases); err != nil { + t.Fatal(err) + } + if len(cases) < 50 { + t.Fatalf("awareness fixture set unexpectedly small: %d", len(cases)) + } + paths := map[string]*plugins.Rule{} + for _, tc := range cases { + if _, ok := paths[tc.Rule]; ok { + continue + } + if !strings.HasPrefix(tc.Rule, "office365/") || !strings.HasSuffix(tc.Rule, ".yml") { + t.Fatalf("unexpected rule path %s", tc.Rule) + } + stem := strings.TrimSuffix(strings.TrimPrefix(tc.Rule, "office365/"), ".yml") + paths[tc.Rule] = o365OutcomeRule(t, stem) + } + if len(paths) != 8 { + t.Fatalf("want eight shipped awareness rules, got %d", len(paths)) + } + group := []string{"lastEvent.tenantId", "lastEvent.log.OrganizationId", "dataSource", "adversary.user", "lastEvent.action", "lastEvent.log.ObjectId", "target.user", "lastEvent.log.MailboxOwnerUPN"} + for path, rule := range paths { + want := append([]string(nil), group...) + if strings.Contains(path, "folder_permissions") { + want = append(want, "lastEvent.log.folderId") + } + if !reflect.DeepEqual(rule.GroupBy, want) { + t.Fatalf("%s: grouping paths %v, want %v", path, rule.GroupBy, want) + } + if len(rule.DeduplicateBy) != 0 || len(rule.Correlation) != 0 || len(rule.AfterEvents) != 0 { + t.Fatalf("%s: awareness alerts should retain every change without history thresholds or suppression", path) + } + if rule.Impact.GetConfidentiality() != 1 || rule.Impact.GetIntegrity() != 1 || rule.Impact.GetAvailability() != 0 || rule.Adversary != "origin" { + t.Fatalf("%s: invalid awareness impact or attribution", path) + } + } + cache := plugins.NewCELCache("o365-awareness") + seen := map[string]bool{} + for _, tc := range cases { + t.Run(tc.Name, func(t *testing.T) { + if seen[tc.Name] { + t.Fatal("duplicate fixture") + } + seen[tc.Name] = true + event := o365ActionResultNormalize(t, tc.Raw) + for path, want := range tc.Expected { + got := gjson.Get(event, path) + if !got.Exists() || !reflect.DeepEqual(got.Value(), want) { + t.Errorf("normalized %s = %v, want %v", path, got.Value(), want) + } + } + for _, path := range tc.Absent { + if gjson.Get(event, path).Exists() { + t.Errorf("unexpected normalized %s", path) + } + } + matches := 0 + for path, rule := range paths { + got, err := cache.Eval(rule.Where, event) + if err != nil { + t.Fatalf("%s: CEL: %v", path, err) + } + want := path == tc.Rule && tc.Match + if got != want { + t.Errorf("%s: predicate = %v, want %v", path, got, want) + } + if got { + matches++ + } + } + if matches > 1 { + t.Errorf("one administrative change matched %d awareness rules", matches) + } + }) + } +} diff --git a/plugins/alerts/testdata/o365_awareness.json b/plugins/alerts/testdata/o365_awareness.json new file mode 100644 index 000000000..7f3dc57f9 --- /dev/null +++ b/plugins/alerts/testdata/o365_awareness.json @@ -0,0 +1,2959 @@ +[ + { + "name": "inbox-New-InboxRule", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"Administrative rule\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:Administrative rule]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-Set-InboxRule", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"Administrative rule\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:Administrative rule]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-UpdateInboxRules", + "raw": "{\"Operation\":\"UpdateInboxRules\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\"}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "UpdateInboxRules", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "target.user": "mailbox@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-Enable-InboxRule", + "raw": "{\"Operation\":\"Enable-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"Administrative rule\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "Enable-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:Administrative rule]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-Disable-InboxRule", + "raw": "{\"Operation\":\"Disable-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"Administrative rule\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "Disable-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:Administrative rule]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-Remove-InboxRule", + "raw": "{\"Operation\":\"Remove-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"Administrative rule\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "Remove-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:Administrative rule]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-New-InboxRule-ForwardTo", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-clear-New-InboxRule-ForwardTo", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardTo\",\"Value\":\"\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardTo Value:]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-New-InboxRule-ForwardAsAttachmentTo", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardAsAttachmentTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardAsAttachmentTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-clear-New-InboxRule-ForwardAsAttachmentTo", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardAsAttachmentTo\",\"Value\":\"\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardAsAttachmentTo Value:]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-New-InboxRule-RedirectTo", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"RedirectTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:RedirectTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-clear-New-InboxRule-RedirectTo", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"RedirectTo\",\"Value\":\"\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:RedirectTo Value:]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-Set-InboxRule-ForwardTo", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-clear-Set-InboxRule-ForwardTo", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardTo\",\"Value\":\"\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardTo Value:]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-Set-InboxRule-ForwardAsAttachmentTo", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardAsAttachmentTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardAsAttachmentTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-clear-Set-InboxRule-ForwardAsAttachmentTo", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardAsAttachmentTo\",\"Value\":\"\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardAsAttachmentTo Value:]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-Set-InboxRule-RedirectTo", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"RedirectTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:RedirectTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-clear-Set-InboxRule-RedirectTo", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"RedirectTo\",\"Value\":\"\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:RedirectTo Value:]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-forward-ForwardingAddress", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingAddress\",\"Value\":\"recipient@example.invalid\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardingAddress Value:recipient@example.invalid]]", + "log.o365MailboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-forward-clear-ForwardingAddress", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingAddress\",\"Value\":\"\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardingAddress Value:]]", + "log.o365MailboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-forward-ForwardingSmtpAddress", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingSmtpAddress\",\"Value\":\"recipient@example.invalid\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardingSmtpAddress Value:recipient@example.invalid]]", + "log.o365MailboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-forward-clear-ForwardingSmtpAddress", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingSmtpAddress\",\"Value\":\"\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardingSmtpAddress Value:]]", + "log.o365MailboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-forward-DeliverToMailboxAndForward", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DeliverToMailboxAndForward\",\"Value\":\"True\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DeliverToMailboxAndForward Value:True]]", + "log.o365MailboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-forward-clear-DeliverToMailboxAndForward", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DeliverToMailboxAndForward\",\"Value\":\"False\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DeliverToMailboxAndForward Value:False]]", + "log.o365MailboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegate-Add-MailboxPermission", + "raw": "{\"Operation\":\"Add-MailboxPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": true, + "expected": { + "action": "Add-MailboxPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegate-Remove-MailboxPermission", + "raw": "{\"Operation\":\"Remove-MailboxPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": true, + "expected": { + "action": "Remove-MailboxPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegate-Add-RecipientPermission", + "raw": "{\"Operation\":\"Add-RecipientPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": true, + "expected": { + "action": "Add-RecipientPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegate-Remove-RecipientPermission", + "raw": "{\"Operation\":\"Remove-RecipientPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": true, + "expected": { + "action": "Remove-RecipientPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegate-GrantSendOnBehalfTo", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"GrantSendOnBehalfTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:GrantSendOnBehalfTo Value:delegate@example.invalid]]", + "log.o365SendOnBehalfChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange" + ] + }, + { + "name": "delegate-clear-GrantSendOnBehalfTo", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"GrantSendOnBehalfTo\",\"Value\":\"\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:GrantSendOnBehalfTo Value:]]", + "log.o365SendOnBehalfChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange" + ] + }, + { + "name": "folder-Add-MailboxFolderPermission", + "raw": "{\"Operation\":\"Add-MailboxFolderPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "Add-MailboxFolderPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-Set-MailboxFolderPermission", + "raw": "{\"Operation\":\"Set-MailboxFolderPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "Set-MailboxFolderPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-Remove-MailboxFolderPermission", + "raw": "{\"Operation\":\"Remove-MailboxFolderPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "Remove-MailboxFolderPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-AddFolderPermissions", + "raw": "{\"Operation\":\"AddFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"}}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "AddFolderPermissions", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "target.user": "mailbox@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success", + "log.folderId": "folder-fixture-001", + "log.folderPath": "/Calendar" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.Folder.Id", + "log.Folder.Path", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-ModifyFolderPermissions", + "raw": "{\"Operation\":\"ModifyFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"}}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "ModifyFolderPermissions", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "target.user": "mailbox@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success", + "log.folderId": "folder-fixture-001", + "log.folderPath": "/Calendar" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.Folder.Id", + "log.Folder.Path", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-RemoveFolderPermissions", + "raw": "{\"Operation\":\"RemoveFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"}}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "RemoveFolderPermissions", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "target.user": "mailbox@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success", + "log.folderId": "folder-fixture-001", + "log.folderPath": "/Calendar" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.Folder.Id", + "log.Folder.Path", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "calendar-UpdateCalendarDelegation", + "raw": "{\"Operation\":\"UpdateCalendarDelegation\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\"}", + "rule": "office365/awareness_calendar_delegation.yml", + "match": true, + "expected": { + "action": "UpdateCalendarDelegation", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "target.user": "mailbox@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "connector-New-InboundConnector", + "raw": "{\"Operation\":\"New-InboundConnector\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": true, + "expected": { + "action": "New-InboundConnector", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "connector-Set-InboundConnector", + "raw": "{\"Operation\":\"Set-InboundConnector\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": true, + "expected": { + "action": "Set-InboundConnector", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "connector-Remove-InboundConnector", + "raw": "{\"Operation\":\"Remove-InboundConnector\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": true, + "expected": { + "action": "Remove-InboundConnector", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "connector-New-OutboundConnector", + "raw": "{\"Operation\":\"New-OutboundConnector\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": true, + "expected": { + "action": "New-OutboundConnector", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "connector-Set-OutboundConnector", + "raw": "{\"Operation\":\"Set-OutboundConnector\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": true, + "expected": { + "action": "Set-OutboundConnector", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "connector-Remove-OutboundConnector", + "raw": "{\"Operation\":\"Remove-OutboundConnector\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": true, + "expected": { + "action": "Remove-OutboundConnector", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "client-access-Set-CASMailbox", + "raw": "{\"Operation\":\"Set-CASMailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"administrative-fixture\"}]}", + "rule": "office365/awareness_mailbox_client_access.yml", + "match": true, + "expected": { + "action": "Set-CASMailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:administrative-fixture]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "collection_microsoft_365_new_inbox_rule-failed-operation", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"False\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"Administrative rule\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": false, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "False", + "actionResult": "failure", + "log.Parameters": "[map[Name:Name Value:Administrative rule]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "collection_microsoft_365_new_inbox_rule-wrong-workload", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"SharePoint\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"Administrative rule\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": false, + "expected": { + "action": "New-InboxRule", + "log.Workload": "SharePoint", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:Administrative rule]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "collection_microsoft_365_new_inbox_rule-missing-optional-identities", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"Administrative rule\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:Administrative rule]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "origin.user", + "log.OrganizationId", + "log.ObjectId", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mail_forwarding_rules-failed-operation", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"False\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": false, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "False", + "actionResult": "failure", + "log.Parameters": "[map[Name:ForwardTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mail_forwarding_rules-wrong-workload", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"SharePoint\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": false, + "expected": { + "action": "New-InboxRule", + "log.Workload": "SharePoint", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardTo Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mail_forwarding_rules-missing-optional-identities", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"Parameters\":[{\"Name\":\"ForwardTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "origin.user", + "log.OrganizationId", + "log.ObjectId", + "target.user", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox_auto_forwarding_set_mailbox-failed-operation", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"False\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingAddress\",\"Value\":\"recipient@example.invalid\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "False", + "actionResult": "failure", + "log.Parameters": "[map[Name:ForwardingAddress Value:recipient@example.invalid]]", + "log.o365MailboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox_auto_forwarding_set_mailbox-wrong-workload", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"SharePoint\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingAddress\",\"Value\":\"recipient@example.invalid\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "SharePoint", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardingAddress Value:recipient@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox_auto_forwarding_set_mailbox-missing-optional-identities", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"Parameters\":[{\"Name\":\"ForwardingAddress\",\"Value\":\"recipient@example.invalid\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardingAddress Value:recipient@example.invalid]]", + "log.o365MailboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "origin.user", + "log.OrganizationId", + "log.ObjectId", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox_delegation_abuse-failed-operation", + "raw": "{\"Operation\":\"Add-MailboxPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"False\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Add-MailboxPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "False", + "actionResult": "failure", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox_delegation_abuse-wrong-workload", + "raw": "{\"Operation\":\"Add-MailboxPermission\",\"Workload\":\"SharePoint\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Add-MailboxPermission", + "log.Workload": "SharePoint", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox_delegation_abuse-missing-optional-identities", + "raw": "{\"Operation\":\"Add-MailboxPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": true, + "expected": { + "action": "Add-MailboxPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "origin.user", + "log.OrganizationId", + "log.ObjectId", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mailbox_folder_permissions-failed-operation", + "raw": "{\"Operation\":\"Add-MailboxFolderPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"False\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": false, + "expected": { + "action": "Add-MailboxFolderPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "False", + "actionResult": "failure", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mailbox_folder_permissions-wrong-workload", + "raw": "{\"Operation\":\"Add-MailboxFolderPermission\",\"Workload\":\"SharePoint\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": false, + "expected": { + "action": "Add-MailboxFolderPermission", + "log.Workload": "SharePoint", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mailbox_folder_permissions-missing-optional-identities", + "raw": "{\"Operation\":\"Add-MailboxFolderPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "Add-MailboxFolderPermission", + "log.Workload": "Exchange", + "log.RecordType": 1, + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:User Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "origin.user", + "log.OrganizationId", + "log.ObjectId", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_calendar_delegation-failed-operation", + "raw": "{\"Operation\":\"UpdateCalendarDelegation\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Failed\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\"}", + "rule": "office365/awareness_calendar_delegation.yml", + "match": false, + "expected": { + "action": "UpdateCalendarDelegation", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "target.user": "mailbox@example.invalid", + "log.ResultStatus": "Failed", + "actionResult": "failure" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_calendar_delegation-wrong-workload", + "raw": "{\"Operation\":\"UpdateCalendarDelegation\",\"Workload\":\"SharePoint\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\"}", + "rule": "office365/awareness_calendar_delegation.yml", + "match": false, + "expected": { + "action": "UpdateCalendarDelegation", + "log.Workload": "SharePoint", + "log.RecordType": 2, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "target.user": "mailbox@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_calendar_delegation-missing-optional-identities", + "raw": "{\"Operation\":\"UpdateCalendarDelegation\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\"}", + "rule": "office365/awareness_calendar_delegation.yml", + "match": true, + "expected": { + "action": "UpdateCalendarDelegation", + "log.Workload": "Exchange", + "log.RecordType": 2, + "log.ResultStatus": "Succeeded", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "origin.user", + "log.OrganizationId", + "log.ObjectId", + "target.user", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mail_connectors-failed-operation", + "raw": "{\"Operation\":\"New-InboundConnector\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"False\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": false, + "expected": { + "action": "New-InboundConnector", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "False", + "actionResult": "failure", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mail_connectors-wrong-workload", + "raw": "{\"Operation\":\"New-InboundConnector\",\"Workload\":\"SharePoint\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": false, + "expected": { + "action": "New-InboundConnector", + "log.Workload": "SharePoint", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mail_connectors-missing-optional-identities", + "raw": "{\"Operation\":\"New-InboundConnector\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"Administrative connector\"}]}", + "rule": "office365/awareness_mail_connectors.yml", + "match": true, + "expected": { + "action": "New-InboundConnector", + "log.Workload": "Exchange", + "log.RecordType": 1, + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:Administrative connector]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "origin.user", + "log.OrganizationId", + "log.ObjectId", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mailbox_client_access-failed-operation", + "raw": "{\"Operation\":\"Set-CASMailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"False\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"administrative-fixture\"}]}", + "rule": "office365/awareness_mailbox_client_access.yml", + "match": false, + "expected": { + "action": "Set-CASMailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "False", + "actionResult": "failure", + "log.Parameters": "[map[Name:Identity Value:administrative-fixture]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mailbox_client_access-wrong-workload", + "raw": "{\"Operation\":\"Set-CASMailbox\",\"Workload\":\"SharePoint\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"administrative-fixture\"}]}", + "rule": "office365/awareness_mailbox_client_access.yml", + "match": false, + "expected": { + "action": "Set-CASMailbox", + "log.Workload": "SharePoint", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:administrative-fixture]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "awareness_mailbox_client_access-missing-optional-identities", + "raw": "{\"Operation\":\"Set-CASMailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"Parameters\":[{\"Name\":\"Identity\",\"Value\":\"administrative-fixture\"}]}", + "rule": "office365/awareness_mailbox_client_access.yml", + "match": true, + "expected": { + "action": "Set-CASMailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Identity Value:administrative-fixture]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "origin.user", + "log.OrganizationId", + "log.ObjectId", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-value-only-New-InboxRule", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"ForwardTo ForwardAsAttachmentTo RedirectTo\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:ForwardTo ForwardAsAttachmentTo RedirectTo]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-no-parameters-New-InboxRule", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\"}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-prefix-parameter-New-InboxRule", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardToBackup\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardToBackup Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-value-only-Set-InboxRule", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"Name\",\"Value\":\"ForwardTo ForwardAsAttachmentTo RedirectTo\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:Name Value:ForwardTo ForwardAsAttachmentTo RedirectTo]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-no-parameters-Set-InboxRule", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\"}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-prefix-parameter-Set-InboxRule", + "raw": "{\"Operation\":\"Set-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardToBackup\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "Set-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardToBackup Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-value-only-ForwardingAddress", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"ForwardingAddress\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:ForwardingAddress]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-value-only-ForwardingSmtpAddress", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"ForwardingSmtpAddress\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:ForwardingSmtpAddress]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-value-only-DeliverToMailboxAndForward", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"DeliverToMailboxAndForward\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:DeliverToMailboxAndForward]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-value-only", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"GrantSendOnBehalfTo\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:GrantSendOnBehalfTo]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-no-parameters", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\"}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-prefix-parameter", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingAddressBackup\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:ForwardingAddressBackup Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-prefix-parameter", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"GrantSendOnBehalfToBackup\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:GrantSendOnBehalfToBackup Value:delegate@example.invalid]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "json-string-parameters-ForwardTo", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":\"[{\\\"Name\\\":\\\"ForwardTo\\\",\\\"Value\\\":\\\"delegate@example.invalid\\\"}]\"}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[{\"Name\":\"ForwardTo\",\"Value\":\"delegate@example.invalid\"}]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "json-string-parameters-ForwardingSmtpAddress", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":\"[{\\\"Name\\\":\\\"ForwardingSmtpAddress\\\",\\\"Value\\\":\\\"delegate@example.invalid\\\"}]\"}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[{\"Name\":\"ForwardingSmtpAddress\",\"Value\":\"delegate@example.invalid\"}]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "json-string-parameters-GrantSendOnBehalfTo", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":\"[{\\\"Name\\\":\\\"GrantSendOnBehalfTo\\\",\\\"Value\\\":\\\"delegate@example.invalid\\\"}]\"}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[{\"Name\":\"GrantSendOnBehalfTo\",\"Value\":\"delegate@example.invalid\"}]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "unrelated-exchange-operation", + "raw": "{\"Operation\":\"Get-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\"}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": false, + "expected": { + "action": "Get-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.Parameters", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "forward-missing-result", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardTo\",\"Value\":\"delegate@example.invalid\"}]}", + "rule": "office365/mail_forwarding_rules.yml", + "match": false, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.Parameters": "[map[Name:ForwardTo Value:delegate@example.invalid]]", + "log.o365InboxForwardingChange": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "actionResult", + "log.ResultStatus", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "spoofed-marker-inbox", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingChange\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:Unrelated setting]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-parameters-string-array", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[\"ForwardTo\",\"ForwardingAddress\",\"GrantSendOnBehalfTo\"]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[ForwardTo ForwardingAddress GrantSendOnBehalfTo]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-parameters-numeric-array", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[1,2,3]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[1 2 3]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-parameters-wrong-name-types", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":[\"ForwardTo\"],\"Value\":\"recipient@example.invalid\"},{\"Name\":{\"nested\":\"ForwardingAddress\"},\"Value\":\"recipient@example.invalid\"},{\"Name\":null,\"Value\":\"GrantSendOnBehalfTo\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:[ForwardTo] Value:recipient@example.invalid] map[Name:map[nested:ForwardingAddress] Value:recipient@example.invalid] map[Name: Value:GrantSendOnBehalfTo]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-parameters-object", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":{\"Name\":\"ForwardTo\",\"Value\":\"recipient@example.invalid\"}}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "map[Name:ForwardTo Value:recipient@example.invalid]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-parameters-empty-array", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-parameters-null", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":null}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-value-spoof-go-map", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"map[Name:ForwardTo Value:recipient@example.invalid] map[Name:ForwardingAddress Value:recipient@example.invalid] map[Name:GrantSendOnBehalfTo Value:recipient@example.invalid]\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:map[Name:ForwardTo Value:recipient@example.invalid] map[Name:ForwardingAddress Value:recipient@example.invalid] map[Name:GrantSendOnBehalfTo Value:recipient@example.invalid]]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "inbox-value-spoof-json", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"{\\\"Name\\\":\\\"ForwardTo\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"} {\\\"Name\\\":\\\"ForwardingAddress\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"} {\\\"Name\\\":\\\"GrantSendOnBehalfTo\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"}\"}]}", + "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", + "match": true, + "expected": { + "action": "New-InboxRule", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:{\"Name\":\"ForwardTo\",\"Value\":\"recipient@example.invalid\"} {\"Name\":\"ForwardingAddress\",\"Value\":\"recipient@example.invalid\"} {\"Name\":\"GrantSendOnBehalfTo\",\"Value\":\"recipient@example.invalid\"}]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "spoofed-marker-mailbox", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingChange\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:Unrelated setting]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-parameters-string-array", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[\"ForwardTo\",\"ForwardingAddress\",\"GrantSendOnBehalfTo\"]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[ForwardTo ForwardingAddress GrantSendOnBehalfTo]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-parameters-numeric-array", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[1,2,3]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[1 2 3]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-parameters-wrong-name-types", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":[\"ForwardTo\"],\"Value\":\"recipient@example.invalid\"},{\"Name\":{\"nested\":\"ForwardingAddress\"},\"Value\":\"recipient@example.invalid\"},{\"Name\":null,\"Value\":\"GrantSendOnBehalfTo\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:[ForwardTo] Value:recipient@example.invalid] map[Name:map[nested:ForwardingAddress] Value:recipient@example.invalid] map[Name: Value:GrantSendOnBehalfTo]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-parameters-object", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":{\"Name\":\"ForwardTo\",\"Value\":\"recipient@example.invalid\"}}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "map[Name:ForwardTo Value:recipient@example.invalid]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-parameters-empty-array", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-parameters-null", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":null}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-value-spoof-go-map", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"map[Name:ForwardTo Value:recipient@example.invalid] map[Name:ForwardingAddress Value:recipient@example.invalid] map[Name:GrantSendOnBehalfTo Value:recipient@example.invalid]\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:map[Name:ForwardTo Value:recipient@example.invalid] map[Name:ForwardingAddress Value:recipient@example.invalid] map[Name:GrantSendOnBehalfTo Value:recipient@example.invalid]]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-value-spoof-json", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"{\\\"Name\\\":\\\"ForwardTo\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"} {\\\"Name\\\":\\\"ForwardingAddress\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"} {\\\"Name\\\":\\\"GrantSendOnBehalfTo\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"}\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:{\"Name\":\"ForwardTo\",\"Value\":\"recipient@example.invalid\"} {\"Name\":\"ForwardingAddress\",\"Value\":\"recipient@example.invalid\"} {\"Name\":\"GrantSendOnBehalfTo\",\"Value\":\"recipient@example.invalid\"}]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "spoofed-marker-delegation", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingChange\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:Unrelated setting]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-parameters-string-array", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[\"ForwardTo\",\"ForwardingAddress\",\"GrantSendOnBehalfTo\"]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[ForwardTo ForwardingAddress GrantSendOnBehalfTo]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-parameters-numeric-array", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[1,2,3]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[1 2 3]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-parameters-wrong-name-types", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":[\"ForwardTo\"],\"Value\":\"recipient@example.invalid\"},{\"Name\":{\"nested\":\"ForwardingAddress\"},\"Value\":\"recipient@example.invalid\"},{\"Name\":null,\"Value\":\"GrantSendOnBehalfTo\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:[ForwardTo] Value:recipient@example.invalid] map[Name:map[nested:ForwardingAddress] Value:recipient@example.invalid] map[Name: Value:GrantSendOnBehalfTo]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-parameters-object", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":{\"Name\":\"ForwardTo\",\"Value\":\"recipient@example.invalid\"}}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "map[Name:ForwardTo Value:recipient@example.invalid]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-parameters-empty-array", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-parameters-null", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":null}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-value-spoof-go-map", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"map[Name:ForwardTo Value:recipient@example.invalid] map[Name:ForwardingAddress Value:recipient@example.invalid] map[Name:GrantSendOnBehalfTo Value:recipient@example.invalid]\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:map[Name:ForwardTo Value:recipient@example.invalid] map[Name:ForwardingAddress Value:recipient@example.invalid] map[Name:GrantSendOnBehalfTo Value:recipient@example.invalid]]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "delegation-value-spoof-json", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"{\\\"Name\\\":\\\"ForwardTo\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"} {\\\"Name\\\":\\\"ForwardingAddress\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"} {\\\"Name\\\":\\\"GrantSendOnBehalfTo\\\",\\\"Value\\\":\\\"recipient@example.invalid\\\"}\"}]}", + "rule": "office365/mailbox_delegation_abuse.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DisplayName Value:{\"Name\":\"ForwardTo\",\"Value\":\"recipient@example.invalid\"} {\"Name\":\"ForwardingAddress\",\"Value\":\"recipient@example.invalid\"} {\"Name\":\"GrantSendOnBehalfTo\",\"Value\":\"recipient@example.invalid\"}]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + } +] diff --git a/rules/office365/awareness_calendar_delegation.yml b/rules/office365/awareness_calendar_delegation.yml new file mode 100644 index 000000000..aec329569 --- /dev/null +++ b/rules/office365/awareness_calendar_delegation.yml @@ -0,0 +1,31 @@ +# Rule version v1.1.0 + +dataTypes: +- o365 +name: Office 365 Calendar Delegate Changed +description: | + A user was added to or removed from another mailbox owner’s calendar delegation. The operation can be routine scheduling administration, but changes who can manage calendar items. + + Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. +category: Administrative Awareness +technique: 'T1098.002 - Account Manipulation: Additional Email Delegate Permissions' +adversary: origin +impact: + confidentiality: 1 + integrity: 1 + availability: 0 +references: +- https://learn.microsoft.com/en-us/purview/audit-log-activities +- https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema +- https://learn.microsoft.com/en-us/purview/audit-log-activities +where: | + equals("log.Workload", "Exchange") && equals("actionResult", "success") && equals("action", "UpdateCalendarDelegation") +groupBy: +- lastEvent.tenantId +- lastEvent.log.OrganizationId +- dataSource +- adversary.user +- lastEvent.action +- lastEvent.log.ObjectId +- target.user +- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/awareness_mail_connectors.yml b/rules/office365/awareness_mail_connectors.yml new file mode 100644 index 000000000..5bfbb31f6 --- /dev/null +++ b/rules/office365/awareness_mail_connectors.yml @@ -0,0 +1,31 @@ +# Rule version v1.1.0 + +dataTypes: +- o365 +name: Office 365 Mail Connector Changed +description: | + An inbound or outbound Exchange Online mail connector was created, changed or removed. Review routing and authentication settings in the audited object and confirm the administrator intended the change. + + Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. +category: Administrative Awareness +technique: Administrative mail flow change +adversary: origin +impact: + confidentiality: 1 + integrity: 1 + availability: 0 +references: +- https://learn.microsoft.com/en-us/purview/audit-log-activities +- https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema +- https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/new-inboundconnector?view=exchange-ps +where: | + equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["New-InboundConnector", "Set-InboundConnector", "Remove-InboundConnector", "New-OutboundConnector", "Set-OutboundConnector", "Remove-OutboundConnector"]) +groupBy: +- lastEvent.tenantId +- lastEvent.log.OrganizationId +- dataSource +- adversary.user +- lastEvent.action +- lastEvent.log.ObjectId +- target.user +- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/awareness_mailbox_client_access.yml b/rules/office365/awareness_mailbox_client_access.yml new file mode 100644 index 000000000..3e6511689 --- /dev/null +++ b/rules/office365/awareness_mailbox_client_access.yml @@ -0,0 +1,31 @@ +# Rule version v1.1.0 + +dataTypes: +- o365 +name: Office 365 Mailbox Client Access Changed +description: | + An administrator changed client access settings on a mailbox with Set-CASMailbox. Examine the changed protocol or access setting and the affected mailbox before deciding whether follow-up is needed. + + Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. +category: Administrative Awareness +technique: Administrative mailbox access change +adversary: origin +impact: + confidentiality: 1 + integrity: 1 + availability: 0 +references: +- https://learn.microsoft.com/en-us/purview/audit-log-activities +- https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema +- https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/set-casmailbox?view=exchange-ps +where: | + equals("log.Workload", "Exchange") && equals("actionResult", "success") && equals("action", "Set-CASMailbox") +groupBy: +- lastEvent.tenantId +- lastEvent.log.OrganizationId +- dataSource +- adversary.user +- lastEvent.action +- lastEvent.log.ObjectId +- target.user +- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/awareness_mailbox_folder_permissions.yml b/rules/office365/awareness_mailbox_folder_permissions.yml new file mode 100644 index 000000000..dde3d24e2 --- /dev/null +++ b/rules/office365/awareness_mailbox_folder_permissions.yml @@ -0,0 +1,32 @@ +# Rule version v1.1.0 + +dataTypes: +- o365 +name: Office 365 Mailbox Folder Permission Changed +description: | + An Exchange mailbox folder permission was added, modified or removed. This includes audited mailbox activity operations and Exchange administrator cmdlets, which can grant or revoke access to messages in a folder. + + Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. +category: Administrative Awareness +technique: 'T1098.002 - Account Manipulation: Additional Email Delegate Permissions' +adversary: origin +impact: + confidentiality: 1 + integrity: 1 + availability: 0 +references: +- https://learn.microsoft.com/en-us/purview/audit-log-activities +- https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema +- https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/add-mailboxfolderpermission?view=exchange-ps +where: | + equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["Add-MailboxFolderPermission", "Set-MailboxFolderPermission", "Remove-MailboxFolderPermission", "AddFolderPermissions", "ModifyFolderPermissions", "RemoveFolderPermissions"]) +groupBy: +- lastEvent.tenantId +- lastEvent.log.OrganizationId +- dataSource +- adversary.user +- lastEvent.action +- lastEvent.log.ObjectId +- target.user +- lastEvent.log.MailboxOwnerUPN +- lastEvent.log.folderId diff --git a/rules/office365/collection_microsoft_365_new_inbox_rule.yml b/rules/office365/collection_microsoft_365_new_inbox_rule.yml index 839453243..36b7c63b3 100644 --- a/rules/office365/collection_microsoft_365_new_inbox_rule.yml +++ b/rules/office365/collection_microsoft_365_new_inbox_rule.yml @@ -1,26 +1,31 @@ -# Rule version v1.0.3 +# Rule version v1.1.0 dataTypes: - - "o365" -name: "Microsoft 365 New Inbox Rule Created" -impact: - confidentiality: 3 - integrity: 2 - availability: 1 -category: "Collection" -technique: "T1114 - Email Collection" +- o365 +name: Office 365 Inbox Rule Changed +description: | + A user or administrator created, changed, enabled, disabled or removed an Exchange inbox rule. New and modified rules with explicit forwarding settings are handled by the dedicated forwarding alert. Outlook client UpdateInboxRules is an audited change whose specific sub-action may require review of OperationProperties. + + Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. +category: Administrative Awareness +technique: 'T1114.003 - Email Collection: Email Forwarding Rule' adversary: origin -description: "Credential Access consists of techniques for stealing credentials like account names and passwords. Techniques used to get credentials include keylogging or credential dumping. Using legitimate credentials can give adversaries access to systems, make them harder to detect, and provide the opportunity to create more accounts to help achieve their goals.
- Identifies when a new Inbox rule is created in Microsoft 365. Inbox rules process messages in the Inbox based on conditions and take actions, such as moving a message to a specified folder or deleting a message. Adequate permissions are required on the mailbox to create an Inbox rule." +impact: + confidentiality: 1 + integrity: 1 + availability: 0 references: - - "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/responding-to-a-compromised-email-account?view=o365-worldwide" - - "https://docs.microsoft.com/en-us/powershell/module/exchange/new-inboxrule?view=exchange-ps" - - "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-outlook-rules-forms-attack?view=o365-worldwide" - - "https://attack.mitre.org/techniques/T1114/" - - "https://attack.mitre.org/techniques/T1114/003/" - - "https://attack.mitre.org/tactics/TA0009/" +- https://learn.microsoft.com/en-us/purview/audit-log-activities +- https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema +- https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/new-inboxrule?view=exchange-ps where: | - equals("log.Workload", "Exchange") && equals("action", "New-InboxRule") && oneOf("actionResult", ["success"]) + equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "Enable-InboxRule", "Disable-InboxRule", "Remove-InboxRule"]) && !(oneOf("action", ["New-InboxRule", "Set-InboxRule"]) && (equals("log.o365InboxForwardingChange", "true") || exists("log.Parameters.#(Name==ForwardTo).Name") || exists("log.Parameters.#(Name==ForwardAsAttachmentTo).Name") || exists("log.Parameters.#(Name==RedirectTo).Name"))) groupBy: - - adversary.ip - - adversary.user +- lastEvent.tenantId +- lastEvent.log.OrganizationId +- dataSource +- adversary.user +- lastEvent.action +- lastEvent.log.ObjectId +- target.user +- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/mail_forwarding_rules.yml b/rules/office365/mail_forwarding_rules.yml index 13c797862..dae646d60 100644 --- a/rules/office365/mail_forwarding_rules.yml +++ b/rules/office365/mail_forwarding_rules.yml @@ -1,33 +1,31 @@ -# Rule version v1.0.0 +# Rule version v1.1.0 dataTypes: - - o365 -name: Suspicious Mail Forwarding Rule Creation -impact: - confidentiality: 3 - integrity: 2 - availability: 1 -category: Data Exfiltration -technique: "T1114.001 - Email Collection: Local Email Collection" -adversary: origin -references: - - https://docs.microsoft.com/en-us/microsoft-365/compliance/auditing-troubleshooting-scenarios - - https://attack.mitre.org/techniques/T1114/001/ +- o365 +name: Office 365 Inbox Forwarding Setting Changed description: | - Detects creation or modification of inbox rules that forward emails to external recipients, which could indicate data exfiltration attempts. This rule monitors for the creation of new inbox rules or modifications to existing rules that contain forwarding parameters. + An Exchange inbox rule creation or modification supplied a ForwardTo, ForwardAsAttachmentTo or RedirectTo setting. Clearing a setting is also a change. - Next Steps: - 1. Review the specific forwarding parameters in the log.Parameters field to identify the destination email address - 2. Verify if the forwarding destination is a legitimate business email or an external/suspicious address - 3. Check if the user who created the rule has legitimate business justification for email forwarding - 4. Review recent authentication logs for the affected user account for signs of compromise - 5. Examine the timing of the rule creation - if created outside business hours or immediately after login, investigate further - 6. Check for other suspicious activities by the same user account around the same timeframe - 7. If malicious, disable the forwarding rule and reset user credentials + Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. +category: Administrative Awareness +technique: 'T1114.003 - Email Collection: Email Forwarding Rule' +adversary: origin +impact: + confidentiality: 1 + integrity: 1 + availability: 0 +references: +- https://learn.microsoft.com/en-us/purview/audit-log-activities +- https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema +- https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/set-inboxrule?view=exchange-ps where: | - oneOf("action", ["New-InboxRule", "Set-InboxRule", "UpdateInboxRules"]) && - equals("actionResult", "success") && - (contains("log.Parameters", "ForwardTo") || contains("log.Parameters", "ForwardAsAttachmentTo") || contains("log.Parameters", "RedirectTo")) + equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["New-InboxRule", "Set-InboxRule"]) && (equals("log.o365InboxForwardingChange", "true") || exists("log.Parameters.#(Name==ForwardTo).Name") || exists("log.Parameters.#(Name==ForwardAsAttachmentTo).Name") || exists("log.Parameters.#(Name==RedirectTo).Name")) groupBy: - - adversary.ip - - adversary.user +- lastEvent.tenantId +- lastEvent.log.OrganizationId +- dataSource +- adversary.user +- lastEvent.action +- lastEvent.log.ObjectId +- target.user +- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/mailbox_auto_forwarding_set_mailbox.yml b/rules/office365/mailbox_auto_forwarding_set_mailbox.yml index 0509cf95c..86c8af6d0 100644 --- a/rules/office365/mailbox_auto_forwarding_set_mailbox.yml +++ b/rules/office365/mailbox_auto_forwarding_set_mailbox.yml @@ -1,21 +1,31 @@ -# Rule version v1.0.0 +# Rule version v1.1.0 dataTypes: - - "o365" -name: "O365 Mailbox Auto-Forwarding (Set-Mailbox)" -impact: - confidentiality: 3 - integrity: 2 - availability: 1 -category: "Data Exfiltration" -technique: "T1114.003 - Email Collection: Email Forwarding Rule" +- o365 +name: Office 365 Mailbox Forwarding Setting Changed +description: | + An administrator changed a mailbox forwarding parameter using Set-Mailbox: ForwardingAddress, ForwardingSmtpAddress or DeliverToMailboxAndForward. Inspect the recorded value to learn whether this enabled, redirected, changed or cleared forwarding. + + Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. +category: Administrative Awareness +technique: 'T1114.003 - Email Collection: Email Forwarding Rule' adversary: origin -description: "Detects when a mailbox is configured to automatically forward mail to another address via Set-Mailbox (the OWA \"Forwarding\" setting). The forwarded address appears in the ForwardingSmtpAddress parameter. Attackers set this to exfiltrate all of a mailbox's mail to an off-tenant or external address without creating an inbox rule, so legacy New-InboxRule / Set-InboxRule detections miss it. Note: this rule matches the indexed string element of the Parameters array (ForwardingSmtpAddress, value of the form smtp:
). Investigate whether the forwarding address is authorized and whether it is external (off-tenant)." +impact: + confidentiality: 1 + integrity: 1 + availability: 0 references: - - "https://learn.microsoft.com/en-us/purview/audit-log-activities" - - "https://learn.microsoft.com/en-us/purview/audit-mailbox-settings" - - "https://attack.mitre.org/techniques/T1114/003/" +- https://learn.microsoft.com/en-us/purview/audit-log-activities +- https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema +- https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/set-mailbox?view=exchange-ps where: | - equals("log.Workload", "Exchange") && equals("action", "Set-Mailbox") && contains("log.Parameters", "smtp:") && equals("actionResult", "success") + equals("log.Workload", "Exchange") && equals("actionResult", "success") && equals("action", "Set-Mailbox") && (equals("log.o365MailboxForwardingChange", "true") || exists("log.Parameters.#(Name==ForwardingAddress).Name") || exists("log.Parameters.#(Name==ForwardingSmtpAddress).Name") || exists("log.Parameters.#(Name==DeliverToMailboxAndForward).Name")) groupBy: - - adversary.user +- lastEvent.tenantId +- lastEvent.log.OrganizationId +- dataSource +- adversary.user +- lastEvent.action +- lastEvent.log.ObjectId +- target.user +- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/mailbox_delegation_abuse.yml b/rules/office365/mailbox_delegation_abuse.yml index 982191273..544b99a9c 100644 --- a/rules/office365/mailbox_delegation_abuse.yml +++ b/rules/office365/mailbox_delegation_abuse.yml @@ -1,36 +1,31 @@ -# Rule version v1.0.0 +# Rule version v1.1.0 dataTypes: - - o365 -name: Office 365 Mailbox Delegation Abuse -impact: - confidentiality: 3 - integrity: 2 - availability: 1 -category: Persistence -technique: "T1098.002 - Account Manipulation: Additional Email Delegate Permissions" -adversary: origin -references: - - https://learn.microsoft.com/en-us/exchange/recipients-in-exchange-online/manage-permissions-for-recipients - - https://attack.mitre.org/techniques/T1098/002/ +- o365 +name: Office 365 Mailbox Delegate Permission Changed description: | - Detects addition of mailbox delegation permissions including FullAccess, SendAs, and SendOnBehalf. Attackers may add mailbox permissions to access sensitive emails, send phishing messages as the compromised user, or maintain persistent access to communications. + An administrator changed mailbox FullAccess, SendAs or SendOnBehalf access through mailbox or recipient permission cmdlets, or supplied GrantSendOnBehalfTo to Set-Mailbox. Microsoft may also emit routine service-account mailbox permission maintenance; verify the actor and mailbox before escalation. - Next Steps: - 1. Verify the mailbox delegation was authorized by the mailbox owner or administrator - 2. Review the specific permissions granted (FullAccess, SendAs, SendOnBehalf) - 3. Check who the delegate user is and their relationship to the mailbox owner - 4. Review recent authentication activity for both the admin and delegate accounts - 5. Examine the timing of the delegation for suspicious patterns - 6. If unauthorized, remove the delegation permissions immediately - 7. Review the mailbox for signs of unauthorized access or data theft - 8. Enable mailbox audit logging if not already enabled + Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. +category: Administrative Awareness +technique: 'T1098.002 - Account Manipulation: Additional Email Delegate Permissions' +adversary: origin +impact: + confidentiality: 1 + integrity: 1 + availability: 0 +references: +- https://learn.microsoft.com/en-us/purview/audit-log-activities +- https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema +- https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/add-mailboxpermission?view=exchange-ps where: | - oneOf("action", ["Add-MailboxPermission", "Add-RecipientPermission", "Set-Mailbox"]) && - equals("actionResult", "success") && - (contains("log.Parameters", "FullAccess") || - contains("log.Parameters", "SendAs") || - contains("log.Parameters", "SendOnBehalf")) + equals("log.Workload", "Exchange") && equals("actionResult", "success") && (oneOf("action", ["Add-MailboxPermission", "Remove-MailboxPermission", "Add-RecipientPermission", "Remove-RecipientPermission"]) || (equals("action", "Set-Mailbox") && (equals("log.o365SendOnBehalfChange", "true") || exists("log.Parameters.#(Name==GrantSendOnBehalfTo).Name")))) groupBy: - - adversary.user - - target.user +- lastEvent.tenantId +- lastEvent.log.OrganizationId +- dataSource +- adversary.user +- lastEvent.action +- lastEvent.log.ObjectId +- target.user +- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/suspicious_inbox_rules.yml b/rules/office365/suspicious_inbox_rules.yml deleted file mode 100644 index 8a8c27a3f..000000000 --- a/rules/office365/suspicious_inbox_rules.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Rule version v1.0.0 - -dataTypes: - - o365 -name: Suspicious Email Forwarding Rule Created -impact: - confidentiality: 3 - integrity: 2 - availability: 1 -category: Persistence -technique: "T1114.003 - Email Collection: Email Forwarding Rule" -adversary: origin -references: - - https://redcanary.com/blog/threat-detection/email-forwarding-rules/ - - https://attack.mitre.org/techniques/T1114/003/ -description: | - Detects creation or modification of inbox rules that forward emails to external domains, which is a common technique used by attackers to exfiltrate emails and maintain persistence after compromising an account. Attackers often create these rules to automatically forward sensitive emails to external addresses under their control. - - Next Steps: - 1. Verify if the user creating the rule is legitimate and authorized - 2. Check the destination email address in the forwarding rule for external domains - 3. Review recent authentication logs for the affected user account - 4. Examine other administrative actions performed by this user recently - 5. Check for any other suspicious inbox rules created by the same user - 6. Validate if the forwarding address belongs to a legitimate business contact - 7. Consider temporarily disabling the forwarding rule pending investigation - 8. Review email logs to see what emails may have already been forwarded -where: | - oneOf("action", ["New-InboxRule", "Set-InboxRule"]) && exists("origin.user") && (contains("log.Parameters", "ForwardTo") || contains("log.Parameters", "RedirectTo") || contains("log.Parameters", "ForwardAsAttachmentTo")) -groupBy: - - adversary.user From be5533e233d54c65b3cc40eb23f4dc2add19e7e5 Mon Sep 17 00:00:00 2001 From: Ricardo Valdes Date: Thu, 24 Sep 2026 10:06:56 -0400 Subject: [PATCH 3/5] fix(o365): keep awareness alerts under the flood guard limit Production counts showed the awareness rules would pass 50 top-level alerts a day on busy tenants: they grouped per object, so every mailbox, folder and target made a new top-level alert (up to 125 a day for folder permissions on one data source), and the rule flood guard switches off a rule after 50. Group the eight awareness rules by acting account and action instead; later changes become child alerts, which stay visible but are not counted. Folder permission changes a user makes to their own mailbox (owner sharing a calendar) are routine and were most of the volume, so the folder rule now skips them. Test fixture added for that case. Co-Authored-By: Claude Opus 5.5 --- plugins/alerts/o365_awareness_test.go | 8 ++--- plugins/alerts/testdata/o365_awareness.json | 31 +++++++++++++++++++ .../awareness_calendar_delegation.yml | 5 +-- rules/office365/awareness_mail_connectors.yml | 5 +-- .../awareness_mailbox_client_access.yml | 5 +-- .../awareness_mailbox_folder_permissions.yml | 9 ++---- ...ollection_microsoft_365_new_inbox_rule.yml | 5 +-- rules/office365/mail_forwarding_rules.yml | 5 +-- .../mailbox_auto_forwarding_set_mailbox.yml | 5 +-- rules/office365/mailbox_delegation_abuse.yml | 5 +-- 10 files changed, 44 insertions(+), 39 deletions(-) diff --git a/plugins/alerts/o365_awareness_test.go b/plugins/alerts/o365_awareness_test.go index 0a6073a5e..534b94979 100644 --- a/plugins/alerts/o365_awareness_test.go +++ b/plugins/alerts/o365_awareness_test.go @@ -47,12 +47,10 @@ func TestO365AwarenessRawPredicatesAndGrouping(t *testing.T) { if len(paths) != 8 { t.Fatalf("want eight shipped awareness rules, got %d", len(paths)) } - group := []string{"lastEvent.tenantId", "lastEvent.log.OrganizationId", "dataSource", "adversary.user", "lastEvent.action", "lastEvent.log.ObjectId", "target.user", "lastEvent.log.MailboxOwnerUPN"} + // One top-level alert per acting account and action; later changes become children, which the + // rule flood guard does not count. Grouping per object passed 50 top-level alerts a day. + want := []string{"lastEvent.tenantId", "lastEvent.log.OrganizationId", "dataSource", "adversary.user", "lastEvent.action"} for path, rule := range paths { - want := append([]string(nil), group...) - if strings.Contains(path, "folder_permissions") { - want = append(want, "lastEvent.log.folderId") - } if !reflect.DeepEqual(rule.GroupBy, want) { t.Fatalf("%s: grouping paths %v, want %v", path, rule.GroupBy, want) } diff --git a/plugins/alerts/testdata/o365_awareness.json b/plugins/alerts/testdata/o365_awareness.json index 7f3dc57f9..f0156db61 100644 --- a/plugins/alerts/testdata/o365_awareness.json +++ b/plugins/alerts/testdata/o365_awareness.json @@ -889,6 +889,37 @@ "log.o365SendOnBehalfChange" ] }, + { + "name": "folder-AddFolderPermissions-own-mailbox", + "raw": "{\"Operation\":\"AddFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"owner@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"owner@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"}}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": false, + "expected": { + "action": "AddFolderPermissions", + "log.Workload": "Exchange", + "log.RecordType": 2, + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success", + "log.folderId": "folder-fixture-001", + "log.folderPath": "/Calendar", + "origin.user": "owner@example.invalid", + "target.user": "owner@example.invalid" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.Folder.Id", + "log.Folder.Path", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, { "name": "folder-ModifyFolderPermissions", "raw": "{\"Operation\":\"ModifyFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"}}", diff --git a/rules/office365/awareness_calendar_delegation.yml b/rules/office365/awareness_calendar_delegation.yml index aec329569..39cf695e6 100644 --- a/rules/office365/awareness_calendar_delegation.yml +++ b/rules/office365/awareness_calendar_delegation.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.0 +# Rule version v1.1.1 dataTypes: - o365 @@ -26,6 +26,3 @@ groupBy: - dataSource - adversary.user - lastEvent.action -- lastEvent.log.ObjectId -- target.user -- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/awareness_mail_connectors.yml b/rules/office365/awareness_mail_connectors.yml index 5bfbb31f6..52f714352 100644 --- a/rules/office365/awareness_mail_connectors.yml +++ b/rules/office365/awareness_mail_connectors.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.0 +# Rule version v1.1.1 dataTypes: - o365 @@ -26,6 +26,3 @@ groupBy: - dataSource - adversary.user - lastEvent.action -- lastEvent.log.ObjectId -- target.user -- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/awareness_mailbox_client_access.yml b/rules/office365/awareness_mailbox_client_access.yml index 3e6511689..370028042 100644 --- a/rules/office365/awareness_mailbox_client_access.yml +++ b/rules/office365/awareness_mailbox_client_access.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.0 +# Rule version v1.1.1 dataTypes: - o365 @@ -26,6 +26,3 @@ groupBy: - dataSource - adversary.user - lastEvent.action -- lastEvent.log.ObjectId -- target.user -- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/awareness_mailbox_folder_permissions.yml b/rules/office365/awareness_mailbox_folder_permissions.yml index dde3d24e2..06010f888 100644 --- a/rules/office365/awareness_mailbox_folder_permissions.yml +++ b/rules/office365/awareness_mailbox_folder_permissions.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.0 +# Rule version v1.1.1 dataTypes: - o365 @@ -19,14 +19,11 @@ references: - https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema - https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/add-mailboxfolderpermission?view=exchange-ps where: | - equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["Add-MailboxFolderPermission", "Set-MailboxFolderPermission", "Remove-MailboxFolderPermission", "AddFolderPermissions", "ModifyFolderPermissions", "RemoveFolderPermissions"]) + equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["Add-MailboxFolderPermission", "Set-MailboxFolderPermission", "Remove-MailboxFolderPermission", "AddFolderPermissions", "ModifyFolderPermissions", "RemoveFolderPermissions"]) && + (!exists("target.user") || safe("origin.user", "") != safe("target.user", "")) groupBy: - lastEvent.tenantId - lastEvent.log.OrganizationId - dataSource - adversary.user - lastEvent.action -- lastEvent.log.ObjectId -- target.user -- lastEvent.log.MailboxOwnerUPN -- lastEvent.log.folderId diff --git a/rules/office365/collection_microsoft_365_new_inbox_rule.yml b/rules/office365/collection_microsoft_365_new_inbox_rule.yml index 36b7c63b3..42a202940 100644 --- a/rules/office365/collection_microsoft_365_new_inbox_rule.yml +++ b/rules/office365/collection_microsoft_365_new_inbox_rule.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.0 +# Rule version v1.1.1 dataTypes: - o365 @@ -26,6 +26,3 @@ groupBy: - dataSource - adversary.user - lastEvent.action -- lastEvent.log.ObjectId -- target.user -- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/mail_forwarding_rules.yml b/rules/office365/mail_forwarding_rules.yml index dae646d60..6918f370a 100644 --- a/rules/office365/mail_forwarding_rules.yml +++ b/rules/office365/mail_forwarding_rules.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.0 +# Rule version v1.1.1 dataTypes: - o365 @@ -26,6 +26,3 @@ groupBy: - dataSource - adversary.user - lastEvent.action -- lastEvent.log.ObjectId -- target.user -- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/mailbox_auto_forwarding_set_mailbox.yml b/rules/office365/mailbox_auto_forwarding_set_mailbox.yml index 86c8af6d0..3e287f338 100644 --- a/rules/office365/mailbox_auto_forwarding_set_mailbox.yml +++ b/rules/office365/mailbox_auto_forwarding_set_mailbox.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.0 +# Rule version v1.1.1 dataTypes: - o365 @@ -26,6 +26,3 @@ groupBy: - dataSource - adversary.user - lastEvent.action -- lastEvent.log.ObjectId -- target.user -- lastEvent.log.MailboxOwnerUPN diff --git a/rules/office365/mailbox_delegation_abuse.yml b/rules/office365/mailbox_delegation_abuse.yml index 544b99a9c..b589232df 100644 --- a/rules/office365/mailbox_delegation_abuse.yml +++ b/rules/office365/mailbox_delegation_abuse.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.0 +# Rule version v1.1.1 dataTypes: - o365 @@ -26,6 +26,3 @@ groupBy: - dataSource - adversary.user - lastEvent.action -- lastEvent.log.ObjectId -- target.user -- lastEvent.log.MailboxOwnerUPN From 029bfa31d14c8ff1790f187fc0f871eac395610b Mon Sep 17 00:00:00 2001 From: Ricardo Valdes Date: Thu, 24 Sep 2026 10:10:58 -0400 Subject: [PATCH 4/5] fix(o365): group password spraying alerts by the attacking address A spray is one address trying many accounts. Grouping by address and user made every targeted account a new top-level alert; yesterday's production counts give up to about 1,200 such pairs a day on one tenant, far above the rule flood guard limit of 50. Group by the attacking address so each sprayer is one top-level alert and the per-account attempts are children. Co-Authored-By: Claude Opus 5.5 --- ...access_microsoft_365_potential_password_spraying_attack.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rules/office365/credential_access_microsoft_365_potential_password_spraying_attack.yml b/rules/office365/credential_access_microsoft_365_potential_password_spraying_attack.yml index 2a6664372..8a118b931 100644 --- a/rules/office365/credential_access_microsoft_365_potential_password_spraying_attack.yml +++ b/rules/office365/credential_access_microsoft_365_potential_password_spraying_attack.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.4 +# Rule version v1.0.5 dataTypes: - "o365" @@ -27,4 +27,3 @@ afterEvents: count: 5 groupBy: - adversary.ip - - adversary.user From c20732087a4d0b798af4ff9e1170535a5bc85ce6 Mon Sep 17 00:00:00 2001 From: Ricardo Valdes Date: Thu, 24 Sep 2026 14:34:51 -0400 Subject: [PATCH 5/5] fix(o365): drop routine noise from awareness alerts, restore forwarding severity Awareness alerts still recorded large amounts of routine activity as child alerts, and each child is stored, passes tag and automation rules, and goes to automatic alert analysis when that module is on. - Inbox Rule Changed no longer includes UpdateInboxRules. Outlook desktop writes these records repeatedly for the same rules, usually with no rule change; they were almost all of this rule's volume. - Folder Permission Changed also skips records with logon type Owner, which works with filters that do not map the mailbox owner, and changes by Microsoft service accounts (ExternalAccess true with an S-1-5 security identifier as the actor), for example group mailbox configuration. - Mailbox Delegate Permission Changed alerts on grants only, not removals. - The Set-Mailbox forwarding alert needs a non-empty ForwardingSmtpAddress or ForwardingAddress. Exchange records a cleared address as an empty value, and DeliverToMailboxAndForward alone sets no destination. The filter flag is renamed log.o365MailboxForwardingSet to match (filter 1.4.1). - Both forwarding rules alert at medium severity in the Collection category and keep their v11 names, so the name-based rule sync updates the existing rules instead of deleting and recreating them. - Standard technique codes for the connector, client access and inbox rule alerts; the calendar rule no longer lists one reference twice. Fabricated regression cases cover each change and fail on the previous head. Co-Authored-By: Claude Opus 5.5 --- filters/office365/o365.yml | 19 +- plugins/alerts/o365_awareness_test.go | 14 +- plugins/alerts/testdata/o365_awareness.json | 491 +++++++++++++----- .../awareness_calendar_delegation.yml | 3 +- rules/office365/awareness_mail_connectors.yml | 4 +- .../awareness_mailbox_client_access.yml | 4 +- .../awareness_mailbox_folder_permissions.yml | 10 +- ...ollection_microsoft_365_new_inbox_rule.yml | 10 +- rules/office365/mail_forwarding_rules.yml | 12 +- .../mailbox_auto_forwarding_set_mailbox.yml | 14 +- rules/office365/mailbox_delegation_abuse.yml | 8 +- 11 files changed, 417 insertions(+), 172 deletions(-) diff --git a/filters/office365/o365.yml b/filters/office365/o365.yml index b4b823fde..5f06c09bc 100755 --- a/filters/office365/o365.yml +++ b/filters/office365/o365.yml @@ -1,4 +1,4 @@ -# Microsoft 365 filter, version 1.4.0 +# Microsoft 365 filter, version 1.4.1 pipeline: - dataTypes: @@ -9,13 +9,15 @@ pipeline: - drop: where: oneOf("log.Operation", ['AINotesUpdate', 'AcceptedSharingLinkOnFolder', 'AccessRequestUpdated', 'AccessedOdataLink', 'AddCommentToIncident.', 'AddFormCoauthor', 'AddRemediatedData', 'AddTagsToIncident', 'AdminThreadMuted', 'AdminThreadUnmuted', 'AlertExcelDownloaded', 'AlertNotificationsRecipientAdded', 'AllowShareFormForCopy', 'AppPublishedToCatalog', 'AppUpdatedInCatalog', 'AppUpgraded', 'ApplyRecordLabel', 'ApproveDisposal', 'AssignUserToIncident', 'AuditSearchCancelled', 'AuditSearchCompleted', 'AuditSearchCreated', 'AuditSearchExportJobCompleted', 'AuditSearchExportJobCreated', 'AuditSearchExportResultsDownloaded', 'BackupItemAdded', 'BackupItemRemoved', 'BackupItemRestoreCompleted', 'BackupItemRestoreTriggered', 'BackupPolicyActivated', 'BackupPolicyPaused', 'BotAddedToTeam', 'BreakEnded', 'BurnJob', 'CanceledQuery', 'CaseUpdated', 'ChannelAdded', 'ChannelOwnerResponded', 'ChatRetrieved', 'ChatUpdated', 'ClassificationAdded', 'ClassificationDefinitionCreated', 'ClientViewSignaled', 'ClockedIn', 'ClockedOut', 'CloseConversation', 'CollectionCreated', 'CollectionHardDeleted', 'CollectionRenamed', 'CollectionSoftDeleted', 'CollectionUpdated', 'ComplianceManagerAutomationChange', 'ComplianceSettingChanged', 'ConnectToExcelWorkbook', 'ConnectorAdded', 'CopilotInteraction', 'Copy', 'Create', 'CreateComment', 'CreateCopilotPlugin', 'CreateCopilotPromptBook', 'CreateForm', 'CreateResponse', 'CreateTag', 'CreateUpdateRequest', 'CreateWorkingSet', 'CreateWorkingSetSearch', 'DataExport', 'DataShareCreated', 'DataShareDeleted', 'DeleteCopilotPlugin', 'DeleteCopilotPromptBook', 'DeleteSummaryLink', 'DeleteTag', 'DeleteWorkingSetSearch', 'DeletedResult', 'DisableCopilotPlugin', 'DisableCopilotPromptBook', 'DisallowShareFormForCopy', 'DocumentSensitivityMismatchDetected', 'DomainControllerCoverageExcelDownloaded', 'DownloadCopyOfLakeData', 'DownloadDocument', 'DownloadedReport', 'DraftRestoreTaskCreated', 'DraftRestoreTaskDeleted', 'DraftRestoreTaskEdited', 'EditUpdateRequest', 'EnableCopilotPlugin', 'EnableCopilotPromptBook', 'EntityCreated', 'ErrorRemediationJob', 'ExchangeDataProactivelyPreserved', 'ExecutedQuery', 'ExportForm', 'ExportJob', 'ExtendRetention', 'FailedValidation', 'FileCheckOutDiscarded', 'FileCheckedIn', 'FileCheckedOut', 'FileCopied', 'FileDeletedFirstStageRecycleBin', 'FileDeletedSecondStageRecycleBin', 'FileModifiedExtended', 'FileRecycled', 'FileRestored', 'FileSyncDownloadedFull', 'FileSyncUploadedFull', 'FileUpdateDescription', 'FileUploaded', 'FileVersionRecycled', 'FileVersionsAllMinorsRecycled', 'FileVersionsAllRecycled', 'FileVisited', 'FolderCopied', 'FolderCreated', 'FolderDeletedFirstStageRecycleBin', 'FolderDeletedSecondStageRecycleBin', 'FolderRecycled', 'FolderRestored', 'FolderSharingLinkShared', 'GenerateCopyOfLakeData', 'GetAllRestoreArtifactsInTask', 'GetBackupItem', 'GetRestoreTaskDetails', 'GetSummaryLink', 'GlossaryTermAssigned', 'GlossaryTermCreated', 'HoldRemoved', 'HoldUpdated', 'HubSiteJoined', 'HubSiteOrphanHubDeleted', 'HubSiteRegistered', 'InformationBarriersInsightsReportCompleted', 'InformationBarriersInsightsReportOneDriveSectionQueried', 'InformationBarriersInsightsReportSchedule', 'InformationBarriersInsightsReportSharePointSectionQueried', 'InviteSent', 'InviteeResponded', 'LabelContentExplorerAccessedItem', 'LegacyWorkflowEnabledSet', 'LinkedEntityCreated', 'ListAllBackupItemsInPolicies', 'ListAllBackupItemsInTenant', 'ListAllBackupItemsInWorkload', 'ListAllBackupPolicies', 'ListAllRestorePoints', 'ListAllRestoreTasks', 'ListColumnCreated', 'ListColumnUpdated', 'ListContentTypeCreated', 'ListContentTypeDeleted', 'ListContentTypeUpdated', 'ListCreated', 'ListForms', 'ListItemCreated', 'ListItemRecycled', 'ListItemRestored', 'LiveNotesUpdate', 'LockRecord', 'LogsCollection', 'ManagedSyncClientAllowed', 'MarkedMessageChanged', 'MeetingDetail', 'MeetingParticipantDetail', 'MessageCreatedHasLink', 'MessageCreatedNotification', 'MessageCreation', 'MessageDeleted', 'MessageDeletedNotification', 'MessageEditedHasLink', 'MessageHostedContentsListed', 'MessageRead', 'MessageUpdated', 'MessageUpdatedNotification', 'MonitoringAlertNotificationRecipientAdded', 'MonitoringAlertUpdated', 'MoveForm', 'MovedFormIntoCollection', 'MovedFormOutofCollection', 'NewAdaptiveScope', 'NewBackupPolicyCreated', 'NewComplianceTag', 'NewRetentionCompliancePolicy', 'NewsFeedEnabledSet', 'OffShiftDialogAccepted', 'OfficeOnDemandSet', 'OpenConversation', 'OpenShiftAdded', 'PagePrefetched', 'PageViewed', 'PageViewedExtended', 'PeopleResultsScopeSet', 'PerformedCardAction', 'PlanCopied', 'PlanListRead', 'PreviewForm', 'PreviewItemDownloaded', 'PreviewItemListed', 'PreviewModeEnabledSet', 'PreviewWorkingSetSearch', 'ProInvitation', 'ProjectCreated', 'ProjectListAccessed', 'PulseCancel', 'PulseCreate', 'PulseCreateDraft', 'PulseDeleteDraft', 'PulseExtendDeadline', 'PulseInvite', 'PulseShareResults', 'PulseSubmit', 'QuarantinePreview', 'QuarantineReleaseRequest', 'QuarantineReleaseRequestDeny', 'QuarantineViewHeader', 'RecordDelete', 'RelabelItem', 'RemediationActionAdded', 'RemediationActionUpdated', 'RemoveAdaptiveScope', 'RemoveComplianceTag', 'RemoveCuratedTopic', 'RemoveFormCoauthor', 'RemoveTagsFromIncident', 'RemovedSearchExported', 'RemovedSearchPreviewed', 'RemovedSearchResultsPurged', 'RemovedSearchResultsSentToZoom', 'ReportDownloaded', 'RequestAdded', 'RequestRespondedTo', 'RestoreTaskActivated', 'RestoreTaskCompleted', 'RoadmapAccessed', 'RoadmapCreated', 'RoadmapItemAccessed', 'RoadmapItemCreated', 'RunAntiVirusScan', 'ScheduleGroupAdded', 'ScheduleShared', 'SearchPermissionUpdated', 'SearchQueryPerformed', 'SearchRemoved', 'SearchReport', 'SearchReportRemoved', 'SearchResultsSentToZoom', 'SearchStopped', 'SearchUpdated', 'SearchViewed', 'Send', 'SensitivityLabelApplied', 'SensitivityLabelChanged', 'SensorActivationMethodConfigurationUpdated', 'SensorCreated', 'SensorDeploymentAccessKeyReceived', 'SensorDeploymentAccessKeyUpdated', 'SetAdvancedFeatures', 'SetRestrictiveRetentionUI', 'SharePointDataProactivelyPreserved', 'SharingInvitationRevoked', 'SharingInvitationUpdated', 'ShiftAdded', 'SiteAdminChangeRequest', 'SiteCollectionCreated', 'SiteCollectionQuotaModified', 'SiteColumnCreated', 'SiteColumnDeleted', 'SiteColumnUpdated', 'SiteContentTypeCreated', 'SiteContentTypeDeleted', 'SiteContentTypeUpdated', 'SoftDeleteSettingsUpdated', 'SubTaskCreated', 'SubmitResponse', 'SubmitUpdate', 'SubscribedToMessages', 'SupervisionRuleMatch', 'SupervisoryReviewTag', 'TabAdded', 'TabUpdated', 'TagFiles', 'TagJob', 'TaggingConfigurationUpdated', 'TaskAccessed', 'TaskAssigned', 'TaskCompleted', 'TaskCreated', 'TaskListCreated', 'TaskListRead', 'TaskRead', 'TeamCreated', 'ThreadAccessFailure', 'ThreadViewed', 'TimeClockEntryAdded', 'TimeOffAdded', 'UnlockRecord', 'Update', 'UpdateCopilotPlugin', 'UpdateCopilotPromptBook', 'UpdateCopilotSettings', 'UpdateIncidentStatus', 'UpdateResponse', 'UpdateTag', 'UpdateUsageReportsPrivacySetting', 'UpdateWorkingSetSearch', 'UpdatedPolicyConfigPriority', 'UploadedOrgData', 'UsagePolicyAcceptance', 'ViewBackupPolicyDetails', 'ViewDocument', 'ViewForm', 'ViewResponse', 'ViewResponses', 'ViewRuntimeForm', 'ViewUpdate', 'ViewedExplore', 'ViewedSearchExported', 'ViewedSearchPreviewed', 'WorkforceIntegrationAdded', 'WorkspaceCreated', 'updateddeviceconfiguration']) # Capture documented Name/Value parameter identities before the legacy string - # cast loses their structure. These flags mean a setting was supplied, including - # clearing it; they do not establish an enabled setting or an external recipient. - # Never trust markers supplied by the input record. + # cast loses their structure. The inbox rule and send-on-behalf flags mean a + # setting was supplied, including clearing it. The mailbox flag needs a non-empty + # forwarding address: Exchange records a cleared address as an empty value, and + # DeliverToMailboxAndForward alone sets no destination. No flag establishes an + # external recipient. Never trust markers supplied by the input record. - delete: fields: - log.o365InboxForwardingChange - - log.o365MailboxForwardingChange + - log.o365MailboxForwardingSet - log.o365SendOnBehalfChange - add: function: string @@ -31,13 +33,12 @@ pipeline: - add: function: string params: - key: log.o365MailboxForwardingChange + key: log.o365MailboxForwardingSet value: "true" where: >- equals("log.Workload", "Exchange") && equals("log.Operation", "Set-Mailbox") && - (exists("log.Parameters.#(Name==ForwardingAddress).Name") || - exists("log.Parameters.#(Name==ForwardingSmtpAddress).Name") || - exists("log.Parameters.#(Name==DeliverToMailboxAndForward).Name")) + (regexMatch("log.Parameters.#(Name==ForwardingAddress).Value", "(?s)^.+$") || + regexMatch("log.Parameters.#(Name==ForwardingSmtpAddress).Value", "(?s)^.+$")) - add: function: string params: diff --git a/plugins/alerts/o365_awareness_test.go b/plugins/alerts/o365_awareness_test.go index 534b94979..cdeae6736 100644 --- a/plugins/alerts/o365_awareness_test.go +++ b/plugins/alerts/o365_awareness_test.go @@ -50,6 +50,12 @@ func TestO365AwarenessRawPredicatesAndGrouping(t *testing.T) { // One top-level alert per acting account and action; later changes become children, which the // rule flood guard does not count. Grouping per object passed 50 top-level alerts a day. want := []string{"lastEvent.tenantId", "lastEvent.log.OrganizationId", "dataSource", "adversary.user", "lastEvent.action"} + // Forwarding mail out of a mailbox is a common step after it is taken over, so the two + // forwarding rules alert at medium severity (highest impact value 2); the others stay low. + medium := map[string]bool{ + "office365/mail_forwarding_rules.yml": true, + "office365/mailbox_auto_forwarding_set_mailbox.yml": true, + } for path, rule := range paths { if !reflect.DeepEqual(rule.GroupBy, want) { t.Fatalf("%s: grouping paths %v, want %v", path, rule.GroupBy, want) @@ -57,8 +63,12 @@ func TestO365AwarenessRawPredicatesAndGrouping(t *testing.T) { if len(rule.DeduplicateBy) != 0 || len(rule.Correlation) != 0 || len(rule.AfterEvents) != 0 { t.Fatalf("%s: awareness alerts should retain every change without history thresholds or suppression", path) } - if rule.Impact.GetConfidentiality() != 1 || rule.Impact.GetIntegrity() != 1 || rule.Impact.GetAvailability() != 0 || rule.Adversary != "origin" { - t.Fatalf("%s: invalid awareness impact or attribution", path) + confidentiality := uint32(1) + if medium[path] { + confidentiality = 2 + } + if rule.Impact.GetConfidentiality() != confidentiality || rule.Impact.GetIntegrity() != 1 || rule.Impact.GetAvailability() != 0 || rule.Adversary != "origin" { + t.Fatalf("%s: invalid impact or attribution", path) } } cache := plugins.NewCELCache("o365-awareness") diff --git a/plugins/alerts/testdata/o365_awareness.json b/plugins/alerts/testdata/o365_awareness.json index f0156db61..eaf9c57aa 100644 --- a/plugins/alerts/testdata/o365_awareness.json +++ b/plugins/alerts/testdata/o365_awareness.json @@ -21,7 +21,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -47,15 +47,15 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, { - "name": "inbox-UpdateInboxRules", + "name": "inbox-UpdateInboxRules-outlook-save", "raw": "{\"Operation\":\"UpdateInboxRules\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"mailbox@example.invalid\"}", "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", - "match": true, + "match": false, "expected": { "action": "UpdateInboxRules", "log.Workload": "Exchange", @@ -74,7 +74,7 @@ "log.MailboxOwnerUPN", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -100,7 +100,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -126,7 +126,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -152,7 +152,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -178,7 +178,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -204,7 +204,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -230,7 +230,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -256,7 +256,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -282,7 +282,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -308,7 +308,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -334,7 +334,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -360,7 +360,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -386,7 +386,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -412,7 +412,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -438,7 +438,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -464,7 +464,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -483,7 +483,7 @@ "log.ResultStatus": "True", "actionResult": "success", "log.Parameters": "[map[Name:ForwardingAddress Value:recipient@example.invalid]]", - "log.o365MailboxForwardingChange": "true" + "log.o365MailboxForwardingSet": "true" }, "absent": [ "log.Operation", @@ -498,7 +498,7 @@ "name": "mailbox-forward-clear-ForwardingAddress", "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingAddress\",\"Value\":\"\"}]}", "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", - "match": true, + "match": false, "expected": { "action": "Set-Mailbox", "log.Workload": "Exchange", @@ -508,8 +508,7 @@ "log.ObjectId": "mailbox@example.invalid", "log.ResultStatus": "True", "actionResult": "success", - "log.Parameters": "[map[Name:ForwardingAddress Value:]]", - "log.o365MailboxForwardingChange": "true" + "log.Parameters": "[map[Name:ForwardingAddress Value:]]" }, "absent": [ "log.Operation", @@ -517,7 +516,8 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365SendOnBehalfChange" + "log.o365SendOnBehalfChange", + "log.o365MailboxForwardingSet" ] }, { @@ -535,7 +535,7 @@ "log.ResultStatus": "True", "actionResult": "success", "log.Parameters": "[map[Name:ForwardingSmtpAddress Value:recipient@example.invalid]]", - "log.o365MailboxForwardingChange": "true" + "log.o365MailboxForwardingSet": "true" }, "absent": [ "log.Operation", @@ -550,7 +550,7 @@ "name": "mailbox-forward-clear-ForwardingSmtpAddress", "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingSmtpAddress\",\"Value\":\"\"}]}", "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", - "match": true, + "match": false, "expected": { "action": "Set-Mailbox", "log.Workload": "Exchange", @@ -560,8 +560,7 @@ "log.ObjectId": "mailbox@example.invalid", "log.ResultStatus": "True", "actionResult": "success", - "log.Parameters": "[map[Name:ForwardingSmtpAddress Value:]]", - "log.o365MailboxForwardingChange": "true" + "log.Parameters": "[map[Name:ForwardingSmtpAddress Value:]]" }, "absent": [ "log.Operation", @@ -569,14 +568,15 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365SendOnBehalfChange" + "log.o365SendOnBehalfChange", + "log.o365MailboxForwardingSet" ] }, { "name": "mailbox-forward-DeliverToMailboxAndForward", "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DeliverToMailboxAndForward\",\"Value\":\"True\"}]}", "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", - "match": true, + "match": false, "expected": { "action": "Set-Mailbox", "log.Workload": "Exchange", @@ -586,8 +586,7 @@ "log.ObjectId": "mailbox@example.invalid", "log.ResultStatus": "True", "actionResult": "success", - "log.Parameters": "[map[Name:DeliverToMailboxAndForward Value:True]]", - "log.o365MailboxForwardingChange": "true" + "log.Parameters": "[map[Name:DeliverToMailboxAndForward Value:True]]" }, "absent": [ "log.Operation", @@ -595,13 +594,65 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365SendOnBehalfChange" + "log.o365SendOnBehalfChange", + "log.o365MailboxForwardingSet" ] }, { "name": "mailbox-forward-clear-DeliverToMailboxAndForward", "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DeliverToMailboxAndForward\",\"Value\":\"False\"}]}", "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.Parameters": "[map[Name:DeliverToMailboxAndForward Value:False]]" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange", + "log.o365MailboxForwardingSet" + ] + }, + { + "name": "mailbox-forward-ForwardingAddress-with-cleared-smtp", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingSmtpAddress\",\"Value\":\"\"},{\"Name\":\"ForwardingAddress\",\"Value\":\"recipient@example.invalid\"},{\"Name\":\"DeliverToMailboxAndForward\",\"Value\":\"False\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": true, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success", + "log.o365MailboxForwardingSet": "true" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "mailbox-forward-ForwardingSmtpAddress-without-copy", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingSmtpAddress\",\"Value\":\"smtp:recipient@example.invalid\"},{\"Name\":\"DeliverToMailboxAndForward\",\"Value\":\"False\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", "match": true, "expected": { "action": "Set-Mailbox", @@ -612,8 +663,7 @@ "log.ObjectId": "mailbox@example.invalid", "log.ResultStatus": "True", "actionResult": "success", - "log.Parameters": "[map[Name:DeliverToMailboxAndForward Value:False]]", - "log.o365MailboxForwardingChange": "true" + "log.o365MailboxForwardingSet": "true" }, "absent": [ "log.Operation", @@ -624,6 +674,56 @@ "log.o365SendOnBehalfChange" ] }, + { + "name": "mailbox-forward-clear-all", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingSmtpAddress\",\"Value\":\"\"},{\"Name\":\"ForwardingAddress\",\"Value\":\"\"},{\"Name\":\"DeliverToMailboxAndForward\",\"Value\":\"False\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange", + "log.o365MailboxForwardingSet" + ] + }, + { + "name": "mailbox-forward-clear-smtp-keep-copy", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"ForwardingSmtpAddress\",\"Value\":\"\"},{\"Name\":\"DeliverToMailboxAndForward\",\"Value\":\"True\"}]}", + "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", + "match": false, + "expected": { + "action": "Set-Mailbox", + "log.Workload": "Exchange", + "log.RecordType": 1, + "origin.user": "administrator@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "mailbox@example.invalid", + "log.ResultStatus": "True", + "actionResult": "success" + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "target.user", + "log.o365InboxForwardingChange", + "log.o365SendOnBehalfChange", + "log.o365MailboxForwardingSet" + ] + }, { "name": "delegate-Add-MailboxPermission", "raw": "{\"Operation\":\"Add-MailboxPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", @@ -646,7 +746,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -654,7 +754,7 @@ "name": "delegate-Remove-MailboxPermission", "raw": "{\"Operation\":\"Remove-MailboxPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", "rule": "office365/mailbox_delegation_abuse.yml", - "match": true, + "match": false, "expected": { "action": "Remove-MailboxPermission", "log.Workload": "Exchange", @@ -672,7 +772,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -698,7 +798,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -706,7 +806,7 @@ "name": "delegate-Remove-RecipientPermission", "raw": "{\"Operation\":\"Remove-RecipientPermission\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"User\",\"Value\":\"delegate@example.invalid\"}]}", "rule": "office365/mailbox_delegation_abuse.yml", - "match": true, + "match": false, "expected": { "action": "Remove-RecipientPermission", "log.Workload": "Exchange", @@ -724,7 +824,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -751,7 +851,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange" + "log.o365MailboxForwardingSet" ] }, { @@ -777,7 +877,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange" + "log.o365MailboxForwardingSet" ] }, { @@ -802,7 +902,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -828,7 +928,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -854,7 +954,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -885,7 +985,7 @@ "log.Folder.Id", "log.Folder.Path", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -916,7 +1016,7 @@ "log.Folder.Id", "log.Folder.Path", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -947,7 +1047,7 @@ "log.Folder.Id", "log.Folder.Path", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -978,7 +1078,136 @@ "log.Folder.Id", "log.Folder.Path", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-ModifyFolderPermissions-microsoft-service", + "raw": "{\"Operation\":\"ModifyFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"S-1-5-21-1111111111-2222222222-3333333333-4444444\",\"ObjectId\":\"group@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"group@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"},\"ExternalAccess\":true,\"LogonType\":1,\"ClientInfoString\":\"Client=WebServices;Action=ConfigureGroupMailbox\"}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": false, + "expected": { + "action": "ModifyFolderPermissions", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "S-1-5-21-1111111111-2222222222-3333333333-4444444", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "group@example.invalid", + "target.user": "group@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success", + "log.folderId": "folder-fixture-001", + "log.folderPath": "/Calendar", + "log.ExternalAccess": true + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.Folder.Id", + "log.Folder.Path", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingSet", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-ModifyFolderPermissions-external-named-actor", + "raw": "{\"Operation\":\"ModifyFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"partner-admin@example.invalid\",\"ObjectId\":\"group@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"group@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"},\"ExternalAccess\":true,\"LogonType\":1,\"ClientInfoString\":\"Client=WebServices;Action=ConfigureGroupMailbox\"}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "ModifyFolderPermissions", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "partner-admin@example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "group@example.invalid", + "target.user": "group@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success", + "log.folderId": "folder-fixture-001", + "log.folderPath": "/Calendar", + "log.ExternalAccess": true + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.Folder.Id", + "log.Folder.Path", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingSet", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-ModifyFolderPermissions-internal-sid-actor", + "raw": "{\"Operation\":\"ModifyFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"S-1-5-21-1111111111-2222222222-3333333333-4444444\",\"ObjectId\":\"group@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"group@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"},\"ExternalAccess\":false,\"LogonType\":1,\"ClientInfoString\":\"Client=WebServices;Action=ConfigureGroupMailbox\"}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": true, + "expected": { + "action": "ModifyFolderPermissions", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "S-1-5-21-1111111111-2222222222-3333333333-4444444", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "group@example.invalid", + "target.user": "group@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success", + "log.folderId": "folder-fixture-001", + "log.folderPath": "/Calendar", + "log.ExternalAccess": false + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.Folder.Id", + "log.Folder.Path", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingSet", + "log.o365SendOnBehalfChange" + ] + }, + { + "name": "folder-ModifyFolderPermissions-owner-logon", + "raw": "{\"Operation\":\"ModifyFolderPermissions\",\"Workload\":\"Exchange\",\"RecordType\":2,\"ResultStatus\":\"Succeeded\",\"UserId\":\"Owner@Example.invalid\",\"ObjectId\":\"owner@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"MailboxOwnerUPN\":\"owner@example.invalid\",\"Folder\":{\"Id\":\"folder-fixture-001\",\"Path\":\"/Calendar\"},\"LogonType\":0,\"ExternalAccess\":false}", + "rule": "office365/awareness_mailbox_folder_permissions.yml", + "match": false, + "expected": { + "action": "ModifyFolderPermissions", + "log.Workload": "Exchange", + "log.RecordType": 2, + "origin.user": "Owner@Example.invalid", + "log.OrganizationId": "11111111-1111-4111-8111-111111111111", + "log.ObjectId": "owner@example.invalid", + "target.user": "owner@example.invalid", + "log.ResultStatus": "Succeeded", + "actionResult": "success", + "log.folderId": "folder-fixture-001", + "log.folderPath": "/Calendar", + "log.LogonType": 0, + "log.ExternalAccess": false + }, + "absent": [ + "log.Operation", + "log.UserId", + "origin.ip", + "log.MailboxOwnerUPN", + "log.Parameters", + "log.Folder.Id", + "log.Folder.Path", + "log.o365InboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1005,7 +1234,7 @@ "log.MailboxOwnerUPN", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1031,7 +1260,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1057,7 +1286,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1083,7 +1312,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1109,7 +1338,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1135,7 +1364,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1161,7 +1390,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1187,7 +1416,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1213,7 +1442,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1239,7 +1468,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1265,7 +1494,7 @@ "log.ObjectId", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1291,7 +1520,7 @@ "log.UserId", "origin.ip", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1317,7 +1546,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1343,7 +1572,7 @@ "log.OrganizationId", "log.ObjectId", "target.user", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1362,7 +1591,7 @@ "log.ResultStatus": "False", "actionResult": "failure", "log.Parameters": "[map[Name:ForwardingAddress Value:recipient@example.invalid]]", - "log.o365MailboxForwardingChange": "true" + "log.o365MailboxForwardingSet": "true" }, "absent": [ "log.Operation", @@ -1395,7 +1624,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1411,7 +1640,7 @@ "log.ResultStatus": "True", "actionResult": "success", "log.Parameters": "[map[Name:ForwardingAddress Value:recipient@example.invalid]]", - "log.o365MailboxForwardingChange": "true" + "log.o365MailboxForwardingSet": "true" }, "absent": [ "log.Operation", @@ -1447,7 +1676,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1473,7 +1702,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1499,7 +1728,7 @@ "log.ObjectId", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1525,7 +1754,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1551,7 +1780,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1577,7 +1806,7 @@ "log.ObjectId", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1604,7 +1833,7 @@ "log.MailboxOwnerUPN", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1631,7 +1860,7 @@ "log.MailboxOwnerUPN", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1657,7 +1886,7 @@ "target.user", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1683,7 +1912,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1709,7 +1938,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1735,7 +1964,7 @@ "log.ObjectId", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1761,7 +1990,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1787,7 +2016,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1813,7 +2042,7 @@ "log.ObjectId", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1839,7 +2068,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1865,7 +2094,7 @@ "target.user", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1891,7 +2120,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1917,7 +2146,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1943,7 +2172,7 @@ "target.user", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1969,7 +2198,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -1995,7 +2224,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2021,7 +2250,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2047,7 +2276,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2073,7 +2302,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2099,7 +2328,7 @@ "target.user", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2125,7 +2354,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2151,7 +2380,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2177,7 +2406,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2203,7 +2432,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2229,7 +2458,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2255,7 +2484,7 @@ "target.user", "log.Parameters", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2281,13 +2510,13 @@ "target.user", "actionResult", "log.ResultStatus", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, { "name": "spoofed-marker-inbox", - "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingChange\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", + "raw": "{\"Operation\":\"New-InboxRule\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingSet\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", "rule": "office365/collection_microsoft_365_new_inbox_rule.yml", "match": true, "expected": { @@ -2307,7 +2536,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2333,7 +2562,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2359,7 +2588,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2385,7 +2614,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2411,7 +2640,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2437,7 +2666,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2463,7 +2692,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2489,7 +2718,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2515,13 +2744,13 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, { "name": "spoofed-marker-mailbox", - "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingChange\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingSet\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", "rule": "office365/mailbox_auto_forwarding_set_mailbox.yml", "match": false, "expected": { @@ -2541,7 +2770,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2567,7 +2796,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2593,7 +2822,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2619,7 +2848,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2645,7 +2874,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2671,7 +2900,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2697,7 +2926,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2723,7 +2952,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2749,13 +2978,13 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, { "name": "spoofed-marker-delegation", - "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingChange\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", + "raw": "{\"Operation\":\"Set-Mailbox\",\"Workload\":\"Exchange\",\"RecordType\":1,\"ResultStatus\":\"True\",\"UserId\":\"administrator@example.invalid\",\"ObjectId\":\"mailbox@example.invalid\",\"OrganizationId\":\"11111111-1111-4111-8111-111111111111\",\"Parameters\":[{\"Name\":\"DisplayName\",\"Value\":\"Unrelated setting\"}],\"o365InboxForwardingChange\":\"true\",\"o365MailboxForwardingSet\":\"true\",\"o365SendOnBehalfChange\":\"true\"}", "rule": "office365/mailbox_delegation_abuse.yml", "match": false, "expected": { @@ -2775,7 +3004,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2801,7 +3030,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2827,7 +3056,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2853,7 +3082,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2879,7 +3108,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2905,7 +3134,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2931,7 +3160,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2957,7 +3186,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] }, @@ -2983,7 +3212,7 @@ "origin.ip", "target.user", "log.o365InboxForwardingChange", - "log.o365MailboxForwardingChange", + "log.o365MailboxForwardingSet", "log.o365SendOnBehalfChange" ] } diff --git a/rules/office365/awareness_calendar_delegation.yml b/rules/office365/awareness_calendar_delegation.yml index 39cf695e6..29a9a1f09 100644 --- a/rules/office365/awareness_calendar_delegation.yml +++ b/rules/office365/awareness_calendar_delegation.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.1 +# Rule version v1.1.2 dataTypes: - o365 @@ -17,7 +17,6 @@ impact: references: - https://learn.microsoft.com/en-us/purview/audit-log-activities - https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema -- https://learn.microsoft.com/en-us/purview/audit-log-activities where: | equals("log.Workload", "Exchange") && equals("actionResult", "success") && equals("action", "UpdateCalendarDelegation") groupBy: diff --git a/rules/office365/awareness_mail_connectors.yml b/rules/office365/awareness_mail_connectors.yml index 52f714352..5f692cc9c 100644 --- a/rules/office365/awareness_mail_connectors.yml +++ b/rules/office365/awareness_mail_connectors.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.1 +# Rule version v1.1.2 dataTypes: - o365 @@ -8,7 +8,7 @@ description: | Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. category: Administrative Awareness -technique: Administrative mail flow change +technique: T1537 - Transfer Data to Cloud Account adversary: origin impact: confidentiality: 1 diff --git a/rules/office365/awareness_mailbox_client_access.yml b/rules/office365/awareness_mailbox_client_access.yml index 370028042..23015c1ad 100644 --- a/rules/office365/awareness_mailbox_client_access.yml +++ b/rules/office365/awareness_mailbox_client_access.yml @@ -1,4 +1,4 @@ -# Rule version v1.1.1 +# Rule version v1.1.2 dataTypes: - o365 @@ -8,7 +8,7 @@ description: | Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. category: Administrative Awareness -technique: Administrative mailbox access change +technique: 'T1114.002 - Email Collection: Remote Email Collection' adversary: origin impact: confidentiality: 1 diff --git a/rules/office365/awareness_mailbox_folder_permissions.yml b/rules/office365/awareness_mailbox_folder_permissions.yml index 06010f888..4fa86b90e 100644 --- a/rules/office365/awareness_mailbox_folder_permissions.yml +++ b/rules/office365/awareness_mailbox_folder_permissions.yml @@ -1,10 +1,12 @@ -# Rule version v1.1.1 +# Rule version v1.1.2 dataTypes: - o365 name: Office 365 Mailbox Folder Permission Changed description: | - An Exchange mailbox folder permission was added, modified or removed. This includes audited mailbox activity operations and Exchange administrator cmdlets, which can grant or revoke access to messages in a folder. + A folder permission on someone else's mailbox was added, modified or removed, either with an Exchange administrator cmdlet or through an audited mailbox client. This can grant or revoke access to the messages in that folder. + + Changes owners make to their own mailbox, such as sharing a calendar, do not raise this alert; the audit record shows them with logon type Owner or with the mailbox owner as the actor. Neither do changes made by Microsoft service accounts, which the audit record marks with ExternalAccess set to true and a Windows security identifier (S-1-5-...) as the actor, for example when Microsoft 365 configures group mailboxes. Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. category: Administrative Awareness @@ -20,7 +22,9 @@ references: - https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/add-mailboxfolderpermission?view=exchange-ps where: | equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["Add-MailboxFolderPermission", "Set-MailboxFolderPermission", "Remove-MailboxFolderPermission", "AddFolderPermissions", "ModifyFolderPermissions", "RemoveFolderPermissions"]) && - (!exists("target.user") || safe("origin.user", "") != safe("target.user", "")) + !equals("log.LogonType", 0) && + (!exists("target.user") || safe("origin.user", "") != safe("target.user", "")) && + !(equals("log.ExternalAccess", true) && startsWith("origin.user", "S-1-5-")) groupBy: - lastEvent.tenantId - lastEvent.log.OrganizationId diff --git a/rules/office365/collection_microsoft_365_new_inbox_rule.yml b/rules/office365/collection_microsoft_365_new_inbox_rule.yml index 42a202940..4109598d7 100644 --- a/rules/office365/collection_microsoft_365_new_inbox_rule.yml +++ b/rules/office365/collection_microsoft_365_new_inbox_rule.yml @@ -1,14 +1,16 @@ -# Rule version v1.1.1 +# Rule version v1.1.2 dataTypes: - o365 name: Office 365 Inbox Rule Changed description: | - A user or administrator created, changed, enabled, disabled or removed an Exchange inbox rule. New and modified rules with explicit forwarding settings are handled by the dedicated forwarding alert. Outlook client UpdateInboxRules is an audited change whose specific sub-action may require review of OperationProperties. + A user or administrator created, changed, enabled, disabled or removed an inbox rule with an Exchange command, for example from Outlook on the web or PowerShell. Rules that move or delete mail can hide messages from the mailbox owner. New and modified rules with forwarding settings raise the separate forwarding alert instead. + + Outlook desktop records its rule saves as UpdateInboxRules and writes them repeatedly for the same rules, usually without any rule change, so those records do not raise this alert. Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. category: Administrative Awareness -technique: 'T1114.003 - Email Collection: Email Forwarding Rule' +technique: 'T1564.008 - Hide Artifacts: Email Hiding Rules' adversary: origin impact: confidentiality: 1 @@ -19,7 +21,7 @@ references: - https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema - https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/new-inboxrule?view=exchange-ps where: | - equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["New-InboxRule", "Set-InboxRule", "UpdateInboxRules", "Enable-InboxRule", "Disable-InboxRule", "Remove-InboxRule"]) && !(oneOf("action", ["New-InboxRule", "Set-InboxRule"]) && (equals("log.o365InboxForwardingChange", "true") || exists("log.Parameters.#(Name==ForwardTo).Name") || exists("log.Parameters.#(Name==ForwardAsAttachmentTo).Name") || exists("log.Parameters.#(Name==RedirectTo).Name"))) + equals("log.Workload", "Exchange") && equals("actionResult", "success") && oneOf("action", ["New-InboxRule", "Set-InboxRule", "Enable-InboxRule", "Disable-InboxRule", "Remove-InboxRule"]) && !(oneOf("action", ["New-InboxRule", "Set-InboxRule"]) && (equals("log.o365InboxForwardingChange", "true") || exists("log.Parameters.#(Name==ForwardTo).Name") || exists("log.Parameters.#(Name==ForwardAsAttachmentTo).Name") || exists("log.Parameters.#(Name==RedirectTo).Name"))) groupBy: - lastEvent.tenantId - lastEvent.log.OrganizationId diff --git a/rules/office365/mail_forwarding_rules.yml b/rules/office365/mail_forwarding_rules.yml index 6918f370a..c3af390b9 100644 --- a/rules/office365/mail_forwarding_rules.yml +++ b/rules/office365/mail_forwarding_rules.yml @@ -1,17 +1,17 @@ -# Rule version v1.1.1 +# Rule version v1.1.2 dataTypes: - o365 -name: Office 365 Inbox Forwarding Setting Changed +name: Suspicious Mail Forwarding Rule Creation description: | - An Exchange inbox rule creation or modification supplied a ForwardTo, ForwardAsAttachmentTo or RedirectTo setting. Clearing a setting is also a change. + An inbox rule was created or changed with a ForwardTo, ForwardAsAttachmentTo or RedirectTo setting. Rules that send a mailbox's mail to an outside address are a common sign that the mailbox has been taken over. - Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. -category: Administrative Awareness + Check the destination in the rule parameters, who made the change and recent sign-ins for the mailbox. Clearing a forwarding setting in an existing rule also raises this alert. The alert does not by itself establish compromise or an external recipient. +category: Collection technique: 'T1114.003 - Email Collection: Email Forwarding Rule' adversary: origin impact: - confidentiality: 1 + confidentiality: 2 integrity: 1 availability: 0 references: diff --git a/rules/office365/mailbox_auto_forwarding_set_mailbox.yml b/rules/office365/mailbox_auto_forwarding_set_mailbox.yml index 3e287f338..977d91e97 100644 --- a/rules/office365/mailbox_auto_forwarding_set_mailbox.yml +++ b/rules/office365/mailbox_auto_forwarding_set_mailbox.yml @@ -1,17 +1,17 @@ -# Rule version v1.1.1 +# Rule version v1.1.2 dataTypes: - o365 -name: Office 365 Mailbox Forwarding Setting Changed +name: O365 Mailbox Auto-Forwarding (Set-Mailbox) description: | - An administrator changed a mailbox forwarding parameter using Set-Mailbox: ForwardingAddress, ForwardingSmtpAddress or DeliverToMailboxAndForward. Inspect the recorded value to learn whether this enabled, redirected, changed or cleared forwarding. + Set-Mailbox set a forwarding address on a mailbox (ForwardingSmtpAddress or ForwardingAddress). Mail delivered to the mailbox is then forwarded to that address without any inbox rule, a common step after a mailbox is taken over. - Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. -category: Administrative Awareness + Check whether the address is outside the organization, who made the change and recent sign-ins for that account. Clearing forwarding, or changing only DeliverToMailboxAndForward, does not raise this alert. The alert does not by itself establish compromise or an external recipient. +category: Collection technique: 'T1114.003 - Email Collection: Email Forwarding Rule' adversary: origin impact: - confidentiality: 1 + confidentiality: 2 integrity: 1 availability: 0 references: @@ -19,7 +19,7 @@ references: - https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema - https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/set-mailbox?view=exchange-ps where: | - equals("log.Workload", "Exchange") && equals("actionResult", "success") && equals("action", "Set-Mailbox") && (equals("log.o365MailboxForwardingChange", "true") || exists("log.Parameters.#(Name==ForwardingAddress).Name") || exists("log.Parameters.#(Name==ForwardingSmtpAddress).Name") || exists("log.Parameters.#(Name==DeliverToMailboxAndForward).Name")) + equals("log.Workload", "Exchange") && equals("actionResult", "success") && equals("action", "Set-Mailbox") && (equals("log.o365MailboxForwardingSet", "true") || regexMatch("log.Parameters.#(Name==ForwardingAddress).Value", "(?s)^.+$") || regexMatch("log.Parameters.#(Name==ForwardingSmtpAddress).Value", "(?s)^.+$")) groupBy: - lastEvent.tenantId - lastEvent.log.OrganizationId diff --git a/rules/office365/mailbox_delegation_abuse.yml b/rules/office365/mailbox_delegation_abuse.yml index b589232df..bcbda9c37 100644 --- a/rules/office365/mailbox_delegation_abuse.yml +++ b/rules/office365/mailbox_delegation_abuse.yml @@ -1,12 +1,12 @@ -# Rule version v1.1.1 +# Rule version v1.1.2 dataTypes: - o365 name: Office 365 Mailbox Delegate Permission Changed description: | - An administrator changed mailbox FullAccess, SendAs or SendOnBehalf access through mailbox or recipient permission cmdlets, or supplied GrantSendOnBehalfTo to Set-Mailbox. Microsoft may also emit routine service-account mailbox permission maintenance; verify the actor and mailbox before escalation. + An administrator granted a mailbox permission such as FullAccess with Add-MailboxPermission, granted SendAs with Add-RecipientPermission, or supplied GrantSendOnBehalfTo to Set-Mailbox. These permissions let another account read the mailbox or send mail as, or on behalf of, its owner. Removing a permission does not raise this alert. - Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. + Some changes are recorded under an Exchange service account instead of the administrator who made them. Review the actor, affected object, change request and authorized owner. This alert reports an audited configuration change; it does not by itself establish compromise, an external recipient, or a currently enabled setting. category: Administrative Awareness technique: 'T1098.002 - Account Manipulation: Additional Email Delegate Permissions' adversary: origin @@ -19,7 +19,7 @@ references: - https://learn.microsoft.com/en-us/office/office-365-management-api/office-365-management-activity-api-schema - https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/add-mailboxpermission?view=exchange-ps where: | - equals("log.Workload", "Exchange") && equals("actionResult", "success") && (oneOf("action", ["Add-MailboxPermission", "Remove-MailboxPermission", "Add-RecipientPermission", "Remove-RecipientPermission"]) || (equals("action", "Set-Mailbox") && (equals("log.o365SendOnBehalfChange", "true") || exists("log.Parameters.#(Name==GrantSendOnBehalfTo).Name")))) + equals("log.Workload", "Exchange") && equals("actionResult", "success") && (oneOf("action", ["Add-MailboxPermission", "Add-RecipientPermission"]) || (equals("action", "Set-Mailbox") && (equals("log.o365SendOnBehalfChange", "true") || exists("log.Parameters.#(Name==GrantSendOnBehalfTo).Name")))) groupBy: - lastEvent.tenantId - lastEvent.log.OrganizationId