diff --git a/filters/audits/sophos.md b/filters/audits/sophos.md new file mode 100644 index 000000000..004d83b66 --- /dev/null +++ b/filters/audits/sophos.md @@ -0,0 +1,112 @@ +# Sophos filter and rule contract review + +Replacement review for #2617, covering Sophos XG Firewall and Sophos Central together. +The SDK version pinned by v11 (`github.com/threatwinds/go-sdk` v1.1.31), its protobuf schema, +and its official wiki define the standard. Vendor documentation defines source semantics. +This draft proposes code changes; it does not deploy them or establish production alert rates. + +## XG Firewall + +- Parse type, component and subtype independently. WAF records can omit subtype without + losing their client/backend addresses, HTTP status or remaining fields. +- Recover consumed values at quote-aware key boundaries. Support plain, PRI, RFC3164 and + RFC5424 envelopes. Preserve vendor aliases and the complete raw message. +- Validate original addresses before standard-field promotion and enrichment, excluding + unspecified IPv4/IPv6 addresses. Keep NAT fields separate. Preserve documented local/remote + SSL VPN roles rather than inferring an unreported public peer. +- Map WAF client/backend addresses, HTTP status, host and source-relative counters; users, + groups, heartbeat endpoints, mail attributes, file information and explicit device time. + Guard numeric types/ranges before strict Event decoding. Preserve textual protocol case. +- Explicit rejection, drop and failed authentication take precedence over allowed statuses + and HTTP success responses. Detect/Alert alone do not prove success. Only an explicit + established connection state sets `connectionStatus=established`. +- Align IDP and ATP predicates with documented components, priorities and outcomes. Exclude + routine updates, successful authentication and IKE parser errors from attack histories. + Match IP Spoof without an incidental case mismatch. +- Scope four histories to collector, firewall identity and source address; IPS also retains + destination. Count only relevant recomputed candidates. Thresholds stay 2/30m, 3/15m, + 10/15m and 10/15m. Device ID/serial takes precedence over the ingress-peer fallback. +- Keep existing impact ratings. Generic critical events do not establish exploitation. + Message 17925 remains a literal notification because the available guide does not explain + its body. Message 17913 alone no longer proves an administrator login failure; the reviewed + authentication contract requires failed sign-in and message 17507. Review legacy coverage + before rollout rather than assuming every firmware version has the same event meanings. + +## Central + +The integration collector consumes `/siem/v1/events` JSON, not Firewall syslog or a separate +MDR/alerts API. Sanitized key spelling and existing camel-case aliases are preserved. + +- Associate validated IP, location and user with the managed computer/server as `target.*`. + Endpoint identity remains usable without an IP. For explicit CryptoGuard `SMBOrigin`, the + endpoint is the remote-encryption initiator and maps to `origin.*`; do not invent a peer. +- Vendor `origin` names the detection engine; `group` classifies the event. Neither names + an attacker or security group. Keep these fields as vendor context. Sophos customer ID + scopes source histories without overwriting the SIEM tenant metadata. +- Retain vendor fields while adding event type as `action`, explicit `when` as `deviceTime`, + and low/info, medium/warning, high/error, critical/critical severity mappings. Validate + artifact hashes. Promote malware labels only for the malware category, not PUA/blocklist + policy labels. +- Promote a single remedy file to path and basename only when both array length and total + count equal one. Preserve collections and archive-member locators as vendor context; + choosing the first item of a multi-file event would falsely attribute the other items. +- Normalize explicit blocked/prevented events to `denied` and exact authentication failures + to `failure`. Detection, cleanup/update success and VPN status do not establish successful + network connections. Unknown outcome variants remain unknown. +- Successful cleanup and dismissed/resolved notifications do not create fresh malware alerts. + Unsuccessful cleanup remains covered. Peripheral blocking is not device compromise. + Cover behavioral detections, PUA events and account-level tamper-protection Raise warnings, + while excluding Resolve. Add a device-health rule for high/critical endpoint protection + unavailability without claiming an attack. +- Preserve all five history thresholds: behavioral 3/30m, exploit 2/30m, MTR 3/1h, ZTNA 10/5m + and 10/1m. Require collector, account and endpoint ID or validated vendor IP. Count relevant + derived candidates rather than arbitrary endpoint events. MTR keeps critical-only history. + Input-supplied scope and candidate markers are cleared before recomputation. +- The one-minute ZTNA rule counts failed attempts, not distinct users. Rename it rapid + authentication failures without changing its threshold. Both ZTNA rules can overlap. +- Managed endpoints remain alert targets, including the credential rule. Group by available + collector/account/endpoint context. Keep ZTNA's IP in vendor context until its endpoint role + is established. All existing impact ratings remain unchanged; the new health rule is 1/2/2. + Generic behavioral/PUA/malware notices do not assert an unsupported specific ATT&CK technique. + +## Tests and deployment limits + +Committed tests use **159 fabricated raw fixtures** (73 XG, 86 Central), positive/negative +assertions for all **29 rules**, strict final Event decoding, Alert-side checks and **nine SDK +history-query tests** with loopback mocks. History tests exercise threshold boundaries, +expiration, wrong/missing identities, unmarked records, unrelated events and MTR severity. +Fixtures contain example identities and documentation address ranges. + +Extraction uses a declared offline model of YAML steps, observed JSON key behavior and the +versioned SDK CEL evaluator. It is **not the closed EventProcessor**. Geolocation and production +alert creation are not executed. No production false-positive-rate reduction is claimed. + +Shared alerts draft #2627 supplies the indexed `lastEvent.*` grouping implementation. Its +rollout is separate. New candidate histories require up to one hour of warm-up; historical +unmarked events do not count. Reconcile renamed rules with installed definitions and review +outcome/severity searches before rollout. Vendor fields remain available; historical SQL +seeds and customer-specific saved searches are not rewritten by these changes. + +Unexercised legacy XG appliance/antivirus variants and Central ZTNA/MTR/mobile/remote-CryptoGuard +variants remain explicit coverage gaps. In particular, broad XG antivirus adversary direction +is not declared verified. The legacy MTR predicate assumes a schema not proven to arrive via +the SIEM collector. Do not infer operational coverage from synthetic predicate tests alone. +Staging must verify closed-executor behavior, XG parsing cost and the complete rollout. + +## Sources + +- [SDK v1.1.31 schema](https://github.com/threatwinds/go-sdk/blob/v1.1.31/plugins/plugins.proto) +- [Standard event schema](https://github.com/threatwinds/go-sdk/wiki/Standard-Event-Schema) +- [Filter lifecycle](https://github.com/threatwinds/go-sdk/wiki/Implementing-Filters) +- [Rule implementation](https://github.com/threatwinds/go-sdk/wiki/Implementing-Rules) +- [SFOS 20.0 syslog guide](https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html) +- [Central events](https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/) +- [Malware, PUA and runtime events](https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/) +- [Behavioral detections](https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/MaliciousBehaviorTypes/) +- [Peripheral/network events](https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/NetworkAccessEventTypes/) +- [Management/protection events](https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/ManagementEventTypes/) +- [Firewall ATP/status alerts](https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/Alerts/FirewallAlerts/) +- [Account tamper-protection warnings](https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/AccountHealthCheck/FixEndpointTamperProtect/) + +The older PDF syslog URL redirects to HTML. Off-allowlist API documentation was not fetched; +these sources do not establish a complete versioned enum contract for unobserved variants. diff --git a/filters/sophos/sophos_central.yml b/filters/sophos/sophos_central.yml index d915b2fc5..d79013c5a 100755 --- a/filters/sophos/sophos_central.yml +++ b/filters/sophos/sophos_central.yml @@ -1,87 +1,264 @@ -# Sophos_Central filter using "SF syslog file guide 20.0", version 1.0.0 - -# See: https://docs.sophos.com/nsg/sophos-firewall/20.0/pdf/sf-syslog-guide-20.0.pdf -# and https://docs.sophos.com/nsg/sophos-firewall/20.0/Help/en-us/webhelp/onlinehelp/AdministratorHelp/Logs/TroubleshootingLogs/LogFileDetails/index.html#https-ftp-waf - +# Sophos Central SIEM /siem/v1/events JSON, not Firewall syslog or the separate alerts API. +# https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/ +# Native aliases remain compatible. Managed endpoint context is not remote-attacker identity. +# Remedy paths require exactly one file and exclude archive-member locators. pipeline: - - dataTypes: - - sophos-central - steps: - - json: - source: raw - - - rename: - from: - - log.coreremedyitems - to: log.coreremedyItems - - - rename: - from: - - log.createdat - to: log.createdAt - - - rename: - from: - - log.customerid - to: log.customerId - - - rename: - from: - - log.endpointid - to: log.endpointId - - - rename: - from: - - log.endpointtype - to: log.endpointType - - - rename: - from: - - log.sourceinfo.ip - to: log.ip - - - rename: - from: - - log.userid - to: log.userId - - - rename: - from: - - log.sourceinfo - to: log.sourceInfo - - # Adding action result - - add: - function: string - params: - key: actionResult - value: "blocked" - where: 'exists("log.action") && equals("log.action", "blocked")' +- dataTypes: + - sophos-central + steps: + - json: + source: raw + - rename: + from: + - log.coreremedyitems + to: log.coreremedyItems + - rename: + from: + - log.createdat + to: log.createdAt + - rename: + from: + - log.customerid + to: log.customerId + - rename: + from: + - log.endpointid + to: log.endpointId + - rename: + from: + - log.endpointtype + to: log.endpointType + - rename: + from: + - log.sourceinfo.ip + to: log.ip + - rename: + from: + - log.userid + to: log.userId + - rename: + from: + - log.sourceinfo + to: log.sourceInfo + - delete: + fields: + - log.sophosCentralScope + - log.correlationCandidate + - grok: + source: log.customerId + patterns: + - fieldName: log.sophosCentralScope + pattern: (?s)^.+$ + where: (regexMatch("log.customerId","[^[:space:]]") && !oneOf("log.customerId",["-","n/a","N/A","unknown"])) + && (true) + - grok: + source: dataSource + patterns: + - fieldName: log.sophosCentralScope + pattern: (?s)^.+$ + where: (regexMatch("dataSource","[^[:space:]]") && !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (!exists("log.sophosCentralScope")) + - grok: + source: log.ip + patterns: + - fieldName: target.ip + pattern: (?s)^.+$ + where: (regexMatch("log.ip","[^[:space:]]") && !oneOf("log.ip",["-","n/a","N/A","unknown"])) && ((regexMatch("log.endpointId","[^[:space:]]") + && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && oneOf("log.endpointType",["computer","server"]) + && !(equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin")) && ((inCIDR("log.ip","0.0.0.0/0") || + inCIDR("log.ip","::/0")) && !inCIDR("log.ip","0.0.0.0/32") && !inCIDR("log.ip","::/128"))) + - grok: + source: log.location + patterns: + - fieldName: target.host + pattern: (?s)^.+$ + where: (regexMatch("log.location","[^[:space:]]") && !oneOf("log.location",["-","n/a","N/A","unknown"])) && + ((regexMatch("log.endpointId","[^[:space:]]") && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && + oneOf("log.endpointType",["computer","server"]) && !(equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin"))) + - grok: + source: log.source + patterns: + - fieldName: target.user + pattern: (?s)^.+$ + where: (regexMatch("log.source","[^[:space:]]") && !oneOf("log.source",["-","n/a","N/A","unknown"])) && ((regexMatch("log.endpointId","[^[:space:]]") + && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && oneOf("log.endpointType",["computer","server"]) + && !(equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin"))) + - grok: + source: log.appSha256 + patterns: + - fieldName: target.sha256 + pattern: (?s)^.+$ + where: (regexMatch("log.appSha256","[^[:space:]]") && !oneOf("log.appSha256",["-","n/a","N/A","unknown"])) + && ((regexMatch("log.endpointId","[^[:space:]]") && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) + && oneOf("log.endpointType",["computer","server"]) && !(equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin")) + && regexMatch("log.appSha256","^[a-fA-F0-9]{64}$")) + - grok: + source: log.threat + patterns: + - fieldName: target.malware + pattern: (?s)^.+$ + where: (regexMatch("log.threat","[^[:space:]]") && !oneOf("log.threat",["-","n/a","N/A","unknown"])) && ((regexMatch("log.endpointId","[^[:space:]]") + && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && oneOf("log.endpointType",["computer","server"]) + && !(equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin")) && equals("log.group","MALWARE")) + - grok: + source: log.ip + patterns: + - fieldName: origin.ip + pattern: (?s)^.+$ + where: (regexMatch("log.ip","[^[:space:]]") && !oneOf("log.ip",["-","n/a","N/A","unknown"])) && ((regexMatch("log.endpointId","[^[:space:]]") + && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && oneOf("log.endpointType",["computer","server"]) + && equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin") && ((inCIDR("log.ip","0.0.0.0/0") || inCIDR("log.ip","::/0")) + && !inCIDR("log.ip","0.0.0.0/32") && !inCIDR("log.ip","::/128"))) + - grok: + source: log.location + patterns: + - fieldName: origin.host + pattern: (?s)^.+$ + where: (regexMatch("log.location","[^[:space:]]") && !oneOf("log.location",["-","n/a","N/A","unknown"])) && + ((regexMatch("log.endpointId","[^[:space:]]") && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && + oneOf("log.endpointType",["computer","server"]) && equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin")) + - grok: + source: log.source + patterns: + - fieldName: origin.user + pattern: (?s)^.+$ + where: (regexMatch("log.source","[^[:space:]]") && !oneOf("log.source",["-","n/a","N/A","unknown"])) && ((regexMatch("log.endpointId","[^[:space:]]") + && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && oneOf("log.endpointType",["computer","server"]) + && equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin")) + - grok: + source: log.appSha256 + patterns: + - fieldName: origin.sha256 + pattern: (?s)^.+$ + where: (regexMatch("log.appSha256","[^[:space:]]") && !oneOf("log.appSha256",["-","n/a","N/A","unknown"])) + && ((regexMatch("log.endpointId","[^[:space:]]") && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) + && oneOf("log.endpointType",["computer","server"]) && equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin") + && regexMatch("log.appSha256","^[a-fA-F0-9]{64}$")) + - grok: + source: log.threat + patterns: + - fieldName: origin.malware + pattern: (?s)^.+$ + where: (regexMatch("log.threat","[^[:space:]]") && !oneOf("log.threat",["-","n/a","N/A","unknown"])) && ((regexMatch("log.endpointId","[^[:space:]]") + && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && oneOf("log.endpointType",["computer","server"]) + && equals("log.type","Event::Endpoint::HmpaCryptoGuardSMBOrigin") && equals("log.group","MALWARE")) + - grok: + source: log.type + patterns: + - fieldName: action + pattern: (?s)^.+$ + where: (regexMatch("log.type","[^[:space:]]") && !oneOf("log.type",["-","n/a","N/A","unknown"])) && (true) + - grok: + source: log.when + patterns: + - fieldName: deviceTime + pattern: (?s)^.+$ + where: (regexMatch("log.when","[^[:space:]]") && !oneOf("log.when",["-","n/a","N/A","unknown"])) && (regexMatch("log.when","^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}([.][0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$")) + - add: + function: string + params: + key: severity + value: info + where: oneOf("log.severity",["low"]) + - add: + function: string + params: + key: severity + value: warning + where: oneOf("log.severity",["medium"]) + - add: + function: string + params: + key: severity + value: error + where: oneOf("log.severity",["high"]) + - add: + function: string + params: + key: severity + value: critical + where: oneOf("log.severity",["critical"]) + - add: + function: string + params: + key: actionResult + value: denied + where: equalsIgnoreCase("log.action","blocked") || oneOf("log.type",["Event::Endpoint::Device::Blocked", "Event::Endpoint::Application::Blocked", + "Event::Endpoint::WebFilteringBlocked", "Event::Endpoint::HmpaExploitPrevented", "Event::Endpoint::HmpaBehaviourPrevented", + "Event::Endpoint::HmpaApplicationHijacking", "Event::Endpoint::HmpaPrivGuard", "Event::Endpoint::Threat::ExploitPrevented", + "Event::Endpoint::Exploit::Prevented"]) + - add: + function: string + params: + key: actionResult + value: failure + where: '!exists("actionResult") && oneOf("log.type",["Event::ZTNA::ZTNAAuthenticationFailure","Event::Endpoint::AuthenticationFailure"])' + - grok: + source: log.coreremedyItems.items.0.descriptor + patterns: + - fieldName: target.path + pattern: ^(?:[A-Za-z]:[\\/]|/|\\\\)[^<>:"|?*\r\n]*[\\/] + - fieldName: target.file + pattern: '[^\\/<>:"|?*\r\n]+$' + where: equals("log.coreremedyItems.totalItems",1) && equals("log.coreremedyItems.items.#",1) && equals("log.coreremedyItems.items.0.type","file") + && !regexMatch("log.coreremedyItems.items.0.descriptor","(?i)[.](zip|cab|7z|rar|tar|gz|iso)[/\\\\]") + - dynamic: + plugin: com.utmstack.geolocation + params: + source: origin.ip + destination: origin.geolocation + where: exists("origin.ip") + - dynamic: + plugin: com.utmstack.geolocation + params: + source: target.ip + destination: target.geolocation + where: exists("target.ip") + - add: + function: string + params: + key: log.correlationCandidate.sophosCentral.behavior + value: match + where: '((oneOf("log.type", ["Event::Endpoint::Threat::BehavioralDetection", "Event::Endpoint::BehaviorDetected"]) + || - - add: - function: string - params: - key: actionResult - value: "blocked" - where: 'exists("log.type") && contains("log.type", "Prevented") && !exists("actionResult")' + (oneOf("log.detectionMethod", ["Behavioral", "HIPS"]) && oneOf("log.severity", ["medium", "high", "critical"])) + || - - add: - function: string - params: - key: actionResult - value: "blocked" - where: 'exists("log.type") && oneOf("log.type", ["Event::Endpoint::HmpaApplicationHijacking", "Event::Endpoint::HmpaPrivGuard"]) && !exists("actionResult")' + (contains("log.name", "Behavioral") && oneOf("log.severity", ["high", "critical"]))) || equals("log.type","Event::Endpoint::CoreBehavioralDetection")) + && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") && (regexMatch("log.endpointId","[^[:space:]]") + && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && (regexMatch("dataSource","[^[:space:]]") && + !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (regexMatch("log.sophosCentralScope","[^[:space:]]") + && !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"]))' + - add: + function: string + params: + key: log.correlationCandidate.sophosCentral.exploit + value: match + where: '(oneOf("log.type", ["Event::Endpoint::Threat::ExploitPrevented", "Event::Endpoint::Exploit::Prevented"]) + || - - add: - function: string - params: - key: actionResult - value: "blocked" - where: 'exists("log.type") && contains("log.type", "HmpaCred") && !exists("actionResult")' + (equals("log.name", "Exploit prevented") && oneOf("log.severity", ["high", "critical"]))) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") + && (regexMatch("log.endpointId","[^[:space:]]") && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) + && (regexMatch("dataSource","[^[:space:]]") && !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (regexMatch("log.sophosCentralScope","[^[:space:]]") + && !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"]))' + - add: + function: string + params: + key: log.correlationCandidate.sophosCentral.mtr + value: match + where: '(oneOf("log.type", ["mtr_alert", "threat_detection"]) && - - add: - function: string - params: - key: actionResult - value: "failed" - where: 'exists("log.type") && contains("log.type", "AuthenticationFailure") && !exists("actionResult")' \ No newline at end of file + oneOf("log.severity", ["critical", "high"])) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") + && (regexMatch("log.endpointId","[^[:space:]]") && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) + && (regexMatch("dataSource","[^[:space:]]") && !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (regexMatch("log.sophosCentralScope","[^[:space:]]") + && !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"])) && equals("log.severity","critical")' + - add: + function: string + params: + key: log.correlationCandidate.sophosCentral.ztnaFailure + value: match + where: (equals("log.type", "Event::ZTNA::ZTNAAuthenticationFailure")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") + && (regexMatch("log.ip","[^[:space:]]") && !oneOf("log.ip",["-","n/a","N/A","unknown"])) && (regexMatch("dataSource","[^[:space:]]") + && !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (regexMatch("log.sophosCentralScope","[^[:space:]]") + && !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"])) && ((inCIDR("log.ip","0.0.0.0/0") || inCIDR("log.ip","::/0")) + && !inCIDR("log.ip","0.0.0.0/32") && !inCIDR("log.ip","::/128")) diff --git a/filters/sophos/sophos_xg_firewall.yml b/filters/sophos/sophos_xg_firewall.yml index fbd6d1ff1..99fcc6898 100644 --- a/filters/sophos/sophos_xg_firewall.yml +++ b/filters/sophos/sophos_xg_firewall.yml @@ -1,759 +1,2413 @@ -# Sophos_XG filter, version 3.0.6 -# Supports SF 20.0 version log types -# See manual: https://docs.sophos.com/nsg/sophos-firewall/20.0/pdf/sf-syslog-guide-20.0.pdf -# and documentation https://docs.sophos.com/nsg/sophos-firewall/20.0/Help/en-us/webhelp/onlinehelp/AdministratorHelp/Logs/TroubleshootingLogs/LogFileDetails/index.html#https-ftp-waf - +# Sophos Firewall legacy and Central Reporting formats. +# https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +# Recover quoted fields independently: a missing subtype must not hide WAF. +# Validate original endpoints before enrichment; explicit rejection wins over Allow/HTTP 200. +# History markers are cleared and rebuilt from their rules’ predicates. pipeline: - - dataTypes: - - firewall-sophos-xg - steps: - # Parsing the common fields - - grok: - patterns: - - fieldName: log.syslogPriority - pattern: '\<{{.integer}}\>' - - fieldName: log.syslogVersion - pattern: '{{.integer}}' - - fieldName: log.syslogDeviceTime - pattern: '{{.year}}-{{.monthNumber}}-{{.monthDay}}{{.space}}{{.time}}' - - fieldName: log.0trash - pattern: '{{.data}}\=' - - fieldName: log.syslogHostIP - pattern: '{{.ipv4}}' - - fieldName: log.notDefined - pattern: '{{.integer}}' - - fieldName: log.restData - pattern: '{{.greedy}}' - source: raw - - - grok: - patterns: - - fieldName: log.syslogPriority - pattern: '\<{{.integer}}\>' - - fieldName: log.restData - pattern: '{{.greedy}}' - source: raw - - - kv: - fieldSplit: " " - valueSplit: "=" - source: log.restData - - # Extracting common fields for all logs - - grok: - patterns: - - fieldName: log.1trash - pattern: '{{.data}}log_type=' - - fieldName: log.type - pattern: '\"{{.data}}\"' - - fieldName: log.2trash - pattern: '{{.data}}log_component=' - - fieldName: log.component - pattern: '\"{{.data}}\"' - - fieldName: log.3trash - pattern: '{{.data}}log_subtype=' - - fieldName: log.subType - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - # Parsing the raw field for log_type="Content Filtering" log_component="HTTP" log_subtype="Allowed" - - grok: - patterns: - - fieldName: log.4trash - pattern: '{{.data}}user_agent=' - - fieldName: log.userAgent - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.5trash - pattern: '{{.data}}download_file_name=' - - fieldName: log.downloadfilename - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.6trash - pattern: '{{.data}}upload_file_name=' - - fieldName: log.uploadfilename - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - # Parsing the raw field for log_type="Content Filtering" log_component="Application" log_subtype="Denied" - - grok: - patterns: - - fieldName: log.4trash - pattern: '{{.data}}category=' - - fieldName: log.category - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.5trash - pattern: '{{.data}}application_name=' - - fieldName: log.applicationName - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.6trash - pattern: '{{.data}}application_technology=' - - fieldName: log.applicationTech - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.7trash - pattern: '{{.data}}application_category=' - - fieldName: log.applicationCategory - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.8trash - pattern: '{{.data}}message=' - - fieldName: log.logMessage - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - # Parsing the raw field for log_type="Firewall" log_component="Firewall Rule|Invalid Traffic" log_subtype="Allowed|Denied" - - grok: - patterns: - - fieldName: log.4trash - pattern: '{{.data}}ether_type=' - - fieldName: log.etherType - pattern: '{{.data}}\)' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - # Parsing the raw field for log_type="Event" log_component="DDNS|DHCP Server|Firewall Authentication" log_subtype="System|Authentication" - - grok: - patterns: - - fieldName: log.4trash - pattern: '{{.data}}raw_data=' - - fieldName: log.rawData - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.5trash - pattern: '{{.data}}raw_data=' - - fieldName: log.rawData - pattern: '\"{{.data}}\"' - source: log.restData - - - grok: - patterns: - - fieldName: log.6trash - pattern: '{{.data}}usergroupname=' - - fieldName: log.userGroupName - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.7trash - pattern: '{{.data}}auth_client=' - - fieldName: log.authClient - pattern: '\"{{.data}}\"' - - fieldName: log.irrelevant - pattern: '{{.greedy}}' - source: log.restData - - - grok: - patterns: - - fieldName: log.8trash - pattern: '{{.data}}message=' - - fieldName: log.logMessage - pattern: '\"{{.data}}\"' - source: log.restData - - # Renaming useful fields - - rename: - from: - - log.appiscloud - to: log.appIsCloud - - - rename: - from: - - log.category - to: log.categoryApp - - - rename: - from: - - log.categorytype - to: log.categoryType - - - rename: - from: - - log.uploadfilename - to: log.uploadFileName - - - rename: - from: - - log.downloadfiletype - to: log.downloadFileType - - - rename: - from: - - log.downloadfilename - to: log.downloadFileName - - - rename: - from: - - log.uploadfiletype - to: log.uploadFileType - - - rename: - from: - - log.contenttype - to: log.contentType - - - rename: - from: - - log.conid - to: log.connectionId - - - rename: - from: - - log.deviceid - to: log.deviceId - - - rename: - from: - - log.domain - to: target.domain - - - rename: - from: - - log.dstip - to: target.ip - - - rename: - from: - - log.dstport - to: target.port - - - rename: - from: - - log.exceptions - to: log.webExceptions - - - rename: - from: - - log.fwruleid - to: log.firewallRuleId - - - rename: - from: - - log.iap - to: log.webPolicy - - - rename: - from: - - log.logid - to: log.Id - - - rename: - from: - - log.bridgedisplayname - to: log.bridgeDisplayName - - - rename: - from: - - log.bridgename - to: log.bridgeName - - - rename: - from: - - log.recvbytes - to: origin.bytesReceived - - - rename: - from: - - log.sentbytes - to: origin.bytesSent - - - rename: - from: - - log.srcip - to: origin.ip - - - rename: - from: - - log.srcport - to: origin.port - - - rename: - from: - - log.statuscode - to: log.statusCode - where: exists("log.statuscode") - - - rename: - from: - - log.protocol - to: protocol - - - rename: - from: - - log.usedquota - to: log.responseTime - - - rename: - from: - - log.usergp - to: log.userGroup - - - rename: - from: - - log.username - to: origin.user - - - rename: - from: - - log.srccountrycode - to: log.srcCountryCode - - - rename: - from: - - log.dstcountrycode - to: log.dstCountryCode - - - rename: - from: - - log.appresolvedby - to: log.appResolvedBy - - - rename: - from: - - log.applicationrisk - to: log.applicationRisk - - - rename: - from: - - log.applicationfilterpolicy - to: log.applicationFilterPolicy - - - rename: - from: - - log.device - to: log.deviceType - - - rename: - from: - - log.devicename - to: log.deviceName - - - rename: - from: - - log.domainname - to: log.domainName - - - rename: - from: - - log.timezone - to: log.timeZone - - - rename: - from: - - log.filename - to: target.file - - - rename: - from: - - log.filepath - to: target.path - - - rename: - from: - - log.indisplayinterface - to: log.inDisplayInterface - - - rename: - from: - - log.ininterface - to: log.inInterface - - - rename: - from: - - log.outdisplayinterface - to: log.outDisplayInterface - - - rename: - from: - - log.outinterface - to: log.outInterface - - - rename: - from: - - log.vlanid - to: log.vLanId - - - rename: - from: - - log.ftpcommand - to: command - - - rename: - from: - - log.FTPurl - to: target.url - - - rename: - from: - - log.FTPdirection - to: log.ftpDirection - - - rename: - from: - - log.ipspolicyid - to: log.ipsPolicyId - - - rename: - from: - - log.appfilterpolicyid - to: log.appFilterPolicyId - - - rename: - from: - - log.natruleid - to: log.natRuleId - - - rename: - from: - - log.srcmac - to: origin.mac - - - rename: - from: - - log.policytype - to: log.policyType - - - rename: - from: - - log.updatedip - to: log.updatedIp - - - rename: - from: - - log.clienthostname - to: log.clientHostName - - - rename: - from: - - log.ipaddress - to: origin.ip - - - rename: - from: - - log.clientphysicaladdress - to: log.clientPhysicalAddress - - - rename: - from: - - log.timestamp - to: log.timesTamp - - - rename: - from: - - log.starttime - to: log.startTime - - - rename: - from: - - log.authmechanism - to: log.authMechanism - - - rename: - from: - - log.eventtype - to: log.eventType - - - rename: - from: - - log.executionpath - to: log.executionPath - - - rename: - from: - - log.loginuser - to: log.loginUser - - - rename: - from: - - log.processuser - to: log.processUser - - - rename: - from: - - log.dstmac - to: target.mac - - - rename: - from: - - log.dstdomain - to: target.domain - - # Removing unnecessary characters - - trim: - function: prefix - substring: '"' - fields: - - log.categoryApp - - log.categoryType - - log.component - - log.subType - - log.type - - log.logMessage - - log.contentType - - log.deviceName - - log.domainName - - target.domain - - log.inDisplayInterface - - log.inInterface - - log.outDisplayInterface - - log.outInterface - - log.vLanId - - log.deviceType - - command - - log.clientHostName - - log.ipAddress - - log.clientPhysicalAddress - - log.authMechanism - - log.eventType - - log.executionPath - - log.loginUser - - log.processUser - - log.rawData - - log.userGroupName - - log.authClient - - target.file - - target.path - - log.ftpDirection - - target.url - - log.downloadFileName - - log.downloadFileType - - log.uploadFileName - - log.uploadFileType - - protocol - - log.reason - - log.referer - - log.status - - log.statusCode - - log.url - - log.virus - - log.userAgent - - log.userGroup - - origin.user - - log.bridgeName - - log.bridgeDisplayName - - log.timeZone - - log.applicationCategory - - log.applicationName - - log.applicationTech - - log.appResolvedBy - - - trim: - function: suffix - substring: '"' - fields: - - log.categoryApp - - log.categoryType - - log.component - - log.subType - - log.type - - log.logMessage - - log.contentType - - log.deviceName - - log.domainName - - target.domain - - log.inDisplayInterface - - log.inInterface - - log.outDisplayInterface - - log.outInterface - - log.vLanId - - log.deviceType - - command - - log.clientHostName - - log.ipAddress - - log.clientPhysicalAddress - - log.authMechanism - - log.eventType - - log.executionPath - - log.loginUser - - log.processUser - - log.rawData - - log.userGroupName - - log.authClient - - target.file - - target.path - - log.ftpDirection - - target.url - - log.downloadFileName - - log.downloadFileType - - log.uploadFileName - - log.uploadFileType - - protocol - - log.reason - - log.referer - - log.status - - log.statusCode - - log.url - - log.virus - - log.userAgent - - log.userGroup - - origin.user - - log.bridgeName - - log.bridgeDisplayName - - log.timeZone - - log.applicationCategory - - log.applicationName - - log.applicationTech - - log.appResolvedBy - - - trim: - function: prefix - substring: '<' - fields: - - log.syslogPriority - - - trim: - function: suffix - substring: '>' - fields: - - log.syslogPriority - - # Adding geolocation to target ip - - dynamic: - plugin: com.utmstack.geolocation - params: - source: target.ip - destination: target.geolocation - where: exists("target.ip") - - # Adding geolocation to origin ip - - dynamic: - plugin: com.utmstack.geolocation - params: - source: origin.ip - destination: origin.geolocation - where: exists("origin.ip") - - # Field conversions - - cast: - fields: - - target.port - to: int - - - cast: - fields: - - log.statusCode - - origin.bytesReceived - - origin.bytesSent - to: float - - # Adding actionResult based on log.subtype value - - add: - function: 'string' - params: - key: actionResult - value: 'denied' - where: exists("log.subType") && regexMatch("log.subType", "(?i)\bdenied\b") - - - add: - function: 'string' - params: - key: actionResult - value: 'accepted' - where: exists("log.subType") && oneOf("log.subType", ["Accepted", "Allowed"]) - - # Renaming "log.statusCode" to "statusCode" to add it to the event structure - - rename: - from: - - log.statusCode - to: statusCode - where: exists("log.statusCode") - - # Adding actionResult - # denied by default - - add: - function: 'string' - params: - key: actionResult - value: 'denied' - where: exists("statusCode") - - - add: - function: 'string' - params: - key: actionResult - value: 'accepted' - where: exists("statusCode") && ((greaterOrEqual("statusCode", 200) && lessOrEqual("statusCode", 299)) || (greaterOrEqual("statusCode", 300) && lessOrEqual("statusCode", 399) && greaterThan("origin.bytesReceived", 0))) - - # Removing unused fields - - delete: - fields: - - log.0trash - - log.1trash - - log.2trash - - log.3trash - - log.4trash - - log.5trash - - log.6trash - - log.7trash - - log.8trash - - log.irrelevant - - log.rawdata - - log.message - - log.restData - - log.useragent - - log.activityname - - log.httpresponsecode - - log.overrideauthorizer - - log.overridename - - log.overridetoken - - log.transactionid - - log.applicationcategory - - log.applicationname - - log.applicationtechnology - - log.avpolicyname - - log.ethertype - - log.bridgedisplayname - - log.bridgename - - log.usergroupname - - log.authclient - - log.logcomponent - - log.logsubtype - - log.name - - log.logtype \ No newline at end of file +- dataTypes: [firewall-sophos-xg] + steps: + - grok: + source: raw + patterns: + - {fieldName: '', pattern: '^(?:<[0-9]{1,3}>)?(?:(?:[A-Za-z]{3}\s+[0-9]{1,2}\s+[0-9]{2}:[0-9]{2}:[0-9]{2}\s+\S+\s+)|(?:[0-9]+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(?:-|\[[^]]*\])\s+))?'} + - {fieldName: log.sophosBody, pattern: '[A-Za-z_][A-Za-z0-9_]*=(?s:.*)'} + - kv: + source: log.sophosBody + fieldSplit: ' ' + valueSplit: '=' + - delete: + fields: [log.FTPdirection, log.FTPurl, log.IPHOSTNAME, log.Mode, log.Reason, log.action, log.activityname, + log.appfilterpolicyid, log.appiscloud, log.application, log.applicationcategory, log.applicationfilterpolicy, + log.applicationname, log.applicationrisk, log.applicationtechnology, log.appresolvedby, log.authclient, + log.authmechanism, log.avpolicyname, log.bridgedisplayname, log.bridgename, log.bytesrcv, log.bytesreceived, + log.bytesrecv, log.bytessent, log.category, log.categorytype, log.classification, log.clienthostname, log.clientphysicaladdress, + log.conid, log.conname, log.connectiontype, log.connevent, log.connid, log.contenttype, log.cookie, log.correlationCandidate, + log.date, log.destination, log.destinationip, log.device, log.deviceid, log.devicemodel, log.devicename, + log.deviceserialid, log.dirdisp, log.domain, log.domainname, log.downloadfilename, log.downloadfiletype, + log.dstcountrycode, log.dstdomain, log.dstdomainname, log.dstip, log.dstmac, log.dstport, log.dstzone, log.dstzonetype, + log.duration, log.emailsubject, log.epeventtime, log.ephealth, log.epip, log.epname, log.epuuid, log.ethertype, + log.eventtimestamp, log.exceptions, log.executionpath, log.extra, log.filename, log.filepath, log.filesize, + log.filetype, log.flags, log.fromemailaddress, log.ftpcommand, log.fwruleid, log.fwrulename, log.fwrulesection, + log.gaSD7Q3K201R, log.gwidreply, log.gwidrequest, log.gwnamereply, log.gwnamerequest, log.hbhealth, log.host, + log.httpresponsecode, log.httpstatus, log.iap, log.idppolicyid, log.indisplayinterface, log.ininterface, + log.ipaddress, log.ipspolicyid, log.localgateway, log.localinterfaceip, log.localip, log.localnetwork, log.logcomponent, + log.logid, log.loginuser, log.logoccurrence, log.logsubtype, log.logtype, log.logversion, log.mailid, log.mailsize, + log.malware, log.message, log.messageid, log.method, log.name, log.natruleid, log.natrulename, log.newversion, + log.oldversion, log.outdisplayinterface, log.outinterface, log.overrideauthorizer, log.overridename, log.overridetoken, + log.packetsreceived, log.packetssent, log.platform, log.policytype, log.priority, log.processuser, log.protocol, + log.quarantinereason, log.querystring, log.reason, log.recvbytes, log.recvpkts, log.referer, log.remoteinterfaceip, + log.remoteip, log.remotenetwork, log.remotepeer, log.resource, log.responsecode, log.responsetime, log.rulepriority, + log.sdwanprofileidreply, log.sdwanprofileidrequest, log.sdwanprofilenamereply, log.sdwanprofilenamerequest, + log.sdwanrouteidreply, log.sdwanrouteidrequest, log.sdwanroutenamereply, log.sdwanroutenamerequest, log.sentbytes, + log.sentpkts, log.server, log.sessionid, log.severity, log.sha1sum, log.signatureid, log.signaturemsg, log.sophosScope, + log.source, log.sourceip, log.spamaction, log.srccountrycode, log.srcdomainname, log.srcip, log.srcmac, + log.srcport, log.srczone, log.srczonetype, log.starttime, log.status, log.statuscode, log.subject, log.target, + log.threatfeed, log.threatname, log.time, log.timestamp, log.timezone, log.toemailaddress, log.trandstip, + log.trandstport, log.transactionid, log.transrcip, log.transrcport, log.type, log.uploadfilename, log.uploadfiletype, + log.url, log.usedquota, log.user, log.useragent, log.usergp, log.usergroup, log.usergroupname, log.username, + log.vconnid, log.vlanid, log.wsprotocol] + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)FTP_direction='} + - {fieldName: log.FTPdirection, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "FTP_direction=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)FTP_url='} + - {fieldName: log.FTPurl, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "FTP_url=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)IP_HOST_NAME='} + - {fieldName: log.IPHOSTNAME, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "IP_HOST_NAME=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)Mode='} + - {fieldName: log.Mode, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "Mode=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)Reason='} + - {fieldName: log.Reason, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "Reason=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)_ga_SD7Q3K201R='} + - {fieldName: log.gaSD7Q3K201R, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "_ga_SD7Q3K201R=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)action='} + - {fieldName: log.action, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "action=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)activityname='} + - {fieldName: log.activityname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "activityname=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)app_is_cloud='} + - {fieldName: log.appiscloud, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "app_is_cloud=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)app_resolved_by='} + - {fieldName: log.appresolvedby, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "app_resolved_by=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)appfilter_policy_id='} + - {fieldName: log.appfilterpolicyid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "appfilter_policy_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)application='} + - {fieldName: log.application, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "application=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)application_category='} + - {fieldName: log.applicationcategory, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "application_category=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)application_filter_policy='} + - {fieldName: log.applicationfilterpolicy, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "application_filter_policy=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)application_name='} + - {fieldName: log.applicationname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "application_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)application_risk='} + - {fieldName: log.applicationrisk, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "application_risk=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)application_technology='} + - {fieldName: log.applicationtechnology, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "application_technology=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)appresolvedby='} + - {fieldName: log.appresolvedby, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "appresolvedby=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)auth_client='} + - {fieldName: log.authclient, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "auth_client=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)auth_mechanism='} + - {fieldName: log.authmechanism, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "auth_mechanism=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)av_policy_name='} + - {fieldName: log.avpolicyname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "av_policy_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)bridge_display_name='} + - {fieldName: log.bridgedisplayname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "bridge_display_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)bridge_name='} + - {fieldName: log.bridgename, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "bridge_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)bytes_received='} + - {fieldName: log.bytesreceived, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "bytes_received=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)bytes_recv='} + - {fieldName: log.bytesrecv, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "bytes_recv=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)bytes_sent='} + - {fieldName: log.bytessent, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "bytes_sent=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)bytesrcv='} + - {fieldName: log.bytesrcv, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "bytesrcv=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)bytessent='} + - {fieldName: log.bytessent, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "bytessent=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)category='} + - {fieldName: log.category, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "category=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)category_type='} + - {fieldName: log.categorytype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "category_type=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)classification='} + - {fieldName: log.classification, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "classification=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)client_host_name='} + - {fieldName: log.clienthostname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "client_host_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)client_physical_address='} + - {fieldName: log.clientphysicaladdress, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "client_physical_address=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)con_id='} + - {fieldName: log.conid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "con_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)con_name='} + - {fieldName: log.conname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "con_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)connectiontype='} + - {fieldName: log.connectiontype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "connectiontype=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)connevent='} + - {fieldName: log.connevent, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "connevent=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)connid='} + - {fieldName: log.connid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "connid=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)content_type='} + - {fieldName: log.contenttype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "content_type=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)contenttype='} + - {fieldName: log.contenttype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "contenttype=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)cookie='} + - {fieldName: log.cookie, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "cookie=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)date='} + - {fieldName: log.date, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "date=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)destination='} + - {fieldName: log.destination, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "destination=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)destinationip='} + - {fieldName: log.destinationip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "destinationip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)device='} + - {fieldName: log.device, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "device=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)device_id='} + - {fieldName: log.deviceid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "device_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)device_model='} + - {fieldName: log.devicemodel, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "device_model=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)device_name='} + - {fieldName: log.devicename, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "device_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)device_serial_id='} + - {fieldName: log.deviceserialid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "device_serial_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dir_disp='} + - {fieldName: log.dirdisp, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dir_disp=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)domain='} + - {fieldName: log.domain, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "domain=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)domainname='} + - {fieldName: log.domainname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "domainname=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)download_file_name='} + - {fieldName: log.downloadfilename, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "download_file_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)download_file_type='} + - {fieldName: log.downloadfiletype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "download_file_type=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dst_country_code='} + - {fieldName: log.dstcountrycode, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dst_country_code=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dst_domainname='} + - {fieldName: log.dstdomainname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dst_domainname=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dst_ip='} + - {fieldName: log.dstip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dst_ip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dst_mac='} + - {fieldName: log.dstmac, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dst_mac=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dst_port='} + - {fieldName: log.dstport, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dst_port=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dstdomain='} + - {fieldName: log.dstdomain, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dstdomain=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dstzone='} + - {fieldName: log.dstzone, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dstzone=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)dstzonetype='} + - {fieldName: log.dstzonetype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "dstzonetype=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)duration='} + - {fieldName: log.duration, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "duration=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)email_subject='} + - {fieldName: log.emailsubject, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "email_subject=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ep_event_time='} + - {fieldName: log.epeventtime, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ep_event_time=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ep_health='} + - {fieldName: log.ephealth, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ep_health=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ep_ip='} + - {fieldName: log.epip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ep_ip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ep_name='} + - {fieldName: log.epname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ep_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ep_uuid='} + - {fieldName: log.epuuid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ep_uuid=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ether_type='} + - {fieldName: log.ethertype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ether_type=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)event_timestamp='} + - {fieldName: log.eventtimestamp, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "event_timestamp=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)exceptions='} + - {fieldName: log.exceptions, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "exceptions=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)execution_path='} + - {fieldName: log.executionpath, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "execution_path=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)extra='} + - {fieldName: log.extra, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "extra=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)file_path='} + - {fieldName: log.filepath, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "file_path=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)file_size='} + - {fieldName: log.filesize, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "file_size=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)filename='} + - {fieldName: log.filename, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "filename=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)filesize='} + - {fieldName: log.filesize, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "filesize=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)filetype='} + - {fieldName: log.filetype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "filetype=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)flags='} + - {fieldName: log.flags, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "flags=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)from_email_address='} + - {fieldName: log.fromemailaddress, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "from_email_address=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ftpcommand='} + - {fieldName: log.ftpcommand, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ftpcommand=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)fw_rule_id='} + - {fieldName: log.fwruleid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "fw_rule_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)fw_rule_name='} + - {fieldName: log.fwrulename, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "fw_rule_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)fw_rule_section='} + - {fieldName: log.fwrulesection, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "fw_rule_section=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)gw_id_reply='} + - {fieldName: log.gwidreply, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "gw_id_reply=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)gw_id_request='} + - {fieldName: log.gwidrequest, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "gw_id_request=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)gw_name_reply='} + - {fieldName: log.gwnamereply, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "gw_name_reply=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)gw_name_request='} + - {fieldName: log.gwnamerequest, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "gw_name_request=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)hb_health='} + - {fieldName: log.hbhealth, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "hb_health=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)host='} + - {fieldName: log.host, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "host=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)httpresponsecode='} + - {fieldName: log.httpresponsecode, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "httpresponsecode=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)httpstatus='} + - {fieldName: log.httpstatus, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "httpstatus=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)iap='} + - {fieldName: log.iap, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "iap=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)idp_policy_id='} + - {fieldName: log.idppolicyid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "idp_policy_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)in_display_interface='} + - {fieldName: log.indisplayinterface, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "in_display_interface=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)in_interface='} + - {fieldName: log.ininterface, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "in_interface=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ipaddress='} + - {fieldName: log.ipaddress, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ipaddress=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ips_policy_id='} + - {fieldName: log.ipspolicyid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ips_policy_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)local_ip='} + - {fieldName: log.localip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "local_ip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)localgateway='} + - {fieldName: log.localgateway, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "localgateway=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)localinterfaceip='} + - {fieldName: log.localinterfaceip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "localinterfaceip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)localip='} + - {fieldName: log.localip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "localip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)localnetwork='} + - {fieldName: log.localnetwork, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "localnetwork=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)log_component='} + - {fieldName: log.logcomponent, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "log_component=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)log_id='} + - {fieldName: log.logid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "log_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)log_occurrence='} + - {fieldName: log.logoccurrence, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "log_occurrence=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)log_subtype='} + - {fieldName: log.logsubtype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "log_subtype=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)log_type='} + - {fieldName: log.logtype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "log_type=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)log_version='} + - {fieldName: log.logversion, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "log_version=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)login_user='} + - {fieldName: log.loginuser, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "login_user=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)mailid='} + - {fieldName: log.mailid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "mailid=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)mailsize='} + - {fieldName: log.mailsize, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "mailsize=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)malware='} + - {fieldName: log.malware, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "malware=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)message='} + - {fieldName: log.message, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "message=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)messageid='} + - {fieldName: log.messageid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "messageid=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)method='} + - {fieldName: log.method, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "method=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)name='} + - {fieldName: log.name, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)nat_rule_id='} + - {fieldName: log.natruleid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "nat_rule_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)nat_rule_name='} + - {fieldName: log.natrulename, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "nat_rule_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)newversion='} + - {fieldName: log.newversion, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "newversion=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)oldversion='} + - {fieldName: log.oldversion, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "oldversion=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)out_display_interface='} + - {fieldName: log.outdisplayinterface, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "out_display_interface=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)out_interface='} + - {fieldName: log.outinterface, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "out_interface=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)override_authorizer='} + - {fieldName: log.overrideauthorizer, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "override_authorizer=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)override_name='} + - {fieldName: log.overridename, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "override_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)override_token='} + - {fieldName: log.overridetoken, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "override_token=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)packets_received='} + - {fieldName: log.packetsreceived, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "packets_received=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)packets_sent='} + - {fieldName: log.packetssent, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "packets_sent=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)platform='} + - {fieldName: log.platform, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "platform=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)policy_type='} + - {fieldName: log.policytype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "policy_type=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)priority='} + - {fieldName: log.priority, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "priority=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)process_user='} + - {fieldName: log.processuser, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "process_user=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)protocol='} + - {fieldName: log.protocol, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "protocol=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)quarantine_reason='} + - {fieldName: log.quarantinereason, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "quarantine_reason=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)querystring='} + - {fieldName: log.querystring, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "querystring=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)reason='} + - {fieldName: log.reason, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "reason=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)recv_bytes='} + - {fieldName: log.recvbytes, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "recv_bytes=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)recv_pkts='} + - {fieldName: log.recvpkts, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "recv_pkts=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)referer='} + - {fieldName: log.referer, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "referer=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)remote_ip='} + - {fieldName: log.remoteip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "remote_ip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)remoteinterfaceip='} + - {fieldName: log.remoteinterfaceip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "remoteinterfaceip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)remotenetwork='} + - {fieldName: log.remotenetwork, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "remotenetwork=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)remotepeer='} + - {fieldName: log.remotepeer, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "remotepeer=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)resource='} + - {fieldName: log.resource, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "resource=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)response_code='} + - {fieldName: log.responsecode, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "response_code=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)response_time='} + - {fieldName: log.responsetime, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "response_time=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)responsetime='} + - {fieldName: log.responsetime, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "responsetime=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)rule_priority='} + - {fieldName: log.rulepriority, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "rule_priority=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sdwan_profile_id_reply='} + - {fieldName: log.sdwanprofileidreply, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sdwan_profile_id_reply=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sdwan_profile_id_request='} + - {fieldName: log.sdwanprofileidrequest, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sdwan_profile_id_request=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sdwan_profile_name_reply='} + - {fieldName: log.sdwanprofilenamereply, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sdwan_profile_name_reply=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sdwan_profile_name_request='} + - {fieldName: log.sdwanprofilenamerequest, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sdwan_profile_name_request=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sdwan_route_id_reply='} + - {fieldName: log.sdwanrouteidreply, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sdwan_route_id_reply=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sdwan_route_id_request='} + - {fieldName: log.sdwanrouteidrequest, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sdwan_route_id_request=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sdwan_route_name_reply='} + - {fieldName: log.sdwanroutenamereply, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sdwan_route_name_reply=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sdwan_route_name_request='} + - {fieldName: log.sdwanroutenamerequest, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sdwan_route_name_request=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sent_bytes='} + - {fieldName: log.sentbytes, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sent_bytes=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sent_pkts='} + - {fieldName: log.sentpkts, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sent_pkts=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)server='} + - {fieldName: log.server, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "server=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sessionid='} + - {fieldName: log.sessionid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sessionid=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)severity='} + - {fieldName: log.severity, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "severity=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sha1sum='} + - {fieldName: log.sha1sum, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sha1sum=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)signature_id='} + - {fieldName: log.signatureid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "signature_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)signature_msg='} + - {fieldName: log.signaturemsg, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "signature_msg=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)source='} + - {fieldName: log.source, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "source=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)sourceip='} + - {fieldName: log.sourceip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "sourceip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)spamaction='} + - {fieldName: log.spamaction, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "spamaction=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)src_country_code='} + - {fieldName: log.srccountrycode, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "src_country_code=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)src_domainname='} + - {fieldName: log.srcdomainname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "src_domainname=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)src_ip='} + - {fieldName: log.srcip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "src_ip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)src_mac='} + - {fieldName: log.srcmac, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "src_mac=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)src_port='} + - {fieldName: log.srcport, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "src_port=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)srczone='} + - {fieldName: log.srczone, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "srczone=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)srczonetype='} + - {fieldName: log.srczonetype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "srczonetype=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)start_time='} + - {fieldName: log.starttime, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "start_time=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)starttime='} + - {fieldName: log.starttime, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "starttime=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)status='} + - {fieldName: log.status, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "status=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)status_code='} + - {fieldName: log.statuscode, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "status_code=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)statuscode='} + - {fieldName: log.statuscode, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "statuscode=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)subject='} + - {fieldName: log.subject, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "subject=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)target='} + - {fieldName: log.target, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "target=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)threatfeed='} + - {fieldName: log.threatfeed, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "threatfeed=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)threatname='} + - {fieldName: log.threatname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "threatname=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)time='} + - {fieldName: log.time, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "time=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)timestamp='} + - {fieldName: log.timestamp, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "timestamp=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)timezone='} + - {fieldName: log.timezone, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "timezone=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)to_email_address='} + - {fieldName: log.toemailaddress, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "to_email_address=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)tran_dst_ip='} + - {fieldName: log.trandstip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "tran_dst_ip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)tran_dst_port='} + - {fieldName: log.trandstport, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "tran_dst_port=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)tran_src_ip='} + - {fieldName: log.transrcip, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "tran_src_ip=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)tran_src_port='} + - {fieldName: log.transrcport, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "tran_src_port=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)transactionid='} + - {fieldName: log.transactionid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "transactionid=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)type='} + - {fieldName: log.type, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "type=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)upload_file_name='} + - {fieldName: log.uploadfilename, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "upload_file_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)upload_file_type='} + - {fieldName: log.uploadfiletype, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "upload_file_type=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)url='} + - {fieldName: log.url, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "url=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)used_quota='} + - {fieldName: log.usedquota, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "used_quota=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)user='} + - {fieldName: log.user, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "user=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)user_agent='} + - {fieldName: log.useragent, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "user_agent=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)user_gp='} + - {fieldName: log.usergp, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "user_gp=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)user_group='} + - {fieldName: log.usergroup, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "user_group=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)user_name='} + - {fieldName: log.username, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "user_name=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)useragent='} + - {fieldName: log.useragent, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "useragent=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)usergroupname='} + - {fieldName: log.usergroupname, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "usergroupname=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)vconnid='} + - {fieldName: log.vconnid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "vconnid=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)vlan_id='} + - {fieldName: log.vlanid, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "vlan_id=") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)ws_protocol='} + - {fieldName: log.wsprotocol, pattern: '(?:"(?:\\.|[^"\\])*"|[^"\s][^"]*?|)'} + - {fieldName: '', pattern: '(?:\s+[A-Za-z_][A-Za-z0-9_]*=|$)'} + where: contains("log.sophosBody", "ws_protocol=") + - trim: + function: prefix + substring: '"' + fields: [log.FTPdirection, log.FTPurl, log.IPHOSTNAME, log.Mode, log.Reason, log.action, log.activityname, + log.appfilterpolicyid, log.appiscloud, log.application, log.applicationcategory, log.applicationfilterpolicy, + log.applicationname, log.applicationrisk, log.applicationtechnology, log.appresolvedby, log.authclient, + log.authmechanism, log.avpolicyname, log.bridgedisplayname, log.bridgename, log.bytesrcv, log.bytesreceived, + log.bytesrecv, log.bytessent, log.category, log.categorytype, log.classification, log.clienthostname, log.clientphysicaladdress, + log.conid, log.conname, log.connectiontype, log.connevent, log.connid, log.contenttype, log.cookie, log.date, + log.destination, log.destinationip, log.device, log.deviceid, log.devicemodel, log.devicename, log.deviceserialid, + log.dirdisp, log.domain, log.domainname, log.downloadfilename, log.downloadfiletype, log.dstcountrycode, + log.dstdomain, log.dstdomainname, log.dstip, log.dstmac, log.dstport, log.dstzone, log.dstzonetype, log.duration, + log.emailsubject, log.epeventtime, log.ephealth, log.epip, log.epname, log.epuuid, log.ethertype, log.eventtimestamp, + log.exceptions, log.executionpath, log.extra, log.filename, log.filepath, log.filesize, log.filetype, log.flags, + log.fromemailaddress, log.ftpcommand, log.fwruleid, log.fwrulename, log.fwrulesection, log.gaSD7Q3K201R, + log.gwidreply, log.gwidrequest, log.gwnamereply, log.gwnamerequest, log.hbhealth, log.host, log.httpresponsecode, + log.httpstatus, log.iap, log.idppolicyid, log.indisplayinterface, log.ininterface, log.ipaddress, log.ipspolicyid, + log.localgateway, log.localinterfaceip, log.localip, log.localnetwork, log.logcomponent, log.logid, log.loginuser, + log.logoccurrence, log.logsubtype, log.logtype, log.logversion, log.mailid, log.mailsize, log.malware, log.message, + log.messageid, log.method, log.name, log.natruleid, log.natrulename, log.newversion, log.oldversion, log.outdisplayinterface, + log.outinterface, log.overrideauthorizer, log.overridename, log.overridetoken, log.packetsreceived, log.packetssent, + log.platform, log.policytype, log.priority, log.processuser, log.protocol, log.quarantinereason, log.querystring, + log.reason, log.recvbytes, log.recvpkts, log.referer, log.remoteinterfaceip, log.remoteip, log.remotenetwork, + log.remotepeer, log.resource, log.responsecode, log.responsetime, log.rulepriority, log.sdwanprofileidreply, + log.sdwanprofileidrequest, log.sdwanprofilenamereply, log.sdwanprofilenamerequest, log.sdwanrouteidreply, + log.sdwanrouteidrequest, log.sdwanroutenamereply, log.sdwanroutenamerequest, log.sentbytes, log.sentpkts, + log.server, log.sessionid, log.severity, log.sha1sum, log.signatureid, log.signaturemsg, log.source, log.sourceip, + log.spamaction, log.srccountrycode, log.srcdomainname, log.srcip, log.srcmac, log.srcport, log.srczone, + log.srczonetype, log.starttime, log.status, log.statuscode, log.subject, log.target, log.threatfeed, log.threatname, + log.time, log.timestamp, log.timezone, log.toemailaddress, log.trandstip, log.trandstport, log.transactionid, + log.transrcip, log.transrcport, log.type, log.uploadfilename, log.uploadfiletype, log.url, log.usedquota, + log.user, log.useragent, log.usergp, log.usergroup, log.usergroupname, log.username, log.vconnid, log.vlanid, + log.wsprotocol] + - trim: + function: suffix + substring: '"' + fields: [log.FTPdirection, log.FTPurl, log.IPHOSTNAME, log.Mode, log.Reason, log.action, log.activityname, + log.appfilterpolicyid, log.appiscloud, log.application, log.applicationcategory, log.applicationfilterpolicy, + log.applicationname, log.applicationrisk, log.applicationtechnology, log.appresolvedby, log.authclient, + log.authmechanism, log.avpolicyname, log.bridgedisplayname, log.bridgename, log.bytesrcv, log.bytesreceived, + log.bytesrecv, log.bytessent, log.category, log.categorytype, log.classification, log.clienthostname, log.clientphysicaladdress, + log.conid, log.conname, log.connectiontype, log.connevent, log.connid, log.contenttype, log.cookie, log.date, + log.destination, log.destinationip, log.device, log.deviceid, log.devicemodel, log.devicename, log.deviceserialid, + log.dirdisp, log.domain, log.domainname, log.downloadfilename, log.downloadfiletype, log.dstcountrycode, + log.dstdomain, log.dstdomainname, log.dstip, log.dstmac, log.dstport, log.dstzone, log.dstzonetype, log.duration, + log.emailsubject, log.epeventtime, log.ephealth, log.epip, log.epname, log.epuuid, log.ethertype, log.eventtimestamp, + log.exceptions, log.executionpath, log.extra, log.filename, log.filepath, log.filesize, log.filetype, log.flags, + log.fromemailaddress, log.ftpcommand, log.fwruleid, log.fwrulename, log.fwrulesection, log.gaSD7Q3K201R, + log.gwidreply, log.gwidrequest, log.gwnamereply, log.gwnamerequest, log.hbhealth, log.host, log.httpresponsecode, + log.httpstatus, log.iap, log.idppolicyid, log.indisplayinterface, log.ininterface, log.ipaddress, log.ipspolicyid, + log.localgateway, log.localinterfaceip, log.localip, log.localnetwork, log.logcomponent, log.logid, log.loginuser, + log.logoccurrence, log.logsubtype, log.logtype, log.logversion, log.mailid, log.mailsize, log.malware, log.message, + log.messageid, log.method, log.name, log.natruleid, log.natrulename, log.newversion, log.oldversion, log.outdisplayinterface, + log.outinterface, log.overrideauthorizer, log.overridename, log.overridetoken, log.packetsreceived, log.packetssent, + log.platform, log.policytype, log.priority, log.processuser, log.protocol, log.quarantinereason, log.querystring, + log.reason, log.recvbytes, log.recvpkts, log.referer, log.remoteinterfaceip, log.remoteip, log.remotenetwork, + log.remotepeer, log.resource, log.responsecode, log.responsetime, log.rulepriority, log.sdwanprofileidreply, + log.sdwanprofileidrequest, log.sdwanprofilenamereply, log.sdwanprofilenamerequest, log.sdwanrouteidreply, + log.sdwanrouteidrequest, log.sdwanroutenamereply, log.sdwanroutenamerequest, log.sentbytes, log.sentpkts, + log.server, log.sessionid, log.severity, log.sha1sum, log.signatureid, log.signaturemsg, log.source, log.sourceip, + log.spamaction, log.srccountrycode, log.srcdomainname, log.srcip, log.srcmac, log.srcport, log.srczone, + log.srczonetype, log.starttime, log.status, log.statuscode, log.subject, log.target, log.threatfeed, log.threatname, + log.time, log.timestamp, log.timezone, log.toemailaddress, log.trandstip, log.trandstport, log.transactionid, + log.transrcip, log.transrcport, log.type, log.uploadfilename, log.uploadfiletype, log.url, log.usedquota, + log.user, log.useragent, log.usergp, log.usergroup, log.usergroupname, log.username, log.vconnid, log.vlanid, + log.wsprotocol] + - rename: + from: [log.logtype] + to: log.type + where: exists("log.logtype") + - rename: + from: [log.logcomponent] + to: log.component + where: exists("log.logcomponent") + - rename: + from: [log.logsubtype] + to: log.subType + where: exists("log.logsubtype") + - rename: + from: [log.message] + to: log.logMessage + where: exists("log.message") + - rename: + from: [log.logid] + to: log.Id + where: exists("log.logid") + - rename: + from: [log.deviceid] + to: log.deviceId + where: exists("log.deviceid") + - rename: + from: [log.devicename] + to: log.deviceName + where: exists("log.devicename") + - rename: + from: [log.device] + to: log.deviceType + where: exists("log.device") + - rename: + from: [log.timezone] + to: log.timeZone + where: exists("log.timezone") + - rename: + from: [log.timestamp] + to: log.timesTamp + where: exists("log.timestamp") + - rename: + from: [log.useragent] + to: log.userAgent + where: exists("log.useragent") + - rename: + from: [log.applicationname] + to: log.applicationName + where: exists("log.applicationname") + - rename: + from: [log.applicationcategory] + to: log.applicationCategory + where: exists("log.applicationcategory") + - rename: + from: [log.applicationtechnology] + to: log.applicationTech + where: exists("log.applicationtechnology") + - rename: + from: [log.category] + to: log.categoryApp + where: exists("log.category") + - rename: + from: [log.ethertype] + to: log.etherType + where: exists("log.ethertype") + - rename: + from: [log.rawdata] + to: log.rawData + where: exists("log.rawdata") + - rename: + from: [log.usergroupname] + to: log.userGroupName + where: exists("log.usergroupname") + - rename: + from: [log.authclient] + to: log.authClient + where: exists("log.authclient") + - rename: + from: [log.statuscode] + to: log.statusCode + where: exists("log.statuscode") + - rename: + from: [log.appiscloud] + to: log.appIsCloud + where: exists("log.appiscloud") + - rename: + from: [log.categorytype] + to: log.categoryType + where: exists("log.categorytype") + - rename: + from: [log.uploadfilename] + to: log.uploadFileName + where: exists("log.uploadfilename") + - rename: + from: [log.downloadfiletype] + to: log.downloadFileType + where: exists("log.downloadfiletype") + - rename: + from: [log.downloadfilename] + to: log.downloadFileName + where: exists("log.downloadfilename") + - rename: + from: [log.uploadfiletype] + to: log.uploadFileType + where: exists("log.uploadfiletype") + - rename: + from: [log.contenttype] + to: log.contentType + where: exists("log.contenttype") + - rename: + from: [log.conid] + to: log.connectionId + where: exists("log.conid") + - rename: + from: [log.exceptions] + to: log.webExceptions + where: exists("log.exceptions") + - rename: + from: [log.fwruleid] + to: log.firewallRuleId + where: exists("log.fwruleid") + - rename: + from: [log.iap] + to: log.webPolicy + where: exists("log.iap") + - rename: + from: [log.bridgedisplayname] + to: log.bridgeDisplayName + where: exists("log.bridgedisplayname") + - rename: + from: [log.bridgename] + to: log.bridgeName + where: exists("log.bridgename") + - rename: + from: [log.usergp] + to: log.userGroup + where: exists("log.usergp") + - rename: + from: [log.srccountrycode] + to: log.srcCountryCode + where: exists("log.srccountrycode") + - rename: + from: [log.dstcountrycode] + to: log.dstCountryCode + where: exists("log.dstcountrycode") + - rename: + from: [log.appresolvedby] + to: log.appResolvedBy + where: exists("log.appresolvedby") + - rename: + from: [log.applicationrisk] + to: log.applicationRisk + where: exists("log.applicationrisk") + - rename: + from: [log.applicationfilterpolicy] + to: log.applicationFilterPolicy + where: exists("log.applicationfilterpolicy") + - rename: + from: [log.domainname] + to: log.domainName + where: exists("log.domainname") + - rename: + from: [log.indisplayinterface] + to: log.inDisplayInterface + where: exists("log.indisplayinterface") + - rename: + from: [log.ininterface] + to: log.inInterface + where: exists("log.ininterface") + - rename: + from: [log.outdisplayinterface] + to: log.outDisplayInterface + where: exists("log.outdisplayinterface") + - rename: + from: [log.outinterface] + to: log.outInterface + where: exists("log.outinterface") + - rename: + from: [log.vlanid] + to: log.vLanId + where: exists("log.vlanid") + - rename: + from: [log.FTPdirection] + to: log.ftpDirection + where: exists("log.FTPdirection") + - rename: + from: [log.ipspolicyid] + to: log.ipsPolicyId + where: exists("log.ipspolicyid") + - rename: + from: [log.appfilterpolicyid] + to: log.appFilterPolicyId + where: exists("log.appfilterpolicyid") + - rename: + from: [log.natruleid] + to: log.natRuleId + where: exists("log.natruleid") + - rename: + from: [log.policytype] + to: log.policyType + where: exists("log.policytype") + - rename: + from: [log.updatedip] + to: log.updatedIp + where: exists("log.updatedip") + - rename: + from: [log.clienthostname] + to: log.clientHostName + where: exists("log.clienthostname") + - rename: + from: [log.clientphysicaladdress] + to: log.clientPhysicalAddress + where: exists("log.clientphysicaladdress") + - rename: + from: [log.starttime] + to: log.startTime + where: exists("log.starttime") + - rename: + from: [log.authmechanism] + to: log.authMechanism + where: exists("log.authmechanism") + - rename: + from: [log.eventtype] + to: log.eventType + where: exists("log.eventtype") + - rename: + from: [log.executionpath] + to: log.executionPath + where: exists("log.executionpath") + - rename: + from: [log.loginuser] + to: log.loginUser + where: exists("log.loginuser") + - rename: + from: [log.processuser] + to: log.processUser + where: exists("log.processuser") + - grok: + source: log.Id + patterns: + - {fieldName: '', pattern: '^[0-9]{7}'} + - {fieldName: log.messageId, pattern: '[0-9]{5}$'} + - grok: + source: log.messageid + patterns: + - {fieldName: log.messageId, pattern: '(?s:.*)'} + where: exists("log.messageid") && (regexMatch("log.messageid","^[0-9]{5}$")) + - grok: + source: log.Id + patterns: + - {fieldName: log.messageId, pattern: '(?s:.*)'} + where: exists("log.Id") && (regexMatch("log.Id","^[0-9]{5}$") && !exists("log.messageId")) + - rename: + from: [log.srcip] + to: origin.ip + where: true && !exists("origin.ip") && ((inCIDR("log.srcip","0.0.0.0/0") || inCIDR("log.srcip","::/0")) && + !inCIDR("log.srcip","0.0.0.0/32") && !inCIDR("log.srcip","::/128")) + - rename: + from: [log.sourceip] + to: origin.ip + where: true && !exists("origin.ip") && ((inCIDR("log.sourceip","0.0.0.0/0") || inCIDR("log.sourceip","::/0")) + && !inCIDR("log.sourceip","0.0.0.0/32") && !inCIDR("log.sourceip","::/128")) + - rename: + from: [log.dstip] + to: target.ip + where: true && !exists("target.ip") && ((inCIDR("log.dstip","0.0.0.0/0") || inCIDR("log.dstip","::/0")) && + !inCIDR("log.dstip","0.0.0.0/32") && !inCIDR("log.dstip","::/128")) + - rename: + from: [log.destinationip] + to: target.ip + where: true && !exists("target.ip") && ((inCIDR("log.destinationip","0.0.0.0/0") || inCIDR("log.destinationip","::/0")) + && !inCIDR("log.destinationip","0.0.0.0/32") && !inCIDR("log.destinationip","::/128")) + - rename: + from: [log.ipaddress] + to: origin.ip + where: oneOf("log.component",["SSL VPN","DHCP Server"]) && !exists("origin.ip") && ((inCIDR("log.ipaddress","0.0.0.0/0") + || inCIDR("log.ipaddress","::/0")) && !inCIDR("log.ipaddress","0.0.0.0/32") && !inCIDR("log.ipaddress","::/128")) + - rename: + from: [log.remoteip] + to: target.ip + where: equals("log.component","SSL VPN") && !exists("target.ip") && ((inCIDR("log.remoteip","0.0.0.0/0") || + inCIDR("log.remoteip","::/0")) && !inCIDR("log.remoteip","0.0.0.0/32") && !inCIDR("log.remoteip","::/128")) + - rename: + from: [log.localip] + to: target.ip + where: equals("log.type","WAF") && !exists("target.ip") && ((inCIDR("log.localip","0.0.0.0/0") || inCIDR("log.localip","::/0")) + && !inCIDR("log.localip","0.0.0.0/32") && !inCIDR("log.localip","::/128")) + - rename: + from: [log.epip] + to: origin.ip + where: equals("log.type","Heartbeat") && equals("log.component","Endpoint") && !exists("origin.ip") && ((inCIDR("log.epip","0.0.0.0/0") + || inCIDR("log.epip","::/0")) && !inCIDR("log.epip","0.0.0.0/32") && !inCIDR("log.epip","::/128")) + - rename: + from: [log.srcmac] + to: origin.mac + where: true && !exists("origin.mac") && (exists("log.srcmac") && !oneOf("log.srcmac",["","-","N/A"])) + - rename: + from: [log.dstmac] + to: target.mac + where: true && !exists("target.mac") && (exists("log.dstmac") && !oneOf("log.dstmac",["","-","N/A"])) + - rename: + from: [log.username] + to: origin.user + where: true && !exists("origin.user") && (exists("log.username") && !oneOf("log.username",["","-","N/A"])) + - rename: + from: [log.user] + to: origin.user + where: true && !exists("origin.user") && (exists("log.user") && !oneOf("log.user",["","-","N/A"])) + - rename: + from: [log.userGroupName] + to: origin.group + where: true && !exists("origin.group") && (exists("log.userGroupName") && !oneOf("log.userGroupName",["","-","N/A"])) + - rename: + from: [log.userGroup] + to: origin.group + where: true && !exists("origin.group") && (exists("log.userGroup") && !oneOf("log.userGroup",["","-","N/A"])) + - rename: + from: [log.usergroup] + to: origin.group + where: true && !exists("origin.group") && (exists("log.usergroup") && !oneOf("log.usergroup",["","-","N/A"])) + - rename: + from: [log.clientHostName] + to: origin.host + where: true && !exists("origin.host") && (exists("log.clientHostName") && !oneOf("log.clientHostName",["","-","N/A"])) + - rename: + from: [log.epname] + to: origin.host + where: true && !exists("origin.host") && (exists("log.epname") && !oneOf("log.epname",["","-","N/A"])) + - rename: + from: [log.domain] + to: target.domain + where: true && !exists("target.domain") && (exists("log.domain") && !oneOf("log.domain",["","-","N/A"])) + - rename: + from: [log.dstdomain] + to: target.domain + where: true && !exists("target.domain") && (exists("log.dstdomain") && !oneOf("log.dstdomain",["","-","N/A"])) + - rename: + from: [log.domainName] + to: target.domain + where: true && !exists("target.domain") && (exists("log.domainName") && !oneOf("log.domainName",["","-","N/A"])) + - rename: + from: [log.srcdomainname] + to: origin.domain + where: true && !exists("origin.domain") && (exists("log.srcdomainname") && !oneOf("log.srcdomainname",["","-","N/A"])) + - rename: + from: [log.dstdomainname] + to: target.domain + where: true && !exists("target.domain") && (exists("log.dstdomainname") && !oneOf("log.dstdomainname",["","-","N/A"])) + - rename: + from: [log.server] + to: target.host + where: true && !exists("target.host") && (exists("log.server") && !oneOf("log.server",["","-","N/A"])) + - rename: + from: [log.filename] + to: target.file + where: true && !exists("target.file") && (exists("log.filename") && !oneOf("log.filename",["","-","N/A"])) + - rename: + from: [log.filepath] + to: target.path + where: true && !exists("target.path") && (exists("log.filepath") && !oneOf("log.filepath",["","-","N/A"])) + - rename: + from: [log.fileSize] + to: target.sizeInBytes + where: regexMatch("log.fileSize","^[0-9]+$") && !exists("target.sizeInBytes") && (exists("log.fileSize") && + !oneOf("log.fileSize",["","-","N/A"])) + - rename: + from: [log.filesize] + to: target.sizeInBytes + where: regexMatch("log.filesize","^[0-9]+$") && !exists("target.sizeInBytes") && (exists("log.filesize") && + !oneOf("log.filesize",["","-","N/A"])) + - rename: + from: [log.sha1sum] + to: target.sha1 + where: regexMatch("log.sha1sum","^[a-fA-F0-9]{40}$") && !exists("target.sha1") && (exists("log.sha1sum") && + !oneOf("log.sha1sum",["","-","N/A"])) + - rename: + from: [log.contentType] + to: target.mimeType + where: true && !exists("target.mimeType") && (exists("log.contentType") && !oneOf("log.contentType",["","-","N/A"])) + - rename: + from: [log.fromemailaddress] + to: origin.email + where: true && !exists("origin.email") && (exists("log.fromemailaddress") && !oneOf("log.fromemailaddress",["","-","N/A"])) + - rename: + from: [log.toemailaddress] + to: target.email + where: true && !exists("target.email") && (exists("log.toemailaddress") && !oneOf("log.toemailaddress",["","-","N/A"])) + - rename: + from: [log.emailsubject] + to: target.emailSubject + where: true && !exists("target.emailSubject") && (exists("log.emailsubject") && !oneOf("log.emailsubject",["","-","N/A"])) + - rename: + from: [log.ftpcommand] + to: origin.command + where: true && !exists("origin.command") && (exists("log.ftpcommand") && !oneOf("log.ftpcommand",["","-","N/A"])) + - rename: + from: [log.url] + to: target.url + where: regexMatch("log.url","^[A-Za-z][A-Za-z0-9+.-]*://") && !exists("target.url") && (exists("log.url") + && !oneOf("log.url",["","-","N/A"])) + - rename: + from: [log.FTPurl] + to: target.url + where: regexMatch("log.FTPurl","^[A-Za-z][A-Za-z0-9+.-]*://") && !exists("target.url") && (exists("log.FTPurl") + && !oneOf("log.FTPurl",["","-","N/A"])) + - rename: + from: [log.srcport] + to: origin.port + where: true && !exists("origin.port") && regexMatch("log.srcport","^[0-9]+$") && greaterOrEqual("log.srcport",0) + && lessOrEqual("log.srcport",65535) + - cast: + fields: [origin.port] + to: int + where: exists("origin.port") + - rename: + from: [log.dstport] + to: target.port + where: true && !exists("target.port") && regexMatch("log.dstport","^[0-9]+$") && greaterOrEqual("log.dstport",0) + && lessOrEqual("log.dstport",65535) + - cast: + fields: [target.port] + to: int + where: exists("target.port") + - rename: + from: [log.statusCode] + to: statusCode + where: true && !exists("statusCode") && regexMatch("log.statusCode","^[0-9]+$") && greaterOrEqual("log.statusCode",100) + && lessOrEqual("log.statusCode",599) + - cast: + fields: [statusCode] + to: int + where: exists("statusCode") + - rename: + from: [log.httpstatus] + to: statusCode + where: true && !exists("statusCode") && regexMatch("log.httpstatus","^[0-9]+$") && greaterOrEqual("log.httpstatus",100) + && lessOrEqual("log.httpstatus",599) + - cast: + fields: [statusCode] + to: int + where: exists("statusCode") + - rename: + from: [log.responsecode] + to: statusCode + where: true && !exists("statusCode") && regexMatch("log.responsecode","^[0-9]+$") && greaterOrEqual("log.responsecode",100) + && lessOrEqual("log.responsecode",599) + - cast: + fields: [statusCode] + to: int + where: exists("statusCode") + - rename: + from: [log.httpresponsecode] + to: statusCode + where: true && !exists("statusCode") && regexMatch("log.httpresponsecode","^[0-9]+$") && greaterOrEqual("log.httpresponsecode",100) + && lessOrEqual("log.httpresponsecode",599) + - cast: + fields: [statusCode] + to: int + where: exists("statusCode") + - rename: + from: [log.bytessent] + to: origin.bytesReceived + where: equals("log.type","WAF") && !exists("origin.bytesReceived") && regexMatch("log.bytessent","^[0-9]+$") + && greaterOrEqual("log.bytessent",0) && lessOrEqual("log.bytessent",9007199254740991) + - cast: + fields: [origin.bytesReceived] + to: float + where: exists("origin.bytesReceived") + - rename: + from: [log.bytesrcv] + to: origin.bytesSent + where: equals("log.type","WAF") && !exists("origin.bytesSent") && regexMatch("log.bytesrcv","^[0-9]+$") && + greaterOrEqual("log.bytesrcv",0) && lessOrEqual("log.bytesrcv",9007199254740991) + - cast: + fields: [origin.bytesSent] + to: float + where: exists("origin.bytesSent") + - rename: + from: [log.bytessent] + to: origin.bytesReceived + where: equals("log.type","WAF") && !exists("origin.bytesReceived") && regexMatch("log.bytessent","^[0-9]+$") + && greaterOrEqual("log.bytessent",0) && lessOrEqual("log.bytessent",9007199254740991) + - cast: + fields: [origin.bytesReceived] + to: float + where: exists("origin.bytesReceived") + - rename: + from: [log.bytesreceived] + to: origin.bytesSent + where: equals("log.type","WAF") && !exists("origin.bytesSent") && regexMatch("log.bytesreceived","^[0-9]+$") + && greaterOrEqual("log.bytesreceived",0) && lessOrEqual("log.bytesreceived",9007199254740991) + - cast: + fields: [origin.bytesSent] + to: float + where: exists("origin.bytesSent") + - rename: + from: [log.sentbytes] + to: origin.bytesSent + where: '!equals("log.type","WAF") && !exists("origin.bytesSent") && regexMatch("log.sentbytes","^[0-9]+$") + && greaterOrEqual("log.sentbytes",0) && lessOrEqual("log.sentbytes",9007199254740991)' + - cast: + fields: [origin.bytesSent] + to: float + where: exists("origin.bytesSent") + - rename: + from: [log.recvbytes] + to: origin.bytesReceived + where: '!equals("log.type","WAF") && !exists("origin.bytesReceived") && regexMatch("log.recvbytes","^[0-9]+$") + && greaterOrEqual("log.recvbytes",0) && lessOrEqual("log.recvbytes",9007199254740991)' + - cast: + fields: [origin.bytesReceived] + to: float + where: exists("origin.bytesReceived") + - rename: + from: [log.bytessent] + to: origin.bytesSent + where: '!equals("log.type","WAF") && !exists("origin.bytesSent") && regexMatch("log.bytessent","^[0-9]+$") + && greaterOrEqual("log.bytessent",0) && lessOrEqual("log.bytessent",9007199254740991)' + - cast: + fields: [origin.bytesSent] + to: float + where: exists("origin.bytesSent") + - rename: + from: [log.bytesreceived] + to: origin.bytesReceived + where: '!equals("log.type","WAF") && !exists("origin.bytesReceived") && regexMatch("log.bytesreceived","^[0-9]+$") + && greaterOrEqual("log.bytesreceived",0) && lessOrEqual("log.bytesreceived",9007199254740991)' + - cast: + fields: [origin.bytesReceived] + to: float + where: exists("origin.bytesReceived") + - rename: + from: [log.bytesrecv] + to: origin.bytesReceived + where: '!equals("log.type","WAF") && !exists("origin.bytesReceived") && regexMatch("log.bytesrecv","^[0-9]+$") + && greaterOrEqual("log.bytesrecv",0) && lessOrEqual("log.bytesrecv",9007199254740991)' + - cast: + fields: [origin.bytesReceived] + to: float + where: exists("origin.bytesReceived") + - rename: + from: [log.sentpkts] + to: origin.packagesSent + where: '!equals("log.type","WAF") && !exists("origin.packagesSent") && regexMatch("log.sentpkts","^[0-9]+$") + && greaterOrEqual("log.sentpkts",0) && lessOrEqual("log.sentpkts",9007199254740991)' + - cast: + fields: [origin.packagesSent] + to: int + where: exists("origin.packagesSent") + - rename: + from: [log.recvpkts] + to: origin.packagesReceived + where: '!equals("log.type","WAF") && !exists("origin.packagesReceived") && regexMatch("log.recvpkts","^[0-9]+$") + && greaterOrEqual("log.recvpkts",0) && lessOrEqual("log.recvpkts",9007199254740991)' + - cast: + fields: [origin.packagesReceived] + to: int + where: exists("origin.packagesReceived") + - rename: + from: [log.packetssent] + to: origin.packagesSent + where: '!equals("log.type","WAF") && !exists("origin.packagesSent") && regexMatch("log.packetssent","^[0-9]+$") + && greaterOrEqual("log.packetssent",0) && lessOrEqual("log.packetssent",9007199254740991)' + - cast: + fields: [origin.packagesSent] + to: int + where: exists("origin.packagesSent") + - rename: + from: [log.packetsreceived] + to: origin.packagesReceived + where: '!equals("log.type","WAF") && !exists("origin.packagesReceived") && regexMatch("log.packetsreceived","^[0-9]+$") + && greaterOrEqual("log.packetsreceived",0) && lessOrEqual("log.packetsreceived",9007199254740991)' + - cast: + fields: [origin.packagesReceived] + to: int + where: exists("origin.packagesReceived") + - rename: + from: [log.protocol] + to: protocol + where: true && !exists("protocol") && (exists("log.protocol") && !oneOf("log.protocol",["","-","N/A"])) + - rename: + from: [log.wsprotocol] + to: protocol + where: true && !exists("protocol") && (exists("log.wsprotocol") && !oneOf("log.wsprotocol",["","-","N/A"])) + - add: + function: string + params: + key: protocol + value: ICMP + where: equals("protocol",1) + - add: + function: string + params: + key: protocol + value: TCP + where: equals("protocol",6) + - add: + function: string + params: + key: protocol + value: UDP + where: equals("protocol",17) + - add: + function: string + params: + key: protocol + value: GRE + where: equals("protocol",47) + - add: + function: string + params: + key: protocol + value: ESP + where: equals("protocol",50) + - add: + function: string + params: + key: protocol + value: AH + where: equals("protocol",51) + - add: + function: string + params: + key: protocol + value: ICMPV6 + where: equals("protocol",58) + - add: + function: string + params: + key: protocol + value: SCTP + where: equals("protocol",132) + - rename: + from: [protocol] + to: log.ipProtocolNumber + where: exists("protocol") && greaterOrEqual("protocol",0) + - grok: + source: log.timesTamp + patterns: + - {fieldName: log.sophosISO, pattern: '(?s:.*)'} + where: exists("log.timesTamp") && (regexMatch("log.timesTamp","^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9:.]+(Z|[+-][0-9]{2}:?[0-9]{2})$")) + - reformat: + fields: [log.sophosISO] + function: time + fromFormat: 2006-01-02T15:04:05Z07:00 + toFormat: 2006-01-02T15:04:05Z07:00 + where: exists("log.sophosISO") && regexMatch("log.sophosISO","(Z|[+-][0-9]{2}:[0-9]{2})$") + - reformat: + fields: [log.sophosISO] + function: time + fromFormat: 2006-01-02T15:04:05-0700 + toFormat: 2006-01-02T15:04:05Z07:00 + where: exists("log.sophosISO") && regexMatch("log.sophosISO","[+-][0-9]{4}$") + - rename: + from: [log.sophosISO] + to: deviceTime + where: regexMatch("log.sophosISO","(Z|[+-][0-9]{2}:[0-9]{2})$") + - grok: + source: log.sophosBody + patterns: + - {fieldName: '', pattern: '^(?:"(?:\\.|[^"\\])*"|[^"])*?(?:^|\s)'} + - {fieldName: log.sophosClock, pattern: 'date=[0-9]{4}-[0-9]{2}-[0-9]{2}\s+time=[0-9]{2}:[0-9]{2}:[0-9]{2}\s+timezone="(?:[+-][0-9]{2}(?::?[0-9]{2})?|GMT|UTC)"'} + - {fieldName: '', pattern: '(?:\s|$)'} + where: '!exists("deviceTime")' + - reformat: + fields: [log.sophosClock] + function: time + fromFormat: date=2006-01-02 time=15:04:05 timezone="-07" + toFormat: 2006-01-02T15:04:05Z07:00 + where: exists("log.sophosClock") && startsWith("log.sophosClock","date=") && regexMatch("log.sophosClock","timezone=\"[+-][0-9]{2}\"$") + - reformat: + fields: [log.sophosClock] + function: time + fromFormat: date=2006-01-02 time=15:04:05 timezone="-0700" + toFormat: 2006-01-02T15:04:05Z07:00 + where: exists("log.sophosClock") && startsWith("log.sophosClock","date=") && regexMatch("log.sophosClock","timezone=\"[+-][0-9]{4}\"$") + - reformat: + fields: [log.sophosClock] + function: time + fromFormat: date=2006-01-02 time=15:04:05 timezone="-07:00" + toFormat: 2006-01-02T15:04:05Z07:00 + where: exists("log.sophosClock") && startsWith("log.sophosClock","date=") && regexMatch("log.sophosClock","timezone=\"[+-][0-9]{2}:[0-9]{2}\"$") + - reformat: + fields: [log.sophosClock] + function: time + fromFormat: date=2006-01-02 time=15:04:05 timezone="GMT" + toFormat: 2006-01-02T15:04:05Z07:00 + where: exists("log.sophosClock") && startsWith("log.sophosClock","date=") && regexMatch("log.sophosClock","timezone=\"GMT\"$") + - reformat: + fields: [log.sophosClock] + function: time + fromFormat: date=2006-01-02 time=15:04:05 timezone="UTC" + toFormat: 2006-01-02T15:04:05Z07:00 + where: exists("log.sophosClock") && startsWith("log.sophosClock","date=") && regexMatch("log.sophosClock","timezone=\"UTC\"$") + - rename: + from: [log.sophosClock] + to: deviceTime + where: regexMatch("log.sophosClock","^[0-9]{4}-[0-9]{2}-[0-9]{2}T") && !exists("deviceTime") + - add: + function: string + params: + key: actionResult + value: denied + where: regexMatch("log.subType","(?i)^(deny|denied|block|blocked|drop|dropped)$") || regexMatch("log.status","(?i)^(deny|denied|block|blocked|drop|dropped|reject|rejected)$") + || regexMatch("log.spamaction","(?i)^(drop|reject|rejected|tmpreject|quarantine|sandstorm block)$") || (equals("log.type","WAF") + && oneOf("log.reason",["waf","cookie","url hardening","form hardening","av","geoip","dnsrbl"])) + - add: + function: string + params: + key: actionResult + value: failure + where: '!exists("actionResult") && regexMatch("log.status","(?i)^(failed|failure|error)$")' + - add: + function: string + params: + key: actionResult + value: denied + where: '!exists("actionResult") && oneOf("statusCode",[401,403])' + - add: + function: string + params: + key: actionResult + value: failure + where: '!exists("actionResult") && greaterOrEqual("statusCode",400) && lessThan("statusCode",600)' + - add: + function: string + params: + key: actionResult + value: success + where: '!exists("actionResult") && (regexMatch("log.status","(?i)^(allow|allowed|accept|accepted|successful|success|established)$") + || regexMatch("log.subType","(?i)^(allowed|accepted)$") || (greaterOrEqual("statusCode",200) && lessThan("statusCode",400)))' + - add: + function: string + params: + key: connectionStatus + value: established + where: equalsIgnoreCase("log.status","Established") + - add: + function: string + params: + key: connectionStatus + value: closed + where: equalsIgnoreCase("log.status","Terminated") + - rename: + from: [log.method] + to: action + where: equals("log.type","WAF") && !exists("action") && (exists("log.method") && !oneOf("log.method",["","-","N/A"])) + - add: + function: string + params: + key: severity + value: critical + where: oneOf("log.severity",["Emergency", "Alert", "Critical"]) || (!exists("log.severity") && oneOf("log.priority",["Emergency", + "Alert", "Critical"])) + - add: + function: string + params: + key: severity + value: error + where: oneOf("log.severity",["Error"]) || (!exists("log.severity") && oneOf("log.priority",["Error"])) + - add: + function: string + params: + key: severity + value: warning + where: oneOf("log.severity",["Warning"]) || (!exists("log.severity") && oneOf("log.priority",["Warning"])) + - add: + function: string + params: + key: severity + value: info + where: oneOf("log.severity",["Information", "Informational", "Notice", "Notification"]) || (!exists("log.severity") + && oneOf("log.priority",["Information", "Informational", "Notice", "Notification"])) + - add: + function: string + params: + key: severity + value: debug + where: oneOf("log.severity",["Debug"]) || (!exists("log.severity") && oneOf("log.priority",["Debug"])) + - dynamic: + plugin: com.utmstack.geolocation + params: + source: origin.ip + destination: origin.geolocation + where: exists("origin.ip") + - dynamic: + plugin: com.utmstack.geolocation + params: + source: target.ip + destination: target.geolocation + where: exists("target.ip") + - delete: + fields: [log.sophosBody, log.sophosClock, log.sophosISO, log.correlationCandidate, log.sophosScope] + - grok: + source: log.deviceId + patterns: + - {fieldName: log.sophosScope, pattern: '(?s:.+)'} + where: '!exists("log.sophosScope") && exists("log.deviceId") && !equals("log.deviceId","") && !oneOf("log.deviceId",["unknown","-"])' + - grok: + source: log.deviceserialid + patterns: + - {fieldName: log.sophosScope, pattern: '(?s:.+)'} + where: '!exists("log.sophosScope") && exists("log.deviceserialid") && !equals("log.deviceserialid","") && + !oneOf("log.deviceserialid",["unknown","-"])' + - grok: + source: dataSource + patterns: + - {fieldName: log.sophosScope, pattern: '(?s:.+)'} + where: '!exists("log.sophosScope") && exists("dataSource") && !equals("dataSource","") && !oneOf("dataSource",["unknown","-"])' + - add: + function: string + params: + key: log.correlationCandidate.sophosXG.atp + value: match + where: (equals("log.type","ATP") && oneOf("log.component",["Firewall","DNS","IPS","Web"]) && oneOf("log.subType",["Alert","Drop"]) + && ((exists("log.malware") && !equals("log.malware","")) || (exists("log.threatname") && !equals("log.threatname","")))) + && exists("origin.ip") && exists("dataSource") && !equals("dataSource","") && exists("log.sophosScope") + && !equals("log.sophosScope","") + - add: + function: string + params: + key: log.correlationCandidate.sophosXG.adminFailure + value: match + where: (equals("log.type","Event") && (oneOf("log.component",["GUI","CLI","API"]) && equals("log.subType","Admin") + && equals("log.messageId","17507") && equals("actionResult","failure"))) && exists("origin.ip") && exists("dataSource") + && !equals("dataSource","") && exists("log.sophosScope") && !equals("log.sophosScope","") + - add: + function: string + params: + key: log.correlationCandidate.sophosXG.ips + value: match + where: (equals("log.type","IDP") && oneOf("log.component",["Signatures","Anomaly"]) && oneOf("log.subType",["Detect","Drop"]) + && (oneOf("log.rulepriority",["1","2"]) || oneOf("log.severity",["Critical","High"])) && exists("origin.ip") + && exists("target.ip")) && exists("origin.ip") && exists("dataSource") && !equals("dataSource","") && exists("log.sophosScope") + && !equals("log.sophosScope","") + - add: + function: string + params: + key: log.correlationCandidate.sophosXG.vpnFailure + value: match + where: (equals("log.type","Event") && equals("log.subType","Authentication") && oneOf("log.component",["SSL + VPN Authentication","VPN Authentication","VPN Portal Authentication"]) && equals("actionResult","failure")) + && exists("origin.ip") && exists("dataSource") && !equals("dataSource","") && exists("log.sophosScope") + && !equals("log.sophosScope","") diff --git a/plugins/alerts/sophos_central_contract_test.go b/plugins/alerts/sophos_central_contract_test.go new file mode 100644 index 000000000..98994d5cf --- /dev/null +++ b/plugins/alerts/sophos_central_contract_test.go @@ -0,0 +1,453 @@ +package main + +// Offline Sophos Central JSON extraction model, not the closed EventProcessor. +// Explicit YAML JSON, grok, rename, add and delete steps are +// modeled. CEL, Event serialization, placeholder expansion, query creation and +// history thresholds use SDK v1.1.31. External geolocation is not executed. +import ( + "bytes" + "encoding/json" + "fmt" + "net" + "os" + "path/filepath" + "reflect" + "regexp" + "strings" + "testing" + "text/template" + "time" + + "github.com/threatwinds/go-sdk/plugins" + "github.com/threatwinds/go-sdk/utils" + "github.com/tidwall/gjson" + "google.golang.org/protobuf/encoding/protojson" +) + +type sophosCentralFixture struct { + Name string `json:"name"` + DataSource string `json:"dataSource"` + Raw string `json:"raw"` + Expected map[string]any `json:"expected"` + Absent []string `json:"absent"` + Matches []string `json:"matches"` +} + +func sophosCentralPut(m map[string]any, path string, value any, remove bool) { + p := strings.Split(path, ".") + for _, k := range p[:len(p)-1] { + n, ok := m[k].(map[string]any) + if !ok { + if remove { + return + } + n = map[string]any{} + m[k] = n + } + m = n + } + if remove { + delete(m, p[len(p)-1]) + } else { + m[p[len(p)-1]] = value + } +} +func sophosCentralGet(m map[string]any, p string) (any, bool) { + b, err := json.Marshal(m) + if err != nil { + return nil, false + } + v := gjson.GetBytes(b, p) + return v.Value(), v.Exists() +} +func sophosCentralConfig(t *testing.T) *plugins.Config { + t.Helper() + b, e := utils.ReadPbYaml("../../filters/sophos/sophos_central.yml") + if e != nil { + t.Fatal(e) + } + c := new(plugins.Config) + if e = protojson.Unmarshal(b, c); e != nil { + t.Fatal(e) + } + return c +} +func sophosCentralRegex(t *testing.T, g *plugins.Grok, cfg *plugins.Config) *regexp.Regexp { + t.Helper() + var pattern strings.Builder + for i, p := range g.Patterns { + if p.FieldName != "" { + fmt.Fprintf(&pattern, "(?P%s)", i, p.Pattern) + } else { + pattern.WriteString("(?:" + p.Pattern + ")") + } + } + pats := map[string]string{"greedy": ".*", "data": ".*?", "word": "[A-Za-z0-9_-]+", "space": "\\s+"} + for k, v := range cfg.Patterns { + pats[k] = v + } + tmpl, e := template.New("grok").Option("missingkey=error").Parse(pattern.String()) + if e != nil { + t.Fatal(e) + } + var b bytes.Buffer + if e = tmpl.Execute(&b, pats); e != nil { + t.Fatal(e) + } + r, e := regexp.Compile(b.String()) + if e != nil { + t.Fatal(e) + } + return r +} +func sophosCentralParse(t *testing.T, cfg *plugins.Config, raw string, dataSource string, cache *plugins.CELCache) string { + t.Helper() + draft := map[string]any{"raw": raw, "dataType": "sophos-central", "dataSource": dataSource, "log": map[string]any{}} + for _, stage := range cfg.Pipeline { + matched := false + for _, dataType := range stage.DataTypes { + if dataType == "sophos-central" { + matched = true + } + } + if !matched { + continue + } + for _, s := range stage.Steps { + b, e := protojson.Marshal(s) + if e != nil { + t.Fatal(e) + } + var step map[string]map[string]any + if e = json.Unmarshal(b, &step); e != nil { + t.Fatal(e) + } + for kind, body := range step { + if w, ok := body["where"].(string); ok && w != "" { + snapshot, err := json.Marshal(draft) + if err != nil { + t.Fatal(err) + } + match, e := cache.Eval(w, string(snapshot)) + if e != nil { + t.Fatal(e) + } + if !match { + continue + } + } + switch kind { + case "grok": + g := s.Grok + src := g.Source + if src == "" { + src = "raw" + } + v, ok := sophosCentralGet(draft, src) + if !ok { + continue + } + str, ok := v.(string) + if !ok { + t.Fatalf("non-string grok source %s", src) + } + r := sophosCentralRegex(t, g, cfg) + m := r.FindStringSubmatch(str) + if m == nil { + continue + } + for i, p := range g.Patterns { + if p.FieldName != "" { + sophosCentralPut(draft, p.FieldName, m[r.SubexpIndex(fmt.Sprintf("f%d", i))], false) + } + } + case "rename": + for _, p := range s.Rename.From { + if v, ok := sophosCentralGet(draft, p); ok { + sophosCentralPut(draft, s.Rename.To, v, false) + sophosCentralPut(draft, p, nil, true) + break + } + } + case "trim": + for _, p := range s.Trim.Fields { + if v, ok := sophosCentralGet(draft, p); ok { + str, ok := v.(string) + if !ok { + continue + } + switch s.Trim.Function { + case "prefix": + str = strings.TrimPrefix(str, s.Trim.Substring) + case "suffix": + str = strings.TrimSuffix(str, s.Trim.Substring) + default: + t.Fatalf("unsupported trim %s", s.Trim.Function) + } + sophosCentralPut(draft, p, str, false) + } + } + case "add": + if s.Add.Function != "string" { + t.Fatalf("unsupported add function %s", s.Add.Function) + } + sophosCentralPut(draft, s.Add.Params["key"].GetStringValue(), s.Add.Params["value"].AsInterface(), false) + case "delete": + for _, p := range s.Delete.Fields { + sophosCentralPut(draft, p, nil, true) + } + case "kv": + v, ok := sophosCentralGet(draft, s.Kv.Source) + if !ok { + continue + } + // Observed KV output splits quoted multiword values. + // Explicit YAML grok steps rebuild consumed fields afterward. + for _, item := range strings.Split(v.(string), s.Kv.FieldSplit) { + pair := strings.SplitN(item, s.Kv.ValueSplit, 2) + if len(pair) != 2 { + continue + } + key := pair[0] + utils.SanitizeField(&key) + if key != "" { + sophosCentralPut(draft, "log."+key, pair[1], false) + } + } + case "dynamic": + if s.Dynamic.Plugin != "com.utmstack.geolocation" { + t.Fatalf("unsupported dynamic plugin %s", s.Dynamic.Plugin) + } + field := s.Dynamic.Params["source"].GetStringValue() + v, ok := sophosCentralGet(draft, field) + if !ok { + t.Fatalf("missing dynamic source %s", field) + } + ip := net.ParseIP(fmt.Sprint(v)) + if ip == nil || ip.IsUnspecified() { + t.Fatalf("invalid address reaches geolocation: %s", field) + } + // The external geolocation service is not executed. + case "json": + source, ok := sophosCentralGet(draft, s.Json.Source) + if !ok { + continue + } + str, ok := source.(string) + if !ok { + t.Fatalf("JSON source is not a string") + } + var parsed map[string]any + if e := json.Unmarshal([]byte(str), &parsed); e != nil { + t.Fatal(e) + } + for key, value := range sophosCentralSanitizeJSON(parsed) { + sophosCentralPut(draft, "log."+key, value, false) + } + case "reformat": + for _, field := range s.Reformat.Fields { + value, ok := sophosCentralGet(draft, field) + if !ok { + continue + } + stamp, err := time.Parse(s.Reformat.FromFormat, fmt.Sprint(value)) + if err != nil { + t.Fatalf("time conversion %s: %v", field, err) + } + sophosCentralPut(draft, field, stamp.Format(s.Reformat.ToFormat), false) + } + case "cast": + for _, field := range s.Cast.Fields { + if value, ok := sophosCentralGet(draft, field); ok { + switch s.Cast.To { + case "string": + sophosCentralPut(draft, field, utils.CastString(value), false) + case "float": + sophosCentralPut(draft, field, utils.CastFloat64(value), false) + case "int": + sophosCentralPut(draft, field, utils.CastInt64(value), false) + default: + t.Fatalf("unsupported cast %s", s.Cast.To) + } + } + } + case "drop": + return "" + default: + t.Fatalf("unsupported filter step %s", kind) + } + } + } + } + b, e := json.Marshal(draft) + if e != nil { + t.Fatal(e) + } + in := string(b) + ev := new(plugins.Event) + if e = protojson.Unmarshal([]byte(in), ev); e != nil { + t.Fatal(e) + } + out, e := utils.ProtoMessageToString(ev) + if e != nil { + t.Fatal(e) + } + return *out +} +func sophosCentralRules(t *testing.T) map[string]*plugins.Rule { + t.Helper() + paths, e := filepath.Glob("../../rules/sophos/sophos_central/*.yml") + if e != nil { + t.Fatal(e) + } + out := map[string]*plugins.Rule{} + for _, p := range paths { + b, e := utils.ReadPbYaml(p) + if e != nil { + t.Fatal(e) + } + r := new(plugins.Rule) + if e = protojson.Unmarshal(b, r); e != nil { + t.Fatal(e) + } + r.Normalize() + out[strings.TrimSuffix(filepath.Base(p), ".yml")] = r + } + return out +} + +func sophosCentralSanitizeJSON(input map[string]any) map[string]any { + out := map[string]any{} + for key, value := range input { + utils.SanitizeField(&key) + if nested, ok := value.(map[string]any); ok { + value = sophosCentralSanitizeJSON(nested) + } + out[key] = value + } + return out +} + +func sophosCentralFixtures(t *testing.T) []sophosCentralFixture { + t.Helper() + b, e := os.ReadFile("testdata/sophos_central_raw.json") + if e != nil { + t.Fatal(e) + } + var cases []sophosCentralFixture + if e = json.Unmarshal(b, &cases); e != nil { + t.Fatal(e) + } + return cases +} + +func sophosCentralCheck(t *testing.T, fixtures []sophosCentralFixture) { + cfg, rules, cache := sophosCentralConfig(t), sophosCentralRules(t), plugins.NewCELCache("sophos_central") + if len(rules) != 20 { + t.Fatalf("rules: %d", len(rules)) + } + coverage := map[string]int{} + for _, f := range fixtures { + for _, name := range f.Matches { + coverage[name]++ + } + } + if len(fixtures) > 45 { + for name := range rules { + if coverage[name] == 0 || coverage[name] == len(fixtures) { + t.Fatalf("missing positive/negative coverage for %s", name) + } + } + } + for _, f := range fixtures { + t.Run(f.Name, func(t *testing.T) { + out := sophosCentralParse(t, cfg, f.Raw, f.DataSource, cache) + for field, want := range f.Expected { + got := gjson.Get(out, field) + if !got.Exists() || !reflect.DeepEqual(got.Value(), want) { + t.Errorf("%s got %v want %v", field, got.Value(), want) + } + } + for _, field := range f.Absent { + if gjson.Get(out, field).Exists() { + t.Errorf("unexpected %s", field) + } + } + if gjson.Get(out, "raw").String() != f.Raw { + t.Error("raw changed") + } + expect := map[string]bool{} + for _, n := range f.Matches { + expect[n] = true + } + for name, r := range rules { + matched, err := cache.Eval(r.Where, out) + if err != nil { + t.Fatal(err) + } + if matched != expect[name] { + t.Errorf("%s matched %v want %v", name, matched, expect[name]) + } + if !matched { + continue + } + event := new(plugins.Event) + if err := protojson.Unmarshal([]byte(out), event); err != nil { + t.Fatal(err) + } + alert := &plugins.Alert{Events: []*plugins.Event{event}} + switch r.Adversary { + case "origin": + alert.Adversary, alert.Target = event.Origin, event.Target + case "target": + alert.Adversary, alert.Target = event.Target, event.Origin + default: + t.Fatalf("unsupported adversary %s", r.Adversary) + } + if event.Target != nil && (alert.Target == nil || alert.Target.Host != event.Target.Host || alert.Target.Ip != event.Target.Ip) { + t.Error("managed endpoint must remain alert target") + } + if event.Origin != nil && (alert.Adversary == nil || alert.Adversary.Ip != event.Origin.Ip) { + t.Error("explicit outbound CryptoGuard initiator must remain adversary") + } + wire, err := utils.ProtoMessageToString(alert) + if err != nil { + t.Fatal(err) + } + for _, field := range r.GroupBy { + path := strings.Replace(field, "lastEvent.", "events.0.", 1) + if (field == "lastEvent.dataSource") && !gjson.Get(*wire, path).Exists() { + t.Errorf("grouping scope missing: %s", field) + } + } + for _, search := range r.Correlation { + for _, term := range search.With { + v := term.Value.GetStringValue() + if strings.HasPrefix(v, "{{.") { + field := strings.TrimSuffix(strings.TrimPrefix(v, "{{."), "}}") + if !gjson.Get(out, field).Exists() { + t.Errorf("unresolved %s", field) + } + } + } + } + } + }) + } +} +func TestSophosCentralRawContracts(t *testing.T) { sophosCentralCheck(t, sophosCentralFixtures(t)) } +func TestSophosCentralPrivateContracts(t *testing.T) { + path := os.Getenv("SOPHOS_CENTRAL_PRIVATE_FIXTURES") + if path == "" { + t.Skip("private fixtures not supplied") + } + b, e := os.ReadFile(path) + if e != nil { + t.Fatal(e) + } + var f []sophosCentralFixture + if e = json.Unmarshal(b, &f); e != nil { + t.Fatal(e) + } + sophosCentralCheck(t, f) +} diff --git a/plugins/alerts/sophos_central_history_test.go b/plugins/alerts/sophos_central_history_test.go new file mode 100644 index 000000000..5916b0ccc --- /dev/null +++ b/plugins/alerts/sophos_central_history_test.go @@ -0,0 +1,213 @@ +package main + +// SDK history contracts for synthetic SophosCentral events. Extraction uses the +// documented offline model in sophos-central_contract_test.go; all search requests, +// placeholder expansion, mapping lookup and count decisions use the pinned SDK. +// The HTTP server below is loopback-only and never queries a customer instance. +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "strings" + "testing" + "time" + + sdkos "github.com/threatwinds/go-sdk/os" + "github.com/threatwinds/go-sdk/plugins" + "github.com/tidwall/gjson" +) + +func TestSophosCentralSDKHistory(t *testing.T) { + // The SDK owns a process-wide OpenSearch singleton. Isolate this local mock + // so other technology tests can initialize their own clients in this suite. + if os.Getenv("UTM_SOPHOS_CENTRAL_HISTORY_CHILD") != "1" { + command := exec.Command(os.Args[0], "-test.run=^TestSophosCentralSDKHistory$") + command.Env = append(os.Environ(), "UTM_SOPHOS_CENTRAL_HISTORY_CHILD=1") + if out, e := command.CombinedOutput(); e != nil { + t.Fatalf("isolated history test: %v\n%s", e, out) + } + return + } + + cfg, rules, cache := sophosCentralConfig(t), sophosCentralRules(t), plugins.NewCELCache("sophos-central-history") + var history []string + var expectedClauses int + 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") { + // Text fields exercise the SDK's .keyword mapping resolution; IP and + // keyword fields exercise exact mappings without that suffix. + _, _ = io.WriteString(w, `{"v11-log-sophos-central-test": {"mappings": {"properties": {"@timestamp": {"type": "date"}, "dataSource": {"type": "text", "fields": {"keyword": {"type": "keyword"}}}, "log": {"properties": {"sophosCentralScope": {"type": "keyword"}, "endpointId": {"type": "text", "fields": {"keyword": {"type": "keyword"}}}, "ip": {"type": "ip"}, "severity": {"type": "keyword"}, "correlationCandidate": {"properties": {"sophosCentral": {"properties": {"behavior": {"type": "keyword"}, "exploit": {"type": "keyword"}, "mtr": {"type": "keyword"}, "ztnaFailure": {"type": "keyword"}}}}}}}}}}}`) + return + } + if r.URL.Path != "/v11-log-sophos-central-*/_search" { + t.Errorf("unexpected path %s", r.URL.Path) + http.Error(w, "unsupported request", http.StatusBadRequest) + return + } + b, e := io.ReadAll(r.Body) + if e != nil { + t.Error(e) + return + } + query := string(b) + clauses := append(gjson.Get(query, "query.bool.must").Array(), gjson.Get(query, "query.bool.filter").Array()...) + if len(clauses) != expectedClauses { + t.Errorf("history clauses: got %d want %d: %s", len(clauses), expectedClauses, query) + } + hits := []map[string]any{} + for _, doc := range history { + yes := true + for _, clause := range clauses { + if term := clause.Get("term"); term.Exists() { + for field, v := range term.Map() { + value := gjson.Get(doc, strings.TrimSuffix(field, ".keyword")) + if !value.Exists() || value.String() != v.Get("value").String() { + yes = false + } + } + } else if span := clause.Get("range"); span.Exists() { + for field, limits := range span.Map() { + stamp, e := time.Parse(time.RFC3339Nano, gjson.Get(doc, field).String()) + if e != nil { + t.Error(e) + } + cutoff, e := time.Parse(time.RFC3339Nano, limits.Get("gte").String()) + if e != nil { + t.Error(e) + } + if stamp.Before(cutoff) { + yes = false + } + } + } else { + t.Errorf("unsupported clause %s", clause.Raw) + yes = false + } + } + if yes { + hits = append(hits, map[string]any{"_id": fmt.Sprint(len(hits)), "_index": "v11-log-sophos-central-test", "_source": map[string]any{}}) + } + } + _ = json.NewEncoder(w).Encode(map[string]any{"took": 1, "hits": map[string]any{"total": map[string]any{"value": len(hits), "relation": "eq"}, "hits": hits}}) + })) + defer server.Close() + if e := sdkos.Connect([]string{server.URL}, "", ""); e != nil { + t.Fatal(e) + } + mutate := func(doc, field string, value any) string { + var m map[string]any + if e := json.Unmarshal([]byte(doc), &m); e != nil { + t.Fatal(e) + } + sophosCentralPut(m, field, value, value == nil) + b, e := json.Marshal(m) + if e != nil { + t.Fatal(e) + } + return string(b) + } + + // All fixture names refer to fabricated documentation-shaped raw logs. + // Require each named case so a missing fixture cannot silently skip a rule. + fixtures := map[string]sophosCentralFixture{} + for _, fixture := range sophosCentralFixtures(t) { + fixtures[fixture.Name] = fixture + } + + cases := []struct { + name, marker, benign string + count uint64 + within string + }{ + {"behavioral_analysis_alerts", "behavior", "normal-update", 3, "30m"}, + {"exploit_prevention_triggers", "exploit", "normal-update", 2, "30m"}, + {"managed_threat_response_alerts", "mtr", "benign-critical-event", 3, "1h"}, + {"sophos_central_possible_brute_force_attack", "ztnaFailure", "normal-update", 10, "5m"}, + {"sophos_central_potential_password_spraying_attack", "ztnaFailure", "normal-update", 10, "1m"}, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + fixture, ok := fixtures["positive-"+c.name] + if !ok { + t.Fatal("missing positive fixture") + } + rule := rules[c.name] + if rule == nil || len(rule.Correlation) != 1 { + t.Fatal("missing history") + } + search := rule.Correlation[0] + if search.Count != c.count || search.Within != c.within { + t.Fatal("threshold changed") + } + expectedClauses = len(search.With) + 1 + out := sophosCentralParse(t, cfg, fixture.Raw, fixture.DataSource, cache) + marker := "log.correlationCandidate.sophosCentral." + c.marker + if match, e := cache.Eval(rule.Where, out); e != nil || !match || gjson.Get(out, marker).String() != "match" { + t.Fatal("positive predicate/marker mismatch") + } + prior := mutate(out, "@timestamp", time.Now().Add(-10*time.Second).UTC().Format(time.RFC3339Nano)) + check := func(name, doc string, count uint64, want bool) { + t.Run(name, func(t *testing.T) { + history = nil + for i := uint64(0); i < count; i++ { + history = append(history, doc) + } + yes, _, err := search.Execute(&out) + if err != nil || yes != want { + t.Fatalf("history got %v want %v: %v", yes, want, err) + } + }) + } + check("below_threshold", prior, c.count-1, false) + check("at_threshold", prior, c.count, true) + duration, e := time.ParseDuration(c.within) + if e != nil { + t.Fatal(e) + } + check("expired", mutate(prior, "@timestamp", time.Now().Add(-duration-time.Minute).UTC().Format(time.RFC3339Nano)), c.count, false) + check("unmarked", mutate(prior, marker, nil), c.count, false) + for _, term := range search.With { + if !strings.HasPrefix(term.Value.GetStringValue(), "{{.") { + continue + } + field := term.Field + check("different_"+field, mutate(prior, field, "203.0.113.99"), c.count, false) + t.Run("missing_"+field, func(t *testing.T) { + missing := mutate(out, field, nil) + if match, e := cache.Eval(rule.Where, missing); e != nil || match { + t.Fatal("predicate allows unresolved identity") + } + if yes, _, e := search.Execute(&missing); e == nil || yes { + t.Fatal("expected SDK missing-placeholder error") + } + }) + } + benign, ok := fixtures[c.benign] + if !ok { + t.Fatal("missing noncandidate fixture") + } + normalized := sophosCentralParse(t, cfg, benign.Raw, fixture.DataSource, cache) + identity := "log.endpointId" + if c.marker == "ztnaFailure" { + identity = "log.ip" + } + if gjson.Get(normalized, identity).String() != gjson.Get(out, identity).String() { + t.Fatal("benign comparison must retain history identity") + } + if match, e := cache.Eval(rule.Where, normalized); e != nil || match || gjson.Get(normalized, marker).Exists() { + t.Fatal("noncandidate contributes marker") + } + if c.marker == "mtr" { + high := fixtures["MTR-high-candidate-not-critical-history"] + highOut := sophosCentralParse(t, cfg, high.Raw, fixture.DataSource, cache) + check("high_does_not_replace_critical_history", mutate(highOut, "@timestamp", time.Now().Add(-10*time.Second).UTC().Format(time.RFC3339Nano)), c.count, false) + } + check("benign_raw_history", mutate(normalized, "@timestamp", time.Now().Add(-10*time.Second).UTC().Format(time.RFC3339Nano)), c.count, false) + }) + } +} diff --git a/plugins/alerts/sophos_xg_contract_test.go b/plugins/alerts/sophos_xg_contract_test.go new file mode 100644 index 000000000..b93b93248 --- /dev/null +++ b/plugins/alerts/sophos_xg_contract_test.go @@ -0,0 +1,453 @@ +package main + +// Offline Sophos XG extraction model, not the closed EventProcessor. +// Explicit YAML grok/rename/cast/trim/add/delete and observed KV splitting are +// modeled. CEL, Event serialization, placeholder expansion, query creation and +// history thresholds use SDK v1.1.31. External geolocation is not executed. +import ( + "bytes" + "encoding/json" + "fmt" + "net" + "os" + "path/filepath" + "reflect" + "regexp" + "strings" + "testing" + "text/template" + "time" + + "github.com/threatwinds/go-sdk/plugins" + "github.com/threatwinds/go-sdk/utils" + "github.com/tidwall/gjson" + "google.golang.org/protobuf/encoding/protojson" +) + +type sophosXGFixture struct { + Name string `json:"name"` + DataSource string `json:"dataSource"` + Raw string `json:"raw"` + Expected map[string]any `json:"expected"` + Absent []string `json:"absent"` + Matches []string `json:"matches"` +} + +func sophosXGPut(m map[string]any, path string, value any, remove bool) { + p := strings.Split(path, ".") + for _, k := range p[:len(p)-1] { + n, ok := m[k].(map[string]any) + if !ok { + if remove { + return + } + n = map[string]any{} + m[k] = n + } + m = n + } + if remove { + delete(m, p[len(p)-1]) + } else { + m[p[len(p)-1]] = value + } +} +func sophosXGGet(m map[string]any, p string) (any, bool) { + var v any = m + for _, k := range strings.Split(p, ".") { + n, ok := v.(map[string]any) + if !ok { + return nil, false + } + v, ok = n[k] + if !ok { + return nil, false + } + } + return v, true +} +func sophosXGConfig(t *testing.T) *plugins.Config { + t.Helper() + b, e := utils.ReadPbYaml("../../filters/sophos/sophos_xg_firewall.yml") + if e != nil { + t.Fatal(e) + } + c := new(plugins.Config) + if e = protojson.Unmarshal(b, c); e != nil { + t.Fatal(e) + } + return c +} +func sophosXGRegex(t *testing.T, g *plugins.Grok, cfg *plugins.Config) *regexp.Regexp { + t.Helper() + var pattern strings.Builder + for i, p := range g.Patterns { + if p.FieldName != "" { + fmt.Fprintf(&pattern, "(?P%s)", i, p.Pattern) + } else { + pattern.WriteString("(?:" + p.Pattern + ")") + } + } + pats := map[string]string{"greedy": ".*", "data": ".*?", "word": "[A-Za-z0-9_-]+", "space": "\\s+"} + for k, v := range cfg.Patterns { + pats[k] = v + } + tmpl, e := template.New("grok").Option("missingkey=error").Parse(pattern.String()) + if e != nil { + t.Fatal(e) + } + var b bytes.Buffer + if e = tmpl.Execute(&b, pats); e != nil { + t.Fatal(e) + } + r, e := regexp.Compile(b.String()) + if e != nil { + t.Fatal(e) + } + return r +} +func sophosXGParse(t *testing.T, cfg *plugins.Config, raw string, dataSource string, cache *plugins.CELCache) string { + t.Helper() + draft := map[string]any{"raw": raw, "dataType": "firewall-sophos-xg", "dataSource": dataSource, "log": map[string]any{}} + for _, stage := range cfg.Pipeline { + matched := false + for _, dataType := range stage.DataTypes { + if dataType == "firewall-sophos-xg" { + matched = true + } + } + if !matched { + continue + } + for _, s := range stage.Steps { + b, e := protojson.Marshal(s) + if e != nil { + t.Fatal(e) + } + var step map[string]map[string]any + if e = json.Unmarshal(b, &step); e != nil { + t.Fatal(e) + } + for kind, body := range step { + if w, ok := body["where"].(string); ok && w != "" { + snapshot, err := json.Marshal(draft) + if err != nil { + t.Fatal(err) + } + match, e := cache.Eval(w, string(snapshot)) + if e != nil { + t.Fatal(e) + } + if !match { + continue + } + } + switch kind { + case "grok": + g := s.Grok + src := g.Source + if src == "" { + src = "raw" + } + v, ok := sophosXGGet(draft, src) + if !ok { + continue + } + str, ok := v.(string) + if !ok { + t.Fatalf("non-string grok source %s", src) + } + r := sophosXGRegex(t, g, cfg) + m := r.FindStringSubmatch(str) + if m == nil { + continue + } + for i, p := range g.Patterns { + if p.FieldName != "" { + sophosXGPut(draft, p.FieldName, m[r.SubexpIndex(fmt.Sprintf("f%d", i))], false) + } + } + case "rename": + for _, p := range s.Rename.From { + if v, ok := sophosXGGet(draft, p); ok { + sophosXGPut(draft, s.Rename.To, v, false) + sophosXGPut(draft, p, nil, true) + break + } + } + case "trim": + for _, p := range s.Trim.Fields { + if v, ok := sophosXGGet(draft, p); ok { + str, ok := v.(string) + if !ok { + continue + } + switch s.Trim.Function { + case "prefix": + str = strings.TrimPrefix(str, s.Trim.Substring) + case "suffix": + str = strings.TrimSuffix(str, s.Trim.Substring) + default: + t.Fatalf("unsupported trim %s", s.Trim.Function) + } + sophosXGPut(draft, p, str, false) + } + } + case "add": + if s.Add.Function != "string" { + t.Fatalf("unsupported add function %s", s.Add.Function) + } + sophosXGPut(draft, s.Add.Params["key"].GetStringValue(), s.Add.Params["value"].AsInterface(), false) + case "delete": + for _, p := range s.Delete.Fields { + sophosXGPut(draft, p, nil, true) + } + case "kv": + v, ok := sophosXGGet(draft, s.Kv.Source) + if !ok { + continue + } + // Observed KV output splits quoted multiword values. + // Explicit YAML grok steps rebuild consumed fields afterward. + for _, item := range strings.Split(v.(string), s.Kv.FieldSplit) { + pair := strings.SplitN(item, s.Kv.ValueSplit, 2) + if len(pair) != 2 { + continue + } + key := pair[0] + utils.SanitizeField(&key) + if key != "" { + sophosXGPut(draft, "log."+key, pair[1], false) + } + } + case "dynamic": + if s.Dynamic.Plugin != "com.utmstack.geolocation" { + t.Fatalf("unsupported dynamic plugin %s", s.Dynamic.Plugin) + } + field := s.Dynamic.Params["source"].GetStringValue() + v, ok := sophosXGGet(draft, field) + if !ok { + t.Fatalf("missing dynamic source %s", field) + } + ip := net.ParseIP(fmt.Sprint(v)) + if ip == nil || ip.IsUnspecified() { + t.Fatalf("invalid address reaches geolocation: %s", field) + } + // The external geolocation service is not executed. + case "json": + source, ok := sophosXGGet(draft, s.Json.Source) + if !ok { + continue + } + str, ok := source.(string) + if !ok { + t.Fatalf("JSON source is not a string") + } + var parsed map[string]any + if e := json.Unmarshal([]byte(str), &parsed); e != nil { + t.Fatal(e) + } + for key, value := range sophosXGSanitizeJSON(parsed) { + sophosXGPut(draft, "log."+key, value, false) + } + case "reformat": + for _, field := range s.Reformat.Fields { + value, ok := sophosXGGet(draft, field) + if !ok { + continue + } + stamp, err := time.Parse(s.Reformat.FromFormat, fmt.Sprint(value)) + if err != nil { + t.Fatalf("time conversion %s: %v", field, err) + } + sophosXGPut(draft, field, stamp.Format(s.Reformat.ToFormat), false) + } + case "cast": + for _, field := range s.Cast.Fields { + if value, ok := sophosXGGet(draft, field); ok { + switch s.Cast.To { + case "string": + sophosXGPut(draft, field, utils.CastString(value), false) + case "float": + sophosXGPut(draft, field, utils.CastFloat64(value), false) + case "int": + sophosXGPut(draft, field, utils.CastInt64(value), false) + default: + t.Fatalf("unsupported cast %s", s.Cast.To) + } + } + } + case "drop": + return "" + default: + t.Fatalf("unsupported filter step %s", kind) + } + } + } + } + b, e := json.Marshal(draft) + if e != nil { + t.Fatal(e) + } + in := string(b) + ev := new(plugins.Event) + if e = protojson.Unmarshal([]byte(in), ev); e != nil { + t.Fatal(e) + } + out, e := utils.ProtoMessageToString(ev) + if e != nil { + t.Fatal(e) + } + return *out +} +func sophosXGRules(t *testing.T) map[string]*plugins.Rule { + t.Helper() + paths, e := filepath.Glob("../../rules/sophos/sophos_xg_firewall/*.yml") + if e != nil { + t.Fatal(e) + } + out := map[string]*plugins.Rule{} + for _, p := range paths { + b, e := utils.ReadPbYaml(p) + if e != nil { + t.Fatal(e) + } + r := new(plugins.Rule) + if e = protojson.Unmarshal(b, r); e != nil { + t.Fatal(e) + } + r.Normalize() + out[strings.TrimSuffix(filepath.Base(p), ".yml")] = r + } + return out +} + +func sophosXGSanitizeJSON(input map[string]any) map[string]any { + out := map[string]any{} + for key, value := range input { + utils.SanitizeField(&key) + if nested, ok := value.(map[string]any); ok { + value = sophosXGSanitizeJSON(nested) + } + out[key] = value + } + return out +} + +func sophosXGFixtures(t *testing.T) []sophosXGFixture { + t.Helper() + b, e := os.ReadFile("testdata/sophos_xg_raw.json") + if e != nil { + t.Fatal(e) + } + var cases []sophosXGFixture + if e = json.Unmarshal(b, &cases); e != nil { + t.Fatal(e) + } + return cases +} + +func sophosXGCheck(t *testing.T, fixtures []sophosXGFixture) { + cfg, rules, cache := sophosXGConfig(t), sophosXGRules(t), plugins.NewCELCache("sophos_xg") + if len(rules) != 9 { + t.Fatalf("rules: %d", len(rules)) + } + coverage := map[string]int{} + for _, f := range fixtures { + for _, name := range f.Matches { + coverage[name]++ + } + } + if len(fixtures) > 60 { + for name := range rules { + if coverage[name] == 0 || coverage[name] == len(fixtures) { + t.Fatalf("missing positive/negative coverage for %s", name) + } + } + } + for _, f := range fixtures { + t.Run(f.Name, func(t *testing.T) { + out := sophosXGParse(t, cfg, f.Raw, f.DataSource, cache) + for field, want := range f.Expected { + got := gjson.Get(out, field) + if !got.Exists() || !reflect.DeepEqual(got.Value(), want) { + t.Errorf("%s got %v want %v", field, got.Value(), want) + } + } + for _, field := range f.Absent { + if gjson.Get(out, field).Exists() { + t.Errorf("unexpected %s", field) + } + } + if gjson.Get(out, "raw").String() != f.Raw { + t.Error("raw changed") + } + expect := map[string]bool{} + for _, n := range f.Matches { + expect[n] = true + } + for name, r := range rules { + matched, err := cache.Eval(r.Where, out) + if err != nil { + t.Fatal(err) + } + if matched != expect[name] { + t.Errorf("%s matched %v want %v", name, matched, expect[name]) + } + if !matched { + continue + } + event := new(plugins.Event) + if err := protojson.Unmarshal([]byte(out), event); err != nil { + t.Fatal(err) + } + alert := &plugins.Alert{Events: []*plugins.Event{event}} + switch r.Adversary { + case "origin": + alert.Adversary, alert.Target = event.Origin, event.Target + case "target": + alert.Adversary, alert.Target = event.Target, event.Origin + default: + t.Fatalf("unsupported adversary %s", r.Adversary) + } + wire, err := utils.ProtoMessageToString(alert) + if err != nil { + t.Fatal(err) + } + for _, field := range r.GroupBy { + path := strings.Replace(field, "lastEvent.", "events.0.", 1) + if (field == "lastEvent.dataSource" || field == "lastEvent.log.sophosScope") && !gjson.Get(*wire, path).Exists() { + t.Errorf("grouping scope missing: %s", field) + } + } + for _, search := range r.Correlation { + for _, term := range search.With { + v := term.Value.GetStringValue() + if strings.HasPrefix(v, "{{.") { + field := strings.TrimSuffix(strings.TrimPrefix(v, "{{."), "}}") + if !gjson.Get(out, field).Exists() { + t.Errorf("unresolved %s", field) + } + } + } + } + } + }) + } +} +func TestSophosXGRawContracts(t *testing.T) { sophosXGCheck(t, sophosXGFixtures(t)) } +func TestSophosXGPrivateContracts(t *testing.T) { + path := os.Getenv("SOPHOS_XG_PRIVATE_FIXTURES") + if path == "" { + t.Skip("private fixtures not supplied") + } + b, e := os.ReadFile(path) + if e != nil { + t.Fatal(e) + } + var f []sophosXGFixture + if e = json.Unmarshal(b, &f); e != nil { + t.Fatal(e) + } + sophosXGCheck(t, f) +} diff --git a/plugins/alerts/sophos_xg_history_test.go b/plugins/alerts/sophos_xg_history_test.go new file mode 100644 index 000000000..c250c3a25 --- /dev/null +++ b/plugins/alerts/sophos_xg_history_test.go @@ -0,0 +1,203 @@ +package main + +// SDK history contracts for synthetic SophosXG events. Extraction uses the +// documented offline model in sophos-xg_contract_test.go; all search requests, +// placeholder expansion, mapping lookup and count decisions use the pinned SDK. +// The HTTP server below is loopback-only and never queries a customer instance. +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "strings" + "testing" + "time" + + sdkos "github.com/threatwinds/go-sdk/os" + "github.com/threatwinds/go-sdk/plugins" + "github.com/tidwall/gjson" +) + +func TestSophosXGSDKHistory(t *testing.T) { + // The SDK owns a process-wide OpenSearch singleton. Isolate this local mock + // so other technology tests can initialize their own clients in this suite. + if os.Getenv("UTM_SOPHOS_XG_HISTORY_CHILD") != "1" { + command := exec.Command(os.Args[0], "-test.run=^TestSophosXGSDKHistory$") + command.Env = append(os.Environ(), "UTM_SOPHOS_XG_HISTORY_CHILD=1") + if out, e := command.CombinedOutput(); e != nil { + t.Fatalf("isolated history test: %v\n%s", e, out) + } + return + } + + cfg, rules, cache := sophosXGConfig(t), sophosXGRules(t), plugins.NewCELCache("sophos-xg-history") + var history []string + var expectedClauses int + 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") { + // Text fields exercise the SDK's .keyword mapping resolution; IP and + // keyword fields exercise exact mappings without that suffix. + _, _ = io.WriteString(w, `{"v11-log-firewall-sophos-xg-test": {"mappings": {"properties": {"@timestamp": {"type": "date"}, "dataSource": {"type": "text", "fields": {"keyword": {"type": "keyword"}}}, "origin": {"properties": {"ip": {"type": "ip"}}}, "target": {"properties": {"ip": {"type": "ip"}}}, "log": {"properties": {"sophosScope": {"type": "keyword"}, "correlationCandidate": {"properties": {"sophosXG": {"properties": {"atp": {"type": "keyword"}, "adminFailure": {"type": "keyword"}, "ips": {"type": "keyword"}, "vpnFailure": {"type": "keyword"}}}}}}}}}}}`) + return + } + if r.URL.Path != "/v11-log-firewall-sophos-xg-*/_search" { + t.Errorf("unexpected path %s", r.URL.Path) + http.Error(w, "unsupported request", http.StatusBadRequest) + return + } + b, e := io.ReadAll(r.Body) + if e != nil { + t.Error(e) + return + } + query := string(b) + clauses := append(gjson.Get(query, "query.bool.must").Array(), gjson.Get(query, "query.bool.filter").Array()...) + if len(clauses) != expectedClauses { + t.Errorf("history clauses: got %d want %d: %s", len(clauses), expectedClauses, query) + } + hits := []map[string]any{} + for _, doc := range history { + yes := true + for _, clause := range clauses { + if term := clause.Get("term"); term.Exists() { + for field, v := range term.Map() { + value := gjson.Get(doc, strings.TrimSuffix(field, ".keyword")) + if !value.Exists() || value.String() != v.Get("value").String() { + yes = false + } + } + } else if span := clause.Get("range"); span.Exists() { + for field, limits := range span.Map() { + stamp, e := time.Parse(time.RFC3339Nano, gjson.Get(doc, field).String()) + if e != nil { + t.Error(e) + } + cutoff, e := time.Parse(time.RFC3339Nano, limits.Get("gte").String()) + if e != nil { + t.Error(e) + } + if stamp.Before(cutoff) { + yes = false + } + } + } else { + t.Errorf("unsupported clause %s", clause.Raw) + yes = false + } + } + if yes { + hits = append(hits, map[string]any{"_id": fmt.Sprint(len(hits)), "_index": "v11-log-firewall-sophos-xg-test", "_source": map[string]any{}}) + } + } + _ = json.NewEncoder(w).Encode(map[string]any{"took": 1, "hits": map[string]any{"total": map[string]any{"value": len(hits), "relation": "eq"}, "hits": hits}}) + })) + defer server.Close() + if e := sdkos.Connect([]string{server.URL}, "", ""); e != nil { + t.Fatal(e) + } + mutate := func(doc, field string, value any) string { + var m map[string]any + if e := json.Unmarshal([]byte(doc), &m); e != nil { + t.Fatal(e) + } + sophosXGPut(m, field, value, value == nil) + b, e := json.Marshal(m) + if e != nil { + t.Fatal(e) + } + return string(b) + } + + // All fixture names refer to fabricated documentation-shaped raw logs. + // Require each named case so a missing fixture cannot silently skip a rule. + fixtures := map[string]sophosXGFixture{} + for _, fixture := range sophosXGFixtures(t) { + fixtures[fixture.Name] = fixture + } + + cases := []struct { + name, marker, benign string + count uint64 + within string + }{ + {"advanced_threat_protection_alerts", "atp", "ATP-system-update-is-not-threat", 2, "30m"}, + {"sophos_password_guessing_on_administrator_account", "adminFailure", "successful-admin-login", 10, "15m"}, + {"sophos_xg_ips_signatures", "ips", "low-priority-IPS-does-not-trigger-high-threshold", 3, "15m"}, + {"sophos_xg_vpn_auth_failures", "vpnFailure", "successful-vpn-is-not-failure", 10, "15m"}, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + fixture, ok := fixtures["positive-"+c.name] + if !ok { + t.Fatal("missing positive fixture") + } + rule := rules[c.name] + if rule == nil || len(rule.Correlation) != 1 { + t.Fatal("missing history") + } + search := rule.Correlation[0] + if search.Count != c.count || search.Within != c.within { + t.Fatal("threshold changed") + } + expectedClauses = len(search.With) + 1 + out := sophosXGParse(t, cfg, fixture.Raw, fixture.DataSource, cache) + marker := "log.correlationCandidate.sophosXG." + c.marker + if match, e := cache.Eval(rule.Where, out); e != nil || !match || gjson.Get(out, marker).String() != "match" { + t.Fatal("positive predicate/marker mismatch") + } + prior := mutate(out, "@timestamp", time.Now().Add(-time.Minute).UTC().Format(time.RFC3339Nano)) + check := func(name, doc string, count uint64, want bool) { + t.Run(name, func(t *testing.T) { + history = nil + for i := uint64(0); i < count; i++ { + history = append(history, doc) + } + yes, _, err := search.Execute(&out) + if err != nil || yes != want { + t.Fatalf("history got %v want %v: %v", yes, want, err) + } + }) + } + check("below_threshold", prior, c.count-1, false) + check("at_threshold", prior, c.count, true) + duration, e := time.ParseDuration(c.within) + if e != nil { + t.Fatal(e) + } + check("expired", mutate(prior, "@timestamp", time.Now().Add(-duration-time.Minute).UTC().Format(time.RFC3339Nano)), c.count, false) + check("unmarked", mutate(prior, marker, nil), c.count, false) + for _, term := range search.With { + if !strings.HasPrefix(term.Value.GetStringValue(), "{{.") { + continue + } + field := term.Field + check("different_"+field, mutate(prior, field, "203.0.113.99"), c.count, false) + t.Run("missing_"+field, func(t *testing.T) { + missing := mutate(out, field, nil) + if match, e := cache.Eval(rule.Where, missing); e != nil || match { + t.Fatal("predicate allows unresolved identity") + } + if yes, _, e := search.Execute(&missing); e == nil || yes { + t.Fatal("expected SDK missing-placeholder error") + } + }) + } + benign, ok := fixtures[c.benign] + if !ok { + t.Fatal("missing noncandidate fixture") + } + normalized := sophosXGParse(t, cfg, benign.Raw, fixture.DataSource, cache) + if gjson.Get(normalized, "origin.ip").String() != gjson.Get(out, "origin.ip").String() { + t.Fatal("benign comparison must retain source address") + } + if match, e := cache.Eval(rule.Where, normalized); e != nil || match || gjson.Get(normalized, marker).Exists() { + t.Fatal("noncandidate contributes marker") + } + check("benign_raw_history", mutate(normalized, "@timestamp", time.Now().Add(-time.Minute).UTC().Format(time.RFC3339Nano)), c.count, false) + }) + } +} diff --git a/plugins/alerts/testdata/filter-contracts/sophos.json b/plugins/alerts/testdata/filter-contracts/sophos.json new file mode 100644 index 000000000..720037699 --- /dev/null +++ b/plugins/alerts/testdata/filter-contracts/sophos.json @@ -0,0 +1,75 @@ +{ + "technology": "Sophos", + "filters": [ + "filters/sophos/sophos_central.yml", + "filters/sophos/sophos_xg_firewall.yml" + ], + "rules": [ + "rules/sophos/sophos_central/behavioral_analysis_alerts.yml", + "rules/sophos/sophos_central/endpoint_threat_detection.yml", + "rules/sophos/sophos_central/exploit_prevention_triggers.yml", + "rules/sophos/sophos_central/managed_threat_response_alerts.yml", + "rules/sophos/sophos_central/ransomware_detection.yml", + "rules/sophos/sophos_central/server_protection_alerts.yml", + "rules/sophos/sophos_central/sophos_central_app_hijacking_prevented.yml", + "rules/sophos/sophos_central/sophos_central_credential_theft_attack_detected.yml", + "rules/sophos/sophos_central/sophos_central_device_compromised.yml", + "rules/sophos/sophos_central/sophos_central_endpoint_protection_unavailable.yml", + "rules/sophos/sophos_central/sophos_central_exploit_detected.yml", + "rules/sophos/sophos_central/sophos_central_malware_detected.yml", + "rules/sophos/sophos_central/sophos_central_man_in_the_middle_attack_detected.yml", + "rules/sophos/sophos_central/sophos_central_possible_botnet_detected.yml", + "rules/sophos/sophos_central/sophos_central_possible_brute_force_attack.yml", + "rules/sophos/sophos_central/sophos_central_potential_password_spraying_attack.yml", + "rules/sophos/sophos_central/sophos_central_ransomware_detected.yml", + "rules/sophos/sophos_central/sophos_central_real_time_protection_disabled.yml", + "rules/sophos/sophos_central/sophos_central_unknown_threat_detected.yml", + "rules/sophos/sophos_central/tamper_protection_alerts.yml", + "rules/sophos/sophos_xg_firewall/advanced_threat_protection_alerts.yml", + "rules/sophos/sophos_xg_firewall/sophos_denial_of_service.yml", + "rules/sophos/sophos_xg_firewall/sophos_firewall_probable_malware_detected.yml", + "rules/sophos/sophos_xg_firewall/sophos_high_severity_alerts.yml", + "rules/sophos/sophos_xg_firewall/sophos_initial_access_by_guest_account.yml", + "rules/sophos/sophos_xg_firewall/sophos_ip_spoofing_attack.yml", + "rules/sophos/sophos_xg_firewall/sophos_password_guessing_on_administrator_account.yml", + "rules/sophos/sophos_xg_firewall/sophos_xg_ips_signatures.yml", + "rules/sophos/sophos_xg_firewall/sophos_xg_vpn_auth_failures.yml" + ], + "fixtures": [ + { + "name": "sophos-central-peripheral-block-is-not-compromise", + "filter": "sophos/sophos_central.yml", + "input": { + "log": { + "type": "Event::Endpoint::Device::Blocked", + "group": "PERIPHERALS" + } + }, + "expected": { + "actionResult": "denied" + }, + "rules": { + "rules/sophos/sophos_central/sophos_central_device_compromised.yml": false + } + }, + { + "name": "sophos-central-cleanup-is-not-fresh-malware", + "filter": "sophos/sophos_central.yml", + "input": { + "log": { + "type": "Event::Endpoint::CoreClean", + "severity": "low" + } + }, + "expected": { + "severity": "info" + }, + "absent": [ + "actionResult" + ], + "rules": { + "rules/sophos/sophos_central/sophos_central_malware_detected.yml": false + } + } + ] +} diff --git a/plugins/alerts/testdata/sophos_central_raw.json b/plugins/alerts/testdata/sophos_central_raw.json new file mode 100644 index 000000000..3fbe6c6bd --- /dev/null +++ b/plugins/alerts/testdata/sophos_central_raw.json @@ -0,0 +1,1460 @@ +[ + { + "name": "positive-behavioral_analysis_alerts", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"high\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreBehavioralDetection\"}", + "expected": { + "log.type": "Event::Endpoint::CoreBehavioralDetection", + "action": "Event::Endpoint::CoreBehavioralDetection", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "error" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "behavioral_analysis_alerts" + ] + }, + { + "name": "positive-endpoint_threat_detection", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"PUA\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CorePuaDetection\"}", + "expected": { + "log.type": "Event::Endpoint::CorePuaDetection", + "action": "Event::Endpoint::CorePuaDetection", + "log.origin": "SAV", + "log.group": "PUA", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "endpoint_threat_detection" + ] + }, + { + "name": "positive-exploit_prevention_triggers", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::Threat::ExploitPrevented\"}", + "expected": { + "log.type": "Event::Endpoint::Threat::ExploitPrevented", + "action": "Event::Endpoint::Threat::ExploitPrevented", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "exploit_prevention_triggers" + ] + }, + { + "name": "positive-managed_threat_response_alerts", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"critical\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"mtr_alert\"}", + "expected": { + "log.type": "mtr_alert", + "action": "mtr_alert", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "critical" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "managed_threat_response_alerts" + ] + }, + { + "name": "positive-ransomware_detection", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::Threat::RansomwareDetected\"}", + "expected": { + "log.type": "Event::Endpoint::Threat::RansomwareDetected", + "action": "Event::Endpoint::Threat::RansomwareDetected", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "ransomware_detection" + ] + }, + { + "name": "positive-server_protection_alerts", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"server\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Server::Protection::Disabled\"}", + "expected": { + "log.type": "Event::Server::Protection::Disabled", + "action": "Event::Server::Protection::Disabled", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "server_protection_alerts" + ] + }, + { + "name": "positive-sophos_central_app_hijacking_prevented", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaApplicationHijacking\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaApplicationHijacking", + "action": "Event::Endpoint::HmpaApplicationHijacking", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_app_hijacking_prevented" + ] + }, + { + "name": "positive-sophos_central_credential_theft_attack_detected", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaCredTheft\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaCredTheft", + "action": "Event::Endpoint::HmpaCredTheft", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_credential_theft_attack_detected" + ] + }, + { + "name": "positive-sophos_central_device_compromised", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::UAV::PotentiallyCompromisedDevice\"}", + "expected": { + "log.type": "Event::UAV::PotentiallyCompromisedDevice", + "action": "Event::UAV::PotentiallyCompromisedDevice", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_device_compromised" + ] + }, + { + "name": "positive-sophos_central_exploit_detected", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaExploitPrevented\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaExploitPrevented", + "action": "Event::Endpoint::HmpaExploitPrevented", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_exploit_detected" + ] + }, + { + "name": "positive-sophos_central_malware_detected", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreDetection\", \"appSha256\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}", + "expected": { + "log.type": "Event::Endpoint::CoreDetection", + "action": "Event::Endpoint::CoreDetection", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_malware_detected" + ] + }, + { + "name": "positive-sophos_central_man_in_the_middle_attack_detected", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Smc::MitmAttackEvent\"}", + "expected": { + "log.type": "Event::Smc::MitmAttackEvent", + "action": "Event::Smc::MitmAttackEvent", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_man_in_the_middle_attack_detected" + ] + }, + { + "name": "positive-sophos_central_possible_botnet_detected", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Firewall::FirewallAdvancedThreatProtection\"}", + "expected": { + "log.type": "Event::Firewall::FirewallAdvancedThreatProtection", + "action": "Event::Firewall::FirewallAdvancedThreatProtection", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_possible_botnet_detected" + ] + }, + { + "name": "positive-sophos_central_possible_brute_force_attack", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::ZTNA::ZTNAAuthenticationFailure\"}", + "expected": { + "log.type": "Event::ZTNA::ZTNAAuthenticationFailure", + "action": "Event::ZTNA::ZTNAAuthenticationFailure", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_possible_brute_force_attack", + "sophos_central_potential_password_spraying_attack" + ] + }, + { + "name": "positive-sophos_central_potential_password_spraying_attack", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::ZTNA::ZTNAAuthenticationFailure\"}", + "expected": { + "log.type": "Event::ZTNA::ZTNAAuthenticationFailure", + "action": "Event::ZTNA::ZTNAAuthenticationFailure", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_possible_brute_force_attack", + "sophos_central_potential_password_spraying_attack" + ] + }, + { + "name": "positive-sophos_central_ransomware_detected", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaCryptoGuardSMB\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaCryptoGuardSMB", + "action": "Event::Endpoint::HmpaCryptoGuardSMB", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_ransomware_detected" + ] + }, + { + "name": "positive-sophos_central_real_time_protection_disabled", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::SavDisabled\"}", + "expected": { + "log.type": "Event::Endpoint::SavDisabled", + "action": "Event::Endpoint::SavDisabled", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_real_time_protection_disabled" + ] + }, + { + "name": "positive-sophos_central_unknown_threat_detected", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreIps\"}", + "expected": { + "log.type": "Event::Endpoint::CoreIps", + "action": "Event::Endpoint::CoreIps", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_unknown_threat_detected" + ] + }, + { + "name": "positive-tamper_protection_alerts", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"DEVICE_AND_PLATFORM_HEALTH\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::AccountHealthCheck::EndpointTamperProtectionRaise\"}", + "expected": { + "log.type": "Event::AccountHealthCheck::EndpointTamperProtectionRaise", + "action": "Event::AccountHealthCheck::EndpointTamperProtectionRaise", + "log.origin": "SAV", + "log.group": "DEVICE_AND_PLATFORM_HEALTH", + "severity": "warning" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "tamper_protection_alerts" + ] + }, + { + "name": "positive-sophos_central_endpoint_protection_unavailable", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"high\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"PROTECTION\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::NotProtected\"}", + "expected": { + "log.type": "Event::Endpoint::NotProtected", + "action": "Event::Endpoint::NotProtected", + "log.origin": "SAV", + "log.group": "PROTECTION", + "severity": "error" + }, + "absent": [ + "connectionStatus", + "origin.group", + "target.group" + ], + "matches": [ + "sophos_central_endpoint_protection_unavailable" + ] + }, + { + "name": "normal-update", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE", + "severity": "info", + "target.ip": "192.0.2.10", + "target.host": "endpoint.example.test", + "target.user": "EXAMPLE\\user", + "deviceTime": "2026-09-17T10:00:00.123Z" + }, + "absent": [ + "actionResult", + "connectionStatus", + "origin" + ], + "matches": [] + }, + { + "name": "source-IP-not-attacker", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreDetection\"}", + "expected": { + "log.type": "Event::Endpoint::CoreDetection", + "action": "Event::Endpoint::CoreDetection", + "log.origin": "SAV", + "log.group": "MALWARE", + "target.ip": "192.0.2.10", + "target.host": "endpoint.example.test" + }, + "absent": [ + "origin", + "actionResult" + ], + "matches": [ + "sophos_central_malware_detected" + ] + }, + { + "name": "outbound-CryptoGuard-initiator", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaCryptoGuardSMBOrigin\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaCryptoGuardSMBOrigin", + "action": "Event::Endpoint::HmpaCryptoGuardSMBOrigin", + "log.origin": "SAV", + "log.group": "MALWARE", + "origin.ip": "192.0.2.10", + "origin.host": "endpoint.example.test" + }, + "absent": [ + "target", + "actionResult" + ], + "matches": [ + "sophos_central_ransomware_detected" + ] + }, + { + "name": "local-CryptoGuard-affected-endpoint", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaCryptoGuard\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaCryptoGuard", + "action": "Event::Endpoint::HmpaCryptoGuard", + "log.origin": "SAV", + "log.group": "MALWARE", + "target.ip": "192.0.2.10" + }, + "absent": [ + "origin", + "actionResult" + ], + "matches": [ + "sophos_central_ransomware_detected" + ] + }, + { + "name": "lifecycle-CoreClean", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreClean\"}", + "expected": { + "log.type": "Event::Endpoint::CoreClean", + "action": "Event::Endpoint::CoreClean", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-CoreHmpaClean", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreHmpaClean\"}", + "expected": { + "log.type": "Event::Endpoint::CoreHmpaClean", + "action": "Event::Endpoint::CoreHmpaClean", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-CoreDismissed", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreDismissed\"}", + "expected": { + "log.type": "Event::Endpoint::CoreDismissed", + "action": "Event::Endpoint::CoreDismissed", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-CorePuaClean", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CorePuaClean\"}", + "expected": { + "log.type": "Event::Endpoint::CorePuaClean", + "action": "Event::Endpoint::CorePuaClean", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-CoreCleanCancelled", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreCleanCancelled\"}", + "expected": { + "log.type": "Event::Endpoint::CoreCleanCancelled", + "action": "Event::Endpoint::CoreCleanCancelled", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-HmpaCryptoGuardSMBResolved", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaCryptoGuardSMBResolved\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaCryptoGuardSMBResolved", + "action": "Event::Endpoint::HmpaCryptoGuardSMBResolved", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-HmpaCryptoGuardSMBOriginResolved", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaCryptoGuardSMBOriginResolved\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaCryptoGuardSMBOriginResolved", + "action": "Event::Endpoint::HmpaCryptoGuardSMBOriginResolved", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-CoreAmsiClean", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreAmsiClean\"}", + "expected": { + "log.type": "Event::Endpoint::CoreAmsiClean", + "action": "Event::Endpoint::CoreAmsiClean", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-CoreAmsiCleanedUp", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreAmsiCleanedUp\"}", + "expected": { + "log.type": "Event::Endpoint::CoreAmsiCleanedUp", + "action": "Event::Endpoint::CoreAmsiCleanedUp", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-CoreAmsiResolved", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreAmsiResolved\"}", + "expected": { + "log.type": "Event::Endpoint::CoreAmsiResolved", + "action": "Event::Endpoint::CoreAmsiResolved", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-HmpaMalwareCleanedUp", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaMalwareCleanedUp\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaMalwareCleanedUp", + "action": "Event::Endpoint::HmpaMalwareCleanedUp", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-Threat::Dismissed", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::Threat::Dismissed\"}", + "expected": { + "log.type": "Event::Endpoint::Threat::Dismissed", + "action": "Event::Endpoint::Threat::Dismissed", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-Threat::CleanedUp", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::Threat::CleanedUp\"}", + "expected": { + "log.type": "Event::Endpoint::Threat::CleanedUp", + "action": "Event::Endpoint::Threat::CleanedUp", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "lifecycle-HmpaCredResolved", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::HmpaCredResolved\"}", + "expected": { + "log.type": "Event::Endpoint::HmpaCredResolved", + "action": "Event::Endpoint::HmpaCredResolved", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "unresolved-CoreCleanFailed", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreCleanFailed\"}", + "expected": { + "log.type": "Event::Endpoint::CoreCleanFailed", + "action": "Event::Endpoint::CoreCleanFailed", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult" + ], + "matches": [ + "sophos_central_malware_detected" + ] + }, + { + "name": "unresolved-CoreHmpaCleanFailed", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreHmpaCleanFailed\"}", + "expected": { + "log.type": "Event::Endpoint::CoreHmpaCleanFailed", + "action": "Event::Endpoint::CoreHmpaCleanFailed", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult" + ], + "matches": [ + "sophos_central_malware_detected" + ] + }, + { + "name": "unresolved-AMSI", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreAmsiCleanFailed\"}", + "expected": { + "log.type": "Event::Endpoint::CoreAmsiCleanFailed", + "action": "Event::Endpoint::CoreAmsiCleanFailed", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [], + "matches": [ + "sophos_central_unknown_threat_detected" + ] + }, + { + "name": "peripheral-blocked-is-not-compromise", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"PERIPHERALS\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::Device::Blocked\"}", + "expected": { + "log.type": "Event::Endpoint::Device::Blocked", + "action": "Event::Endpoint::Device::Blocked", + "log.origin": "SAV", + "log.group": "PERIPHERALS", + "actionResult": "denied" + }, + "absent": [], + "matches": [] + }, + { + "name": "peripheral-read-only-is-not-compromise", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"PERIPHERALS\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::Device::ReadOnly\"}", + "expected": { + "log.type": "Event::Endpoint::Device::ReadOnly", + "action": "Event::Endpoint::Device::ReadOnly", + "log.origin": "SAV", + "log.group": "PERIPHERALS" + }, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "application-policy-block-is-not-malware", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"APPLICATION_CONTROL\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::Application::Blocked\"}", + "expected": { + "log.type": "Event::Endpoint::Application::Blocked", + "action": "Event::Endpoint::Application::Blocked", + "log.origin": "SAV", + "log.group": "APPLICATION_CONTROL", + "actionResult": "denied", + "target.host": "endpoint.example.test" + }, + "absent": [ + "target.ip", + "origin" + ], + "matches": [] + }, + { + "name": "application-detected-is-not-malware", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"APPLICATION_CONTROL\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::Application::Detected\"}", + "expected": { + "log.type": "Event::Endpoint::Application::Detected", + "action": "Event::Endpoint::Application::Detected", + "log.origin": "SAV", + "log.group": "APPLICATION_CONTROL" + }, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "web-prevention", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"WEB\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::WebFilteringBlocked\"}", + "expected": { + "log.type": "Event::Endpoint::WebFilteringBlocked", + "action": "Event::Endpoint::WebFilteringBlocked", + "log.origin": "SAV", + "log.group": "WEB", + "actionResult": "denied" + }, + "absent": [ + "connectionStatus" + ], + "matches": [] + }, + { + "name": "PUA-cleanup-failed", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"PUA\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CorePuaCleanFailed\", \"threat\": \"Restricted utility\"}", + "expected": { + "log.type": "Event::Endpoint::CorePuaCleanFailed", + "action": "Event::Endpoint::CorePuaCleanFailed", + "log.origin": "SAV", + "log.group": "PUA" + }, + "absent": [ + "target.malware" + ], + "matches": [ + "endpoint_threat_detection" + ] + }, + { + "name": "policy-blocklist-not-malware", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"BLOCKLISTED\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreBlocklistDetection\", \"threat\": \"Blocked by Administrator\"}", + "expected": { + "log.type": "Event::Endpoint::CoreBlocklistDetection", + "action": "Event::Endpoint::CoreBlocklistDetection", + "log.origin": "SAV", + "log.group": "BLOCKLISTED" + }, + "absent": [ + "target.malware", + "actionResult" + ], + "matches": [] + }, + { + "name": "account-EndpointTamperProtectionResolve", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::AccountHealthCheck::EndpointTamperProtectionResolve\"}", + "expected": { + "log.type": "Event::AccountHealthCheck::EndpointTamperProtectionResolve", + "action": "Event::AccountHealthCheck::EndpointTamperProtectionResolve", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [], + "matches": [] + }, + { + "name": "account-ServerTamperProtectionResolve", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::AccountHealthCheck::ServerTamperProtectionResolve\"}", + "expected": { + "log.type": "Event::AccountHealthCheck::ServerTamperProtectionResolve", + "action": "Event::AccountHealthCheck::ServerTamperProtectionResolve", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [], + "matches": [] + }, + { + "name": "account-server-tamper-warning", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::AccountHealthCheck::ServerTamperProtectionRaise\"}", + "expected": { + "log.type": "Event::AccountHealthCheck::ServerTamperProtectionRaise", + "action": "Event::AccountHealthCheck::ServerTamperProtectionRaise", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [], + "matches": [ + "tamper_protection_alerts" + ] + }, + { + "name": "protection-service-unavailable", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"high\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::ServiceNotRunning\"}", + "expected": { + "log.type": "Event::Endpoint::ServiceNotRunning", + "action": "Event::Endpoint::ServiceNotRunning", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [], + "matches": [ + "sophos_central_endpoint_protection_unavailable" + ] + }, + { + "name": "protection-low-severity", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::NotProtected\"}", + "expected": { + "log.type": "Event::Endpoint::NotProtected", + "action": "Event::Endpoint::NotProtected", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [], + "matches": [] + }, + { + "name": "IPv6-associated-endpoint", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"2001:db8::10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreDetection\"}", + "expected": { + "log.type": "Event::Endpoint::CoreDetection", + "action": "Event::Endpoint::CoreDetection", + "log.origin": "SAV", + "log.group": "MALWARE", + "target.ip": "2001:db8::10" + }, + "absent": [ + "origin" + ], + "matches": [ + "sophos_central_malware_detected" + ] + }, + { + "name": "invalid-IP-0.0.0.0", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"0.0.0.0\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.ip", + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-IP-::", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"::\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.ip", + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-IP-0:0:0:0:0:0:0:0", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"0:0:0:0:0:0:0:0\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.ip", + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-IP-::ffff:0.0.0.0", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"::ffff:0.0.0.0\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.ip", + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-IP-bad-ip", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"bad-ip\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.ip", + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-IP-999.1.1.1", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"999.1.1.1\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.ip", + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-IP-", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.ip", + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-IP-None", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": null}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.ip", + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-hash", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\", \"appSha256\": \"not-a-hash\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.sha256" + ], + "matches": [] + }, + { + "name": "valid-hash-and-malware", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreDetection\", \"appSha256\": \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\", \"threat\": \"Synthetic.Malware\"}", + "expected": { + "log.type": "Event::Endpoint::CoreDetection", + "action": "Event::Endpoint::CoreDetection", + "log.origin": "SAV", + "log.group": "MALWARE", + "target.sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "target.malware": "Synthetic.Malware" + }, + "absent": [], + "matches": [ + "sophos_central_malware_detected" + ] + }, + { + "name": "endpoint-missing-no-invented-side", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target", + "origin" + ], + "matches": [] + }, + { + "name": "non-string-source-fields", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": {\"name\": \"x\"}, \"source\": [\"x\"], \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": 17, \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\", \"appSha256\": 17}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "target.host", + "target.user", + "deviceTime", + "target.sha256" + ], + "matches": [] + }, + { + "name": "unknown-vendor-severity", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"urgent\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "severity" + ], + "matches": [] + }, + { + "name": "routine-firewall-status", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Firewall::FirewallVPNTunnelUp\"}", + "expected": { + "log.type": "Event::Firewall::FirewallVPNTunnelUp", + "action": "Event::Firewall::FirewallVPNTunnelUp", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "origin", + "target", + "actionResult", + "connectionStatus" + ], + "matches": [] + }, + { + "name": "admin-role-change-not-attack", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Other::AdminRoleChangedEvent\"}", + "expected": { + "log.type": "Event::Other::AdminRoleChangedEvent", + "action": "Event::Other::AdminRoleChangedEvent", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "origin", + "target", + "actionResult" + ], + "matches": [] + }, + { + "name": "spoofed-markers-cleared", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\", \"sophosCentralScope\": \"forged\", \"correlationCandidate\": {\"sophosCentral\": {\"behavior\": \"match\", \"exploit\": \"match\", \"mtr\": \"match\", \"ztnaFailure\": \"match\"}}}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE", + "log.sophosCentralScope": "tenant-fixture" + }, + "absent": [ + "log.correlationCandidate" + ], + "matches": [] + }, + { + "name": "null-account-fallback", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": null, \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE", + "log.sophosCentralScope": "fixture-collector" + }, + "absent": [], + "matches": [] + }, + { + "name": "behavior-IP-less-identified-endpoint", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"high\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreBehavioralDetection\"}", + "expected": { + "log.type": "Event::Endpoint::CoreBehavioralDetection", + "action": "Event::Endpoint::CoreBehavioralDetection", + "log.origin": "SAV", + "log.group": "MALWARE", + "target.host": "endpoint.example.test" + }, + "absent": [ + "target.ip" + ], + "matches": [ + "behavioral_analysis_alerts" + ] + }, + { + "name": "behavior-missing-endpoint", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"high\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreBehavioralDetection\"}", + "expected": { + "log.type": "Event::Endpoint::CoreBehavioralDetection", + "action": "Event::Endpoint::CoreBehavioralDetection", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "log.correlationCandidate.sophosCentral.behavior" + ], + "matches": [] + }, + { + "name": "history-missing-all-scope", + "dataSource": "", + "raw": "{\"customer_id\": null, \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"high\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreBehavioralDetection\"}", + "expected": { + "log.type": "Event::Endpoint::CoreBehavioralDetection", + "action": "Event::Endpoint::CoreBehavioralDetection", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "log.correlationCandidate.sophosCentral.behavior" + ], + "matches": [] + }, + { + "name": "ZTNA-IP-role-remains-vendor", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": null, \"endpoint_type\": null, \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::ZTNA::ZTNAAuthenticationFailure\"}", + "expected": { + "log.type": "Event::ZTNA::ZTNAAuthenticationFailure", + "action": "Event::ZTNA::ZTNAAuthenticationFailure", + "log.origin": "SAV", + "log.group": "MALWARE", + "log.ip": "192.0.2.10", + "actionResult": "failure" + }, + "absent": [ + "origin", + "target" + ], + "matches": [ + "sophos_central_possible_brute_force_attack", + "sophos_central_potential_password_spraying_attack" + ] + }, + { + "name": "ZTNA-missing-IP", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::ZTNA::ZTNAAuthenticationFailure\"}", + "expected": { + "log.type": "Event::ZTNA::ZTNAAuthenticationFailure", + "action": "Event::ZTNA::ZTNAAuthenticationFailure", + "log.origin": "SAV", + "log.group": "MALWARE", + "actionResult": "failure" + }, + "absent": [ + "log.correlationCandidate.sophosCentral.ztnaFailure" + ], + "matches": [] + }, + { + "name": "MTR-high-candidate-not-critical-history", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"high\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"mtr_alert\"}", + "expected": { + "log.type": "mtr_alert", + "action": "mtr_alert", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "log.correlationCandidate.sophosCentral.mtr" + ], + "matches": [ + "managed_threat_response_alerts" + ] + }, + { + "name": "benign-critical-event", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"critical\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::UpdateSuccess\"}", + "expected": { + "log.type": "Event::Endpoint::UpdateSuccess", + "action": "Event::Endpoint::UpdateSuccess", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "log.correlationCandidate.sophosCentral.mtr" + ], + "matches": [] + }, + { + "name": "legacy-generic-prevention-not-inferred", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"VendorCustomPreventedDetail\"}", + "expected": { + "log.type": "VendorCustomPreventedDetail", + "action": "VendorCustomPreventedDetail", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "authentication-lookalike-not-failure", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"VendorAuthenticationFailureResolved\"}", + "expected": { + "log.type": "VendorAuthenticationFailureResolved", + "action": "VendorAuthenticationFailureResolved", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "malware-prefix-lookalike", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"PrefixEvent::Endpoint::CoreDetection\"}", + "expected": { + "log.type": "PrefixEvent::Endpoint::CoreDetection", + "action": "PrefixEvent::Endpoint::CoreDetection", + "log.origin": "SAV", + "log.group": "MALWARE" + }, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "multiple-remedy-items-preserved", + "dataSource": "fixture-collector", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"medium\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreClean\", \"core_remedy_items\": {\"totalItems\": 2, \"items\": [{\"type\": \"file\", \"descriptor\": \"C:\\\\one.exe\", \"processPath\": \"\", \"result\": \"SUCCESS\"}, {\"type\": \"file\", \"descriptor\": \"C:\\\\two.exe\", \"result\": \"SUCCESS\"}]}}", + "expected": { + "log.type": "Event::Endpoint::CoreClean", + "action": "Event::Endpoint::CoreClean", + "log.origin": "SAV", + "log.group": "MALWARE", + "log.coreremedyItems.totalItems": 2 + }, + "absent": [ + "target.file", + "target.path", + "actionResult" + ], + "matches": [] + }, + { + "name": "single-windows-remedy", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreClean\", \"core_remedy_items\": {\"items\": [{\"type\": \"file\", \"descriptor\": \"C:\\\\samples\\\\test.exe\", \"result\": \"SUCCESS\"}], \"totalItems\": 1}}", + "dataSource": "fixture-collector", + "expected": { + "target.path": "C:\\samples\\", + "target.file": "test.exe" + }, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "single-posix-remedy", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreClean\", \"core_remedy_items\": {\"items\": [{\"type\": \"file\", \"descriptor\": \"/opt/samples/test.bin\", \"result\": \"SUCCESS\"}], \"totalItems\": 1}}", + "dataSource": "fixture-collector", + "expected": { + "target.path": "/opt/samples/", + "target.file": "test.bin" + }, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "archive-remedy-remains-vendor", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreClean\", \"core_remedy_items\": {\"items\": [{\"type\": \"file\", \"descriptor\": \"C:/samples/archive.cab/inner/test.exe\", \"result\": \"SUCCESS\"}], \"totalItems\": 1}}", + "dataSource": "fixture-collector", + "expected": {}, + "absent": [ + "actionResult", + "target.path", + "target.file" + ], + "matches": [] + }, + { + "name": "truncated-remedy-count-is-not-single", + "raw": "{\"customer_id\": \"tenant-fixture\", \"endpoint_id\": \"endpoint-fixture\", \"endpoint_type\": \"computer\", \"location\": \"endpoint.example.test\", \"source\": \"EXAMPLE\\\\user\", \"source_info\": {\"ip\": \"192.0.2.10\"}, \"severity\": \"low\", \"when\": \"2026-09-17T10:00:00.123Z\", \"created_at\": \"2026-09-17T10:01:00Z\", \"group\": \"MALWARE\", \"origin\": \"SAV\", \"name\": \"Synthetic vendor event\", \"type\": \"Event::Endpoint::CoreClean\", \"core_remedy_items\": {\"items\": [{\"type\": \"file\", \"descriptor\": \"C:/samples/test.exe\", \"result\": \"SUCCESS\"}], \"totalItems\": 2}}", + "dataSource": "fixture-collector", + "expected": {}, + "absent": [ + "actionResult", + "target.path", + "target.file" + ], + "matches": [] + } +] diff --git a/plugins/alerts/testdata/sophos_xg_raw.json b/plugins/alerts/testdata/sophos_xg_raw.json new file mode 100644 index 000000000..d44bb2a82 --- /dev/null +++ b/plugins/alerts/testdata/sophos_xg_raw.json @@ -0,0 +1,810 @@ +[ + { + "name": "denied-firewall", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": { + "actionResult": "denied", + "origin.ip": "198.51.100.10", + "target.ip": "192.0.2.10", + "origin.port": 12345, + "target.port": 443, + "deviceTime": "2026-08-02T10:11:12-03:00", + "severity": "info" + }, + "absent": [], + "matches": [] + }, + { + "name": "deny-subtype-Drop", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Drop\" status=\"\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\" status_code=\"200\"", + "expected": { + "actionResult": "denied", + "statusCode": 200 + }, + "absent": [], + "matches": [] + }, + { + "name": "deny-subtype-Dropped", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Dropped\" status=\"\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\" status_code=\"200\"", + "expected": { + "actionResult": "denied", + "statusCode": 200 + }, + "absent": [], + "matches": [] + }, + { + "name": "deny-subtype-Blocked", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Blocked\" status=\"\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\" status_code=\"200\"", + "expected": { + "actionResult": "denied", + "statusCode": 200 + }, + "absent": [], + "matches": [] + }, + { + "name": "deny-subtype-Denied", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\" status_code=\"200\"", + "expected": { + "actionResult": "denied", + "statusCode": 200 + }, + "absent": [], + "matches": [] + }, + { + "name": "http-200", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Content Filtering\" log_component=\"HTTP\" log_subtype=\"Allowed\" status_code=\"200\"", + "expected": { + "actionResult": "success", + "statusCode": 200 + }, + "absent": [], + "matches": [] + }, + { + "name": "http-302", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Content Filtering\" log_component=\"HTTP\" log_subtype=\"Allowed\" status_code=\"302\"", + "expected": { + "actionResult": "success", + "statusCode": 302 + }, + "absent": [], + "matches": [] + }, + { + "name": "http-401", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Content Filtering\" log_component=\"HTTP\" log_subtype=\"Allowed\" status_code=\"401\"", + "expected": { + "actionResult": "denied", + "statusCode": 401 + }, + "absent": [], + "matches": [] + }, + { + "name": "http-403", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Content Filtering\" log_component=\"HTTP\" log_subtype=\"Allowed\" status_code=\"403\"", + "expected": { + "actionResult": "denied", + "statusCode": 403 + }, + "absent": [], + "matches": [] + }, + { + "name": "http-404", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Content Filtering\" log_component=\"HTTP\" log_subtype=\"Allowed\" status_code=\"404\"", + "expected": { + "actionResult": "failure", + "statusCode": 404 + }, + "absent": [], + "matches": [] + }, + { + "name": "http-500", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Content Filtering\" log_component=\"HTTP\" log_subtype=\"Allowed\" status_code=\"500\"", + "expected": { + "actionResult": "failure", + "statusCode": 500 + }, + "absent": [], + "matches": [] + }, + { + "name": "waf-no-subtype", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"WAF\" log_component=\"Web Application Firewall\" sourceip=\"198.51.100.20\" localip=\"192.0.2.20\" server=\"web.example.test\" url=\"/login\" httpstatus=\"200\" reason=\"-\" bytessent=\"900\" bytesrcv=\"100\" ws_protocol=\"HTTP/1.1\" method=\"POST\"", + "expected": { + "log.type": "WAF", + "log.component": "Web Application Firewall", + "origin.ip": "198.51.100.20", + "target.ip": "192.0.2.20", + "target.host": "web.example.test", + "statusCode": 200, + "actionResult": "success", + "origin.bytesReceived": 900, + "origin.bytesSent": 100, + "protocol": "HTTP/1.1", + "action": "POST" + }, + "absent": [ + "target.url" + ], + "matches": [] + }, + { + "name": "waf-denied-block-page", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"WAF\" log_component=\"Web Application Firewall\" sourceip=\"198.51.100.20\" localip=\"-\" httpstatus=\"200\" reason=\"waf\"", + "expected": { + "actionResult": "denied" + }, + "absent": [ + "target.ip" + ], + "matches": [] + }, + { + "name": "smtp-rejection-wins", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Anti-Spam\" log_component=\"SMTP\" log_subtype=\"Allowed\" spamaction=\"REJECTED\" from_email_address=\"sender@example.test\" to_email_address=\"recipient@example.test\" email_subject=\"Quarterly report\"", + "expected": { + "actionResult": "denied", + "origin.email": "sender@example.test", + "target.email": "recipient@example.test", + "target.emailSubject": "Quarterly report" + }, + "absent": [], + "matches": [] + }, + { + "name": "allowed-is-not-established", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Allowed\" status=\"Allow\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": { + "actionResult": "success" + }, + "absent": [ + "connectionStatus" + ], + "matches": [] + }, + { + "name": "vpn-established", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"SSL VPN\" log_subtype=\"System\" ipaddress=\"192.0.2.1\" remote_ip=\"192.0.2.2\" status=\"Established\"", + "expected": { + "origin.ip": "192.0.2.1", + "target.ip": "192.0.2.2", + "actionResult": "success", + "connectionStatus": "established" + }, + "absent": [], + "matches": [] + }, + { + "name": "vpn-terminated", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"SSL VPN\" log_subtype=\"System\" status=\"Terminated\"", + "expected": { + "connectionStatus": "closed" + }, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "invalid-src_ip-hostname.example", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"hostname.example\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-src_ip--", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"-\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-src_ip-0.0.0.0", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"0.0.0.0\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-src_ip-::", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"::\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-src_ip-0:0:0:0:0:0:0:0", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"0:0:0:0:0:0:0:0\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-src_ip-::ffff:0.0.0.0", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"::ffff:0.0.0.0\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "invalid-dst_ip-hostname.example", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"hostname.example\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "target.ip" + ], + "matches": [] + }, + { + "name": "invalid-dst_ip--", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"-\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "target.ip" + ], + "matches": [] + }, + { + "name": "invalid-dst_ip-0.0.0.0", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"0.0.0.0\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "target.ip" + ], + "matches": [] + }, + { + "name": "invalid-dst_ip-::", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"::\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "target.ip" + ], + "matches": [] + }, + { + "name": "invalid-dst_ip-0:0:0:0:0:0:0:0", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"0:0:0:0:0:0:0:0\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "target.ip" + ], + "matches": [] + }, + { + "name": "invalid-dst_ip-::ffff:0.0.0.0", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"::ffff:0.0.0.0\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": {}, + "absent": [ + "target.ip" + ], + "matches": [] + }, + { + "name": "bad-port--1", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"-1\" dst_port=\"-1\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.port", + "target.port" + ], + "matches": [] + }, + { + "name": "bad-port-1.5", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"1.5\" dst_port=\"1.5\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.port", + "target.port" + ], + "matches": [] + }, + { + "name": "bad-port-65536", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"65536\" dst_port=\"65536\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.port", + "target.port" + ], + "matches": [] + }, + { + "name": "bad-port-invalid", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"invalid\" dst_port=\"invalid\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.port", + "target.port" + ], + "matches": [] + }, + { + "name": "bad-port-", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"\" dst_port=\"\" priority=\"Information\"", + "expected": {}, + "absent": [ + "origin.port", + "target.port" + ], + "matches": [] + }, + { + "name": "bad-http--1", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" status_code=\"-1\"", + "expected": {}, + "absent": [ + "statusCode", + "actionResult" + ], + "matches": [] + }, + { + "name": "bad-http-1.5", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" status_code=\"1.5\"", + "expected": {}, + "absent": [ + "statusCode", + "actionResult" + ], + "matches": [] + }, + { + "name": "bad-http-4294967296", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" status_code=\"4294967296\"", + "expected": {}, + "absent": [ + "statusCode", + "actionResult" + ], + "matches": [] + }, + { + "name": "bad-http-NaN", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" status_code=\"NaN\"", + "expected": {}, + "absent": [ + "statusCode", + "actionResult" + ], + "matches": [] + }, + { + "name": "bad-http-0", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" status_code=\"0\"", + "expected": {}, + "absent": [ + "statusCode", + "actionResult" + ], + "matches": [] + }, + { + "name": "quoted-text-is-not-fields", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" message=\"x src_ip=198.51.100.99 status=Allow log_type=ATP log_component=Firewall log_subtype=Drop threatname=evil\"", + "expected": { + "log.type": "Event", + "log.logMessage": "x src_ip=198.51.100.99 status=Allow log_type=ATP log_component=Firewall log_subtype=Drop threatname=evil" + }, + "absent": [ + "origin.ip", + "actionResult", + "log.component", + "log.subType", + "log.threatname" + ], + "matches": [] + }, + { + "name": "fields-reordered-with-final-key", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" status=\"Deny\" log_component=\"Invalid Traffic\" src_ip=\"2001:db8::1\" log_subtype=\"Denied\" log_type=\"Firewall\" dst_ip=\"2001:db8::2\"", + "expected": { + "log.type": "Firewall", + "origin.ip": "2001:db8::1", + "target.ip": "2001:db8::2", + "actionResult": "denied" + }, + "absent": [], + "matches": [] + }, + { + "name": "envelope-0", + "dataSource": "collector-A", + "raw": "device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": { + "actionResult": "denied", + "origin.ip": "198.51.100.10" + }, + "absent": [], + "matches": [] + }, + { + "name": "envelope-33", + "dataSource": "collector-A", + "raw": "Oct 18 04:46:59 firewall.example device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": { + "actionResult": "denied", + "origin.ip": "198.51.100.10" + }, + "absent": [], + "matches": [] + }, + { + "name": "envelope-54", + "dataSource": "collector-A", + "raw": "<30>1 2026-08-02T10:11:12Z firewall.example app 7 - - device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\"", + "expected": { + "actionResult": "denied", + "origin.ip": "198.51.100.10" + }, + "absent": [], + "matches": [] + }, + { + "name": "new-iso-timestamp", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" timestamp=\"2026-08-02T10:11:12-0400\" log_type=\"Firewall\" log_subtype=\"Drop\"", + "expected": { + "deviceTime": "2026-08-02T10:11:12-04:00", + "actionResult": "denied" + }, + "absent": [], + "matches": [] + }, + { + "name": "packet-counters-and-protocol", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"Firewall Rule\" log_subtype=\"Denied\" status=\"Deny\" src_ip=\"198.51.100.10\" dst_ip=\"192.0.2.10\" src_port=\"12345\" dst_port=\"443\" priority=\"Information\" sent_pkts=\"42\" recv_pkts=\"7\" sent_bytes=\"120\" recv_bytes=\"60\" protocol=\"6\"", + "expected": { + "origin.packagesSent": "42", + "origin.packagesReceived": "7", + "origin.bytesSent": 120, + "origin.bytesReceived": 60, + "protocol": "TCP" + }, + "absent": [], + "matches": [] + }, + { + "name": "positive-advanced_threat_protection_alerts", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"ATP\" log_component=\"Firewall\" log_subtype=\"Alert\" threatname=\"C2/Test\" sourceip=\"198.51.100.4\" destinationip=\"192.0.2.4\"", + "expected": {}, + "absent": [], + "matches": [ + "advanced_threat_protection_alerts" + ] + }, + { + "name": "positive-sophos_denial_of_service", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"DoS attacks\" log_subtype=\"DoS\" src_ip=\"198.51.100.4\" dst_ip=\"192.0.2.4\"", + "expected": {}, + "absent": [], + "matches": [ + "sophos_denial_of_service" + ] + }, + { + "name": "positive-sophos_firewall_probable_malware_detected", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Anti-Virus\" log_component=\"HTTPS\" log_subtype=\"Virus\" virus=\"Test-Malware\" src_ip=\"198.51.100.4\" dst_ip=\"192.0.2.4\"", + "expected": {}, + "absent": [], + "matches": [ + "sophos_firewall_probable_malware_detected" + ] + }, + { + "name": "positive-sophos_high_severity_alerts", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"Appliance\" priority=\"Critical\" message=\"Critical device event\"", + "expected": {}, + "absent": [], + "matches": [ + "sophos_high_severity_alerts" + ] + }, + { + "name": "positive-sophos_initial_access_by_guest_account", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"Guest User\" log_id=\"060011517925\"", + "expected": {}, + "absent": [], + "matches": [ + "sophos_initial_access_by_guest_account" + ] + }, + { + "name": "positive-sophos_ip_spoofing_attack", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Firewall\" log_component=\"IP Spoof\" log_subtype=\"Denied\" src_ip=\"198.51.100.4\" dst_ip=\"192.0.2.4\"", + "expected": {}, + "absent": [], + "matches": [ + "sophos_ip_spoofing_attack" + ] + }, + { + "name": "positive-sophos_password_guessing_on_administrator_account", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"GUI\" log_subtype=\"Admin\" log_id=\"062009517507\" status=\"Failed\" src_ip=\"198.51.100.4\" user_name=\"admin\"", + "expected": {}, + "absent": [], + "matches": [ + "sophos_password_guessing_on_administrator_account" + ] + }, + { + "name": "positive-sophos_xg_ips_signatures", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"IDP\" log_component=\"Signatures\" log_subtype=\"Drop\" rule_priority=\"1\" src_ip=\"198.51.100.4\" dst_ip=\"192.0.2.4\"", + "expected": {}, + "absent": [], + "matches": [ + "sophos_xg_ips_signatures" + ] + }, + { + "name": "positive-sophos_xg_vpn_auth_failures", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"SSL VPN Authentication\" log_subtype=\"Authentication\" status=\"Failed\" src_ip=\"198.51.100.4\" user_name=\"alice\"", + "expected": {}, + "absent": [], + "matches": [ + "sophos_xg_vpn_auth_failures" + ] + }, + { + "name": "successful-vpn-is-not-failure", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"SSL VPN Authentication\" log_subtype=\"Authentication\" status=\"Successful\" src_ip=\"198.51.100.4\" user_name=\"alice\"", + "expected": { + "actionResult": "success" + }, + "absent": [], + "matches": [] + }, + { + "name": "generic-IKE-error-is-not-login", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"IPSec\" log_subtype=\"System\" status=\"Failed\" src_ip=\"198.51.100.4\" message=\"Could not parse IKE header\"", + "expected": { + "actionResult": "failure" + }, + "absent": [], + "matches": [] + }, + { + "name": "routine-admin-change-is-not-password-guess", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"GUI\" log_subtype=\"Admin\" log_id=\"062009517502\" status=\"Failed\" src_ip=\"198.51.100.4\" user_name=\"admin\"", + "expected": { + "actionResult": "failure" + }, + "absent": [], + "matches": [] + }, + { + "name": "successful-admin-login", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"GUI\" log_subtype=\"Admin\" log_id=\"062009517507\" status=\"Successful\" src_ip=\"198.51.100.4\" user_name=\"admin\"", + "expected": { + "actionResult": "success" + }, + "absent": [], + "matches": [] + }, + { + "name": "ATP-system-update-is-not-threat", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"ATP\" log_subtype=\"System\" status=\"Successful\" src_ip=\"198.51.100.4\"", + "expected": { + "actionResult": "success" + }, + "absent": [], + "matches": [] + }, + { + "name": "low-priority-IPS-does-not-trigger-high-threshold", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"IDP\" log_component=\"Signatures\" log_subtype=\"Drop\" rule_priority=\"5\" src_ip=\"198.51.100.4\" dst_ip=\"192.0.2.4\"", + "expected": { + "actionResult": "denied" + }, + "absent": [], + "matches": [] + }, + { + "name": "forged-history-marker", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" correlationCandidate.sophosXG.vpnFailure=\"match\"", + "expected": {}, + "absent": [ + "log.correlationCandidate" + ], + "matches": [] + }, + { + "name": "severity-modern-priority", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"Appliance\" priority=\"Information\" message=\"Critical device event\" severity=\"Critical\"", + "expected": { + "severity": "critical" + }, + "absent": [], + "matches": [ + "sophos_high_severity_alerts" + ] + }, + { + "name": "no-actor-advanced_threat_protection_alerts", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"ATP\" log_component=\"Firewall\" log_subtype=\"Alert\" threatname=\"C2/Test\" destinationip=\"192.0.2.4\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "no-actor-sophos_xg_vpn_auth_failures", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"SSL VPN Authentication\" log_subtype=\"Authentication\" status=\"Failed\" user_name=\"alice\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "no-actor-sophos_password_guessing_on_administrator_account", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"GUI\" log_subtype=\"Admin\" log_id=\"062009517507\" status=\"Failed\" user_name=\"admin\"", + "expected": {}, + "absent": [ + "origin.ip" + ], + "matches": [] + }, + { + "name": "atp-empty-threat-is-not-detection", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"ATP\" log_component=\"Firewall\" log_subtype=\"Alert\" threatname=\"\" sourceip=\"198.51.100.4\" destinationip=\"192.0.2.4\"", + "expected": {}, + "absent": [ + "actionResult" + ], + "matches": [] + }, + { + "name": "invalid-file-size-and-hash", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" filename=\"sample.exe\" filesize=\"-1\" sha1sum=\"not-a-hash\"", + "expected": {}, + "absent": [ + "target.sizeInBytes", + "target.sha1" + ], + "matches": [] + }, + { + "name": "additional-vendor-values", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" log_component=\"Firewall Authentication\" status=\"Successful\" user_name=\"alice\" usergroupname=\"VPN Users\" src_ip=\"2001:db8::1\" fw_rule_name=\"Outbound business traffic\" hb_health=\"No Heartbeat\"", + "expected": { + "origin.user": "alice", + "origin.group": "VPN Users", + "origin.ip": "2001:db8::1", + "log.fwrulename": "Outbound business traffic", + "log.hbhealth": "No Heartbeat" + }, + "absent": [], + "matches": [] + }, + { + "name": "malformed-quoted-message", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" message=\"unterminated src_ip=198.51.100.90 status=Allow", + "expected": {}, + "absent": [ + "origin.ip", + "actionResult" + ], + "matches": [] + }, + { + "name": "escaped-quote-text-is-not-an-address", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_type=\"Event\" message=\"A \\\"quoted\\\" value src_ip=198.51.100.90 status=Allow\"", + "expected": {}, + "absent": [ + "origin.ip", + "actionResult" + ], + "matches": [] + }, + { + "name": "messageid-format-admin", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" messageid=\"17507\" log_type=\"Event\" log_component=\"GUI\" log_subtype=\"Admin\" status=\"Failed\" user=\"admin\" src_ip=\"198.51.100.4\"", + "expected": { + "log.messageId": "17507", + "origin.user": "admin" + }, + "absent": [], + "matches": [ + "sophos_password_guessing_on_administrator_account" + ] + }, + { + "name": "legacy-code-alone-is-not-authentication-proof", + "dataSource": "collector-A", + "raw": "<30>device=\"SFW\" date=2026-08-02 time=10:11:12 timezone=\"-03\" device_name=\"XG-test\" device_id=\"lab-A\" log_id=\"060011517913\" log_type=\"Event\" log_component=\"Appliance\" src_ip=\"198.51.100.4\"", + "expected": {}, + "absent": [], + "matches": [] + } +] diff --git a/rules/sophos/sophos_central/behavioral_analysis_alerts.yml b/rules/sophos/sophos_central/behavioral_analysis_alerts.yml index 6966d41de..7238d0189 100644 --- a/rules/sophos/sophos_central/behavioral_analysis_alerts.yml +++ b/rules/sophos/sophos_central/behavioral_analysis_alerts.yml @@ -1,41 +1,49 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - sophos-central -name: Sophos Central Behavioral Analysis Alert +- sophos-central +name: Repeated Sophos Central Behavioral Detections impact: confidentiality: 3 integrity: 3 availability: 2 -category: Suspicious Behavior -technique: "T1055 - Process Injection" +category: Threat Detection +technique: Vendor threat detection adversary: origin references: - - https://developer.sophos.com/siem-api-schemas - - https://attack.mitre.org/techniques/T1055/ -description: | - Detects suspicious behavior patterns identified by Sophos behavioral analysis engine, including process injection attempts, privilege escalation, and other anomalous activities that indicate potential compromise. +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/MaliciousBehaviorTypes/ +description: Repeated behavioral detections on the same managed endpoint and Sophos account. Inspect the vendor + threat name for its specific behavior or MITRE technique; these events do not all indicate process injection. +where: '((oneOf("log.type", ["Event::Endpoint::Threat::BehavioralDetection", "Event::Endpoint::BehaviorDetected"]) + || + + (oneOf("log.detectionMethod", ["Behavioral", "HIPS"]) && oneOf("log.severity", ["medium", "high", "critical"])) + || - Next Steps: - 1. Review the specific behavioral detection details in the Sophos Central console - 2. Examine the affected endpoint for signs of compromise - 3. Check process execution history and parent-child relationships - 4. Investigate network connections from the affected endpoint - 5. Review file system changes and registry modifications - 6. Consider isolating the endpoint if malicious activity is confirmed - 7. Update endpoint security policies based on findings -where: | - oneOf("log.type", ["Event::Endpoint::Threat::BehavioralDetection", "Event::Endpoint::BehaviorDetected"]) || - (oneOf("log.detectionMethod", ["Behavioral", "HIPS"]) && oneOf("log.severity", ["medium", "high", "critical"])) || - (contains("log.name", "Behavioral") && oneOf("log.severity", ["high", "critical"])) + (contains("log.name", "Behavioral") && oneOf("log.severity", ["high", "critical"]))) || equals("log.type","Event::Endpoint::CoreBehavioralDetection")) + && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") && (regexMatch("log.endpointId","[^[:space:]]") + && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && (regexMatch("dataSource","[^[:space:]]") && !oneOf("dataSource",["-","n/a","N/A","unknown"])) + && (regexMatch("log.sophosCentralScope","[^[:space:]]") && !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"]))' afterEvents: - - indexPattern: v11-log-sophos-central-* - with: - - field: origin.ip - operator: filter_term - value: '{{.origin.ip}}' - within: 30m - count: 3 +- indexPattern: v11-log-sophos-central-* + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosCentralScope + operator: filter_term + value: '{{.log.sophosCentralScope}}' + - field: log.endpointId + operator: filter_term + value: '{{.log.endpointId}}' + - field: log.correlationCandidate.sophosCentral.behavior + operator: filter_term + value: match + within: 30m + count: 3 groupBy: - - lastEvent.log.processPath - - adversary.host +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/endpoint_threat_detection.yml b/rules/sophos/sophos_central/endpoint_threat_detection.yml index 7cc19b979..9228275a8 100644 --- a/rules/sophos/sophos_central/endpoint_threat_detection.yml +++ b/rules/sophos/sophos_central/endpoint_threat_detection.yml @@ -1,34 +1,27 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - sophos-central -name: Endpoint Threat Detection +- sophos-central +name: Sophos Central Endpoint Threat or PUA Detection impact: confidentiality: 3 integrity: 3 availability: 2 -category: Malware Detection -technique: "T1055 - Process Injection" +category: Threat Detection +technique: Vendor threat detection adversary: origin references: - - https://developer.sophos.com/docs/endpoint-v1/1/routes/events/get - - https://attack.mitre.org/techniques/T1055/ -description: | - Detects threats identified on endpoints by Sophos Central, including malware, PUAs (Potentially Unwanted Applications), and suspicious behavior. This rule triggers when Sophos Central identifies threats such as process injection, malware execution, or other malicious activities on managed endpoints. +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +description: Sophos reports an endpoint threat, potentially unwanted application, or failed PUA cleanup. A PUA can + be legitimate software restricted by policy. Completed cleanup and dismissed events are excluded. +where: '((oneOf("log.type", ["Event::Endpoint::Threat::Detected", "Event::Endpoint::Threat::HIPSDetected", "Event::Endpoint::Threat::PuaDetected"]) + || - Next Steps: - 1. Immediately isolate the affected endpoint from the network to prevent lateral movement - 2. Review the threat details including threat name, file path, and detection method - 3. Examine the endpoint's recent activity logs for signs of compromise - 4. Check if the threat was successfully quarantined or requires manual intervention - 5. Verify if other endpoints in the environment show similar threat indicators - 6. Review user activity on the affected endpoint around the time of detection - 7. Perform forensic analysis of the affected files and processes if needed - 8. Update security policies and endpoint configurations if gaps are identified - 9. Conduct threat hunting across the environment for similar indicators of compromise -where: | - oneOf("log.type", ["Event::Endpoint::Threat::Detected", "Event::Endpoint::Threat::HIPSDetected", "Event::Endpoint::Threat::PuaDetected"]) || - (oneOf("log.severity", ["high", "critical"]) && equals("log.category", "threat") && exists("log.threatName")) + (oneOf("log.severity", ["high", "critical"]) && equals("log.category", "threat") && exists("log.threatName"))) + || oneOf("log.type",["Event::Endpoint::CorePuaDetection","Event::Endpoint::CorePuaCleanFailed"])) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$")' groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/exploit_prevention_triggers.yml b/rules/sophos/sophos_central/exploit_prevention_triggers.yml index 707041353..27773021d 100644 --- a/rules/sophos/sophos_central/exploit_prevention_triggers.yml +++ b/rules/sophos/sophos_central/exploit_prevention_triggers.yml @@ -1,41 +1,68 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - sophos-central +- sophos-central name: Sophos Central Exploit Prevention Triggered impact: confidentiality: 3 integrity: 3 availability: 2 category: Exploit Attempt -technique: "T1203 - Exploitation for Client Execution" +technique: T1203 - Exploitation for Client Execution adversary: origin references: - - https://developer.sophos.com/siem-api-schemas - - https://attack.mitre.org/techniques/T1203/ -description: | - Detects when Sophos exploit prevention is triggered, indicating attempted exploitation of vulnerable applications. This includes shellcode protection, CTF protocol exploitation attempts, and process hijacking attempts. +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/techniques/T1203/ +description: 'Detects when Sophos exploit prevention is triggered, indicating attempted exploitation of vulnerable + applications. This includes shellcode protection, CTF protocol exploitation attempts, and process hijacking attempts. + Next Steps: + 1. Immediately isolate the affected endpoint to prevent lateral movement + 2. Review the exploit details including target application and attack vector + 3. Check for additional suspicious activity on the affected host within the past 24 hours + 4. Verify if the targeted application is up to date with security patches + 5. Examine network connections from the affected host for C2 communication + 6. Review user activity and authentication logs for the affected endpoint + 7. Consider running additional endpoint scans for indicators of compromise + 8. Update security policies if the exploit targeted a previously unknown vulnerability -where: | - oneOf("log.type", ["Event::Endpoint::Threat::ExploitPrevented", "Event::Endpoint::Exploit::Prevented"]) || - (equals("log.name", "Exploit prevented") && oneOf("log.severity", ["high", "critical"])) + + ' +where: '(oneOf("log.type", ["Event::Endpoint::Threat::ExploitPrevented", "Event::Endpoint::Exploit::Prevented"]) + || + + (equals("log.name", "Exploit prevented") && oneOf("log.severity", ["high", "critical"]))) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") + && (regexMatch("log.endpointId","[^[:space:]]") && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && (regexMatch("dataSource","[^[:space:]]") + && !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (regexMatch("log.sophosCentralScope","[^[:space:]]") && + !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"]))' afterEvents: - - indexPattern: v11-log-sophos-central-* - with: - - field: log.endpointId - operator: filter_term - value: '{{.log.endpointId}}' - within: 30m - count: 2 +- indexPattern: v11-log-sophos-central-* + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosCentralScope + operator: filter_term + value: '{{.log.sophosCentralScope}}' + - field: log.endpointId + operator: filter_term + value: '{{.log.endpointId}}' + - field: log.correlationCandidate.sophosCentral.exploit + operator: filter_term + value: match + within: 30m + count: 2 groupBy: - - lastEvent.log.name - - adversary.host +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/managed_threat_response_alerts.yml b/rules/sophos/sophos_central/managed_threat_response_alerts.yml index 244649dfe..71e0eb232 100644 --- a/rules/sophos/sophos_central/managed_threat_response_alerts.yml +++ b/rules/sophos/sophos_central/managed_threat_response_alerts.yml @@ -1,42 +1,67 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - sophos-central +- sophos-central name: Managed Threat Response Critical Alert impact: confidentiality: 3 integrity: 3 availability: 3 category: Threat Detection -technique: "T1562 - Impair Defenses" +technique: T1562 - Impair Defenses adversary: origin references: - - https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/ThreatAnalysisCenter/index.html - - https://attack.mitre.org/tactics/TA0005/ -description: | - Detects critical alerts from Sophos Managed Threat Response (MTR) service indicating active threats that require immediate investigation and response, including advanced persistent threats and sophisticated attack techniques. +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/ +- https://attack.mitre.org/tactics/TA0005/ +description: 'Detects critical alerts from Sophos Managed Threat Response (MTR) service indicating active threats + that require immediate investigation and response, including advanced persistent threats and sophisticated attack + techniques. + Next Steps: + 1. Review the MTR alert details in Sophos Central console + 2. Examine the affected endpoint for signs of compromise + 3. Check for lateral movement indicators on the network + 4. Verify if the threat has been successfully contained + 5. Update security policies based on threat intelligence from the alert + 6. Document the incident and response actions taken -where: | - oneOf("log.type", ["mtr_alert", "threat_detection"]) && - oneOf("log.severity", ["critical", "high"]) + + ' +where: '(oneOf("log.type", ["mtr_alert", "threat_detection"]) && + + oneOf("log.severity", ["critical", "high"])) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") + && (regexMatch("log.endpointId","[^[:space:]]") && !oneOf("log.endpointId",["-","n/a","N/A","unknown"])) && (regexMatch("dataSource","[^[:space:]]") + && !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (regexMatch("log.sophosCentralScope","[^[:space:]]") && + !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"]))' afterEvents: - - indexPattern: v11-log-sophos-central-* - with: - - field: log.endpointId - operator: filter_term - value: '{{.log.endpointId}}' - - field: log.severity - operator: filter_term - value: 'critical' - within: 1h - count: 3 +- indexPattern: v11-log-sophos-central-* + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosCentralScope + operator: filter_term + value: '{{.log.sophosCentralScope}}' + - field: log.endpointId + operator: filter_term + value: '{{.log.endpointId}}' + - field: log.correlationCandidate.sophosCentral.mtr + operator: filter_term + value: match + - field: log.severity + operator: filter_term + value: critical + within: 1h + count: 3 groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/ransomware_detection.yml b/rules/sophos/sophos_central/ransomware_detection.yml index a395e22c8..00813bbed 100644 --- a/rules/sophos/sophos_central/ransomware_detection.yml +++ b/rules/sophos/sophos_central/ransomware_detection.yml @@ -1,37 +1,31 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - sophos-central +- sophos-central name: Sophos Central Ransomware Detection impact: confidentiality: 3 integrity: 3 availability: 3 category: Ransomware Activity -technique: "T1486 - Data Encrypted for Impact" +technique: T1486 - Data Encrypted for Impact adversary: origin references: - - https://developer.sophos.com/siem-api-schemas - - https://attack.mitre.org/techniques/T1486/ -description: | - Detects ransomware activity including CryptoGuard alerts, master boot record attacks, and file system encryption attempts. This is a critical security event requiring immediate response. +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/techniques/T1486/ +description: Sophos reports ransomware behavior or blocked encryption. Review vendor details and affected files; + detection or prevention does not prove successful encryption. +where: '(oneOf("log.type", ["Event::Endpoint::Threat::RansomwareDetected", "Event::Endpoint::CryptoGuard::FileEncryption"]) + || - Next Steps: - 1. Immediately isolate the affected endpoint from the network - 2. Identify the user account and processes involved in the ransomware activity - 3. Check for lateral movement to other systems using the same user credentials - 4. Verify backup integrity and availability for potential restoration - 5. Analyze file system changes and encrypted file patterns - 6. Review network connections for command and control communications - 7. Search for ransomware notes or payment demands on the system - 8. Coordinate with incident response team for containment and recovery - 9. Monitor for similar patterns on other endpoints in the environment - 10. Document all findings for forensic analysis and threat intelligence -where: | - oneOf("log.type", ["Event::Endpoint::Threat::RansomwareDetected", "Event::Endpoint::CryptoGuard::FileEncryption"]) || (equals("log.name", "CryptoGuard") && equals("log.action", "blocked")) || + (equals("log.name", "Ransomware detected") && equals("log.severity", "critical")) || - (equals("log.type", "Event::Endpoint::Threat::Detected") && equals("log.threatType", "Ransomware")) + + (equals("log.type", "Event::Endpoint::Threat::Detected") && equals("log.threatType", "Ransomware"))) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$")' groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/server_protection_alerts.yml b/rules/sophos/sophos_central/server_protection_alerts.yml index 7a562cf3c..4feffb2a8 100644 --- a/rules/sophos/sophos_central/server_protection_alerts.yml +++ b/rules/sophos/sophos_central/server_protection_alerts.yml @@ -1,35 +1,54 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - sophos-central +- sophos-central name: Server Protection Alerts impact: confidentiality: 3 integrity: 3 availability: 2 category: Server Security -technique: "T1505 - Server Software Component" +technique: T1505 - Server Software Component adversary: origin references: - - https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/Servers/index.html - - https://attack.mitre.org/techniques/T1505/ -description: | - Detects critical security alerts on servers protected by Sophos Central, including unauthorized access attempts, service tampering, and malware targeting server infrastructure. This rule monitors for high-severity threats specifically targeting server endpoints. +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/ManagementEventTypes/ +- https://attack.mitre.org/techniques/T1505/ +description: 'Detects critical security alerts on servers protected by Sophos Central, including unauthorized access + attempts, service tampering, and malware targeting server infrastructure. This rule monitors for high-severity + threats specifically targeting server endpoints. + Next Steps: + 1. Immediately isolate the affected server from the network if threat is confirmed active + 2. Review the specific threat details in Sophos Central console to understand the attack vector + 3. Check server logs for unauthorized access attempts or privilege escalation activities + 4. Verify integrity of critical server services and configurations + 5. Scan for additional indicators of compromise on the server and connected systems + 6. Review recent server changes, updates, or new software installations + 7. Check for lateral movement attempts from the compromised server + 8. Implement additional monitoring for the affected server endpoint + 9. Update security policies and access controls based on findings + 10. Document the incident and update security procedures if necessary -where: | - oneOf("log.type", ["Event::Server::Threat::Detected", "Event::Server::Protection::Disabled", "Event::Server::Exploit::Prevented"]) || - (equals("log.endpointType", "server") && oneOf("log.severity", ["high", "critical"]) && exists("log.threatName")) + + ' +where: '(oneOf("log.type", ["Event::Server::Threat::Detected", "Event::Server::Protection::Disabled", "Event::Server::Exploit::Prevented"]) + || + + (equals("log.endpointType", "server") && oneOf("log.severity", ["high", "critical"]) && exists("log.threatName"))) + && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$")' groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_app_hijacking_prevented.yml b/rules/sophos/sophos_central/sophos_central_app_hijacking_prevented.yml index c81a623f5..4acab9104 100644 --- a/rules/sophos/sophos_central/sophos_central_app_hijacking_prevented.yml +++ b/rules/sophos/sophos_central/sophos_central_app_hijacking_prevented.yml @@ -1,22 +1,27 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Application Hijacking prevented in Sophos Central" +- sophos-central +name: Application Hijacking prevented in Sophos Central impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Persistence" -technique: "T1574 - Hijack Execution Flow" +category: Persistence +technique: T1574 - Hijack Execution Flow adversary: origin references: - - "https://attack.mitre.org/tactics/TA0003/" - - "https://attack.mitre.org/techniques/T1574/" -description: "Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. - Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over time. - Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control or other restrictions on execution." -where: equals("log.type", "Event::Endpoint::HmpaApplicationHijacking") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/tactics/TA0003/ +- https://attack.mitre.org/techniques/T1574/ +description: Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. + Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over + time. Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control + or other restrictions on execution. +where: (equals("log.type", "Event::Endpoint::HmpaApplicationHijacking")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_credential_theft_attack_detected.yml b/rules/sophos/sophos_central/sophos_central_credential_theft_attack_detected.yml index fc7b833e0..a322ecd8b 100644 --- a/rules/sophos/sophos_central/sophos_central_credential_theft_attack_detected.yml +++ b/rules/sophos/sophos_central/sophos_central_credential_theft_attack_detected.yml @@ -1,22 +1,26 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Credential Theft Attemp detected in Sophos Central" +- sophos-central +name: Credential Theft Attemp detected in Sophos Central impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Credential Access" -technique: "T1003 - OS Credential Dumping" -adversary: target +category: Credential Access +technique: T1003 - OS Credential Dumping +adversary: origin references: - - "https://attack.mitre.org/tactics/TA0006/" - - "https://attack.mitre.org/techniques/T1003/" -description: "The theft of access credentials to different pages or apps occurs due to the use - of insecure passwords, which are used in different accounts. - This data is often exposed as a result of leaks that arise from the exploitation of vulnerabilities in different platforms." -where: contains("log.type", "Event::Endpoint::HmpaCred") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/tactics/TA0006/ +- https://attack.mitre.org/techniques/T1003/ +description: The theft of access credentials to different pages or apps occurs due to the use of insecure passwords, + which are used in different accounts. This data is often exposed as a result of leaks that arise from the exploitation + of vulnerabilities in different platforms. +where: (startsWith("log.type","Event::Endpoint::HmpaCred")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - target.host - - target.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_device_compromised.yml b/rules/sophos/sophos_central/sophos_central_device_compromised.yml index f501c050f..ca2ffb862 100644 --- a/rules/sophos/sophos_central/sophos_central_device_compromised.yml +++ b/rules/sophos/sophos_central/sophos_central_device_compromised.yml @@ -1,19 +1,23 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Potentially compromised or blocked device detected in Sophos Central" +- sophos-central +name: Sophos Central Potentially Compromised Device impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Resource Development" -technique: "T1584" +category: Threat Detection +technique: Vendor threat detection adversary: origin -references: - - "https://attack.mitre.org/techniques/T1584/" -description: "Adversaries may compromise third-party infrastructure that can be used during targeting" -where: oneOf("log.type", ['Event::Endpoint::Device::Blocked', 'Event::UAV::PotentiallyCompromisedDevice']) +references: +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/NetworkAccessEventTypes/ +description: Sophos reports a potentially compromised device. Investigate device health and network activity. Blocking + a peripheral is a separate policy event and does not establish device compromise. +where: (equals("log.type","Event::UAV::PotentiallyCompromisedDevice")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_endpoint_protection_unavailable.yml b/rules/sophos/sophos_central/sophos_central_endpoint_protection_unavailable.yml new file mode 100644 index 000000000..b7373ad8e --- /dev/null +++ b/rules/sophos/sophos_central/sophos_central_endpoint_protection_unavailable.yml @@ -0,0 +1,24 @@ +dataTypes: +- sophos-central +name: Sophos Central Endpoint Protection Unavailable +impact: + confidentiality: 1 + integrity: 2 + availability: 2 +category: Device Health +technique: Endpoint protection health +adversary: origin +references: +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/ManagementEventTypes/ +description: Sophos reports an unprotected computer/server or a protection service + that is not running, at high or critical vendor severity. Verify installation, service + health and approved maintenance. This warning does not establish an attack. +where: oneOf("log.type",["Event::Endpoint::NotProtected","Event::Endpoint::ServiceNotRunning"]) + && oneOf("log.severity",["high","critical"]) +groupBy: +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_exploit_detected.yml b/rules/sophos/sophos_central/sophos_central_exploit_detected.yml index e00b3144e..7b7c45616 100644 --- a/rules/sophos/sophos_central/sophos_central_exploit_detected.yml +++ b/rules/sophos/sophos_central/sophos_central_exploit_detected.yml @@ -1,22 +1,27 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Probable attempt to exploit vulnerabilities detected in Sophos Central" +- sophos-central +name: Probable attempt to exploit vulnerabilities detected in Sophos Central impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Credential Access" -technique: "T1212" +category: Credential Access +technique: T1212 adversary: origin references: - - "https://attack.mitre.org/tactics/TA0006/" - - "https://attack.mitre.org/techniques/T1212/" -description: "An exploit is a small program designed to exploit a particular bug in an operating system or program for various purposes. - Depending on the type of vulnerability, the exploit can have different purposes, - such as gaining administrator permissions on the system or bypassing security measures in order to carry out a deeper infection." -where: oneOf("log.type", ["Event::Endpoint::HmpaPrivGuard", "Event::Endpoint::HmpaExploitPrevented"]) +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/tactics/TA0006/ +- https://attack.mitre.org/techniques/T1212/ +description: An exploit is a small program designed to exploit a particular bug in an operating system or program + for various purposes. Depending on the type of vulnerability, the exploit can have different purposes, such as + gaining administrator permissions on the system or bypassing security measures in order to carry out a deeper + infection. +where: (oneOf("log.type", ["Event::Endpoint::HmpaPrivGuard", "Event::Endpoint::HmpaExploitPrevented"])) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_malware_detected.yml b/rules/sophos/sophos_central/sophos_central_malware_detected.yml index 5f07d4e0a..779b41510 100644 --- a/rules/sophos/sophos_central/sophos_central_malware_detected.yml +++ b/rules/sophos/sophos_central/sophos_central_malware_detected.yml @@ -1,26 +1,24 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Malware detected in Sophos Central" +- sophos-central +name: Sophos Central Malware Detection or Cleanup Failure impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Execution" -technique: "T1204 - User Execution" +category: Threat Detection +technique: Vendor threat detection adversary: origin references: - - "https://www.mcafee.com/en-us/antivirus/malware.html" -description: "A computer virus is a piece of malicious code that is prepended or appended to existing files on your computer. - Viruses are named after biological viruses because they use similar techniques to spread from one place to another. - Virus is often misused to refer to any threat. This usage is gradually being replaced with a more accurate term, malware (malicious software). - Computer viruses primarly attack executable files and documents. In short, this is how a computer virus works: - after running the infected file, the malicious code is called and executed prior to the execution of the original application. - A virus can infect any files that the current user has write permissions for. - Computer viruses can range in purpose and severity. Some of them are extremely dangerous because of their ability to delete files purposely from the hard drive. - On the other hand, some viruses do not cause any damage they only serve to annoy the user and demonstrate the technical skills of their authors." -where: regexMatch("log.type", "^Event::Endpoint::(CoreDetection|CoreRemoteDetection|CoreHmpaClean|CoreClean)$|Event::Endpoint::(HmpaMalware|CoreHmpaCleanFailed|CoreCleanFailed)|Event::SpamOrVirus::Alert|Event::Endpoint::Threat::(HIPS|Dismissed|CleanedUp)|Event::OutboundMalwareProtection::BlockedSender") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +description: Sophos reports malware detection or unsuccessful cleanup. Review the vendor event and remediation status. + Successful cleanup and dismissed detections do not create a fresh malware alert. +where: (regexMatch("log.type","^(Event::Endpoint::(CoreDetection|CoreRemoteDetection|HmpaMalware|CoreHmpaCleanFailed|CoreCleanFailed)|Event::SpamOrVirus::Alert|Event::Endpoint::Threat::HIPS|Event::OutboundMalwareProtection::BlockedSender)($|::|[A-Z])")) + && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_man_in_the_middle_attack_detected.yml b/rules/sophos/sophos_central/sophos_central_man_in_the_middle_attack_detected.yml index cd7e9d579..ca328d0ea 100644 --- a/rules/sophos/sophos_central/sophos_central_man_in_the_middle_attack_detected.yml +++ b/rules/sophos/sophos_central/sophos_central_man_in_the_middle_attack_detected.yml @@ -1,24 +1,28 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Man in the Middle Attack detected in Sophos Central" +- sophos-central +name: Man in the Middle Attack detected in Sophos Central impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Credential Access" -technique: "T1557 - Adversary-in-the-Middle" +category: Credential Access +technique: T1557 - Adversary-in-the-Middle adversary: origin references: - - "https://attack.mitre.org/tactics/TA0006/" - - "https://attack.mitre.org/techniques/T1557/" -description: "Adversaries may attempt to position themselves between two or more networked devices - using an adversary-in-the-middle technique to support follow-on behaviors such as Network Sniffing - or Transmitted Data Manipulation. By abusing features of common networking protocols that can determine - the flow of network traffic (e.g. ARP, DNS, LLMNR, etc.), adversaries may force a device to communicate - through an adversary controlled system so they can collect information or perform additional actions." -where: contains("log.type", "Event::Smc::MitmAttackEvent") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/tactics/TA0006/ +- https://attack.mitre.org/techniques/T1557/ +description: Adversaries may attempt to position themselves between two or more networked devices using an adversary-in-the-middle + technique to support follow-on behaviors such as Network Sniffing or Transmitted Data Manipulation. By abusing + features of common networking protocols that can determine the flow of network traffic (e.g. ARP, DNS, LLMNR, + etc.), adversaries may force a device to communicate through an adversary controlled system so they can collect + information or perform additional actions. +where: (equals("log.type","Event::Smc::MitmAttackEvent")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_possible_botnet_detected.yml b/rules/sophos/sophos_central/sophos_central_possible_botnet_detected.yml index 0e6007932..64af02d82 100644 --- a/rules/sophos/sophos_central/sophos_central_possible_botnet_detected.yml +++ b/rules/sophos/sophos_central/sophos_central_possible_botnet_detected.yml @@ -1,25 +1,24 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Possible Botnet detected in Sophos Central" +- sophos-central +name: Sophos Central Firewall ATP Detection impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Impact" -technique: "T1071 - Application Layer Protocol" +category: Command and Control +technique: T1071 - Application Layer Protocol adversary: origin references: - - "https://attack.mitre.org/tactics/TA0040/" - - "https://attack.mitre.org/techniques/T1565/" -description: "A bot, or a web robot is an automated malware program that scans blocks of network addresses and infects vulnerable computers. - This allow hackers to take control of many computers at the same time and turn them into bots (also known as a zombie). - Hackers typically use bots to infect large numbers of computers, which form a network or a botnet. - Once the botnet is in your computer, it can be used in distributed denial of service (DDoS) attacks, - proxy and also can be used to perform automated tasks over the Internet, without you knowing it - (for example sending spam, viruses or stealing personal and private information such as bank credentials or credit card numbers)." -where: equals("log.type", "Event::Firewall::FirewallAdvancedThreatProtection") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/Alerts/FirewallAlerts/ +- https://attack.mitre.org/techniques/T1071/ +description: Sophos Firewall ATP logged an attempt to communicate with a known botnet or command-and-control server. + The notification alone does not prove that the connection succeeded or that the endpoint is compromised. +where: (equals("log.type", "Event::Firewall::FirewallAdvancedThreatProtection")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_possible_brute_force_attack.yml b/rules/sophos/sophos_central/sophos_central_possible_brute_force_attack.yml index 8aae4055e..8961f3b38 100644 --- a/rules/sophos/sophos_central/sophos_central_possible_brute_force_attack.yml +++ b/rules/sophos/sophos_central/sophos_central_possible_brute_force_attack.yml @@ -1,33 +1,43 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Possible Brute Force Attack detected in Sophos Central" +- sophos-central +name: Repeated Sophos Central ZTNA Authentication Failures impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Credential Access" -technique: "T1110 - Brute Force" +category: Credential Access +technique: T1110 - Brute Force adversary: origin references: - - "https://attack.mitre.org/tactics/TA0006/" - - "https://attack.mitre.org/techniques/T1110/" -description: "Adversaries may use brute force techniques to gain access to accounts when passwords are unknown or when password hashes are obtained. - Without knowledge of the password for an account or set of accounts, an adversary may systematically guess the password using a repetitive or iterative mechanism. - Brute forcing passwords can take place via interaction with a service that will check the validity of those credentials or offline against previously acquired credential data, such as password hashes." -where: equals("log.type", "Event::ZTNA::ZTNAAuthenticationFailure") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/tactics/TA0006/ +- https://attack.mitre.org/techniques/T1110/ +description: Ten ZTNA authentication failures for the same vendor-reported IP and Sophos account in five minutes. + Investigate failed sign-ins; the events do not establish successful access. +where: (equals("log.type", "Event::ZTNA::ZTNAAuthenticationFailure")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") + && (regexMatch("log.ip","[^[:space:]]") && !oneOf("log.ip",["-","n/a","N/A","unknown"])) && (regexMatch("dataSource","[^[:space:]]") + && !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (regexMatch("log.sophosCentralScope","[^[:space:]]") && + !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"])) && ((inCIDR("log.ip","0.0.0.0/0") || inCIDR("log.ip","::/0")) + && !inCIDR("log.ip","0.0.0.0/32") && !inCIDR("log.ip","::/128")) afterEvents: - - indexPattern: v11-log-sophos-central-* - with: - - field: log.type - operator: filter_term - value: "Event::ZTNA::ZTNAAuthenticationFailure" - - field: log.ip - operator: filter_term - value: "{{.log.ip}}" - within: 5m - count: 10 +- indexPattern: v11-log-sophos-central-* + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosCentralScope + operator: filter_term + value: '{{.log.sophosCentralScope}}' + - field: log.ip + operator: filter_term + value: '{{.log.ip}}' + - field: log.correlationCandidate.sophosCentral.ztnaFailure + operator: filter_term + value: match + within: 5m + count: 10 groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.sophosCentralScope +- lastEvent.log.ip diff --git a/rules/sophos/sophos_central/sophos_central_potential_password_spraying_attack.yml b/rules/sophos/sophos_central/sophos_central_potential_password_spraying_attack.yml index bfabab056..09dec143e 100644 --- a/rules/sophos/sophos_central/sophos_central_potential_password_spraying_attack.yml +++ b/rules/sophos/sophos_central/sophos_central_potential_password_spraying_attack.yml @@ -1,33 +1,43 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Potential Password Spraying Attack detected in Sophos Central" +- sophos-central +name: Rapid Sophos Central ZTNA Authentication Failures impact: confidentiality: 1 integrity: 2 availability: 2 -category: "Credential Access" -technique: "T1110 - Brute Force" +category: Credential Access +technique: T1110 - Brute Force adversary: origin references: - - "https://attack.mitre.org/tactics/TA0006/" - - "https://attack.mitre.org/techniques/T1110/" -description: "Adversaries may use brute force techniques to gain access to accounts when passwords are unknown or when password hashes are obtained. - Without knowledge of the password for an account or set of accounts, an adversary may systematically guess the password using a repetitive or iterative mechanism. - Brute forcing passwords can take place via interaction with a service that will check the validity of those credentials or offline against previously acquired credential data, such as password hashes." -where: equals("log.type", "Event::ZTNA::ZTNAAuthenticationFailure") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/tactics/TA0006/ +- https://attack.mitre.org/techniques/T1110/ +description: Ten ZTNA authentication failures for the same vendor-reported IP and Sophos account in one minute. + This counts failures, not distinct users, and does not establish password spraying. +where: (equals("log.type", "Event::ZTNA::ZTNAAuthenticationFailure")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") + && (regexMatch("log.ip","[^[:space:]]") && !oneOf("log.ip",["-","n/a","N/A","unknown"])) && (regexMatch("dataSource","[^[:space:]]") + && !oneOf("dataSource",["-","n/a","N/A","unknown"])) && (regexMatch("log.sophosCentralScope","[^[:space:]]") && + !oneOf("log.sophosCentralScope",["-","n/a","N/A","unknown"])) && ((inCIDR("log.ip","0.0.0.0/0") || inCIDR("log.ip","::/0")) + && !inCIDR("log.ip","0.0.0.0/32") && !inCIDR("log.ip","::/128")) afterEvents: - - indexPattern: v11-log-sophos-central-* - with: - - field: log.type - operator: filter_term - value: "Event::ZTNA::ZTNAAuthenticationFailure" - - field: log.ip - operator: filter_term - value: "{{.log.ip}}" - within: 1m - count: 10 +- indexPattern: v11-log-sophos-central-* + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosCentralScope + operator: filter_term + value: '{{.log.sophosCentralScope}}' + - field: log.ip + operator: filter_term + value: '{{.log.ip}}' + - field: log.correlationCandidate.sophosCentral.ztnaFailure + operator: filter_term + value: match + within: 1m + count: 10 groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.sophosCentralScope +- lastEvent.log.ip diff --git a/rules/sophos/sophos_central/sophos_central_ransomware_detected.yml b/rules/sophos/sophos_central/sophos_central_ransomware_detected.yml index 56626682a..556516da3 100644 --- a/rules/sophos/sophos_central/sophos_central_ransomware_detected.yml +++ b/rules/sophos/sophos_central/sophos_central_ransomware_detected.yml @@ -1,22 +1,28 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Possible Ransomware Attack detected in Sophos Central" +- sophos-central +name: Sophos Central CryptoGuard Detection impact: confidentiality: 3 integrity: 3 availability: 2 -category: "Impact" -technique: "T1486 - Data Encrypted for Impact" +category: Impact +technique: T1486 - Data Encrypted for Impact adversary: origin references: - - "https://attack.mitre.org/tactics/TA0040/" - - "https://attack.mitre.org/techniques/T1565/" -description: "Ransomware, is a type of malware that prevents users from accessing their system or - personal files and requires payment of a ransom in order to gain access to them again. Identifies - ransomware attempts" -where: regexMatch("log.type", "Event::Endpoint::(HmpaCryptoGuardSMBOrigin|HmpaCryptoGuardSMB)|^Event::Endpoint::HmpaCryptoGuard$") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +- https://attack.mitre.org/techniques/T1486/ +description: Sophos reports local or remote ransomware activity. The managed endpoint is the affected target, except + SMBOrigin, which explicitly identifies the endpoint attempting remote encryption. Remote peer addresses are not + inferred from the message. +where: (oneOf("log.type",["Event::Endpoint::HmpaCryptoGuardSMBOrigin","Event::Endpoint::HmpaCryptoGuardSMB","Event::Endpoint::HmpaCryptoGuard"])) + && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip +- adversary.host +- adversary.ip diff --git a/rules/sophos/sophos_central/sophos_central_real_time_protection_disabled.yml b/rules/sophos/sophos_central/sophos_central_real_time_protection_disabled.yml index 4e64cc7a4..863222975 100644 --- a/rules/sophos/sophos_central/sophos_central_real_time_protection_disabled.yml +++ b/rules/sophos/sophos_central/sophos_central_real_time_protection_disabled.yml @@ -1,19 +1,23 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Real Time Protection disabled in Sophos Central" +- sophos-central +name: Sophos Central Real-Time Protection Disabled impact: confidentiality: 2 integrity: 2 availability: 1 -category: "Defense Evasion" -technique: "T1562 - Impair Defenses" +category: Defense Evasion +technique: T1562 - Impair Defenses adversary: origin references: - - "https://www.makeuseof.com/real-time-protection/" -description: "Real-time protection has been disabled, which can help malware and attacks go undetected" -where: equals("log.type", "Event::Endpoint::SavDisabled") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/ManagementEventTypes/ +description: Sophos reports disabled real-time protection. Review approved maintenance and device health before + concluding that an adversary impaired defenses. +where: (equals("log.type", "Event::Endpoint::SavDisabled")) && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/sophos_central_unknown_threat_detected.yml b/rules/sophos/sophos_central/sophos_central_unknown_threat_detected.yml index 8ba19f77b..dd1beecc8 100644 --- a/rules/sophos/sophos_central/sophos_central_unknown_threat_detected.yml +++ b/rules/sophos/sophos_central/sophos_central_unknown_threat_detected.yml @@ -1,26 +1,24 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - "sophos-central" -name: "Unknown Threat detected in Sophos Central" +- sophos-central +name: Sophos Central Threat or Cleanup Failure impact: confidentiality: 3 integrity: 3 availability: 2 -category: "Execution" -technique: "T1204 - User Execution" +category: Threat Detection +technique: Vendor threat detection adversary: origin references: - - "https://www.mcafee.com/en-us/antivirus/malware.html" -description: "A computer virus is a piece of malicious code that is prepended or appended to existing files on your computer. - Viruses are named after biological viruses because they use similar techniques to spread from one place to another. - Virus is often misused to refer to any threat. This usage is gradually being replaced with a more accurate term, malware (malicious software). - Computer viruses primarly attack executable files and documents. In short, this is how a computer virus works: - after running the infected file, the malicious code is called and executed prior to the execution of the original application. - A virus can infect any files that the current user has write permissions for. - Computer viruses can range in purpose and severity. Some of them are extremely dangerous because of their ability to delete files purposely from the hard drive. - On the other hand, some viruses do not cause any damage they only serve to annoy the user and demonstrate the technical skills of their authors." -where: regexMatch("log.type", "Event::Endpoint::(CoreIps|HomeThreatRemnants|HmpaBehaviourPrevented|HmpaThreat|HmpaSafeBrowsing|CoreAmsi|CoreOutbreak)|Event::Endpoint::Threat::(CleanupFailed::|Ips|CommandAndControl)") +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/LogsReports/Logs/Events/EventTypes/ +description: Sophos reports a runtime, network, AMSI or outbreak detection, or failed cleanup. Review the exact + vendor type and remediation status; successful cleanup and resolved events are excluded. +where: (regexMatch("log.type","^Event::Endpoint::(CoreIps|HomeThreatRemnants|HmpaBehaviourPrevented|HmpaThreat|HmpaSafeBrowsing|CoreAmsi|CoreOutbreak|Threat::(CleanupFailed::|Ips|CommandAndControl))")) + && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$") groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_central/tamper_protection_alerts.yml b/rules/sophos/sophos_central/tamper_protection_alerts.yml index 7500b5654..bf4ed08cc 100644 --- a/rules/sophos/sophos_central/tamper_protection_alerts.yml +++ b/rules/sophos/sophos_central/tamper_protection_alerts.yml @@ -1,34 +1,30 @@ -# Rule version v1.0.0 - +# Sophos Central SIEM event review; impact ratings and history thresholds preserved. dataTypes: - - sophos-central -name: Sophos Central Tamper Protection Alert +- sophos-central +name: Sophos Central Tamper Protection Warning impact: confidentiality: 2 integrity: 3 availability: 2 category: Defense Evasion -technique: "T1562.001 - Impair Defenses: Disable or Modify Tools" +technique: 'T1562.001 - Impair Defenses: Disable or Modify Tools' adversary: origin references: - - https://developer.sophos.com/siem-api-schemas - - https://attack.mitre.org/techniques/T1562/001/ -description: | - Detects when tamper protection is triggered, indicating an attempt to disable or modify Sophos security components. This could indicate malware or an attacker attempting to bypass security controls. +- https://docs.sophos.com/central/customer/help/en-us/ManageYourProducts/AccountHealthCheck/FixEndpointTamperProtect/ +- https://attack.mitre.org/techniques/T1562/001/ +description: Sophos reports a tamper-protection trigger or an account health warning that endpoint/server tamper + protection is off. Account health warnings can cover multiple devices; they do not identify an attacker. Resolution + events are excluded. +where: '((equals("log.type", "Event::Endpoint::Threat::TamperProtection") || - Next Steps: - 1. Immediately investigate the affected endpoint to determine the source of the tamper protection trigger - 2. Check if the endpoint shows signs of malware infection or unauthorized software installation - 3. Review recent user activity and process execution on the affected system - 4. Verify the integrity of Sophos security components and ensure they are functioning properly - 5. Scan the endpoint for threats and malware using full system scans - 6. If malicious activity is confirmed, isolate the endpoint and perform incident response procedures - 7. Review security policies and user permissions to prevent future tamper attempts - 8. Consider implementing additional endpoint monitoring for systems with tamper protection alerts -where: | - equals("log.type", "Event::Endpoint::Threat::TamperProtection") || (equals("log.name", "Tamper protection") && equals("log.severity", "high")) || - (equals("log.type", "Event::Endpoint::TamperProtection") && equals("log.action", "blocked")) + + (equals("log.type", "Event::Endpoint::TamperProtection") && equals("log.action", "blocked"))) || oneOf("log.type",["Event::AccountHealthCheck::EndpointTamperProtectionRaise","Event::AccountHealthCheck::ServerTamperProtectionRaise"])) + && !regexMatch("log.type","(?i)(clean|cleanedup|resolved|dismissed|cancelled|success)$")' groupBy: - - adversary.host - - adversary.ip +- lastEvent.dataSource +- lastEvent.log.customerId +- lastEvent.log.endpointId +- lastEvent.log.type +- target.host +- target.ip diff --git a/rules/sophos/sophos_xg_firewall/advanced_threat_protection_alerts.yml b/rules/sophos/sophos_xg_firewall/advanced_threat_protection_alerts.yml index 749795f9f..f065806a3 100644 --- a/rules/sophos/sophos_xg_firewall/advanced_threat_protection_alerts.yml +++ b/rules/sophos/sophos_xg_firewall/advanced_threat_protection_alerts.yml @@ -1,40 +1,41 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - firewall-sophos-xg -name: Sophos XG Advanced Threat Protection Alert +- firewall-sophos-xg +name: Repeated Sophos Advanced Threat Protection Detections impact: confidentiality: 3 integrity: 3 availability: 2 category: Malware -technique: "T1204 - User Execution" +technique: T1204 - User Execution adversary: origin references: - - https://docs.sophos.com/nsg/sophos-firewall/20.0/Help/en-us/webhelp/onlinehelp/AdministratorHelp/AdvancedProtection/index.html - - https://attack.mitre.org/techniques/T1204/ -description: | - Detects when Sophos XG Firewall's Advanced Threat Protection (ATP) identifies malicious activity, including sandboxing results, malware detection, and zero-day threats. This rule triggers on ATP events indicating threat detection, malware identification, or virus findings. - - Next Steps: - 1. Immediately isolate the affected host from the network - 2. Review the ATP threat details and sandbox analysis results - 3. Check for any file transfers or downloads from the source IP - 4. Scan the internal network for indicators of compromise - 5. Update threat intelligence feeds and firewall signatures - 6. Review user activity from the affected source - 7. Consider reimaging the affected system if malware is confirmed -where: | - equals("log.type", "ATP") && equals("log.component", "Threat Protection") && - (oneOf("log.subType", ["Malware", "Threat"]) || exists("log.virus")) -afterEvents: - - indexPattern: v11-log-firewall-sophos-xg-* - with: - - field: origin.ip - operator: filter_term - value: '{{.origin.ip}}' - within: 30m - count: 2 +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +- https://attack.mitre.org/techniques/T1204/ +description: Repeated ATP Alert or Drop records from the same source address and firewall. ATP signature detection + does not establish a successful connection or endpoint compromise. +where: (equals("log.type","ATP") && oneOf("log.component",["Firewall","DNS","IPS","Web"]) && oneOf("log.subType",["Alert","Drop"]) + && ((exists("log.malware") && !equals("log.malware","")) || (exists("log.threatname") && !equals("log.threatname","")))) + && exists("origin.ip") && exists("dataSource") && !equals("dataSource","") && exists("log.sophosScope") && !equals("log.sophosScope","") groupBy: - - adversary.ip - - target.ip +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- target.ip +correlation: +- indexPattern: v11-log-firewall-sophos-xg-* + within: 30m + count: 2 + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosScope + operator: filter_term + value: '{{.log.sophosScope}}' + - field: origin.ip + operator: filter_term + value: '{{.origin.ip}}' + - field: log.correlationCandidate.sophosXG.atp + operator: filter_term + value: match diff --git a/rules/sophos/sophos_xg_firewall/sophos_denial_of_service.yml b/rules/sophos/sophos_xg_firewall/sophos_denial_of_service.yml index 08f841773..23a53c416 100644 --- a/rules/sophos/sophos_xg_firewall/sophos_denial_of_service.yml +++ b/rules/sophos/sophos_xg_firewall/sophos_denial_of_service.yml @@ -1,25 +1,25 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - "firewall-sophos-xg" -name: "Probable Sophos denial of service (DoS) attack" +- firewall-sophos-xg +name: Probable Sophos denial of service (DoS) attack impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Impact" -technique: "T1499 - Endpoint Denial of Service" +category: Impact +technique: T1499 - Endpoint Denial of Service adversary: origin -references: - - "https://support.sophos.com/support/s/article/KB-000035754?language=en_US" - - "https://docs.sophos.com/nsg/sophos-firewall/18.5/PDF/SF%20syslog%20guide%2018.5.pdf" - - "https://attack.mitre.org/tactics/TA0040" - - "https://attack.mitre.org/techniques/T1499/" -description: "A Denial of Service (DoS) attack is an attempt to make a machine or network resource unavailable to the intended users. - One common method of attack involves saturating the target machine with external communications requests so that it cannot - respond to legitimate traffic or the machine responds so slowly that it is essentially useless." -where: | - equalsIgnoreCase("log.component", "dos attacks") && equalsIgnoreCase("log.subType", "dos") +references: +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +- https://attack.mitre.org/tactics/TA0040 +- https://attack.mitre.org/techniques/T1499/ +description: A Denial of Service (DoS) attack is an attempt to make a machine or network resource unavailable to + the intended users. One common method of attack involves saturating the target machine with external communications + requests so that it cannot respond to legitimate traffic or the machine responds so slowly that it is essentially + useless. +where: equals("log.type","Firewall") && equalsIgnoreCase("log.component","DoS attacks") && equalsIgnoreCase("log.subType","DoS") groupBy: - - adversary.ip - - target.ip +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- target.ip diff --git a/rules/sophos/sophos_xg_firewall/sophos_firewall_probable_malware_detected.yml b/rules/sophos/sophos_xg_firewall/sophos_firewall_probable_malware_detected.yml index 1ed45fa8f..9c47eff5f 100644 --- a/rules/sophos/sophos_xg_firewall/sophos_firewall_probable_malware_detected.yml +++ b/rules/sophos/sophos_xg_firewall/sophos_firewall_probable_malware_detected.yml @@ -1,21 +1,20 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - "firewall-sophos-xg" -name: "Probable malware detected by sophos firewall" +- firewall-sophos-xg +name: Probable malware detected by sophos firewall impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Execution" -technique: "T1204 - User Execution" +category: Execution +technique: T1204 - User Execution adversary: origin -references: - - "https://www.mcafee.com/en-us/antivirus/malware.html" - - "https://www.fortinet.com/resources/cyberglossary/computer-virus" -description: "The Sophos firewall has detected a suspicious event and made some actions according to his configuration" -where: | - regexMatch("log.subType", "(?i)^(virus|pua)$") +references: +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +description: The Sophos firewall has detected a suspicious event and made some actions according to his configuration +where: equals("log.type","Anti-Virus") && regexMatch("log.subType","(?i)^(virus|pua)$") groupBy: - - adversary.ip - - target.ip +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- target.ip diff --git a/rules/sophos/sophos_xg_firewall/sophos_high_severity_alerts.yml b/rules/sophos/sophos_xg_firewall/sophos_high_severity_alerts.yml index c3271e99f..8ede376d1 100644 --- a/rules/sophos/sophos_xg_firewall/sophos_high_severity_alerts.yml +++ b/rules/sophos/sophos_xg_firewall/sophos_high_severity_alerts.yml @@ -1,24 +1,24 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - "firewall-sophos-xg" -name: "Sophos detected high priority alerts" +- firewall-sophos-xg +name: Sophos Critical Priority Event impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Initial Access" -technique: "T1190 - Exploit Public-Facing Application" +category: Device Health +technique: Vendor critical event adversary: origin -references: - - "https://docs.sophos.com/nsg/sophos-firewall/17.5/Help/en-us/webhelp/onlinehelp/nsg/concepts/LogIDStructure.html" - - "https://docs.sophos.com/nsg/sophos-firewall/17.5/Help/en-us/webhelp/onlinehelp/nsg/sfos/concepts/LogMessages.html" -description: "The Sophos firewall device has detected a high priority event. For the alert purpose, high priority is when log priority is: Emergency, Critical or Alert, and not part of the list of risked applications. - Please see the logs attached to this alert for additional details." -where: | - oneOf("log.priority", ["Emergency", "Critical", "Alert"]) && - !regexMatch("log.application", "(Torrent|Proxy|EXE File Download|eMule P2P|Ares P2P|Avast Antivirus|NetFlix|McAfee Antivirus|AVG Antivirus|ISAKMP VPN|WeTransfer Base|Xbox LIVE|OSC_AMU)") && - !regexMatch("log.applicationName", "(Torrent|Proxy|EXE File Download|eMule P2P|Ares P2P|Avast Antivirus|NetFlix|McAfee Antivirus|AVG Antivirus|ISAKMP VPN|WeTransfer Base|Xbox LIVE|OSC_AMU)") +references: +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +description: Sophos reports Emergency, Alert or Critical priority/severity. Review the vendor event details; this + broad device signal alone does not establish exploitation. +where: equals("severity","critical") && !regexMatch("log.application", "(Torrent|Proxy|EXE File Download|eMule P2P|Ares + P2P|Avast Antivirus|NetFlix|McAfee Antivirus|AVG Antivirus|ISAKMP VPN|WeTransfer Base|Xbox LIVE|OSC_AMU)") && + !regexMatch("log.applicationName", "(Torrent|Proxy|EXE File Download|eMule P2P|Ares P2P|Avast Antivirus|NetFlix|McAfee + Antivirus|AVG Antivirus|ISAKMP VPN|WeTransfer Base|Xbox LIVE|OSC_AMU)") groupBy: - - adversary.ip - - target.ip +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- target.ip diff --git a/rules/sophos/sophos_xg_firewall/sophos_initial_access_by_guest_account.yml b/rules/sophos/sophos_xg_firewall/sophos_initial_access_by_guest_account.yml index 879e19ae1..0ca6070d2 100644 --- a/rules/sophos/sophos_xg_firewall/sophos_initial_access_by_guest_account.yml +++ b/rules/sophos/sophos_xg_firewall/sophos_initial_access_by_guest_account.yml @@ -1,21 +1,24 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - "firewall-sophos-xg" -name: "Probable Sophos initial access vulnerability" +- firewall-sophos-xg +name: Sophos Appliance Event 17925 impact: confidentiality: 2 integrity: 2 availability: 1 -category: "Initial Access" -technique: "T1078.001 - Valid Accounts" +category: System Administration +technique: Vendor appliance event adversary: origin -references: - - "https://attack.mitre.org/tactics/TA0001/" - - "https://attack.mitre.org/techniques/T1078/001/" -description: "Sophos firewall has detected the Guest account activation" -where: | - equals("log.Id", "17925") +references: +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +- https://attack.mitre.org/tactics/TA0001/ +- https://attack.mitre.org/techniques/T1078/001/ +description: Sophos reports appliance message ID 17925. Inspect the original vendor message and approved administration. + The available field guide lists this legacy identifier without a message body; this event alone does not establish + a vulnerability, account abuse or unauthorized access. +where: equals("log.type","Event") && equals("log.messageId","17925") groupBy: - - adversary.ip - - adversary.user +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- adversary.user diff --git a/rules/sophos/sophos_xg_firewall/sophos_ip_spoofing_attack.yml b/rules/sophos/sophos_xg_firewall/sophos_ip_spoofing_attack.yml index cffdfb391..e8f04977e 100644 --- a/rules/sophos/sophos_xg_firewall/sophos_ip_spoofing_attack.yml +++ b/rules/sophos/sophos_xg_firewall/sophos_ip_spoofing_attack.yml @@ -1,26 +1,24 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - "firewall-sophos-xg" -name: "Probable Sophos ip spoofing attack" +- firewall-sophos-xg +name: Probable Sophos ip spoofing attack impact: confidentiality: 3 integrity: 3 availability: 3 -category: "Impact" -technique: "T1499 - Endpoint Denial of Service" +category: Impact +technique: T1499 - Endpoint Denial of Service adversary: origin -references: - - "https://support.sophos.com/support/s/article/KB-000035616?language=en_US" - - "https://docs.sophos.com/nsg/sophos-firewall/17.5/Help/en-us/webhelp/onlinehelp/nsg/sfos/concepts/DoSBypassRuleManage.html" - - "https://attack.mitre.org/tactics/TA0040" - - "https://attack.mitre.org/techniques/T1499/" - - "https://www.cloudflare.com/learning/ddos/glossary/ip-spoofing/" -description: "IP spoofing is the creation of Internet Protocol (IP) packets which have a modified source address in order to either hide - the identity of the sender, to impersonate another computer system, or both. It is a technique often used by bad actors to - invoke DDoS attacks against a target device or the surrounding infrastructure." -where: | - equals("log.component", "IP spoof") +references: +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +- https://attack.mitre.org/tactics/TA0040 +- https://attack.mitre.org/techniques/T1499/ +description: IP spoofing is the creation of Internet Protocol (IP) packets which have a modified source address + in order to either hide the identity of the sender, to impersonate another computer system, or both. It is a technique + often used by bad actors to invoke DDoS attacks against a target device or the surrounding infrastructure. +where: equals("log.type","Firewall") && equalsIgnoreCase("log.component","IP Spoof") groupBy: - - adversary.ip - - target.ip +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- target.ip diff --git a/rules/sophos/sophos_xg_firewall/sophos_password_guessing_on_administrator_account.yml b/rules/sophos/sophos_xg_firewall/sophos_password_guessing_on_administrator_account.yml index 58ae4c048..059ed1748 100644 --- a/rules/sophos/sophos_xg_firewall/sophos_password_guessing_on_administrator_account.yml +++ b/rules/sophos/sophos_xg_firewall/sophos_password_guessing_on_administrator_account.yml @@ -1,36 +1,42 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - firewall-sophos-xg -name: "Probable password guessing in Sophos Administrator account" +- firewall-sophos-xg +name: Repeated Sophos Administrator Authentication Failures impact: confidentiality: 3 integrity: 3 availability: 2 -category: "Credential Access" -technique: "T1110.001 - Brute Force" +category: Credential Access +technique: T1110.001 - Brute Force adversary: origin references: - - "https://support.sophos.com/support/s/article/KB-000034986?language=en_US" - - "https://attack.mitre.org/tactics/TA0006" - - "https://attack.mitre.org/techniques/T1110/001/" -description: "Adversaries with no prior knowledge of legitimate credentials within the system or environment - may guess passwords to attempt access to accounts. Without knowledge of the password for an account, - an adversary may opt to systematically guess the password using a repetitive or iterative mechanism. - An adversary may guess login credentials without prior knowledge of system or environment passwords - during an operation by using a list of common passwords. Password guessing may or may not take into - account the target's policies on password complexity or use policies that may lock accounts out after - a number of failed attempts." -where: | - equals("log.Id", "17913") -afterEvents: - - indexPattern: v11-log-firewall-sophos-xg-* - with: - - field: log.Id - operator: filter_term - value: '17913' - within: 15m - count: 10 +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +- https://attack.mitre.org/tactics/TA0006 +- https://attack.mitre.org/techniques/T1110/001/ +description: Repeated administrator sign-in failures from the same source address and firewall within 15 minutes. + Successful administration and unrelated configuration failures are excluded. +where: (equals("log.type","Event") && (oneOf("log.component",["GUI","CLI","API"]) && equals("log.subType","Admin") + && equals("log.messageId","17507") && equals("actionResult","failure"))) && exists("origin.ip") && exists("dataSource") + && !equals("dataSource","") && exists("log.sophosScope") && !equals("log.sophosScope","") groupBy: - - adversary.ip - - adversary.user +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- adversary.user +correlation: +- indexPattern: v11-log-firewall-sophos-xg-* + within: 15m + count: 10 + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosScope + operator: filter_term + value: '{{.log.sophosScope}}' + - field: origin.ip + operator: filter_term + value: '{{.origin.ip}}' + - field: log.correlationCandidate.sophosXG.adminFailure + operator: filter_term + value: match diff --git a/rules/sophos/sophos_xg_firewall/sophos_xg_ips_signatures.yml b/rules/sophos/sophos_xg_firewall/sophos_xg_ips_signatures.yml index 10e0be3af..e2f6a6f9d 100644 --- a/rules/sophos/sophos_xg_firewall/sophos_xg_ips_signatures.yml +++ b/rules/sophos/sophos_xg_firewall/sophos_xg_ips_signatures.yml @@ -1,42 +1,46 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - firewall-sophos-xg -name: Sophos XG IPS Alert Detection +- firewall-sophos-xg +name: Repeated Sophos IPS Priority 1 or 2 Detections impact: confidentiality: 3 integrity: 3 availability: 2 category: Intrusion Detection -technique: "T1190 - Exploit Public-Facing Application" +technique: T1190 - Exploit Public-Facing Application adversary: origin references: - - https://docs.sophos.com/nsg/sophos-firewall/20.0/Help/en-us/webhelp/onlinehelp/AdministratorHelp/IPS/index.html - - https://attack.mitre.org/techniques/T1190/ -description: | - Detects IPS alert triggers on Sophos XG Firewall indicating active exploitation attempts, vulnerability scanning, or known attack signatures targeting protected hosts. - - Next Steps: - 1. Review the IPS signature details and severity level - 2. Investigate the source IP for additional malicious activity - 3. Check if the attack was blocked or only logged - 4. Verify the target system is patched against the detected vulnerability - 5. Scan the target for signs of compromise if the attack may have succeeded - 6. Update IPS signatures and security policies -where: | - equals("log.type", "IPS") && - (oneOf("log.severity", ["Critical", "High"]) || - contains("log.priority", ["1", "2"])) && - exists("origin.ip") && - exists("target.ip") -afterEvents: - - indexPattern: v11-log-firewall-sophos-xg-* - with: - - field: origin.ip - operator: filter_term - value: '{{.origin.ip}}' - within: 15m - count: 3 +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +- https://attack.mitre.org/techniques/T1190/ +description: Repeated IDP signature/anomaly detections carrying rule priority 1 or 2 (or explicit High/Critical + severity), from the same source to the same destination on the same firewall. A Drop remains denied; a Detect + does not prove exploitation succeeded. +where: (equals("log.type","IDP") && oneOf("log.component",["Signatures","Anomaly"]) && oneOf("log.subType",["Detect","Drop"]) + && (oneOf("log.rulepriority",["1","2"]) || oneOf("log.severity",["Critical","High"])) && exists("origin.ip") && + exists("target.ip")) && exists("origin.ip") && exists("dataSource") && !equals("dataSource","") && exists("log.sophosScope") + && !equals("log.sophosScope","") groupBy: - - adversary.ip - - target.ip +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- target.ip +correlation: +- indexPattern: v11-log-firewall-sophos-xg-* + within: 15m + count: 3 + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosScope + operator: filter_term + value: '{{.log.sophosScope}}' + - field: origin.ip + operator: filter_term + value: '{{.origin.ip}}' + - field: target.ip + operator: filter_term + value: '{{.target.ip}}' + - field: log.correlationCandidate.sophosXG.ips + operator: filter_term + value: match diff --git a/rules/sophos/sophos_xg_firewall/sophos_xg_vpn_auth_failures.yml b/rules/sophos/sophos_xg_firewall/sophos_xg_vpn_auth_failures.yml index 4bc1bbc53..14b5f4e29 100644 --- a/rules/sophos/sophos_xg_firewall/sophos_xg_vpn_auth_failures.yml +++ b/rules/sophos/sophos_xg_firewall/sophos_xg_vpn_auth_failures.yml @@ -1,42 +1,41 @@ -# Rule version v1.0.0 - +# Sophos source-contract review; thresholds and impact ratings preserved. dataTypes: - - firewall-sophos-xg -name: Sophos XG VPN Authentication Failures +- firewall-sophos-xg +name: Repeated Sophos VPN Authentication Failures impact: confidentiality: 3 integrity: 2 availability: 1 category: Credential Access -technique: "T1110 - Brute Force" +technique: T1110 - Brute Force adversary: origin references: - - https://docs.sophos.com/nsg/sophos-firewall/20.0/Help/en-us/webhelp/onlinehelp/AdministratorHelp/VPN/index.html - - https://attack.mitre.org/techniques/T1110/ -description: | - Detects multiple VPN authentication failures on Sophos XG Firewall, indicating potential brute force attacks against SSL VPN or IPsec VPN services. - - Next Steps: - 1. Investigate the source IP and check geographic location - 2. Verify the targeted user account exists and is active - 3. Check for successful VPN connections from the same IP - 4. Consider blocking the source IP - 5. Enable MFA for VPN access - 6. Review VPN portal exposure settings -where: | - (equals("log.component", "SSL VPN") || equals("log.component", "IPSec")) && - equals("log.type", "Event") && - (contains("log.message", ["authentication failed", "login failed", "invalid credentials", "auth failure"]) || - contains("log.subType", "Authentication")) && - exists("origin.ip") -afterEvents: - - indexPattern: v11-log-firewall-sophos-xg-* - with: - - field: origin.ip - operator: filter_term - value: '{{.origin.ip}}' - within: 15m - count: 10 +- https://docs.sophos.com/nsg/sophos-firewall/20.0/syslog/index.html +- https://attack.mitre.org/techniques/T1110/ +description: Repeated failed SSL VPN, VPN or VPN portal authentication from the same source address and firewall. + Successful authentication, tunnel termination and IKE parsing errors are excluded. +where: (equals("log.type","Event") && equals("log.subType","Authentication") && oneOf("log.component",["SSL VPN + Authentication","VPN Authentication","VPN Portal Authentication"]) && equals("actionResult","failure")) && exists("origin.ip") + && exists("dataSource") && !equals("dataSource","") && exists("log.sophosScope") && !equals("log.sophosScope","") groupBy: - - adversary.ip - - adversary.user +- lastEvent.dataSource +- lastEvent.log.sophosScope +- adversary.ip +- adversary.user +correlation: +- indexPattern: v11-log-firewall-sophos-xg-* + within: 15m + count: 10 + with: + - field: dataSource + operator: filter_term + value: '{{.dataSource}}' + - field: log.sophosScope + operator: filter_term + value: '{{.log.sophosScope}}' + - field: origin.ip + operator: filter_term + value: '{{.origin.ip}}' + - field: log.correlationCandidate.sophosXG.vpnFailure + operator: filter_term + value: match