/* Zscaler Deception event logs: https://help.zscaler.com/deception/about-event-logs */ // #region PREPARSE /************************************************************ ****** Parse timestamp and log headers ****** Extract message field for parsing ****** Parse structured data ************************************************************/ case { // Parse logs ingested in Syslog format and extract the JSON Structured Data for parseJSON. @rawstring = /^\<(?\d+?)\>(?\d+?)? (?<__timestamp>\S+)? (\-|(?\S+?)) (\-|(?\S+?)) (\-|(?\S+?)) (\-|(?.*?))? (\-|(?.*?)) (?.*)$/ | parseJson(prefix="Vendor.", excludeEmpty="true", handleNull="discard", field="syslog.message") | drop(syslog.message); // Only ParseJSON in the event that the logs are not Syslog format. * | parseJson(prefix="Vendor.", excludeEmpty=true, handleNull=discard); } // Timestamp Parsing | case { // Timestamp example: 2023-10-16T18:21:58Z Vendor.timestamp = * | parseTimestamp(field="Vendor.timestamp", timezone="Z"); // Parse timestamp from syslog header * | parseTimestamp(field="__timestamp", timezone="Z"); } // #endregion // #region METADATA /************************************************************ ****** Static Metadata Definitions ************************************************************/ | Parser.version := "2.1.0" | Vendor := "zscaler" | event.kind := "event" | event.module := "deception" | ecs.version := "9.0.0" | Cps.version := "1.0.0" // #endregion // #region NORMALIZATION /************************************************************ ****** Parse unstructured data (i.e. message field) ****** Normalize fields to data model ************************************************************/ // Event Categorization and Outcome | case { // Identity Audit events and apply categorization/outcome determination Vendor.module = * | event.dataset := "deception.audit" | case { Vendor.description = /added|generated/i | array:append("event.category[]", values=["configuration"]) | array:append("event.type[]", values=["creation"]); Vendor.description = /updated|changed|start|stop|put|enabled/i | array:append("event.category[]", values=["configuration"]) | array:append("event.type[]", values=["change"]); Vendor.description = /delete/i | array:append("event.category[]", values=["configuration"]) | array:append("event.type[]", values=["deletion"]); Vendor.description = /^There was a failed attempt to login as (?(?.*?)@.*)/ | array:append("event.category[]", values=["authentication"]) | array:append("event.type[]", values=["start"]); Vendor.module = /login/i | array:append("event.category[]", values=["authentication"]) | array:append("event.type[]", values=["start"]) | event.outcome := "success"; Vendor.module = "Logout" | array:append("event.category[]", values=["authentication"]) | array:append("event.type[]", values=["end"]); Vendor.description = /^Isolate attacker (?\S+)/ | array:append("event.category[]", values=["network","configuration","threat"]) | array:append("event.type[]", values=["change","indicator"]); } | case { // event.outcome event.outcome != * AND Vendor.status_code = /^1|2/ | event.outcome := "success"; Vendor.status_code != * | event.outcome := "success"; event.outcome != * | event.outcome := "failure"; }; // Remaining Threat-Related Datasets * | event.dataset := "deception.threat" | array:append("event.category[]", values=["network","threat"]) | array:append("event.type[]", values=["indicator"]) | event.outcome := "success"; } // Client fields | client.address := Vendor.decoy.client.name | client.bytes := Vendor.network.orig_ip_bytes | client.packets := Vendor.network.orig_pkts // Event fields | event.duration := Vendor.network.duration | event.id := Vendor.id | event.risk_score := Vendor.score | event.reason := Vendor.description | log.level := coalesce([Vendor.severity,Vendor.threat.alert.severity]) | case { log.level = /^Critical|5/i | event.severity := "90"; log.level = /^High|4/i | event.severity := "70"; log.level = /^Medium|3/i | event.severity := "50"; log.level = /^Low|2/i | event.severity := "30"; log.level = /^Informational|1/i | event.severity := "10"; *; } // Network fields | network.protocol := Vendor.network.protocol | network.name := Vendor.decoy.network_name | network.protocol := Vendor.recon.scheme // Observer fields | observer.name := Vendor.decoy.appliance.name // Process fields | process.command_line := Vendor.linux.command_line | process.pid := Vendor.linux.pid | process.name := Vendor.linux.process_name | process.user.name := Vendor.linux.user // HTTP fields | http.request.bytes := Vendor.recon.bytes_sent | http.request.method := coalesce([Vendor.recon.method,Vendor.web.method,Vendor.method]) | http.response.status_code := coalesce([Vendor.web.status, Vendor.recon.status, Vendor.status_code]) | regex(field="Vendor.recon.server_protocol", regex="\\/(?\\d+\\.\\d+)", strict=false) | regex(field="Vendor.web.server_protocol", regex="\\/(?\\d+\\.\\d+)", strict=false) // Server fields | server.address := coalesce([Vendor.decoy.name,Vendor.recon.server_name]) | server.bytes := Vendor.network.resp_ip_bytes | server.packets := Vendor.network.resp_pkts | server.port := Vendor.decoy.port // Source fields | source.ip := threat.indicator.ip | source.port := threat.indicator.port // Threat fields | threat.indicator.port := Vendor.attacker.port | threat.indicator.name := Vendor.attacker.name | threat.indicator.type := Vendor.type | concatArray(field="Vendor.mitre_ids", separator=",", as="threat.technique.id") | case { // Test if Vendor.attacker.ip format is "10.10.0.1 [10.10.0.1]" then extract the first value as the IP address and the second as the device name. Vendor.attacker.ip = /^(?\d+\.\d+\.\d+\.\d+)\s+(\[(?[^\]]*)\])?$/; *; } // TLS fields | tls.cipher := Vendor.ssl.cipher | tls.version := Vendor.ssl.version // Trace fields | trace.id := Vendor.id // URL fields | url.domain := coalesce([Vendor.recon.host,Vendor.web.host]) | url.path := coalesce([Vendor.recon.request_uri,Vendor.recon.uri,Vendor.web.request_uri]) | url.full := Vendor.web.uri | url.scheme := Vendor.web.scheme // User Fields | case { Vendor.username = /(?.*?) \((?.*?)\)/; Vendor.username != "Unauthenticated" | user.name := Vendor.username; *; } // User Agent fields | user_agent.name := coalesce([Vendor.web.user_agent.string, Vendor.recon.user_agent.string]) | user_agent.version := Vendor.recon.user_agent.patch // IP address validation before field normalization | case { cidr(field="Vendor.abuseip.ipAddress", subnet=["0.0.0.0/0", "::/0"]) | threat.indicator.ip := Vendor.abuseip.ipAddress; cidr(field="Vendor.decoy.ip", subnet=["0.0.0.0/0", "::/0"]) | server.ip := Vendor.decoy.ip; * } // #endregion // #region POST-NORMALIZATION /************************************************************ ****** Post Normalization ****** Custom parser logic needed after normalization ************************************************************/ | drop(__timestamp) // #endregion