From 1a4ba7e7f42d5a25cc002a13d5d825c37e35ca8d Mon Sep 17 00:00:00 2001 From: Ricardo Valdes Date: Wed, 30 Sep 2026 15:53:57 -0400 Subject: [PATCH] fix(windows): simplify authentication correlation and repair rules that never fire Authentication correlation (filter 3.2.2 and seven rules): - Keep one derived source, log.authenticationSource. Drop log.authenticationSourceType and log.authenticationSourceDomain: on 27 servers the kind never separated a source, and the domain split one account written two ways more often than it separated two accounts. - Drop the two logon markers. The failed-logon marker repeated the search terms; the success marker was written on every successful logon and no rule read it. Kerberos and AD FS markers stay; their predicates cannot be written as exact terms. Remove the checks and history terms they imply. - Brute force counts failures per computer and source, whatever account they target, so password spraying is caught and one source raises one alert. Success after failures skips computer accounts. Rules that could never fire or broke at runtime: - LSASS handle access: both patterns were invalid (\l, \P), so the rule never matched; access mask 0x120089 was written as 1180185. - Certificate services: read Requester; SubjectUserName does not exist in events 4886 and 4887. - AdminSDHolder: read the ObjectDN of event 5136; 4662 names objects by GUID and 4670 does not cover directory objects. - SMBv1: event 3000 of the SMB server is the signal; the agent sends no message text. - Ransomware file writes: history searched target.user, which 4663 never has, so every candidate failed evaluation and tripped the circuit breaker. Count by dataSource, account and access mask. Alert keys that never resolved now use fields that exist (SAM, LSASS, ransomware, certificate, SMBv1). Dead branches removed: Sysmon event 1 with NewProcessName, pre-Vista logon codes and 4769 in the loopback Remote Desktop rule, and an NTDS history block that counted any object access on the computer. Co-Authored-By: Claude Opus 5.5 --- filters/audits/windows.md | 67 ++- filters/windows/windows-events.yml | 108 +--- .../testdata/filter-contracts/windows.json | 50 +- plugins/alerts/testdata/windows_raw.json | 545 ++++++++++++------ plugins/alerts/windows_contract_test.go | 66 ++- .../windows/adfs_authentication_anomalies.yml | 14 +- rules/windows/adminsdholder_abuse.yml | 22 +- rules/windows/asrep_roasting_detection.yml | 23 +- rules/windows/bruteforce_attack.yml | 31 +- ...iple_logon_failure_followed_by_success.yml | 28 +- rules/windows/certificate_services_abuse.yml | 15 +- rules/windows/golden_ticket_detection.yml | 15 +- rules/windows/kerberoasting_detection.yml | 22 +- rules/windows/lsass_memdump_handle_access.yml | 18 +- rules/windows/ntds_extraction_attempts.yml | 13 +- ...rse_tunneling_using_stolen_credentials.yml | 4 +- .../printspooler_service_suspicious_file.yml | 4 +- .../windows/ransom_multiple_file_deletion.yml | 24 +- rules/windows/sam_database_access.yml | 10 +- rules/windows/silver_ticket_detection.yml | 29 +- rules/windows/smbv1_usage_detection.yml | 11 +- .../unusual_process_network_connection.yml | 4 +- .../windows_remote_management_abuse.yml | 6 +- 23 files changed, 606 insertions(+), 523 deletions(-) diff --git a/filters/audits/windows.md b/filters/audits/windows.md index 52b9fe61d..117f311bc 100644 --- a/filters/audits/windows.md +++ b/filters/audits/windows.md @@ -20,12 +20,13 @@ are rejected while the exact original vendor value is preserved. Tests cover account and workstation fallback, no qualified fallback, and a valid mapped-IPv4 control. These alternate-spelling regressions are synthetic; no additional customer occurrence is claimed. Authentication correlation chooses a real source IP, -then workstation, then actor account, recorded in `log.authenticationSource` -and `log.authenticationSourceType`. The account fallback identifies an account, -not a network client. Every affected history search scopes that identity by -its kind, domain scope, the agent's `dataSource`, and event code. Brute-force rules also -require the target account; Kerberos searches constrain ticket encryption and, -for AS-REP, preauthentication type. No shared placeholder is an identity. A username-only fallback requires its +then workstation, then actor account, recorded in `log.authenticationSource`. +The account fallback identifies an account, not a network client. Every affected +history search pairs that identity with the agent's `dataSource`. The brute-force +rule counts failures from one source whatever account they target; success after +failures also requires the same account. Kerberos searches use their candidate +marker, which already fixes the event code and ticket encryption. No shared +placeholder is an identity. A username-only fallback requires its domain or an already qualified UPN; an unqualified username without a domain is not treated as a safe correlation identity. @@ -38,12 +39,37 @@ correlation fields, so the updated history windows warm up after deployment. Golden Ticket's historical query previously depended on `origin.host`, not `origin.ip`; native Kerberos records can lack that workstation too. Its -correlation now uses the same identity selection. Filter-derived `log.authenticationCandidate.*` markers repeat each exact -trigger predicate so benign events with the same event code cannot satisfy the -historical threshold. The tests assert marker/predicate parity. Success after -failures searches the failed-logon marker. The update preserves each rule's -existing count and time window. It does not claim that the existing -Golden/Silver Ticket heuristics prove forged tickets. +correlation now uses the same identity selection. Filter-derived `log.authenticationCandidate.*` markers repeat the +trigger predicates that a history search cannot express (Kerberoasting, AS-REP +roasting, Silver and Golden Ticket, AD FS), so benign events with the same event +code cannot satisfy the historical threshold. The tests assert marker/predicate +parity. The two logon rules need no marker: their exact terms (event 4625, +`dataSource`, source and, for success, the account) already are the predicate. +The update preserves each rule's existing count and time window. It does not +claim that the existing Golden/Silver Ticket heuristics prove forged tickets. + +## Simplification after production use (2026-09-30) + +The first version also stored the kind of source (`log.authenticationSourceType`) +and a domain scope (`log.authenticationSourceDomain`), and marked every failed +and successful logon. Read-only counts on 27 v11.2.15 servers, which run this +filter unchanged, showed that none of it changed which events were counted: + +- Across 26,418 source values seen in two days, no value ever appeared with two + kinds. The domain scope separated five values; four of them were one domain + written two ways (short and full name), so it split one account in two. +- The failed-logon marker only repeated the event code and the presence of the + source and account, which the search terms already require. The success + marker was written on every successful logon (about three million a day) and + no rule read it. + +Both fields and both logon markers are removed. Counting failures per source +instead of per source and account follows the rule's description and also +catches password spraying. Replaying two days of production failures, the +per-account version would have raised 100 alerts, up to 26 in one hour on one +server; the per-source version raises 69, at most 5 in one hour. The success +rule no longer searches history for computer accounts, which are 44% of +successful logons and whose passwords are machine-generated. ## Standard field promotion @@ -70,15 +96,18 @@ placeholder cleanup, and event-versus-alert grouping remain included. - `windows_contract_test.go` is standalone and runs with `go test ./...` in `plugins/alerts`, without the shared test-runner PR. -- 60 sanitized raw JSON fixtures exercise valid IPv4/IPv6, missing/placeholder - addresses, host/account fallback, valid/invalid ports, host roles and time. -- 50 positive predicate cases cover all seven changed correlation consumers. - Negative identity cases also compile/evaluate all 38 shipped Windows rules. +- 77 sanitized raw JSON fixtures exercise valid IPv4/IPv6, missing/placeholder + addresses, host/account fallback, valid/invalid ports, host roles and time, + and the LSASS, certificate, AdminSDHolder, SMBv1, ransomware and loopback + Remote Desktop rules. +- Positive predicate cases cover every changed correlation consumer. Negative + identity cases also compile/evaluate all 48 shipped Windows rules. - The real SDK executes historical requests against a local mock OpenSearch server, including mapping resolution, placeholder expansion, query creation, - time/count boundaries and separation of different sources, identity kinds, - collectors, account domains, event types and non-candidate history. The old missing-IP regression is reproduced with - the SDK, without a customer connection. + time/count boundaries and separation by every exact search term. A spray of + failures against different accounts fills the brute-force threshold but not + the success-after-failures threshold. The old missing-IP regression is + reproduced with the SDK, without a customer connection. - The shared manifest adds seven nonempty rule assertions to its normalization cases. Its runner is supplied by draft #2590. diff --git a/filters/windows/windows-events.yml b/filters/windows/windows-events.yml index bbdfcd01e..e23b155e5 100644 --- a/filters/windows/windows-events.yml +++ b/filters/windows/windows-events.yml @@ -1,4 +1,4 @@ -# Windows_Agent filter, version 3.2.1 +# Windows_Agent filter, version 3.2.2 # Based on winlogbeat fields, reference [8.15] # See https://www.elastic.co/guide/en/beats/winlogbeat/current/exported-fields-winlog.html @@ -3291,22 +3291,16 @@ pipeline: to: int # Correlation requires a real identity, never the shared '-' placeholder. - # Prefer the network source, then workstation, then authenticated account. - # Rules also scope this derived value by its kind and by dataSource. + # Prefer the network source, then the workstation, then an account that a + # domain or UPN qualifies. Rules pair this value with dataSource. - delete: - fields: [log.authenticationSource, log.authenticationSourceType, log.authenticationSourceDomain, log.authenticationCandidate] + fields: [log.authenticationSource, log.authenticationCandidate] - grok: source: origin.ip patterns: - fieldName: log.authenticationSource pattern: '{{.greedy}}' where: exists("origin.ip") - - add: - function: string - params: - key: log.authenticationSourceType - value: ip - where: exists("log.authenticationSource") - grok: source: origin.host patterns: @@ -3314,12 +3308,6 @@ pipeline: pattern: '{{.greedy}}' where: >- !exists("log.authenticationSource") && exists("origin.host") - - add: - function: string - params: - key: log.authenticationSourceType - value: host - where: exists("log.authenticationSource") && !exists("log.authenticationSourceType") - grok: source: origin.user patterns: @@ -3327,38 +3315,12 @@ pipeline: pattern: '{{.greedy}}' where: >- !exists("log.authenticationSource") && exists("origin.user") && (exists("origin.domain") || regexMatch("origin.user", "^[^@]+@[^@]+$")) - - add: - function: string - params: - key: log.authenticationSourceType - value: user - where: exists("log.authenticationSource") && !exists("log.authenticationSourceType") - - # User-only identities require a domain or an already qualified UPN. The - # explicit scope prevents equal usernames from different domains joining. - - grok: - source: origin.domain - patterns: - - fieldName: log.authenticationSourceDomain - pattern: '{{.greedy}}' - where: equals("log.authenticationSourceType", "user") && exists("origin.domain") - - add: - function: string - params: - key: log.authenticationSourceDomain - value: qualified-upn - where: equals("log.authenticationSourceType", "user") && !exists("log.authenticationSourceDomain") - - add: - function: string - params: - key: log.authenticationSourceDomain - value: network-source - where: oneOf("log.authenticationSourceType", ["ip", "host"]) # Historical searches support exact terms, not a CEL predicate. Mark the - # same candidates tested by these authentication rules so routine events - # with the same event ID cannot fill an attack threshold. Keep predicates - # and markers together; the raw/CEL regression checks assert their parity. + # candidates of the authentication rules whose predicate a history search + # cannot repeat, so routine events with the same event ID cannot fill an + # attack threshold. Keep predicates and markers together; the raw/CEL + # regression checks assert their parity. - add: function: string params: @@ -3366,16 +3328,14 @@ pipeline: value: match where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && - ( + exists("log.authenticationSource") && equals("log.eventCode", "4769") && equals("log.channel", "Security") && equals("log.eventDataTicketEncryptionType", "23") && !regexMatch("log.eventDataServiceName", "(?i)\\$$") && !equals("log.eventDataServiceName", "krbtgt") && - !oneOf("log.eventDataTicketOptions", ["1082195968", "1082130432", "1082130432"]) && + !oneOf("log.eventDataTicketOptions", ["1082195968", "1082130432"]) && exists("log.eventDataServiceName") - ) - add: function: string params: @@ -3383,15 +3343,13 @@ pipeline: value: match where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && - ( + exists("log.authenticationSource") && equals("log.eventCode", "4768") && equals("log.channel", "Security") && equals("log.eventDataTicketEncryptionType", "23") && equals("log.eventDataPreAuthType", "0") && !regexMatch("target.user", "(?i)\\$$") && exists("target.user") - ) - add: function: string params: @@ -3399,17 +3357,12 @@ pipeline: value: match where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && - ( + exists("log.authenticationSource") && equals("log.eventCode", "4769") && equals("log.channel", "Security") && - ( - equals("log.eventDataTicketEncryptionType", "23") && - !regexMatch("log.eventDataServiceName", "(?i)(krbtgt|\\$$)") && - !oneOf("log.eventDataStatus", ["0", "6"]) && - exists("log.authenticationSource") - ) - ) + equals("log.eventDataTicketEncryptionType", "23") && + !regexMatch("log.eventDataServiceName", "(?i)(krbtgt|\\$$)") && + !oneOf("log.eventDataStatus", ["0", "6"]) - add: function: string params: @@ -3417,14 +3370,13 @@ pipeline: value: match where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && + exists("log.authenticationSource") && ( ( equals("log.eventCode", "4769") && equals("log.channel", "Security") && equals("log.eventDataServiceName", "krbtgt") && - !equals("log.eventDataStatus", "0") && - exists("log.authenticationSource") + !equals("log.eventDataStatus", "0") ) || ( equals("log.eventCode", "4768") && @@ -3448,29 +3400,5 @@ pipeline: value: match where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && - ( + exists("log.authenticationSource") && equals("log.providerName", "AD FS") && (equals("log.eventCode", "342") || equals("log.eventCode", "516")) && contains("log.message", "token validation failed") - ) - - add: - function: string - params: - key: log.authenticationCandidate.bruteforceAttack - value: match - where: | - !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && exists("target.user") && - ( - equals("log.eventCode", 4625) - ) - - add: - function: string - params: - key: log.authenticationCandidate.bruteforceMultipleLogonFailureFollowedBySuccess - value: match - where: | - !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && exists("target.user") && - ( - equals("log.eventCode", 4624) - ) diff --git a/plugins/alerts/testdata/filter-contracts/windows.json b/plugins/alerts/testdata/filter-contracts/windows.json index 53e348676..241f6d68f 100644 --- a/plugins/alerts/testdata/filter-contracts/windows.json +++ b/plugins/alerts/testdata/filter-contracts/windows.json @@ -200,17 +200,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "rules": { "rules/windows/kerberoasting_detection.yml": true @@ -244,17 +244,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.asrepRoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "rules": { "rules/windows/asrep_roasting_detection.yml": true @@ -289,17 +289,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.silverTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "rules": { "rules/windows/silver_ticket_detection.yml": true @@ -332,17 +332,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.goldenTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "rules": { "rules/windows/golden_ticket_detection.yml": true @@ -375,17 +375,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", - "log.authenticationCandidate.bruteforceAttack": "match" + "log.data.IpAddress": "-" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "rules": { "rules/windows/bruteforce_attack.yml": true @@ -418,17 +418,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", - "log.authenticationCandidate.bruteforceMultipleLogonFailureFollowedBySuccess": "match" + "log.data.IpAddress": "-" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "rules": { "rules/windows/bruteforce_multiple_logon_failure_followed_by_success.yml": true @@ -461,17 +461,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "AD FS", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.adfsAuthenticationAnomalies": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "rules": { "rules/windows/adfs_authentication_anomalies.yml": true diff --git a/plugins/alerts/testdata/windows_raw.json b/plugins/alerts/testdata/windows_raw.json index 79180da70..e97ec98cb 100644 --- a/plugins/alerts/testdata/windows_raw.json +++ b/plugins/alerts/testdata/windows_raw.json @@ -7,17 +7,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "192.0.2.41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "192.0.2.41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -31,17 +31,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "2001:db8::41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "2001:db8::41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -55,17 +55,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "host", "log.authenticationSource": "client01", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -79,17 +79,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -103,16 +103,16 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -126,17 +126,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "0.0.0.0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -150,17 +150,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "192.0.2.41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "192.0.2.41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.asrepRoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "asrep_roasting_detection" @@ -174,17 +174,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "2001:db8::41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "2001:db8::41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.asrepRoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "asrep_roasting_detection" @@ -198,17 +198,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "host", "log.authenticationSource": "client01", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.asrepRoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "asrep_roasting_detection" @@ -222,17 +222,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.asrepRoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "asrep_roasting_detection" @@ -246,16 +246,16 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.asrepRoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "asrep_roasting_detection" @@ -269,17 +269,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "0.0.0.0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.asrepRoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "asrep_roasting_detection" @@ -293,17 +293,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "192.0.2.41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "192.0.2.41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.silverTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "silver_ticket_detection" @@ -317,17 +317,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "2001:db8::41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "2001:db8::41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.silverTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "silver_ticket_detection" @@ -341,17 +341,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "host", "log.authenticationSource": "client01", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.silverTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "silver_ticket_detection" @@ -365,17 +365,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.silverTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "silver_ticket_detection" @@ -389,16 +389,16 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.silverTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "silver_ticket_detection" @@ -412,17 +412,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "0.0.0.0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.silverTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "silver_ticket_detection" @@ -436,17 +436,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "192.0.2.41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "192.0.2.41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.goldenTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "golden_ticket_detection" @@ -460,17 +460,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "2001:db8::41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "2001:db8::41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.goldenTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "golden_ticket_detection" @@ -484,17 +484,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "host", "log.authenticationSource": "client01", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.goldenTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "golden_ticket_detection" @@ -508,17 +508,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.goldenTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "golden_ticket_detection" @@ -532,16 +532,16 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.goldenTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "golden_ticket_detection" @@ -555,17 +555,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "0.0.0.0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.goldenTicketDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "golden_ticket_detection" @@ -579,17 +579,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "192.0.2.41", "origin.port": 49152, "origin.user": "alice", - "origin.ip": "192.0.2.41", - "log.authenticationSourceDomain": "network-source", - "log.authenticationCandidate.bruteforceAttack": "match" + "origin.ip": "192.0.2.41" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_attack" @@ -603,17 +603,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "2001:db8::41", "origin.port": 49152, "origin.user": "alice", - "origin.ip": "2001:db8::41", - "log.authenticationSourceDomain": "network-source", - "log.authenticationCandidate.bruteforceAttack": "match" + "origin.ip": "2001:db8::41" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_attack" @@ -627,17 +627,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "host", "log.authenticationSource": "client01", "origin.port": 49152, "origin.user": "alice", - "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "network-source", - "log.authenticationCandidate.bruteforceAttack": "match" + "log.data.IpAddress": "-" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_attack" @@ -651,17 +651,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", - "log.authenticationCandidate.bruteforceAttack": "match" + "log.data.IpAddress": "-" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_attack" @@ -675,16 +675,16 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, - "origin.user": "alice", - "log.authenticationSourceDomain": "EXAMPLE", - "log.authenticationCandidate.bruteforceAttack": "match" + "origin.user": "alice" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_attack" @@ -698,17 +698,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.data.IpAddress": "0.0.0.0", - "log.authenticationSourceDomain": "EXAMPLE", - "log.authenticationCandidate.bruteforceAttack": "match" + "log.data.IpAddress": "0.0.0.0" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_attack" @@ -722,17 +722,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "192.0.2.41", "origin.port": 49152, "origin.user": "alice", - "origin.ip": "192.0.2.41", - "log.authenticationSourceDomain": "network-source", - "log.authenticationCandidate.bruteforceMultipleLogonFailureFollowedBySuccess": "match" + "origin.ip": "192.0.2.41" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_multiple_logon_failure_followed_by_success" @@ -746,17 +746,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "2001:db8::41", "origin.port": 49152, "origin.user": "alice", - "origin.ip": "2001:db8::41", - "log.authenticationSourceDomain": "network-source", - "log.authenticationCandidate.bruteforceMultipleLogonFailureFollowedBySuccess": "match" + "origin.ip": "2001:db8::41" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_multiple_logon_failure_followed_by_success" @@ -770,17 +770,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "host", "log.authenticationSource": "client01", "origin.port": 49152, "origin.user": "alice", - "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "network-source", - "log.authenticationCandidate.bruteforceMultipleLogonFailureFollowedBySuccess": "match" + "log.data.IpAddress": "-" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_multiple_logon_failure_followed_by_success" @@ -794,17 +794,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", - "log.authenticationCandidate.bruteforceMultipleLogonFailureFollowedBySuccess": "match" + "log.data.IpAddress": "-" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_multiple_logon_failure_followed_by_success" @@ -818,16 +818,16 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, - "origin.user": "alice", - "log.authenticationSourceDomain": "EXAMPLE", - "log.authenticationCandidate.bruteforceMultipleLogonFailureFollowedBySuccess": "match" + "origin.user": "alice" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_multiple_logon_failure_followed_by_success" @@ -841,17 +841,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.data.IpAddress": "0.0.0.0", - "log.authenticationSourceDomain": "EXAMPLE", - "log.authenticationCandidate.bruteforceMultipleLogonFailureFollowedBySuccess": "match" + "log.data.IpAddress": "0.0.0.0" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain", + "log.authenticationCandidate" ], "matches": [ "bruteforce_multiple_logon_failure_followed_by_success" @@ -865,17 +865,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "AD FS", - "log.authenticationSourceType": "ip", "log.authenticationSource": "192.0.2.41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "192.0.2.41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.adfsAuthenticationAnomalies": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "adfs_authentication_anomalies" @@ -889,17 +889,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "AD FS", - "log.authenticationSourceType": "ip", "log.authenticationSource": "2001:db8::41", "origin.port": 49152, "origin.user": "alice", "origin.ip": "2001:db8::41", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.adfsAuthenticationAnomalies": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "adfs_authentication_anomalies" @@ -913,17 +913,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "AD FS", - "log.authenticationSourceType": "host", "log.authenticationSource": "client01", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.adfsAuthenticationAnomalies": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "adfs_authentication_anomalies" @@ -937,17 +937,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "AD FS", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "-", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.adfsAuthenticationAnomalies": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "adfs_authentication_anomalies" @@ -961,16 +961,16 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "AD FS", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.adfsAuthenticationAnomalies": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "adfs_authentication_anomalies" @@ -984,17 +984,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "AD FS", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "0.0.0.0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.adfsAuthenticationAnomalies": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "adfs_authentication_anomalies" @@ -1082,13 +1082,13 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "actionResult": "success", - "log.authenticationSource": "CLIENT01", - "log.authenticationSourceType": "host", - "log.authenticationSourceDomain": "network-source" + "log.authenticationSource": "CLIENT01" }, "absent": [ "origin.ip", - "origin.port" + "origin.port", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [] }, @@ -1120,11 +1120,11 @@ "origin.domain": "EXAMPLE", "origin.path": "C:\\Windows\\System32\\winlogon.exe", "log.eventDataSubjectDomainName": "NT AUTHORITY", - "log.eventDataSubjectUserName": "SYSTEM", - "log.authenticationCandidate.bruteforceAttack": "match" + "log.eventDataSubjectUserName": "SYSTEM" }, "absent": [ - "origin.ip" + "origin.ip", + "log.authenticationCandidate" ], "matches": [ "bruteforce_attack" @@ -1151,12 +1151,12 @@ "raw": "{\"eventCode\": 4625, \"data\": {\"IpAddress\": \"-\", \"TargetUserName\": \"alice@example.test\"}}", "expected": { "origin.user": "alice@example.test", - "log.authenticationSource": "alice@example.test", - "log.authenticationSourceType": "user", - "log.authenticationSourceDomain": "qualified-upn" + "log.authenticationSource": "alice@example.test" }, "absent": [ - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "bruteforce_attack" @@ -1183,13 +1183,13 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "actionResult": "failed", - "log.authenticationSource": "CLIENT01", - "log.authenticationSourceType": "host", - "log.authenticationSourceDomain": "network-source" + "log.authenticationSource": "CLIENT01" }, "absent": [ "origin.ip", - "origin.port" + "origin.port", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [] }, @@ -1201,17 +1201,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "0:0:0:0:0:0:0:0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -1225,17 +1225,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "::0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -1249,17 +1249,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "::ffff:0.0.0.0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -1273,17 +1273,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "user", "log.authenticationSource": "alice", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "::ffff:0:0", - "log.authenticationSourceDomain": "EXAMPLE", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -1297,17 +1297,17 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "host", "log.authenticationSource": "client01", "origin.port": 49152, "origin.user": "alice", "log.data.IpAddress": "0:0:0:0:0:0:0:0", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "origin.ip" + "origin.ip", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" @@ -1337,20 +1337,199 @@ "target.host": "dc01.example.test", "deviceTime": "2026-09-17T12:00:00Z", "log.providerName": "Microsoft-Windows-Security-Auditing", - "log.authenticationSourceType": "ip", "log.authenticationSource": "::ffff:192.0.2.10", "origin.port": 49152, "origin.user": "alice", "origin.ip": "::ffff:192.0.2.10", - "log.authenticationSourceDomain": "network-source", "log.authenticationCandidate.kerberoastingDetection": "match" }, "absent": [ "log.unparsedOriginIp", - "log.data.IpAddress" + "log.data.IpAddress", + "log.authenticationSourceType", + "log.authenticationSourceDomain" ], "matches": [ "kerberoasting_detection" ] + }, + { + "name": "bruteforce_attack failure without a target account still counts", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"TargetUserName\":\"-\",\"TargetDomainName\":\"-\",\"Status\":3221225578,\"IpAddress\":\"192.0.2.41\",\"WorkstationName\":\"client01\",\"IpPort\":\"49152\"},\"eventCode\":4625}", + "expected": { + "log.authenticationSource": "192.0.2.41", + "origin.ip": "192.0.2.41" + }, + "absent": [ + "target.user", + "log.authenticationCandidate" + ], + "matches": [ + "bruteforce_attack" + ] + }, + { + "name": "Computer account success is not searched for earlier failures", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"TargetUserName\":\"CLIENT01$\",\"TargetDomainName\":\"EXAMPLE\",\"Status\":0,\"IpAddress\":\"192.0.2.41\",\"WorkstationName\":\"client01\",\"IpPort\":\"49152\",\"LogonType\":\"3\"},\"eventCode\":4624}", + "expected": { + "log.authenticationSource": "192.0.2.41", + "target.user": "CLIENT01$" + }, + "absent": [ + "log.authenticationCandidate" + ], + "matches": [] + }, + { + "name": "Remote Desktop logon from loopback", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"TargetUserName\":\"alice\",\"TargetDomainName\":\"EXAMPLE\",\"Status\":0,\"IpAddress\":\"127.0.0.1\",\"WorkstationName\":\"dc01\",\"IpPort\":\"0\",\"LogonType\":\"10\"},\"eventCode\":4624}", + "expected": { + "origin.ip": "127.0.0.1", + "log.eventDataLogonType": "10" + }, + "absent": [], + "matches": [ + "possible_exploit_over_reverse_tunneling_using_stolen_credentials", + "bruteforce_multiple_logon_failure_followed_by_success" + ] + }, + { + "name": "LSASS handle requested by a dump tool", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-21-1111111111-2222222222-3333333333-1105\",\"SubjectUserName\":\"alice\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"ObjectServer\":\"Security\",\"ObjectType\":\"Process\",\"ObjectName\":\"\\\\Device\\\\HarddiskVolume3\\\\Windows\\\\System32\\\\lsass.exe\",\"HandleId\":0,\"AccessMask\":2097151,\"ProcessId\":6700,\"ProcessName\":\"C:\\\\Users\\\\Public\\\\procdump64.exe\"},\"eventCode\":4656}", + "expected": { + "log.eventDataAccessMask": 2097151, + "origin.user": "alice" + }, + "absent": [], + "matches": [ + "lsass_memdump_handle_access" + ] + }, + { + "name": "LSASS handle requested by a dump tool through the drive path", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-21-1111111111-2222222222-3333333333-1105\",\"SubjectUserName\":\"alice\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"ObjectServer\":\"Security\",\"ObjectType\":\"Process\",\"ObjectName\":\"C:\\\\Windows\\\\System32\\\\lsass.exe\",\"HandleId\":0,\"AccessMask\":4112,\"ProcessId\":6700,\"ProcessName\":\"C:\\\\Temp\\\\m.exe\"},\"eventCode\":4656}", + "expected": {}, + "absent": [], + "matches": [ + "lsass_memdump_handle_access" + ] + }, + { + "name": "LSASS handle requested by Microsoft Defender", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-21-1111111111-2222222222-3333333333-1105\",\"SubjectUserName\":\"alice\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"ObjectServer\":\"Security\",\"ObjectType\":\"Process\",\"ObjectName\":\"\\\\Device\\\\HarddiskVolume3\\\\Windows\\\\System32\\\\lsass.exe\",\"HandleId\":0,\"AccessMask\":4112,\"ProcessId\":6700,\"ProcessName\":\"C:\\\\ProgramData\\\\Microsoft\\\\Windows Defender\\\\Platform\\\\4.18.25080.5-0\\\\MsMpEng.exe\"},\"eventCode\":4656}", + "expected": {}, + "absent": [], + "matches": [] + }, + { + "name": "LSASS handle requested by an installed security agent", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-21-1111111111-2222222222-3333333333-1105\",\"SubjectUserName\":\"alice\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"ObjectServer\":\"Security\",\"ObjectType\":\"Process\",\"ObjectName\":\"\\\\Device\\\\HarddiskVolume3\\\\Windows\\\\System32\\\\lsass.exe\",\"HandleId\":0,\"AccessMask\":2097151,\"ProcessId\":6700,\"ProcessName\":\"C:\\\\Program Files\\\\Example Vendor\\\\agent.exe\"},\"eventCode\":4656}", + "expected": {}, + "absent": [], + "matches": [] + }, + { + "name": "LSASS handle with a query-only access mask", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-21-1111111111-2222222222-3333333333-1105\",\"SubjectUserName\":\"alice\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"ObjectServer\":\"Security\",\"ObjectType\":\"Process\",\"ObjectName\":\"\\\\Device\\\\HarddiskVolume3\\\\Windows\\\\System32\\\\lsass.exe\",\"HandleId\":0,\"AccessMask\":5136,\"ProcessId\":6700,\"ProcessName\":\"C:\\\\Users\\\\Public\\\\procdump64.exe\"},\"eventCode\":4656}", + "expected": {}, + "absent": [], + "matches": [] + }, + { + "name": "Certificate issued to a computer account", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"RequestId\":\"4521\",\"Requester\":\"EXAMPLE\\\\CLIENT01$\",\"Attributes\":\"\",\"Disposition\":\"3\",\"SubjectKeyIdentifier\":\"00\",\"Subject\":\"CN=client01.example.test\"},\"eventCode\":4887}", + "expected": { + "log.data.Requester": "EXAMPLE\\CLIENT01$" + }, + "absent": [], + "matches": [ + "certificate_services_abuse" + ] + }, + { + "name": "Certificate requested by an anonymous logon", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"RequestId\":\"4522\",\"Requester\":\"NT AUTHORITY\\\\ANONYMOUS LOGON\",\"Attributes\":\"\"},\"eventCode\":4886}", + "expected": {}, + "absent": [], + "matches": [ + "certificate_services_abuse" + ] + }, + { + "name": "Certificate requested by a user account", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"RequestId\":\"4523\",\"Requester\":\"EXAMPLE\\\\alice\",\"Attributes\":\"\"},\"eventCode\":4886}", + "expected": {}, + "absent": [], + "matches": [] + }, + { + "name": "AdminSDHolder permissions changed", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-21-1111111111-2222222222-3333333333-1105\",\"SubjectUserName\":\"alice\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"OpCorrelationID\":\"{00000000-0000-0000-0000-000000000001}\",\"DSName\":\"example.test\",\"DSType\":\"%%14676\",\"ObjectDN\":\"CN=AdminSDHolder,CN=System,DC=example,DC=test\",\"ObjectGUID\":\"{00000000-0000-0000-0000-000000000002}\",\"ObjectClass\":\"container\",\"AttributeLDAPDisplayName\":\"nTSecurityDescriptor\",\"AttributeSyntaxOID\":\"2.5.5.15\",\"AttributeValue\":\"O:DAG:DAD:(A;;RP;;;WD)\",\"OperationType\":\"%%14674\"},\"eventCode\":5136}", + "expected": { + "log.data.ObjectDN": "CN=AdminSDHolder,CN=System,DC=example,DC=test" + }, + "absent": [], + "matches": [ + "adminsdholder_abuse" + ] + }, + { + "name": "AdminSDHolder changed by SYSTEM", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-18\",\"SubjectUserName\":\"SISTEMA\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"OpCorrelationID\":\"{00000000-0000-0000-0000-000000000003}\",\"DSName\":\"example.test\",\"DSType\":\"%%14676\",\"ObjectDN\":\"CN=AdminSDHolder,CN=System,DC=example,DC=test\",\"ObjectGUID\":\"{00000000-0000-0000-0000-000000000002}\",\"ObjectClass\":\"container\",\"AttributeLDAPDisplayName\":\"nTSecurityDescriptor\",\"AttributeSyntaxOID\":\"2.5.5.15\",\"AttributeValue\":\"O:DAG:DAD:(A;;RP;;;WD)\",\"OperationType\":\"%%14674\"},\"eventCode\":5136}", + "expected": {}, + "absent": [], + "matches": [] + }, + { + "name": "Directory change on another object", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-21-1111111111-2222222222-3333333333-1105\",\"SubjectUserName\":\"alice\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"OpCorrelationID\":\"{00000000-0000-0000-0000-000000000004}\",\"DSName\":\"example.test\",\"DSType\":\"%%14676\",\"ObjectDN\":\"CN=alice,CN=Users,DC=example,DC=test\",\"ObjectGUID\":\"{00000000-0000-0000-0000-000000000005}\",\"ObjectClass\":\"user\",\"AttributeLDAPDisplayName\":\"description\",\"AttributeSyntaxOID\":\"2.5.5.12\",\"AttributeValue\":\"x\",\"OperationType\":\"%%14674\"},\"eventCode\":5136}", + "expected": {}, + "absent": [], + "matches": [] + }, + { + "name": "SMBv1 access audit", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-SMBServer\",\"provider_guid\":\"{d48ce617-33a2-4bc3-a5c7-11aa4f29619e}\",\"recordId\":1234,\"channel\":\"Microsoft-Windows-SMBServer/Audit\",\"computer\":\"dc01.example.test\",\"data\":{\"ClientName\":\"192.0.2.10\"},\"eventCode\":3000}", + "expected": {}, + "absent": [], + "matches": [ + "smbv1_usage_detection" + ] + }, + { + "name": "Event 3000 from another provider", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Example-Provider\",\"provider_guid\":\"{00000000-0000-0000-0000-000000000006}\",\"recordId\":1234,\"channel\":\"Application\",\"computer\":\"dc01.example.test\",\"data\":{\"param1\":\"x\"},\"eventCode\":3000}", + "expected": {}, + "absent": [], + "matches": [] + }, + { + "name": "Document written in a user folder", + "dataSource": "dc01", + "raw": "{\"timestamp\":\"2026-09-17T12:00:00Z\",\"provider_name\":\"Microsoft-Windows-Security-Auditing\",\"provider_guid\":\"{54849625-5478-4994-a5ba-3e3b0328c30d}\",\"recordId\":1234,\"channel\":\"Security\",\"computer\":\"dc01.example.test\",\"data\":{\"SubjectUserSid\":\"S-1-5-21-1111111111-2222222222-3333333333-1105\",\"SubjectUserName\":\"alice\",\"SubjectDomainName\":\"EXAMPLE\",\"SubjectLogonId\":255905,\"ObjectServer\":\"Security\",\"ObjectType\":\"File\",\"ObjectName\":\"C:\\\\Users\\\\alice\\\\Documents\\\\report.docx\",\"HandleId\":500,\"AccessList\":\"%%4417\",\"AccessMask\":2,\"ProcessId\":11024,\"ProcessName\":\"C:\\\\Users\\\\alice\\\\AppData\\\\Roaming\\\\x.exe\"},\"eventCode\":4663}", + "expected": { + "origin.user": "alice", + "log.eventDataAccessMask": 2 + }, + "absent": [], + "matches": [ + "ransom_multiple_file_deletion" + ] } ] diff --git a/plugins/alerts/windows_contract_test.go b/plugins/alerts/windows_contract_test.go index 1c2a62585..27261cf64 100644 --- a/plugins/alerts/windows_contract_test.go +++ b/plugins/alerts/windows_contract_test.go @@ -315,7 +315,7 @@ func TestWindowsRawContracts(t *testing.T) { t.Error("raw changed") } for name, r := range rules { - if len(r.Correlation) == 0 || !strings.Contains(r.Where, "log.authenticationSourceDomain") { + if !winUsesCandidateMarker(r) { continue } matched, e := cache.Eval(r.Where, out) @@ -367,7 +367,7 @@ func TestWindowsRawContracts(t *testing.T) { func winHistoryMatches(t *testing.T, query string, event string) bool { t.Helper() clauses := append(gjson.Get(query, "query.bool.filter").Array(), gjson.Get(query, "query.bool.must").Array()...) - if len(clauses) < 5 { + if len(clauses) < 4 { t.Errorf("missing history constraints: %s", query) } for _, term := range clauses { @@ -411,7 +411,7 @@ func TestWindowsSDKHistory(t *testing.T) { 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") { - _, _ = w.Write([]byte(`{"v11-log-wineventlog-test":{"mappings":{"properties":{"@timestamp":{"type":"date"},"dataSource":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"log":{"properties":{"authenticationSource":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"authenticationSourceType":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"eventCode":{"type":"long"},"eventDataTicketEncryptionType":{"type":"long"},"eventDataPreAuthType":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"authenticationSourceDomain":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"authenticationCandidate":{"properties":{"kerberoastingDetection":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"asrepRoastingDetection":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"silverTicketDetection":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"goldenTicketDetection":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"adfsAuthenticationAnomalies":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"bruteforceAttack":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"bruteforceMultipleLogonFailureFollowedBySuccess":{"type":"text","fields":{"keyword":{"type":"keyword"}}}}}}},"target":{"properties":{"user":{"type":"text","fields":{"keyword":{"type":"keyword"}}}}}}}}}`)) + _, _ = w.Write([]byte(`{"v11-log-wineventlog-test":{"mappings":{"properties":{"@timestamp":{"type":"date"},"dataSource":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"log":{"properties":{"authenticationSource":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"eventCode":{"type":"long"},"eventDataTicketEncryptionType":{"type":"long"},"eventDataPreAuthType":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"authenticationCandidate":{"properties":{"kerberoastingDetection":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"asrepRoastingDetection":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"silverTicketDetection":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"goldenTicketDetection":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"adfsAuthenticationAnomalies":{"type":"text","fields":{"keyword":{"type":"keyword"}}}}}}},"target":{"properties":{"user":{"type":"text","fields":{"keyword":{"type":"keyword"}}}}}}}}}`)) return } requests++ @@ -490,7 +490,10 @@ func TestWindowsSDKHistory(t *testing.T) { if e != nil || !ok { t.Fatalf("%s threshold result=%v error=%v", name, ok, e) } - for _, field := range []string{"dataSource", "log.authenticationSource", "log.authenticationSourceType", "log.authenticationSourceDomain", "log.authenticationCandidate", "log.eventCode"} { + // Every exact term of the search must separate: history that + // differs in any one of them cannot fill the threshold. + for _, term := range search.With { + field := strings.TrimSuffix(term.Field, ".keyword") history = nil for i := uint64(0); i < search.Count; i++ { history = append(history, mutate(previous, field, "different")) @@ -509,16 +512,42 @@ func TestWindowsSDKHistory(t *testing.T) { t.Fatalf("%s expired history result=%v error=%v", name, ok, e) } } - for _, field := range []string{"log.authenticationSource", "log.authenticationSourceType", "log.authenticationSourceDomain"} { - missing := mutate(trigger, field, nil) + if winSearchesField(r, "log.authenticationSource.keyword") { + missing := mutate(trigger, "log.authenticationSource", nil) ok, e := cache.Eval(r.Where, missing) if e != nil || ok { - t.Errorf("%s accepted missing %s", name, field) + t.Errorf("%s accepted missing log.authenticationSource", name) } } } }) } + // Password spraying: failures from one source against different accounts + // fill the brute-force threshold, while the success rule still needs the + // failures to belong to the account that finally logged on. + fixtures := map[string]winFixture{} + for _, f := range winFixtures(t) { + fixtures[f.Name] = f + } + failure := fixtures["bruteforce_attack ipv4"] + sprayTrigger := winParse(t, cfg, failure.Raw, failure.DataSource, cache) + brute := rules["bruteforce_attack"].Correlation[0] + history = nil + for i := uint64(0); i < brute.Count; i++ { + previous := mutate(sprayTrigger, "@timestamp", time.Now().Add(-time.Minute).UTC().Format(time.RFC3339Nano)) + previous = mutate(previous, "target.user", fmt.Sprintf("user%d", i)) + previous = mutate(previous, "origin.user", fmt.Sprintf("user%d", i)) + history = append(history, previous) + } + if ok, _, e := brute.Execute(&sprayTrigger); e != nil || !ok { + t.Fatalf("spray from one source did not fill the brute-force threshold result=%v error=%v", ok, e) + } + logon := fixtures["bruteforce_multiple_logon_failure_followed_by_success ipv4"] + successTrigger := winParse(t, cfg, logon.Raw, logon.DataSource, cache) + if ok, _, e := rules["bruteforce_multiple_logon_failure_followed_by_success"].Correlation[0].Execute(&successTrigger); e != nil || ok { + t.Fatalf("success rule counted failures of other accounts result=%v error=%v", ok, e) + } + // Reproduce the original regression with the actual SDK. An `or` sibling // cannot rescue this: Execute returns before it reaches Or on missing IP. before := requests @@ -611,6 +640,29 @@ func TestWindowsPrivateEvidence(t *testing.T) { t.Logf("private unique raw samples=%d projected IP-less=%d standard field mismatches in stored output=%v projected CEL candidates=%v", samples, ipless, observed, matches) } +// A rule relies on a filter marker when its history search requires one. +func winUsesCandidateMarker(r *plugins.Rule) bool { + for _, search := range r.Correlation { + for _, term := range search.With { + if strings.HasPrefix(term.Field, "log.authenticationCandidate.") { + return true + } + } + } + return false +} + +func winSearchesField(r *plugins.Rule, field string) bool { + for _, search := range r.Correlation { + for _, term := range search.With { + if term.Field == field { + return true + } + } + } + return false +} + func winCandidateField(ruleName string) string { parts := strings.Split(ruleName, "_") key := parts[0] diff --git a/rules/windows/adfs_authentication_anomalies.yml b/rules/windows/adfs_authentication_anomalies.yml index c57f002c2..3c8aac3a1 100644 --- a/rules/windows/adfs_authentication_anomalies.yml +++ b/rules/windows/adfs_authentication_anomalies.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - wineventlog @@ -26,10 +26,8 @@ description: | 7. Correlate with other authentication events across the domain where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && - ( + exists("log.authenticationSource") && equals("log.providerName", "AD FS") && (equals("log.eventCode", "342") || equals("log.eventCode", "516")) && contains("log.message", "token validation failed") - ) afterEvents: - indexPattern: v11-log-wineventlog-* with: @@ -39,12 +37,6 @@ afterEvents: - field: log.authenticationSource.keyword operator: filter_term value: '{{.log.authenticationSource}}' - - field: log.authenticationSourceType.keyword - operator: filter_term - value: '{{.log.authenticationSourceType}}' - - field: log.authenticationSourceDomain.keyword - operator: filter_term - value: '{{.log.authenticationSourceDomain}}' - field: log.authenticationCandidate.adfsAuthenticationAnomalies.keyword operator: filter_term value: match @@ -55,7 +47,5 @@ afterEvents: count: 10 groupBy: - dataSource - - lastEvent.log.authenticationSourceType - lastEvent.log.authenticationSource - - lastEvent.log.authenticationSourceDomain - target.user diff --git a/rules/windows/adminsdholder_abuse.yml b/rules/windows/adminsdholder_abuse.yml index ff8055d48..388c23be1 100644 --- a/rules/windows/adminsdholder_abuse.yml +++ b/rules/windows/adminsdholder_abuse.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.1.0 dataTypes: - wineventlog @@ -15,7 +15,7 @@ references: - https://adsecurity.org/?p=1906 - https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory description: | - Detects modifications to the AdminSDHolder object which can be used for persistence by granting elevated privileges. The SDProp process propagates these permissions to protected groups every 60 minutes, making this a critical security event. + Detects modifications to the AdminSDHolder object which can be used for persistence by granting elevated privileges. The SDProp process propagates these permissions to protected groups every 60 minutes, making this a critical security event. It reads directory service change events (5136), whose ObjectDN field names the changed object; access events (4662) name objects by GUID and cannot identify AdminSDHolder. Changes made by SYSTEM (S-1-5-18) are excluded. One alert is raised per domain controller and account; repeats are suppressed for seven days. Next Steps: 1. Immediately review the user account that performed the modification @@ -26,16 +26,10 @@ description: | 6. Audit recent administrative activities by the same user account 7. Consider temporarily disabling the user account if unauthorized activity is suspected where: | - oneOf("log.eventCode", ["4662", "5136", "4670"]) && + equals("log.eventCode", 5136) && equals("log.channel", "Security") && - ( - contains("log.eventDataObjectName", "CN=AdminSDHolder,CN=System") - ) && - ( - oneOf("log.eventDataOperationType", ["Object Access", "Write Property"]) || - oneOf("log.eventDataAccessMask", ["131072", "262144", "524288"]) - ) && - !equals("log.eventDataSubjectUserName", "SYSTEM") -groupBy: - - lastEvent.log.eventDataObjectName - - lastEvent.log.eventDataSubjectUserName + contains("log.data.ObjectDN", "CN=AdminSDHolder,CN=System") && + !equals("log.eventDataSubjectUserSid", "S-1-5-18") +deduplicateBy: + - dataSource + - lastEvent.log.eventDataSubjectUserSid diff --git a/rules/windows/asrep_roasting_detection.yml b/rules/windows/asrep_roasting_detection.yml index f998b3487..e951acdc1 100644 --- a/rules/windows/asrep_roasting_detection.yml +++ b/rules/windows/asrep_roasting_detection.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - wineventlog @@ -29,15 +29,13 @@ description: | 6. Monitor for subsequent credential usage from the requesting IP where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && - ( + exists("log.authenticationSource") && equals("log.eventCode", "4768") && equals("log.channel", "Security") && equals("log.eventDataTicketEncryptionType", "23") && equals("log.eventDataPreAuthType", "0") && !regexMatch("target.user", "(?i)\\$$") && exists("target.user") - ) afterEvents: - indexPattern: v11-log-wineventlog-* with: @@ -47,29 +45,12 @@ afterEvents: - field: log.authenticationSource.keyword operator: filter_term value: '{{.log.authenticationSource}}' - - field: log.authenticationSourceType.keyword - operator: filter_term - value: '{{.log.authenticationSourceType}}' - - field: log.authenticationSourceDomain.keyword - operator: filter_term - value: '{{.log.authenticationSourceDomain}}' - field: log.authenticationCandidate.asrepRoastingDetection.keyword operator: filter_term value: match - - field: log.eventCode - operator: filter_term - value: '{{.log.eventCode}}' - - field: log.eventDataTicketEncryptionType - operator: filter_term - value: '{{.log.eventDataTicketEncryptionType}}' - - field: log.eventDataPreAuthType - operator: filter_term - value: '{{.log.eventDataPreAuthType}}' within: 15m count: 3 groupBy: - dataSource - - lastEvent.log.authenticationSourceType - lastEvent.log.authenticationSource - - lastEvent.log.authenticationSourceDomain - target.user diff --git a/rules/windows/bruteforce_attack.yml b/rules/windows/bruteforce_attack.yml index 7e82bd3d9..2ec1e43da 100644 --- a/rules/windows/bruteforce_attack.yml +++ b/rules/windows/bruteforce_attack.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.3 +# Rule version v1.1.0 dataTypes: - wineventlog name: "Windows: Possible Brute Force Attack" @@ -9,45 +9,28 @@ impact: category: "Credential Access" technique: "T1110 - Brute Force" adversary: origin -description: "This rule is triggered when a pattern of repeated and rapid login attempts from the same IP address or source is detected. These login attempts may target specific user accounts or services in an attempt to crack passwords through automated brute force. The purpose of this rule is to identify possible malicious unauthorized access attempts and prevent a brute force attack against the system." +description: "This rule is triggered when a pattern of repeated and rapid login attempts from the same IP address or source is detected. These login attempts may target specific user accounts or services in an attempt to crack passwords through automated brute force. The purpose of this rule is to identify possible malicious unauthorized access attempts and prevent a brute force attack against the system. It counts failed logons (4625) on one computer from one source (the network address, else the workstation name, else the domain-qualified account), whichever accounts they target, so password spraying that tries each account only a few times is caught as well. Ten failures within five minutes raise one alert per computer and source; repeats are suppressed for seven days." references: - "https://attack.mitre.org/tactics/TA0006/" - "https://attack.mitre.org/techniques/T1110/" where: | + equals("log.eventCode", 4625) && !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && exists("target.user") && - ( - equals("log.eventCode", 4625) - ) + exists("log.authenticationSource") afterEvents: - indexPattern: v11-log-wineventlog-* with: + - field: log.eventCode + operator: filter_term + value: 4625 - field: dataSource.keyword operator: filter_term value: '{{.dataSource}}' - field: log.authenticationSource.keyword operator: filter_term value: '{{.log.authenticationSource}}' - - field: log.authenticationSourceType.keyword - operator: filter_term - value: '{{.log.authenticationSourceType}}' - - field: log.authenticationSourceDomain.keyword - operator: filter_term - value: '{{.log.authenticationSourceDomain}}' - - field: log.authenticationCandidate.bruteforceAttack.keyword - operator: filter_term - value: match - - field: log.eventCode - operator: filter_term - value: '{{.log.eventCode}}' - - field: target.user.keyword - operator: filter_term - value: '{{.target.user}}' within: 5m count: 10 deduplicateBy: - dataSource - - lastEvent.log.authenticationSourceType - lastEvent.log.authenticationSource - - lastEvent.log.authenticationSourceDomain - - target.user diff --git a/rules/windows/bruteforce_multiple_logon_failure_followed_by_success.yml b/rules/windows/bruteforce_multiple_logon_failure_followed_by_success.yml index e5a2ea5a4..d060f6890 100644 --- a/rules/windows/bruteforce_multiple_logon_failure_followed_by_success.yml +++ b/rules/windows/bruteforce_multiple_logon_failure_followed_by_success.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.3 +# Rule version v1.1.0 dataTypes: - wineventlog name: "Windows: Multiple Logon Failure Followed by Logon Success" @@ -9,37 +9,27 @@ impact: category: "Credential Access" technique: "T1110 - Brute Force" adversary: origin -description: "This rule is triggered when a sequence of multiple failed login attempts followed immediately by a successful login from the same IP address or source is detected. This unusual sequence of events may indicate a possible unauthorized access attempt using a brute force or password guessing technique. The purpose of this rule is to identify suspicious patterns of login activity and alert you to potential unauthorized access attempts." +description: "This rule is triggered when a sequence of multiple failed login attempts followed immediately by a successful login from the same IP address or source is detected. This unusual sequence of events may indicate a possible unauthorized access attempt using a brute force or password guessing technique. The purpose of this rule is to identify suspicious patterns of login activity and alert you to potential unauthorized access attempts. A successful logon (4624) alerts when the same computer recorded ten failed logons (4625) for the same account from the same source within the previous five minutes. Computer accounts (names ending in $) are skipped: their passwords are machine-generated and they make up almost half of all successful logons." references: - "https://attack.mitre.org/tactics/TA0006/" - "https://attack.mitre.org/techniques/T1110/" where: | + equals("log.eventCode", 4624) && !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && exists("target.user") && - ( - equals("log.eventCode", 4624) - ) + exists("log.authenticationSource") && + exists("target.user") && !endsWith("target.user", "$") afterEvents: - indexPattern: v11-log-wineventlog-* with: + - field: log.eventCode + operator: filter_term + value: 4625 - field: dataSource.keyword operator: filter_term value: '{{.dataSource}}' - field: log.authenticationSource.keyword operator: filter_term value: '{{.log.authenticationSource}}' - - field: log.authenticationSourceType.keyword - operator: filter_term - value: '{{.log.authenticationSourceType}}' - - field: log.authenticationSourceDomain.keyword - operator: filter_term - value: '{{.log.authenticationSourceDomain}}' - - field: log.authenticationCandidate.bruteforceAttack.keyword - operator: filter_term - value: match - - field: log.eventCode - operator: filter_term - value: 4625 - field: target.user.keyword operator: filter_term value: '{{.target.user}}' @@ -47,7 +37,5 @@ afterEvents: count: 10 deduplicateBy: - dataSource - - lastEvent.log.authenticationSourceType - lastEvent.log.authenticationSource - - lastEvent.log.authenticationSourceDomain - target.user diff --git a/rules/windows/certificate_services_abuse.yml b/rules/windows/certificate_services_abuse.yml index 317a15782..cae886709 100644 --- a/rules/windows/certificate_services_abuse.yml +++ b/rules/windows/certificate_services_abuse.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.1.0 dataTypes: - wineventlog @@ -14,7 +14,7 @@ references: - https://www.splunk.com/en_us/blog/security/breaking-the-chain-defending-against-certificate-services-abuse.html - https://attack.mitre.org/techniques/T1558/ description: | - Detects suspicious certificate requests and issuance that could indicate Golden Certificate attacks or unauthorized certificate generation for persistence. This rule monitors Windows Certificate Services events for potentially malicious certificate operations, particularly those involving machine accounts or anonymous logons that could be leveraged for persistence and privilege escalation. + Detects suspicious certificate requests and issuance that could indicate Golden Certificate attacks or unauthorized certificate generation for persistence. This rule monitors Windows Certificate Services events for potentially malicious certificate operations, particularly those involving machine accounts or anonymous logons that could be leveraged for persistence and privilege escalation. The requesting account is read from the Requester field of events 4886 and 4887. One alert is raised per computer and requester; repeats are suppressed for seven days. Next Steps: 1. Investigate the certificate request details including the requesting user/machine @@ -24,7 +24,10 @@ description: | 5. Examine the requesting host for signs of compromise 6. Consider revoking any suspicious certificates issued 7. Validate Certificate Authority security configurations and access controls -where: (equals("log.eventCode", "4886") || equals("log.eventCode", "4887")) && equals("log.providerName", "Microsoft-Windows-Security-Auditing") && (contains("log.eventDataSubjectUserName", "$") || equals("log.eventDataSubjectUserName", "ANONYMOUS LOGON")) -groupBy: - - lastEvent.log.eventDataSubjectUserName - - adversary.host +where: | + oneOf("log.eventCode", [4886, 4887]) && + equals("log.providerName", "Microsoft-Windows-Security-Auditing") && + (endsWith("log.data.Requester", "$") || contains("log.data.Requester", "ANONYMOUS LOGON")) +deduplicateBy: + - dataSource + - lastEvent.log.data.Requester diff --git a/rules/windows/golden_ticket_detection.yml b/rules/windows/golden_ticket_detection.yml index cfe85948b..e33871b1c 100644 --- a/rules/windows/golden_ticket_detection.yml +++ b/rules/windows/golden_ticket_detection.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - wineventlog @@ -31,14 +31,13 @@ description: | 8. Implement Kerberos armoring and constrained delegation where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && + exists("log.authenticationSource") && ( ( equals("log.eventCode", "4769") && equals("log.channel", "Security") && equals("log.eventDataServiceName", "krbtgt") && - !equals("log.eventDataStatus", "0") && - exists("log.authenticationSource") + !equals("log.eventDataStatus", "0") ) || ( equals("log.eventCode", "4768") && @@ -64,12 +63,6 @@ afterEvents: - field: log.authenticationSource.keyword operator: filter_term value: '{{.log.authenticationSource}}' - - field: log.authenticationSourceType.keyword - operator: filter_term - value: '{{.log.authenticationSourceType}}' - - field: log.authenticationSourceDomain.keyword - operator: filter_term - value: '{{.log.authenticationSourceDomain}}' - field: log.authenticationCandidate.goldenTicketDetection.keyword operator: filter_term value: match @@ -80,7 +73,5 @@ afterEvents: count: 3 groupBy: - dataSource - - lastEvent.log.authenticationSourceType - lastEvent.log.authenticationSource - - lastEvent.log.authenticationSourceDomain - target.user diff --git a/rules/windows/kerberoasting_detection.yml b/rules/windows/kerberoasting_detection.yml index 98ae74b87..3b5b80709 100644 --- a/rules/windows/kerberoasting_detection.yml +++ b/rules/windows/kerberoasting_detection.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - wineventlog @@ -32,16 +32,14 @@ description: | 8. Monitor for follow-up lateral movement using obtained credentials where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && - ( + exists("log.authenticationSource") && equals("log.eventCode", "4769") && equals("log.channel", "Security") && equals("log.eventDataTicketEncryptionType", "23") && !regexMatch("log.eventDataServiceName", "(?i)\\$$") && !equals("log.eventDataServiceName", "krbtgt") && - !oneOf("log.eventDataTicketOptions", ["1082195968", "1082130432", "1082130432"]) && + !oneOf("log.eventDataTicketOptions", ["1082195968", "1082130432"]) && exists("log.eventDataServiceName") - ) afterEvents: - indexPattern: v11-log-wineventlog-* with: @@ -51,26 +49,12 @@ afterEvents: - field: log.authenticationSource.keyword operator: filter_term value: '{{.log.authenticationSource}}' - - field: log.authenticationSourceType.keyword - operator: filter_term - value: '{{.log.authenticationSourceType}}' - - field: log.authenticationSourceDomain.keyword - operator: filter_term - value: '{{.log.authenticationSourceDomain}}' - field: log.authenticationCandidate.kerberoastingDetection.keyword operator: filter_term value: match - - field: log.eventCode - operator: filter_term - value: '{{.log.eventCode}}' - - field: log.eventDataTicketEncryptionType - operator: filter_term - value: '{{.log.eventDataTicketEncryptionType}}' within: 15m count: 3 groupBy: - dataSource - - lastEvent.log.authenticationSourceType - lastEvent.log.authenticationSource - - lastEvent.log.authenticationSourceDomain - target.user diff --git a/rules/windows/lsass_memdump_handle_access.yml b/rules/windows/lsass_memdump_handle_access.yml index e01d84ef6..5fbd35527 100644 --- a/rules/windows/lsass_memdump_handle_access.yml +++ b/rules/windows/lsass_memdump_handle_access.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.3 +# Rule version v1.1.0 dataTypes: - wineventlog name: "Windows: LSASS Memory Dump Handle Access" @@ -13,13 +13,17 @@ description: "Identifies handle requests for the Local Security Authority Subsys specific access masks that many tools with a capability to dump memory to disk use (0x1fffff, 0x1010, 0x120089). This rule is tool agnostic as it has been validated against a host of various LSASS dump tools such as SharpDump, Procdump, Mimikatz, Comsvcs etc. It detects this behavior at a low level and does not depend on a specific tool or dump - file name." + file name. Programs under Program Files, Microsoft Defender and the listed Windows components are excluded. One alert + is raised per computer and requesting program; repeats are suppressed for seven days." references: - "https://attack.mitre.org/tactics/TA0006/" - "https://attack.mitre.org/techniques/T1003/" - "https://attack.mitre.org/techniques/T1003/001/" -where: equals("log.eventCode", 4656) && regexMatch("log.eventDataObjectName", "(:\\Windows\\System32\\lsass.exe|\\Device\\HarddiskVolume[A-Za-z?:\\]([A-Za-z?])?\\Windows\\System32\\lsass.exe)") && !regexMatch("log.eventDataProcessName", "(:\\Program Files\\(.+).exe|:\\Program Files (x86)\\(.+).exe|:\\Windows\\system32\\wbem\\WmiPrvSE.exe|:\\Windows\\System32\\dllhost.exe|:\\Windows\\System32\\svchost.exe|:\\Windows\\System32\\msiexec.exe|:\\ProgramData\\Microsoft\\Windows Defender\\(.+).exe|:\\Windows\\explorer.exe)") && - oneOf("log.eventDataAccessMask", ["2097151", "4112", "1040", "1180185", "2031615"]) -groupBy: - - adversary.ip - - target.user +where: | + equals("log.eventCode", 4656) && + regexMatch("log.eventDataObjectName", "(?i)(^[a-z]:|harddiskvolume[0-9]+).windows.system32.lsass[.]exe$") && + oneOf("log.eventDataAccessMask", ["2097151", "4112", "1040", "1179785", "2031615"]) && + !regexMatch("log.eventDataProcessName", "(?i)^[a-z]:.(program files( [(]x86[)])?.|programdata.microsoft.windows defender.|windows.(system32.(wbem.wmiprvse|dllhost|svchost|msiexec)|explorer)[.]exe$)") +deduplicateBy: + - dataSource + - lastEvent.log.eventDataProcessName diff --git a/rules/windows/ntds_extraction_attempts.yml b/rules/windows/ntds_extraction_attempts.yml index 4b238aff0..f0f133749 100644 --- a/rules/windows/ntds_extraction_attempts.yml +++ b/rules/windows/ntds_extraction_attempts.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.1.0 dataTypes: - wineventlog @@ -28,17 +28,6 @@ description: | 9. Coordinate with incident response team for full forensic analysis where: | oneOf("log.eventCode", ["4663","4656"]) && (contains("log.eventDataObjectName", "ntds.dit") || endsWith("log.eventDataProcessName", "ntdsutil.exe")) && !equals("log.eventDataAccessMask", "0") -afterEvents: - - indexPattern: v11-log-wineventlog-* - with: - - field: log.eventCode - operator: filter_term - value: '4663' - - field: dataSource.keyword - operator: filter_term - value: '{{.dataSource}}' - within: 30m - count: 2 groupBy: - dataSource deduplicateBy: [] diff --git a/rules/windows/possible_exploit_over_reverse_tunneling_using_stolen_credentials.yml b/rules/windows/possible_exploit_over_reverse_tunneling_using_stolen_credentials.yml index b28ce6ac1..d57945c1c 100644 --- a/rules/windows/possible_exploit_over_reverse_tunneling_using_stolen_credentials.yml +++ b/rules/windows/possible_exploit_over_reverse_tunneling_using_stolen_credentials.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.2 +# Rule version v1.0.3 dataTypes: - wineventlog name: "Windows: User logged using Remote Desktop Connection from loopback address, possible exploit over reverse tunneling using stolen credentials" @@ -12,7 +12,7 @@ adversary: origin description: "Adversaries may use Valid Accounts to log into a computer using the Remote Desktop Protocol (RDP). The adversary may then perform actions as the logged-on user." references: - "https://attack.mitre.org/techniques/T1021/001/" -where: equals("log.eventDataLogonType", "10") && oneOf("origin.ip", ["::1", "127.0.0.1"]) && oneOf("log.eventCode", [528, 540, 673, 4624, 4769]) +where: equals("log.eventCode", 4624) && equals("log.eventDataLogonType", "10") && oneOf("origin.ip", ["::1", "127.0.0.1"]) groupBy: - adversary.ip - target.user diff --git a/rules/windows/printspooler_service_suspicious_file.yml b/rules/windows/printspooler_service_suspicious_file.yml index 5022bc7c2..032eba397 100644 --- a/rules/windows/printspooler_service_suspicious_file.yml +++ b/rules/windows/printspooler_service_suspicious_file.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.3 +# Rule version v1.0.4 dataTypes: - "wineventlog" @@ -17,7 +17,7 @@ references: - "https://attack.mitre.org/tactics/TA0004/" - "https://attack.mitre.org/techniques/T1068/" where: | - (equals("log.eventCode",4688) || equals("log.eventCode",1)) && contains("log.data.NewProcessName", "spoolsv.exe") && !regexMatch("log.data.NewProcessName", "[Ss]ystem32.spoolsv[.]exe$") + equals("log.eventCode",4688) && contains("log.data.NewProcessName", "spoolsv.exe") && !regexMatch("log.data.NewProcessName", "[Ss]ystem32.spoolsv[.]exe$") groupBy: - dataSource deduplicateBy: [] diff --git a/rules/windows/ransom_multiple_file_deletion.yml b/rules/windows/ransom_multiple_file_deletion.yml index 96131cb11..bd39ab86b 100644 --- a/rules/windows/ransom_multiple_file_deletion.yml +++ b/rules/windows/ransom_multiple_file_deletion.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.3 +# Rule version v1.1.0 dataTypes: - "wineventlog" @@ -13,11 +13,13 @@ adversary: origin description: "Detects potential ransomware activity by monitoring multiple file write/modification events (Event ID 4663) with write access masks in user directories within a short timeframe. Modern ransomware typically encrypts files in-place rather than deleting them, making write access monitoring more effective - than deletion monitoring alone." + than deletion monitoring alone. Fifty accesses with the same write access mask by one account on one computer + within five minutes raise one alert per computer and account; repeats are suppressed for seven days." references: - "https://attack.mitre.org/tactics/TA0040/" where: | - equals("log.eventCode", 4663) && + equals("log.eventCode", 4663) && + exists("origin.user") && oneOf("log.eventDataAccessMask", ["2", "4", "6"]) && !(regexMatch("log.eventDataProcessName", "(?i).*(trustedinstaller|svchost|wuauclt|msiexec|windows10upgrade|setuphost|tiworker|dism).*")) && regexMatch("log.eventDataObjectName", "(?i).*\\\\(users|documents|desktop|downloads|pictures|videos|music)\\\\.*") && @@ -30,11 +32,17 @@ afterEvents: - field: log.eventCode operator: filter_term value: "4663" - - field: target.user.keyword + - field: dataSource.keyword operator: filter_term - value: "{{.target.user}}" + value: "{{.dataSource}}" + - field: origin.user.keyword + operator: filter_term + value: "{{.origin.user}}" + - field: log.eventDataAccessMask + operator: filter_term + value: "{{.log.eventDataAccessMask}}" within: 5m count: 50 -groupBy: - - adversary.ip - - target.user +deduplicateBy: + - dataSource + - adversary.user diff --git a/rules/windows/sam_database_access.yml b/rules/windows/sam_database_access.yml index 7d55c4948..6a2ea1761 100644 --- a/rules/windows/sam_database_access.yml +++ b/rules/windows/sam_database_access.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.1.0 dataTypes: - wineventlog @@ -14,7 +14,7 @@ references: - https://attack.mitre.org/techniques/T1003/002/ - https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4661 description: | - Detects attempts to access the Security Account Manager (SAM) database, which contains local user account hashes. This activity may indicate credential dumping attempts by attackers trying to extract password hashes for offline cracking or lateral movement. + Detects attempts to access the Security Account Manager (SAM) database, which contains local user account hashes. This activity may indicate credential dumping attempts by attackers trying to extract password hashes for offline cracking or lateral movement. One alert is raised per computer and account; repeats are suppressed for seven days. Next Steps: 1. Immediately investigate the user account and process that accessed the SAM database @@ -33,6 +33,6 @@ where: | endsWith("log.eventDataObjectName", "\\SYSTEM") ) && oneOf("log.eventDataAccessMask", ["131097", "2032127", "64", "32", "1"]) -groupBy: - - adversary.host - - target.user +deduplicateBy: + - dataSource + - adversary.user diff --git a/rules/windows/silver_ticket_detection.yml b/rules/windows/silver_ticket_detection.yml index 9db0d04ad..746b82622 100644 --- a/rules/windows/silver_ticket_detection.yml +++ b/rules/windows/silver_ticket_detection.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - wineventlog @@ -31,17 +31,12 @@ description: | 8. Enable Kerberos PAC validation on the targeted services where: | !oneOf("dataSource", ["", "unknown"]) && - exists("log.authenticationSource") && exists("log.authenticationSourceType") && exists("log.authenticationSourceDomain") && - ( + exists("log.authenticationSource") && equals("log.eventCode", "4769") && equals("log.channel", "Security") && - ( - equals("log.eventDataTicketEncryptionType", "23") && - !regexMatch("log.eventDataServiceName", "(?i)(krbtgt|\\$$)") && - !oneOf("log.eventDataStatus", ["0", "6"]) && - exists("log.authenticationSource") - ) - ) + equals("log.eventDataTicketEncryptionType", "23") && + !regexMatch("log.eventDataServiceName", "(?i)(krbtgt|\\$$)") && + !oneOf("log.eventDataStatus", ["0", "6"]) afterEvents: - indexPattern: v11-log-wineventlog-* with: @@ -51,26 +46,12 @@ afterEvents: - field: log.authenticationSource.keyword operator: filter_term value: '{{.log.authenticationSource}}' - - field: log.authenticationSourceType.keyword - operator: filter_term - value: '{{.log.authenticationSourceType}}' - - field: log.authenticationSourceDomain.keyword - operator: filter_term - value: '{{.log.authenticationSourceDomain}}' - field: log.authenticationCandidate.silverTicketDetection.keyword operator: filter_term value: match - - field: log.eventCode - operator: filter_term - value: '{{.log.eventCode}}' - - field: log.eventDataTicketEncryptionType - operator: filter_term - value: '{{.log.eventDataTicketEncryptionType}}' within: 15m count: 5 groupBy: - dataSource - - lastEvent.log.authenticationSourceType - lastEvent.log.authenticationSource - - lastEvent.log.authenticationSourceDomain - target.user diff --git a/rules/windows/smbv1_usage_detection.yml b/rules/windows/smbv1_usage_detection.yml index ebb4547ca..6f6090511 100644 --- a/rules/windows/smbv1_usage_detection.yml +++ b/rules/windows/smbv1_usage_detection.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.1.0 dataTypes: - wineventlog @@ -14,7 +14,7 @@ references: - https://learn.microsoft.com/en-us/windows-server/storage/file-server/troubleshoot/detect-enable-and-disable-smbv1-v2-v3 - https://attack.mitre.org/techniques/T1210/ description: | - Detects usage of the deprecated and vulnerable SMBv1 protocol which could be exploited for lateral movement or ransomware propagation. SMBv1 is susceptible to numerous security vulnerabilities including EternalBlue and should be disabled in favor of SMBv2/SMBv3. + Detects usage of the deprecated and vulnerable SMBv1 protocol which could be exploited for lateral movement or ransomware propagation. SMBv1 is susceptible to numerous security vulnerabilities including EternalBlue and should be disabled in favor of SMBv2/SMBv3. Once SMBv1 access auditing is enabled (Set-SmbServerConfiguration -AuditSmb1Access $true), Windows writes event 3000 to the Microsoft-Windows-SMBServer/Audit log each time a client uses SMBv1, so the event itself is the signal. One alert is raised per server; repeats are suppressed for seven days. Next Steps: 1. Immediately investigate the source system using SMBv1 and identify which service or application is still dependent on this protocol @@ -24,7 +24,6 @@ description: | 5. Plan migration to SMBv2/SMBv3 and disable SMBv1 on all systems where possible 6. Monitor for any lateral movement patterns that may indicate ongoing compromise 7. Consider implementing network segmentation to limit exposure if SMBv1 cannot be immediately disabled -where: equals("log.eventCode", "3000") && equals("log.providerName", "Microsoft-Windows-SMBServer") && contains("log.message", "SMB1") -groupBy: - - adversary.host - - adversary.ip +where: equals("log.eventCode", 3000) && equals("log.providerName", "Microsoft-Windows-SMBServer") +deduplicateBy: + - dataSource diff --git a/rules/windows/unusual_process_network_connection.yml b/rules/windows/unusual_process_network_connection.yml index 86059cd5a..8662c4a67 100644 --- a/rules/windows/unusual_process_network_connection.yml +++ b/rules/windows/unusual_process_network_connection.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.3 +# Rule version v1.0.4 dataTypes: - "wineventlog" @@ -16,7 +16,7 @@ references: description: "Identifies network activity from unexpected system applications. This may indicate adversarial activity as these applications are often leveraged by adversaries to execute code and evade detection." where: | - (equals("log.eventCode",4688) || equals("log.eventCode",1)) && regexMatch("log.data.NewProcessName", "(Microsoft.Workflow.Compiler.exe|bginfo.exe|cdb.exe|cmstp.exe|csi.exe|dnx.exe|fsi.exe|ieexec.exe|iexpress.exe|odbcconf.exe|rcsi.exe|xwizard.exe)") + equals("log.eventCode",4688) && regexMatch("log.data.NewProcessName", "(Microsoft.Workflow.Compiler.exe|bginfo.exe|cdb.exe|cmstp.exe|csi.exe|dnx.exe|fsi.exe|ieexec.exe|iexpress.exe|odbcconf.exe|rcsi.exe|xwizard.exe)") groupBy: - dataSource deduplicateBy: [] diff --git a/rules/windows/windows_remote_management_abuse.yml b/rules/windows/windows_remote_management_abuse.yml index 6cc34a15d..a44649e60 100644 --- a/rules/windows/windows_remote_management_abuse.yml +++ b/rules/windows/windows_remote_management_abuse.yml @@ -1,4 +1,4 @@ -# Rule version v1.0.0 +# Rule version v1.0.1 dataTypes: - wineventlog @@ -14,7 +14,7 @@ references: - https://jpcertcc.github.io/ToolAnalysisResultSheet/details/WinRM.htm - https://attack.mitre.org/techniques/T1021/006/ description: | - Detects potential abuse of Windows Remote Management (WinRM) for lateral movement. Monitors for successful logon events (4624) with network logon type 3 combined with privilege escalation (4672) and WinRM-related process activity, indicating remote command execution via WinRM. + Detects potential abuse of Windows Remote Management (WinRM) for lateral movement: a shell or a discovery or administration tool started (4688) by the WinRM host processes (wsmprovhost.exe or winrshost.exe), indicating remote command execution via WinRM. Next Steps: 1. Investigate the source IP address and verify if it's an authorized administrative workstation @@ -26,7 +26,7 @@ description: | 7. Validate the legitimacy of any processes spawned through the WinRM session 8. Consider implementing additional monitoring for WinRM usage if this represents unexpected activity where: | - (equals("log.eventCode",4688) || equals("log.eventCode",1)) && regexMatch("log.data.ParentProcessName","(?i)(wsmprovhost|winrshost)[.]exe$") && regexMatch("log.data.NewProcessName","(?i)(cmd|powershell|pwsh|net1?|whoami|systeminfo|reg|sc|schtasks|wmic|bitsadmin|certutil|nltest|quser|tasklist|netstat|ipconfig|arp|route|psexec)[.]exe$") + equals("log.eventCode",4688) && regexMatch("log.data.ParentProcessName","(?i)(wsmprovhost|winrshost)[.]exe$") && regexMatch("log.data.NewProcessName","(?i)(cmd|powershell|pwsh|net1?|whoami|systeminfo|reg|sc|schtasks|wmic|bitsadmin|certutil|nltest|quser|tasklist|netstat|ipconfig|arp|route|psexec)[.]exe$") groupBy: - dataSource deduplicateBy: []