File: //usr/share/filebeat/module/cisco/shared/ingest/asa-ftd-pipeline.yml
---
description: "Pipeline for Cisco {< .internal_PREFIX >} logs"
processors:
- set:
field: event.ingested
value: '{{_ingest.timestamp}}'
#
# Parse the syslog header
#
# This populates the host.hostname, process.name, timestamp and other fields
# from the header and stores the message contents in log.original.
- grok:
field: message
patterns:
- "(?:%{SYSLOG_HEADER})?\\s*%{GREEDYDATA:log.original}"
pattern_definitions:
SYSLOG_HEADER: "(?:%{SYSPRIORITY}\\s*)?(?:%{FTD_DATE:_temp_.raw_date}:?\\s+)?(?:%{PROCESS_HOST}|%{HOST_PROCESS})(?:{DATA})?%{SYSLOG_END}?"
SYSPRIORITY: "<%{NONNEGINT:log.syslog.priority:int}>"
# Beginning with version 6.3, Firepower Threat Defense provides the option to enable timestamp as per RFC 5424.
FTD_DATE: "(?:%{TIMESTAMP_ISO8601}|%{ASA_DATE})"
ASA_DATE: "(?:%{DAY} )?%{MONTH} *%{MONTHDAY}(?: %{YEAR})? %{TIME}(?: %{TZ:_temp_.tz})?"
TZ: "(?:[APMCE][SD]T|UTC)"
TIMESTAMP_ISO8601: "%{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE:_temp_.tz}?"
ISO8601_TIMEZONE: "(?:Z|[+-]%{HOUR}(?::?%{MINUTE}))"
PROCESS: "(?:[^%\\s:\\[]+)"
SYSLOG_END: "(?:(:|\\s)\\s+)"
# exactly match the syntax for firepower management logs
PROCESS_HOST: "(?:%{PROCESS:process.name}:\\s%{SYSLOGHOST:host.name})"
HOST_PROCESS: "(?:%{SYSLOGHOST:host.hostname}:?\\s+)?(?:%{PROCESS:process.name}?(?:\\[%{POSINT:process.pid:long}\\])?)?"
- script:
lang: painless
source: |
if (ctx.log?.syslog?.priority != null) {
def severity = new HashMap();
severity['code'] = ctx.log.syslog.priority&0x7;
ctx.log.syslog['severity'] = severity;
def facility = new HashMap();
facility['code'] = ctx.log.syslog.priority>>3;
ctx.log.syslog['facility'] = facility;
}
#
# Parse FTD/ASA style message
#
# This parses the header of an EMBLEM-style message for FTD and ASA prefixes.
- grok:
field: log.original
patterns:
- "%{FTD_PREFIX}-(?:%{FTD_SUFFIX:_temp_.cisco.suffix}-)?%{NONNEGINT:event.severity:int}-%{POSINT:_temp_.cisco.message_id}?:?\\s*%{GREEDYDATA:message}"
# Before version 6.3, messages for connection, security intelligence, and intrusion events didn't include an event type ID in the message header.
- "%{GREEDYDATA:message}"
pattern_definitions:
FTD_SUFFIX: "[^0-9-]+"
# Before version 6.3, FTD used ASA prefix in syslog messages
FTD_PREFIX: "%{DATA}%(?:[A-Z]+)"
#
# Create missing fields when no %FTD label is present
#
# message_id is needed in order for some processors below to work.
- set:
field: _temp_.cisco.message_id
value: ""
if: "ctx?._temp_?.cisco?.message_id == null"
#
# set default event.severity to 7 (debug):
#
# This value is read from the EMBLEM header and won't be present if this is not
# an emblem message (firewalls can be configured to report other kinds of events)
# This has no effect unless var.log_level is above 7 (default) to filter some
# messages.
- set:
field: event.severity
value: 7
if: "ctx?.event?.severity == null"
#
# Drop messages above configured log_level
#
- drop:
if: "ctx.event.severity > {< .log_level >}"
# Time zone can come from three sources, choose in order: log, config, locale, default to UTC.
- set:
field: _temp_.tz
value: UTC
if: ctx._temp_?.tz == 'Z'
- set:
field: _temp_.tz
copy_from: _temp_.timezone_offset
override: false
if: ctx._temp_?.timezone_offset != null && ctx._temp_?.timezone_offset != 'local'
- set:
field: _temp_.tz
copy_from: event.timezone
override: false
if: ctx.event?.timezone != null
- set:
field: _temp_.tz
value: UTC
override: false
- set:
field: event.timezone
copy_from: _temp_.tz
#
# Parse the date included in FTD logs
#
- date:
if: ctx._temp_?.raw_date != null
timezone: "{{{ event.timezone }}}"
field: "_temp_.raw_date"
formats:
- "ISO8601"
- "MMM d HH:mm:ss"
- "MMM dd HH:mm:ss"
- "EEE MMM d HH:mm:ss"
- "EEE MMM dd HH:mm:ss"
- "MMM d HH:mm:ss z"
- "MMM dd HH:mm:ss z"
- "EEE MMM d HH:mm:ss z"
- "EEE MMM dd HH:mm:ss z"
- "MMM d yyyy HH:mm:ss"
- "MMM dd yyyy HH:mm:ss"
- "EEE MMM d yyyy HH:mm:ss"
- "EEE MMM dd yyyy HH:mm:ss"
- "MMM d yyyy HH:mm:ss z"
- "MMM dd yyyy HH:mm:ss z"
- "EEE MMM d yyyy HH:mm:ss z"
- "EEE MMM dd yyyy HH:mm:ss z"
on_failure:
# Try to re-parse as UTC to catch when TZ is invalid or unknown.
- remove:
field: event.timezone
ignore_missing: true
- date:
if: ctx._temp_?.raw_date != null
field: "_temp_.raw_date"
formats:
- "ISO8601"
- "MMM d HH:mm:ss"
- "MMM dd HH:mm:ss"
- "EEE MMM d HH:mm:ss"
- "EEE MMM dd HH:mm:ss"
- "MMM d HH:mm:ss z"
- "MMM dd HH:mm:ss z"
- "EEE MMM d HH:mm:ss z"
- "EEE MMM dd HH:mm:ss z"
- "MMM d yyyy HH:mm:ss"
- "MMM dd yyyy HH:mm:ss"
- "EEE MMM d yyyy HH:mm:ss"
- "EEE MMM dd yyyy HH:mm:ss"
- "MMM d yyyy HH:mm:ss z"
- "MMM dd yyyy HH:mm:ss z"
- "EEE MMM d yyyy HH:mm:ss z"
- "EEE MMM dd yyyy HH:mm:ss z"
on_failure:
- append:
field: error.message
value: "{{{ _ingest.on_failure_message }}}"
#
# Set log.level
#
- set:
field: "log.level"
if: "ctx.event.severity == 0"
value: unknown
- set:
field: "log.level"
if: "ctx.event.severity == 1"
value: alert
- set:
field: "log.level"
if: "ctx.event.severity == 2"
value: critical
- set:
field: "log.level"
if: "ctx.event.severity == 3"
value: error
- set:
field: "log.level"
if: "ctx.event.severity == 4"
value: warning
- set:
field: "log.level"
if: "ctx.event.severity == 5"
value: notification
- set:
field: "log.level"
if: "ctx.event.severity == 6"
value: informational
- set:
field: "log.level"
if: "ctx.event.severity == 7"
value: debug
#
# Firewall messages
#
# This set of messages is shared between FTD and ASA.
- set:
if: 'ctx._temp_.cisco.message_id != ""'
field: "event.action"
value: "firewall-rule"
- dissect:
if: "ctx._temp_.cisco.message_id == '106001'"
field: "message"
description: "106001"
pattern: "%{network.direction} %{network.transport} connection %{event.outcome} from %{source.address}/%{source.port} to %{destination.address}/%{destination.port} flags %{} on interface %{_temp_.cisco.source_interface}"
- dissect:
if: "ctx._temp_.cisco.message_id == '106002'"
field: "message"
description: "106002"
pattern: "%{network.transport} Connection %{event.outcome} by %{network.direction} list %{_temp_.cisco.list_id} src %{source.address} dest %{destination.address}"
- dissect:
if: "ctx._temp_.cisco.message_id == '106006'"
field: "message"
description: "106006"
pattern: "%{event.outcome} %{network.direction} %{network.transport} from %{source.address}/%{source.port} to %{destination.address}/%{destination.port} on interface %{_temp_.cisco.source_interface}"
- dissect:
if: "ctx._temp_.cisco.message_id == '106007'"
field: "message"
description: "106007"
pattern: "%{event.outcome} %{network.direction} %{network.transport} from %{source.address}/%{source.port} to %{destination.address}/%{destination.port} due to %{network.protocol} %{}"
- grok:
if: "ctx._temp_.cisco.message_id == '106010'"
field: "message"
description: "106010"
patterns:
- "%{NOTSPACE:event.outcome} %{NOTSPACE:network.direction} %{NOTSPACE:network.transport} src %{NOTSPACE:_temp_.cisco.source_interface}:%{NOTSPACE:source.address}/%{POSINT:source.port} (%{DATA})?dst %{NOTSPACE:_temp_.cisco.destination_interface}:%{NOTSPACE:destination.address}/%{POSINT:destination.port}(%{GREEDYDATA})?"
- dissect:
if: "ctx._temp_.cisco.message_id == '106013'"
field: "message"
description: "106013"
pattern: "Dropping echo request from %{source.address} to PAT address %{destination.address}"
- set:
if: "ctx._temp_.cisco.message_id == '106013'"
field: "network.transport"
description: "106013"
value: icmp
- set:
if: "ctx._temp_.cisco.message_id == '106013'"
field: "network.direction"
description: "106013"
value: inbound
- grok:
if: "ctx._temp_.cisco.message_id == '106014'"
field: "message"
description: "106014"
patterns:
- "%{NOTSPACE:event.outcome} %{NOTSPACE:network.direction} %{NOTSPACE:network.transport} src %{NOTSPACE:_temp_.cisco.source_interface}:%{NOTSPACE:source.address} (%{DATA})?dst %{NOTSPACE:_temp_.cisco.destination_interface}:(?<destination.address>[^ (]*)(%{GREEDYDATA})?"
- grok:
if: "ctx._temp_.cisco.message_id == '106015'"
field: "message"
description: "106015"
patterns:
- "%{NOTSPACE:event.outcome} %{NOTSPACE:network.transport} %{NOTSPACE} %{NOTSPACE} from %{IP:source.address}/%{POSINT:source.port} to %{IPORHOST:destination.address}/%{POSINT:destination.port} flags %{DATA} on interface %{NOTSPACE:_temp_.cisco.source_interface}"
- dissect:
if: "ctx._temp_.cisco.message_id == '106016'"
field: "message"
pattern: "%{event.outcome} IP spoof from (%{source.address}) to %{destination.address} on interface %{_temp_.cisco.source_interface}"
description: "106016"
- dissect:
if: "ctx._temp_.cisco.message_id == '106017'"
field: "message"
pattern: "%{event.outcome} IP due to Land Attack from %{source.address} to %{destination.address}"
description: "106017"
- dissect:
if: "ctx._temp_.cisco.message_id == '106018'"
field: "message"
pattern: "%{network.transport} packet type %{_temp_.cisco.icmp_type} %{event.outcome} by %{network.direction} list %{_temp_.cisco.list_id} src %{source.address} dest %{destination.address}"
description: "106018"
- dissect:
if: "ctx._temp_.cisco.message_id == '106020'"
field: "message"
pattern: "%{event.outcome} IP teardrop fragment (size = %{}, offset = %{}) from %{source.address} to %{destination.address}"
description: "106020"
- dissect:
if: "ctx._temp_.cisco.message_id == '106021'"
field: "message"
pattern: "%{event.outcome} %{network.transport} reverse path check from %{source.address} to %{destination.address} on interface %{_temp_.cisco.source_interface}"
description: "106021"
- dissect:
if: "ctx._temp_.cisco.message_id == '106022'"
field: "message"
pattern: "%{event.outcome} %{network.transport} connection spoof from %{source.address} to %{destination.address} on interface %{_temp_.cisco.source_interface}"
description: "106022"
- grok:
if: "ctx._temp_.cisco.message_id == '106023'"
field: "message"
description: "106023"
patterns:
- ^%{NOTSPACE:event.outcome} ((protocol %{POSINT:network.iana_number})|%{NOTSPACE:network.transport}) src %{NOTCOLON:_temp_.cisco.source_interface}:%{IPORHOST:source.address}(/%{POSINT:source.port})?\s*(\(%{CISCO_USER:_temp_.cisco.source_username}\) )?dst %{NOTCOLON:_temp_.cisco.destination_interface}:%{IPORHOST:destination.address}(/%{POSINT:destination.port})?%{DATA}by access-group "%{NOTSPACE:_temp_.cisco.list_id}"
pattern_definitions:
HOSTNAME: '\b(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62}))*(\.?|\b)'
IPORHOST: "(?:%{IP}|%{HOSTNAME})"
NOTCOLON: "[^:]*"
CISCO_USER: ((LOCAL\\)?(%{HOSTNAME}\\)?%{USERNAME}(@%{HOSTNAME})?(, *%{NUMBER})?)
- dissect:
if: "ctx._temp_.cisco.message_id == '106027'"
field: "message"
description: "106027"
pattern: '%{} %{event.outcome} src %{source.address} dst %{destination.address} by access-group "%{_temp_.cisco.list_id}"'
- dissect:
if: "ctx._temp_.cisco.message_id == '106100'"
field: "message"
description: "106100"
pattern: "access-list %{_temp_.cisco.list_id} %{event.outcome} %{network.transport} %{_temp_.cisco.source_interface}/%{source.address}(%{source.port})%{}-> %{_temp_.cisco.destination_interface}/%{destination.address}(%{destination.port})%{}"
- dissect:
if: "ctx._temp_.cisco.message_id == '106102' || ctx._temp_.cisco.message_id == '106103'"
field: "message"
description: "106103"
pattern: "access-list %{_temp_.cisco.list_id} %{event.outcome} %{network.transport} for user %{user.name} %{_temp_.cisco.source_interface}/%{source.address}(%{source.port})%{}-> %{_temp_.cisco.destination_interface}/%{destination.address}(%{destination.port})%{}"
- dissect:
if: "ctx._temp_.cisco.message_id == '111004'"
field: "message"
description: "111004"
pattern: "%{source.address} end configuration: %{_temp_.cisco.cli_outcome}"
- set:
field: event.outcome
description: "111004"
value: "success"
if: "ctx._temp_.cisco.message_id == '111004' && ctx?._temp_?.cisco?.cli_outcome == 'OK'"
- set:
field: event.outcome
description: "111004"
value: "failure"
if: "ctx._temp_.cisco.message_id == '111004' && ctx?._temp_?.cisco?.cli_outcome == 'FAILED'"
- remove:
field: _temp_.cisco.cli_outcome
ignore_missing: true
- append:
field: event.type
description: "111004"
value: "change"
if: "ctx._temp_.cisco.message_id == '111004'"
- grok:
if: "ctx._temp_.cisco.message_id == '111009'"
description: "111009"
field: "message"
patterns:
- "^%{NOTSPACE} '%{NOTSPACE:user.name}' executed %{NOTSPACE} %{GREEDYDATA:_temp_.cisco.command_line_arguments}"
- grok:
if: "ctx._temp_.cisco.message_id == '111010'"
field: "message"
description: "111010"
patterns:
- "User '%{NOTSPACE:user.name}', running %{QUOTEDSTRING} from IP %{IP:source.address}, executed %{QUOTEDSTRING:_temp_.cisco.command_line_arguments}"
- dissect:
if: "ctx._temp_.cisco.message_id == '113019'"
field: "message"
description: "113019"
pattern: "Group = %{source.user.group.name}, Username = %{source.user.name}, IP = %{destination.address}, Session disconnected. Session Type: %{_temp_.cisco.session_type}, Duration: %{_temp_.duration_hms}, Bytes xmt: %{source.bytes}, Bytes rcv: %{destination.bytes}, Reason: %{event.reason}"
- grok:
if: '["302013", "302015"].contains(ctx._temp_.cisco.message_id)'
field: "message"
description: "302013, 302015"
patterns:
- Built %{NOTSPACE:network.direction} %{NOTSPACE:network.transport} connection %{NUMBER:_temp_.cisco.connection_id} for %{NOTCOLON:_temp_.cisco.source_interface}:%{IPORHOST:source.address}/%{NUMBER:source.port} \(%{IPORHOST:_temp_.natsrcip}/%{NUMBER:_temp_.cisco.mapped_source_port}\)(\(%{CISCO_USER:_temp_.cisco.source_username}\))? to %{NOTCOLON:_temp_.cisco.destination_interface}:%{NOTSPACE:destination.address}/%{NUMBER:destination.port} \(%{NOTSPACE:_temp_.natdstip}/%{NUMBER:_temp_.cisco.mapped_destination_port}\)(\(%{CISCO_USER:_temp_.cisco.destination_username}\))?( \(%{CISCO_USER:_temp_.cisco.termination_user}\))?%{GREEDYDATA}
pattern_definitions:
HOSTNAME: '\b(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62}))*(\.?|\b)'
IPORHOST: "(?:%{IP}|%{HOSTNAME})"
NOTCOLON: "[^:]*"
CISCO_USER: ((LOCAL\\)?(%{HOSTNAME}\\)?%{USERNAME}(@%{HOSTNAME})?(, *%{NUMBER})?)
- dissect:
if: "ctx._temp_.cisco.message_id == '303002'"
field: "message"
description: "303002"
pattern: "%{network.protocol} connection from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port}, user %{client.user.name} %{} file %{file.path}"
- grok:
if: "ctx._temp_.cisco.message_id == '305012'"
field: "message"
description: "305012"
patterns:
- Teardown %{DATA} %{NOTSPACE:network.transport} translation from %{NOTCOLON:_temp_.cisco.source_interface}:%{IPORHOST:source.address}/%{NUMBER:source.port}(\s*\(%{CISCO_USER:_temp_.cisco.source_username}\))? to %{NOTCOLON:_temp_.cisco.destination_interface}:%{IP:destination.address}/%{NUMBER:destination.port} duration %{DURATION:_temp_.duration_hms}
pattern_definitions:
NOTCOLON: "[^:]*"
HOSTNAME: '\b(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62}))*(\.?|\b)'
IPORHOST: "(?:%{IP}|%{HOSTNAME})"
CISCO_USER: ((LOCAL\\)?(%{HOSTNAME}\\)?%{USERNAME}(@%{HOSTNAME})?(, *%{NUMBER})?)
DURATION: "%{INT}:%{MINUTE}:%{SECOND}"
- set:
if: '["302020"].contains(ctx._temp_.cisco.message_id)'
field: "event.action"
value: "flow-creation"
description: "302020"
- grok:
if: "ctx._temp_.cisco.message_id == '302020'"
field: "message"
description: "302020"
patterns:
- "Built %{NOTSPACE:network.direction} %{NOTSPACE:network.protocol} connection for faddr (?:%{NOTCOLON:_temp_.cisco.source_interface}:)?%{ECSDESTIPORHOST}/%{NUMBER}\\s*(?:\\(%{CISCO_USER:_temp_.cisco.destination_username}\\) )?gaddr (?:%{NOTCOLON}:)?%{MAPPEDSRC}/%{NUMBER} laddr (?:%{NOTCOLON:_temp_.cisco.source_interface}:)?%{ECSSOURCEIPORHOST}/%{NUMBER}\\s*(?:\\(%{CISCO_USER:_temp_.cisco.source_username}\\) )?(type %{NUMBER:_temp_.cisco.icmp_type} code %{NUMBER:_temp_.cisco.icmp_code})?"
pattern_definitions:
HOSTNAME: '\b(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62}))*(\.?|\b)'
IPORHOST: "(?:%{IP}|%{HOSTNAME})"
NOTCOLON: "[^:]*"
ECSSOURCEIPORHOST: "(?:%{IP:source.address}|%{HOSTNAME:source.domain})"
ECSDESTIPORHOST: "(?:%{IP:destination.address}|%{HOSTNAME:destination.domain})"
MAPPEDSRC: "(?:%{DATA:_temp_.natsrcip}|%{HOSTNAME})"
CISCO_USER: ((LOCAL\\)?(%{HOSTNAME}\\)?%{USERNAME}(@%{HOSTNAME})?(, *%{NUMBER})?)
- dissect:
if: "ctx._temp_.cisco.message_id == '302022'"
field: "message"
description: "302022"
pattern: "Built %{} stub %{network.transport} connection for %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} %{} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} %{}"
- dissect:
if: "ctx._temp_.cisco.message_id == '302023'"
field: "message"
description: "302023"
pattern: "Teardown stub %{network.transport} connection for %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} duration %{_temp_.duration_hms} forwarded bytes %{network.bytes} %{event.reason}"
- grok:
if: "ctx._temp_.cisco.message_id == '304001'"
field: "message"
description: "304001"
patterns:
- "(%{NOTSPACE:source.user.name}@)?%{IP:source.address}(\\(%{DATA}\\))? %{DATA} (%{NOTSPACE}@)?%{IPORHOST:destination.address}:%{GREEDYDATA:url.original}"
- set:
if: "ctx._temp_.cisco.message_id == '304001'"
field: "event.outcome"
description: "304001"
value: allowed
- dissect:
if: "ctx._temp_.cisco.message_id == '304002'"
field: "message"
description: "304002"
pattern: "Access %{event.outcome} URL %{url.original} SRC %{source.address} %{}EST %{destination.address} on interface %{_temp_.cisco.source_interface}"
- grok:
if: "ctx._temp_.cisco.message_id == '305011'"
field: "message"
description: "305011"
patterns:
- Built %{NOTSPACE} %{NOTSPACE:network.transport} translation from %{NOTSPACE:_temp_.cisco.source_interface}:%{IPORHOST:source.address}/%{NUMBER:source.port}(\(%{NOTSPACE:source.user.name}\))? to %{NOTSPACE:_temp_.cisco.destination_interface}:%{IP:destination.address}/%{NUMBER:destination.port}
- dissect:
if: "ctx._temp_.cisco.message_id == '313001'"
field: "message"
description: "313001"
pattern: "%{event.outcome} %{network.transport} type=%{_temp_.cisco.icmp_type}, code=%{_temp_.cisco.icmp_code} from %{source.address} on interface %{_temp_.cisco.source_interface}"
- dissect:
if: "ctx._temp_.cisco.message_id == '313004'"
field: "message"
description: "313004"
pattern: "%{event.outcome} %{network.transport} type=%{_temp_.cisco.icmp_type}, from%{}addr %{source.address} on interface %{_temp_.cisco.source_interface} to %{destination.address}: no matching session"
- dissect:
if: "ctx._temp_.cisco.message_id == '313005'"
field: "message"
description: "313005"
pattern: "No matching connection for %{network.transport} error message: %{} on %{_temp_.cisco.source_interface} interface.%{}riginal IP payload: %{}"
- dissect:
if: "ctx._temp_.cisco.message_id == '313008'"
field: "message"
description: "313008"
pattern: "%{event.outcome} %{network.transport} type=%{_temp_.cisco.icmp_type}, code=%{_temp_.cisco.icmp_code} from %{source.address} on interface %{_temp_.cisco.source_interface}"
- dissect:
if: "ctx._temp_.cisco.message_id == '313009'"
field: "message"
description: "313009"
pattern: "%{event.outcome} invalid %{network.transport} code %{_temp_.cisco.icmp_code}, for %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}"
- dissect:
if: "ctx._temp_.cisco.message_id == '322001'"
field: "message"
description: "322001"
pattern: "%{event.outcome} MAC address %{source.mac}, possible spoof attempt on interface %{_temp_.cisco.source_interface}"
- dissect:
if: "ctx._temp_.cisco.message_id == '338001'"
field: "message"
description: "338001"
pattern: "Dynamic filter %{event.outcome} black%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}source %{} resolved from %{_temp_.cisco.list_id} list: %{source.domain}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- set:
if: "ctx._temp_.cisco.message_id == '338001'"
field: "server.domain"
description: "338001"
value: "{{source.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338002'"
field: "message"
description: "338002"
pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}destination %{} resolved from %{_temp_.cisco.list_id} list: %{destination.domain}"
- set:
if: "ctx._temp_.cisco.message_id == '338002'"
field: "server.domain"
description: "338002"
value: "{{destination.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338003'"
field: "message"
description: "338003"
pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}source %{} resolved from %{_temp_.cisco.list_id} list: %{}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- dissect:
if: "ctx._temp_.cisco.message_id == '338004'"
field: "message"
description: "338004"
pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}destination %{} resolved from %{_temp_.cisco.list_id} list: %{}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- dissect:
if: "ctx._temp_.cisco.message_id == '338005'"
field: "message"
description: "338005"
pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}source %{} resolved from %{_temp_.cisco.list_id} list: %{source.domain}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- set:
if: "ctx._temp_.cisco.message_id == '338005'"
field: "server.domain"
description: "338005"
value: "{{source.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338006'"
field: "message"
description: "338006"
pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}destination %{} resolved from %{_temp_.cisco.list_id} list: %{destination.domain}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- set:
if: "ctx._temp_.cisco.message_id == '338006'"
field: "server.domain"
description: "338006"
value: "{{destination.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338007'"
field: "message"
description: "338007"
pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}source %{} resolved from %{_temp_.cisco.list_id} list: %{}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- dissect:
if: "ctx._temp_.cisco.message_id == '338008'"
field: "message"
description: "338008"
pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}destination %{} resolved from %{_temp_.cisco.list_id} list: %{}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- dissect:
if: "ctx._temp_.cisco.message_id == '338101'"
field: "message"
description: "338101"
pattern: "Dynamic %{}ilter %{event.outcome} white%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}source %{} resolved from %{_temp_.cisco.list_id} list: %{source.domain}"
- set:
if: "ctx._temp_.cisco.message_id == '338101'"
field: "server.domain"
description: "338101"
value: "{{source.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338102'"
field: "message"
description: "338102"
pattern: "Dynamic %{}ilter %{event.outcome} white%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}destination %{} resolved from %{_temp_.cisco.list_id} list: %{destination.domain}"
- set:
if: "ctx._temp_.cisco.message_id == '338102'"
field: "server.domain"
description: "338102"
value: "{{destination.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338103'"
field: "message"
description: "338103"
pattern: "Dynamic %{}ilter %{event.outcome} white%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}source %{} resolved from %{_temp_.cisco.list_id} list: %{}"
- dissect:
if: "ctx._temp_.cisco.message_id == '338104'"
field: "message"
description: "338104"
pattern: "Dynamic %{}ilter %{event.outcome} white%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}destination %{} resolved from %{_temp_.cisco.list_id} list: %{}"
- dissect:
if: "ctx._temp_.cisco.message_id == '338201'"
field: "message"
description: "338201"
pattern: "Dynamic %{}ilter %{event.outcome} grey%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}source %{} resolved from %{_temp_.cisco.list_id} list: %{source.domain}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- set:
if: "ctx._temp_.cisco.message_id == '338201'"
field: "server.domain"
description: "338201"
value: "{{source.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338202'"
field: "message"
description: "338202"
pattern: "Dynamic %{}ilter %{event.outcome} grey%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}destination %{} resolved from %{_temp_.cisco.list_id} list: %{destination.domain}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- set:
if: "ctx._temp_.cisco.message_id == '338202'"
field: "server.domain"
description: "338202"
value: "{{destination.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338203'"
field: "message"
description: "338203"
pattern: "Dynamic %{}ilter %{event.outcome} grey%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}source %{} resolved from %{_temp_.cisco.list_id} list: %{source.domain}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- set:
if: "ctx._temp_.cisco.message_id == '338203'"
field: "server.domain"
description: "338203"
value: "{{source.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338204'"
field: "message"
description: "338204"
pattern: "Dynamic %{}ilter %{event.outcome} grey%{}d %{network.transport} traffic from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})%{}destination %{} resolved from %{_temp_.cisco.list_id} list: %{destination.domain}, threat-level: %{_temp_.cisco.threat_level}, category: %{_temp_.cisco.threat_category}"
- set:
if: "ctx._temp_.cisco.message_id == '338204'"
field: "server.domain"
description: "338204"
value: "{{destination.domain}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '338301'"
field: "message"
description: "338301"
pattern: "Intercepted DNS reply for domain %{source.domain} from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port}, matched %{_temp_.cisco.list_id}"
- set:
if: "ctx._temp_.cisco.message_id == '338301'"
field: "client.address"
description: "338301"
value: "{{destination.address}}"
ignore_empty_value: true
- set:
if: "ctx._temp_.cisco.message_id == '338301'"
field: "client.port"
description: "338301"
value: "{{destination.port}}"
ignore_empty_value: true
- set:
if: "ctx._temp_.cisco.message_id == '338301'"
field: "server.address"
description: "338301"
value: "{{source.address}}"
ignore_empty_value: true
- set:
if: "ctx._temp_.cisco.message_id == '338301'"
field: "server.port"
description: "338301"
value: "{{source.port}}"
ignore_empty_value: true
- dissect:
if: "ctx._temp_.cisco.message_id == '502103'"
field: "message"
description: "502103"
pattern: "User priv level changed: Uname: %{user.name} From: %{_temp_.cisco.privilege.old} To: %{_temp_.cisco.privilege.new}"
- append:
if: "ctx._temp_.cisco.message_id == '502103'"
field: "event.type"
description: "502103"
value:
- "group"
- "change"
- append:
if: "ctx._temp_.cisco.message_id == '502103'"
field: "event.category"
description: "502103"
value: "iam"
- dissect:
if: "ctx._temp_.cisco.message_id == '507003'"
field: "message"
description: "507003"
pattern: "%{network.transport} flow from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} terminated by inspection engine, reason - %{message}"
- dissect:
if: '["605004", "605005"].contains(ctx._temp_.cisco.message_id)'
field: "message"
description: "605004, 605005"
pattern: 'Login %{event.outcome} from %{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{network.protocol} for user "%{source.user.name}"'
- dissect:
if: "ctx._temp_.cisco.message_id == '609001'"
field: "message"
description: "609001"
pattern: "Built local-host %{_temp_.cisco.source_interface}:%{source.address}"
- dissect:
if: "ctx._temp_.cisco.message_id == '609002'"
field: "message"
description: "609002"
pattern: "Teardown local-host %{_temp_.cisco.source_interface}:%{source.address} duration %{_temp_.duration_hms}"
- dissect:
if: '["611102", "611101"].contains(ctx._temp_.cisco.message_id)'
field: "message"
description: "611102, 611101"
pattern: 'User authentication %{event.outcome}: IP address: %{source.address}, Uname: %{user.name}'
- dissect:
if: "ctx._temp_.cisco.message_id == '710003'"
field: "message"
description: "710003"
pattern: "%{network.transport} access %{event.outcome} by ACL from %{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port}"
- dissect:
if: "ctx._temp_.cisco.message_id == '710005'"
field: "message"
description: "710005"
pattern: "%{network.transport} request %{event.outcome} from %{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port}"
- dissect:
if: "ctx._temp_.cisco.message_id == '713049'"
field: "message"
description: "713049"
pattern: "Group = %{}, IP = %{source.address}, Security negotiation complete for LAN-to-LAN Group (%{}) %{}, Inbound SPI = %{}, Outbound SPI = %{}"
ignore_failure: true
- dissect:
if: "ctx._temp_.cisco.message_id == '713049'"
field: "message"
description: "713049"
pattern: "Group = %{}, Username = %{user.name}, IP = %{source.address}, Security negotiation complete for User (%{}) %{}, Inbound SPI = %{}, Outbound SPI = %{}"
ignore_failure: true
- grok:
if: "ctx._temp_.cisco.message_id == '716002'"
field: "message"
description: "716002"
patterns:
- "Group <%{NOTSPACE:_temp_.cisco.webvpn.group_name}> User <%{NOTSPACE:source.user.name}> IP <%{IP:source.address}> WebVPN session terminated: %{GREEDYDATA:event.reason}."
- "Group %{NOTSPACE:_temp_.cisco.webvpn.group_name} User %{NOTSPACE:source.user.name} IP %{IP:source.address} WebVPN session terminated: %{GREEDYDATA:event.reason}."
- grok:
if: "ctx._temp_.cisco.message_id == '722051'"
field: "message"
description: "722051"
patterns:
- "Group <%{NOTSPACE:_temp_.cisco.webvpn.group_name}> User <%{NOTSPACE:source.user.name}> IP <%{IP:source.address}> IPv4 Address <%{IP:_temp_.cisco.assigned_ip}> %{GREEDYDATA}"
- "Group %{NOTSPACE:_temp_.cisco.webvpn.group_name} User %{NOTSPACE:source.user.name} IP %{IP:source.address} IPv4 Address %{IP:_temp_.cisco.assigned_ip} %{GREEDYDATA}"
- grok:
if: "ctx._temp_.cisco.message_id == '733100'"
field: "message"
description: "733100"
patterns:
- \[(%{SPACE})?%{DATA:_temp_.cisco.burst.object}\] drop %{NOTSPACE:_temp_.cisco.burst.id} exceeded. Current burst rate is %{INT:_temp_.cisco.burst.current_rate} per second, max configured rate is %{INT:_temp_.cisco.burst.configured_rate}; Current average rate is %{INT:_temp_.cisco.burst.avg_rate} per second, max configured rate is %{INT:_temp_.cisco.burst.configured_avg_rate}; Cumulative total count is %{INT:_temp_.cisco.burst.cumulative_count}
- dissect:
if: "ctx._temp_.cisco.message_id == '734001'"
field: "message"
description: "734001"
pattern: "DAP: User %{user.email}, Addr %{source.address}, Connection %{_temp_.cisco.connection_type}: The following DAP records were selected for this connection: %{_temp_.cisco.dap_records->}"
- dissect:
if: "ctx._temp_.cisco.message_id == '805001'"
field: "message"
description: "805001"
pattern: "Offloaded %{network.transport} Flow for connection %{_temp_.cisco.connection_id} from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})"
- dissect:
if: "ctx._temp_.cisco.message_id == '805002'"
field: "message"
description: "805002"
pattern: "%{network.transport} Flow is no longer offloaded for connection %{_temp_.cisco.connection_id} from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} (%{_temp_.natsrcip}/%{_temp_.cisco.mapped_source_port}) to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} (%{_temp_.natdstip}/%{_temp_.cisco.mapped_destination_port})"
- split:
field: "_temp_.cisco.dap_records"
separator: ",\\s+"
ignore_missing: true
- dissect:
if: "ctx._temp_.cisco.message_id == '434001'"
field: "message"
pattern: "SFR card not up and fail-close mode used, %{event.action}ping %{network.protocol} packet from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port}"
- dissect:
if: "ctx._temp_.cisco.message_id == '434002'"
field: "message"
pattern: "SFR requested to %{event.action} %{network.protocol} packet from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port}"
- dissect:
if: "ctx._temp_.cisco.message_id == '434003'"
field: "message"
pattern: "SFR requested to %{event.action} %{network.protocol} connection from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port}"
- dissect:
if: "ctx._temp_.cisco.message_id == '434004'"
field: "message"
pattern: "SFR requested ASA to %{event.action} further packet redirection and process %{network.protocol} flow from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} locally"
- dissect:
if: "ctx._temp_.cisco.message_id == '110002'"
field: "message"
pattern: "%{event.reason} for %{network.protocol} from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{destination.address}/%{destination.port}"
- dissect:
if: "ctx._temp_.cisco.message_id == '419002'"
field: "message"
pattern: "%{event.reason}from %{_temp_.cisco.source_interface}:%{source.address}/%{source.port} to %{_temp_.cisco.destination_interface}:%{destination.address}/%{destination.port} %{+event.reason}"
- dissect:
if: '["602303", "602304"].contains(ctx._temp_.cisco.message_id)'
field: "message"
pattern: "%{network.type}: An %{network.direction} %{_temp_.cisco.tunnel_type} SA (SPI= %{}) between %{source.address} and %{destination.address} (user= %{user.name}) has been %{event.action}."
- dissect:
if: "ctx._temp_.cisco.message_id == '750002'"
field: "message"
pattern: "Local:%{source.address}:%{source.port} Remote:%{destination.address}:%{destination.port} Username:%{user.name} %{event.reason}"
- dissect:
if: "ctx._temp_.cisco.message_id == '713120'"
field: "message"
pattern: "Group = %{}, IP = %{source.address}, %{event.reason} (msgid=%{event.id})"
- dissect:
if: "ctx._temp_.cisco.message_id == '713202'"
field: "message"
pattern: "IP = %{source.address}, %{event.reason}. %{} packet."
- dissect:
if: "ctx._temp_.cisco.message_id == '750003'"
field: "message"
pattern: "Local:%{source.address}:%{source.port} Remote:%{destination.address}:%{destination.port} Username:%{user.name} %{event.reason} ERROR:%{+event.reason}"
- grok:
if: '["713905", "713904", "713906", "713902", "713901"].contains(ctx._temp_.cisco.message_id)'
field: "message"
patterns:
- "^(Group = %{IP}, )?(IP = %{IP:source.address}, )?%{GREEDYDATA:event.reason}$"
# Handle ecs action outcome protocol
- set:
if: '["434001", "434002", "434003", "434004"].contains(ctx._temp_.cisco.message_id)'
field: "event.outcome"
value: "unknown"
- set:
if: '["419002"].contains(ctx._temp_.cisco.message_id)'
field: "network.protocol"
value: "tcp"
- set:
if: '["110002"].contains(ctx._temp_.cisco.message_id)'
field: "event.outcome"
value: "dropped"
- set:
if: '["713120"].contains(ctx._temp_.cisco.message_id)'
field: "event.outcome"
value: "success"
- set:
if: '["602303", "602304"].contains(ctx._temp_.cisco.message_id)'
field: "event.outcome"
value: "success"
- set:
if: '["710005"].contains(ctx._temp_.cisco.message_id)'
field: "event.outcome"
value: "dropped"
- set:
if: '["713901", "713902", "713903", "713904", "713905"].contains(ctx._temp_.cisco.message_id)'
field: "event.outcome"
value: "failure"
- set:
if: '["750002", "750003"].contains(ctx._temp_.cisco.message_id)'
field: "event.action"
value: "connection-started"
- set:
if: '["750003", "713905", "713904", "713906", "713902", "713901"].contains(ctx._temp_.cisco.message_id)'
field: "event.action"
value: "error"
- append:
if: '["750003", "713905", "713904", "713906", "713902", "713901"].contains(ctx._temp_.cisco.message_id)'
field: "event.type"
value: "error"
#
# Handle 302xxx messages (Flow expiration a.k.a "Teardown")
#
- set:
if: '["305012", "302014", "302016", "302018", "302021", "302036", "302304", "302306", "609001", "609002"].contains(ctx._temp_.cisco.message_id)'
field: "event.action"
value: "flow-expiration"
description: "305012, 302014, 302016, 302018, 302021, 302036, 302304, 302306, 609001, 609002"
- grok:
field: "message"
if: '["302014", "302016", "302018", "302021", "302036", "302304", "302306"].contains(ctx._temp_.cisco.message_id)'
description: "302014, 302016, 302018, 302021, 302036, 302304, 302306"
patterns:
- ^Teardown %{NOTSPACE:network.transport} (?:state-bypass )?connection %{NOTSPACE:_temp_.cisco.connection_id} (?:for|from) %{NOTCOLON:_temp_.cisco.source_interface}:%{DATA:source.address}/%{NUMBER:source.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.source_username}\)? )?to %{NOTCOLON:_temp_.cisco.destination_interface}:%{DATA:destination.address}/%{NUMBER:destination.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.destination_username}\)? )?duration (?:%{DURATION:_temp_.duration_hms} bytes %{NUMBER:network.bytes}) %{NOTCOLON:event.reason} from %{NOTCOLON:_temp_.cisco.termination_initiator} \(%{CISCO_USER:_temp_.cisco.termination_user}\)
- ^Teardown %{NOTSPACE:network.transport} (?:state-bypass )?connection %{NOTSPACE:_temp_.cisco.connection_id} (?:for|from) %{NOTCOLON:_temp_.cisco.source_interface}:%{DATA:source.address}/%{NUMBER:source.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.source_username}\)? )?to %{NOTCOLON:_temp_.cisco.destination_interface}:%{DATA:destination.address}/%{NUMBER:destination.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.destination_username}\)? )?duration (?:%{DURATION:_temp_.duration_hms} bytes %{NUMBER:network.bytes}) %{NOTCOLON:event.reason} from %{NOTCOLON:_temp_.cisco.termination_initiator}
- ^Teardown %{NOTSPACE:network.transport} (?:state-bypass )?connection %{NOTSPACE:_temp_.cisco.connection_id} (?:for|from) %{NOTCOLON:_temp_.cisco.source_interface}:%{DATA:source.address}/%{NUMBER:source.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.source_username}\)? )?to %{NOTCOLON:_temp_.cisco.destination_interface}:%{DATA:destination.address}/%{NUMBER:destination.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.destination_username}\)? )?duration (?:%{DURATION:_temp_.duration_hms} bytes %{NUMBER:network.bytes}) %{NOTCOLON:event.reason} \(%{CISCO_USER:_temp_.cisco.termination_user}\)
- ^Teardown %{NOTSPACE:network.transport} (?:state-bypass )?connection %{NOTSPACE:_temp_.cisco.connection_id} (?:for|from) %{NOTCOLON:_temp_.cisco.source_interface}:%{DATA:source.address}/%{NUMBER:source.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.source_username}\)? )?to %{NOTCOLON:_temp_.cisco.destination_interface}:%{DATA:destination.address}/%{NUMBER:destination.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.destination_username}\)? )?duration (?:%{DURATION:_temp_.duration_hms} bytes %{NUMBER:network.bytes}) \(%{CISCO_USER:_temp_.cisco.termination_user}\)
- ^Teardown %{NOTSPACE:network.transport} (?:state-bypass )?connection %{NOTSPACE:_temp_.cisco.connection_id} (?:for|from) %{NOTCOLON:_temp_.cisco.source_interface}:%{DATA:source.address}/%{NUMBER:source.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.source_username}\)? )?to %{NOTCOLON:_temp_.cisco.destination_interface}:%{DATA:destination.address}/%{NUMBER:destination.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.destination_username}\)? )?duration (?:%{DURATION:_temp_.duration_hms} bytes %{NUMBER:network.bytes}) %{NOTCOLON:event.reason}
- ^Teardown %{NOTSPACE:network.transport} (?:state-bypass )?connection %{NOTSPACE:_temp_.cisco.connection_id} (?:for|from) %{NOTCOLON:_temp_.cisco.source_interface}:%{DATA:source.address}/%{NUMBER:source.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.source_username}\)? )?to %{NOTCOLON:_temp_.cisco.destination_interface}:%{DATA:destination.address}/%{NUMBER:destination.port:int}\s*(?:\(?%{CISCO_USER:_temp_.cisco.destination_username}\)? )?duration (?:%{DURATION:_temp_.duration_hms} bytes %{NUMBER:network.bytes})
- ^Teardown %{NOTSPACE:network.transport} connection for faddr (?:%{NOTCOLON:_temp_.cisco.source_interface}:)?%{ECSDESTIPORHOST}/%{NUMBER}\s*(?:\(?%{CISCO_USER:_temp_.cisco.destination_username}\)? )?gaddr (?:%{NOTCOLON}:)?%{MAPPEDSRC}/%{NUMBER} laddr (?:%{NOTCOLON:_temp_.cisco.source_interface}:)?%{ECSSOURCEIPORHOST}/%{NUMBER}\s*(?:\(%{CISCO_USER:_temp_.cisco.source_username}\))?(\s*type %{NUMBER:_temp_.cisco.icmp_type} code %{NUMBER:_temp_.cisco.icmp_code})?
pattern_definitions:
HOSTNAME: '\b(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z\-_]{0,62}))*(\.?|\b)'
IPORHOST: "(?:%{IP}|%{HOSTNAME})"
NOTCOLON: "[^:]*"
ECSSOURCEIPORHOST: "(?:%{IP:source.address}|%{HOSTNAME:source.domain})"
ECSDESTIPORHOST: "(?:%{IP:destination.address}|%{HOSTNAME:destination.domain})"
MAPPEDSRC: "(?:%{IPORHOST:_temp_.natsrcip}|%{HOSTNAME})"
DURATION: "%{INT}:%{MINUTE}:%{SECOND}"
CISCO_USER: ((LOCAL\\)?(%{HOSTNAME}\\)?%{USERNAME}(@%{HOSTNAME})?(, *%{NUMBER})?)
#
# Decode FTD's Security Event Syslog Messages
#
# 43000x messages are security event syslog messages specific to FTD.
# Format is a comma-separated sequence of key: value pairs.
#
# The result of this decoding is saved as _temp_.orig_security.{Key}: {Value}
- kv:
if: '["430001", "430002", "430003", "430004", "430005", ""].contains(ctx._temp_.cisco.message_id)'
field: "message"
description: "430001, 430002, 430003, 430004, 430005"
field_split: ",(?=[A-za-z1-9\\s]+:)"
value_split: ":"
target_field: "_temp_.orig_security"
trim_key: " "
trim_value: " "
ignore_failure: true
#
# Remove message.
#
# The field has been used as temporary buffer while decoding. The full message
# is kept log.original. Processors below can still add a message field, as some
# security events contain an explanatory Message field.
- remove:
field:
- message
ignore_missing: true
#
# Populate ECS fields from Security Events
#
# This script uses the key-value pairs from Security Events to populate
# the appropriate ECS fields.
#
# A single key can be mapped to multiple ECS fields, and more than one key can
# map to the same ECS field, which results in an array being created.
#
# This script performs an additional job:
#
# Before FTD version 6.3, the message_id was not included in Security Events.
# As this field encodes the kind of event (intrusion, connection, malware...)
# the script below will guess the right message_id from the keys present in
# the event.
#
# The reason for overloading this script with different behaviors is
# that this pipeline is already reaching the limit on script compilations.
#
#*******************************************************************************
# Code generated by go generate. DO NOT EDIT.
#*******************************************************************************
- script:
if: ctx._temp_?.orig_security != null
params:
ACPolicy:
target: ac_policy
id: ["430001", "430002", "430003"]
ecs: [_temp_.cisco.rule_name]
AccessControlRuleAction:
target: access_control_rule_action
id: ["430002", "430003"]
ecs: [event.outcome]
AccessControlRuleName:
target: access_control_rule_name
id: ["430002", "430003"]
ecs: [_temp_.cisco.rule_name]
AccessControlRuleReason:
target: access_control_rule_reason
id: ["430002", "430003"]
ApplicationProtocol:
target: application_protocol
ecs: [network.protocol]
ArchiveDepth:
target: archive_depth
id: ["430004", "430005"]
ArchiveFileName:
target: archive_file_name
id: ["430004", "430005"]
ecs: [file.name]
ArchiveFileStatus:
target: archive_file_status
id: ["430004", "430005"]
ArchiveSHA256:
target: archive_sha256
id: ["430004", "430005"]
ecs: [file.hash.sha256]
Classification:
target: classification
id: ["430001"]
Client:
target: client
ecs: [network.application]
ClientVersion:
target: client_version
id: ["430002", "430003"]
ConnectionDuration:
target: connection_duration
id: ["430003"]
ecs: [event.duration]
DNS_Sinkhole:
target: dns_sinkhole
id: ["430002", "430003"]
DNS_TTL:
target: dns_ttl
id: ["430002", "430003"]
DNSQuery:
target: dns_query
id: ["430002", "430003"]
ecs: [dns.question.name]
DNSRecordType:
target: dns_record_type
id: ["430002", "430003"]
ecs: [dns.question.type]
DNSResponseType:
target: dns_response_type
id: ["430002", "430003"]
ecs: [dns.response_code]
DNSSICategory:
target: dnssi_category
id: ["430002", "430003"]
DstIP:
target: dst_ip
ecs: [destination.address]
DstPort:
target: dst_port
ecs: [destination.port]
EgressInterface:
target: egress_interface
id: ["430001", "430002", "430003"]
ecs: [_temp_.cisco.destination_interface]
EgressZone:
target: egress_zone
id: ["430001", "430002", "430003"]
ecs: [observer.egress.zone]
Endpoint Profile:
target: endpoint_profile
id: ["430002", "430003"]
FileAction:
target: file_action
id: ["430004", "430005"]
FileCount:
target: file_count
id: ["430002", "430003"]
FileDirection:
target: file_direction
id: ["430004", "430005"]
FileName:
target: file_name
id: ["430004", "430005"]
ecs: [file.name]
FilePolicy:
target: file_policy
id: ["430004", "430005"]
ecs: [_temp_.cisco.rule_name]
FileSHA256:
target: file_sha256
id: ["430004", "430005"]
ecs: [file.hash.sha256]
FileSandboxStatus:
target: file_sandbox_status
id: ["430004", "430005"]
FileSize:
target: file_size
id: ["430004", "430005"]
ecs: [file.size]
FileStorageStatus:
target: file_storage_status
id: ["430004", "430005"]
FileType:
target: file_type
id: ["430004", "430005"]
FirstPacketSecond:
target: first_packet_second
id: ["430004", "430005"]
ecs: [event.start]
GID:
target: gid
id: ["430001"]
ecs: [service.id]
HTTPReferer:
target: http_referer
id: ["430002", "430003"]
ecs: [http.request.referrer]
HTTPResponse:
target: http_response
id: ["430001", "430002", "430003"]
ecs: [http.response.status_code]
ICMPCode:
target: icmp_code
id: ["430001", "430002", "430003"]
ICMPType:
target: icmp_type
id: ["430001", "430002", "430003"]
IPReputationSICategory:
target: ip_reputation_si_category
id: ["430002", "430003"]
IPSCount:
target: ips_count
id: ["430002", "430003"]
IngressInterface:
target: ingress_interface
id: ["430001", "430002", "430003"]
ecs: [_temp_.cisco.source_interface]
IngressZone:
target: ingress_zone
id: ["430001", "430002", "430003"]
ecs: [observer.ingress.zone]
InitiatorBytes:
target: initiator_bytes
id: ["430003"]
ecs: [source.bytes]
InitiatorPackets:
target: initiator_packets
id: ["430003"]
ecs: [source.packets]
InlineResult:
target: inline_result
id: ["430001"]
ecs: [event.outcome]
IntrusionPolicy:
target: intrusion_policy
id: ["430001"]
ecs: [_temp_.cisco.rule_name]
MPLS_Label:
target: mpls_label
id: ["430001"]
Message:
target: message
id: ["430001"]
ecs: [message]
NAPPolicy:
target: nap_policy
id: ["430001", "430002", "430003"]
NetBIOSDomain:
target: net_bios_domain
id: ["430002", "430003"]
ecs: [host.hostname]
NumIOC:
target: num_ioc
id: ["430001"]
Prefilter Policy:
target: prefilter_policy
id: ["430002", "430003"]
Priority:
target: priority
id: ["430001"]
Protocol:
target: protocol
ecs: [network.transport]
ReferencedHost:
target: referenced_host
id: ["430002", "430003"]
ecs: [url.domain]
ResponderBytes:
target: responder_bytes
id: ["430003"]
ecs: [destination.bytes]
ResponderPackets:
target: responder_packets
id: ["430003"]
ecs: [destination.packets]
Revision:
target: revision
id: ["430001"]
SHA_Disposition:
target: sha_disposition
id: ["430004", "430005"]
SID:
target: sid
id: ["430001"]
SSLActualAction:
target: ssl_actual_action
ecs: [event.outcome]
SSLCertificate:
target: ssl_certificate
id: ["430002", "430003", "430004", "430005"]
SSLExpectedAction:
target: ssl_expected_action
id: ["430002", "430003"]
SSLFlowStatus:
target: ssl_flow_status
id: ["430002", "430003", "430004", "430005"]
SSLPolicy:
target: ssl_policy
id: ["430002", "430003"]
SSLRuleName:
target: ssl_rule_name
id: ["430002", "430003"]
SSLServerCertStatus:
target: ssl_server_cert_status
id: ["430002", "430003"]
SSLServerName:
target: ssl_server_name
id: ["430002", "430003"]
ecs: [server.domain]
SSLSessionID:
target: ssl_session_id
id: ["430002", "430003"]
SSLTicketID:
target: ssl_ticket_id
id: ["430002", "430003"]
SSLURLCategory:
target: sslurl_category
id: ["430002", "430003"]
SSLVersion:
target: ssl_version
id: ["430002", "430003"]
SSSLCipherSuite:
target: sssl_cipher_suite
id: ["430002", "430003"]
SecIntMatchingIP:
target: sec_int_matching_ip
id: ["430002", "430003"]
Security Group:
target: security_group
id: ["430002", "430003"]
SperoDisposition:
target: spero_disposition
id: ["430004", "430005"]
SrcIP:
target: src_ip
ecs: [source.address]
SrcPort:
target: src_port
ecs: [source.port]
TCPFlags:
target: tcp_flags
id: ["430002", "430003"]
ThreatName:
target: threat_name
id: ["430005"]
ecs: [_temp_.cisco.threat_category]
ThreatScore:
target: threat_score
id: ["430005"]
ecs: [_temp_.cisco.threat_level]
Tunnel or Prefilter Rule:
target: tunnel_or_prefilter_rule
id: ["430002", "430003"]
URI:
target: uri
id: ["430004", "430005"]
ecs: [url.original]
URL:
target: url
id: ["430002", "430003"]
ecs: [url.original]
URLCategory:
target: url_category
id: ["430002", "430003"]
URLReputation:
target: url_reputation
id: ["430002", "430003"]
URLSICategory:
target: urlsi_category
id: ["430002", "430003"]
User:
target: user
ecs: [user.id, user.name]
UserAgent:
target: user_agent
id: ["430002", "430003"]
ecs: [user_agent.original]
VLAN_ID:
target: vlan_id
id: ["430001", "430002", "430003"]
WebApplication:
target: web_application
ecs: [network.application]
originalClientSrcIP:
target: original_client_src_ip
id: ["430002", "430003"]
ecs: [client.address]
lang: painless
source: |
boolean isEmpty(def value) {
return (value instanceof AbstractList? value.size() : value.length()) == 0;
}
def appendOrCreate(Map dest, String[] path, def value) {
for (int i=0; i<path.length-1; i++) {
dest = dest.computeIfAbsent(path[i], _ -> new HashMap());
}
String key = path[path.length - 1];
def existing = dest.get(key);
return existing == null?
dest.put(key, value)
: existing instanceof AbstractList?
existing.add(value)
: dest.put(key, new ArrayList([existing, value]));
}
def msg = ctx._temp_.orig_security;
def counters = new HashMap();
def dest = new HashMap();
ctx._temp_.cisco['security'] = dest;
for (entry in msg.entrySet()) {
def param = params.get(entry.getKey());
if (param == null) {
continue;
}
param.getOrDefault('id', []).forEach( id -> counters[id] = 1 + counters.getOrDefault(id, 0) );
if (!isEmpty(entry.getValue())) {
param.getOrDefault('ecs', []).forEach( field -> appendOrCreate(ctx, field.splitOnToken('.'), entry.getValue()) );
dest[param.target] = entry.getValue();
}
}
if (ctx._temp_.cisco.message_id != "") return;
def best;
for (entry in counters.entrySet()) {
if (best == null || best.getValue() < entry.getValue()) best = entry;
}
if (best != null) ctx._temp_.cisco.message_id = best.getKey();
#*******************************************************************************
# End of generated code.
#*******************************************************************************
#
# Normalize ECS field values
#
- script:
lang: painless
params:
"ctx._temp_.cisco.message_id":
target: event.action
map:
"430001": intrusion-detected
"430002": connection-started
"430003": connection-finished
"430004": file-detected
"430005": malware-detected
"dns.question.type":
map:
"a host address": A
"ip6 address": AAAA
"text strings": TXT
"a domain name pointer": PTR
"an authoritative name server": NS
"the canonical name for an alias": CNAME
"marks the start of a zone of authority": SOA
"mail exchange": MX
"server selection": SRV
"dns.response_code":
map:
"non-existent domain": NXDOMAIN
"server failure": SERVFAIL
"query refused": REFUSED
"no error": NOERROR
source: |
def getField(Map src, String[] path) {
for (int i=0; i<path.length-1; i++) {
src = src.getOrDefault(path[i], null);
if (src == null || !(src instanceof Map)) {
return null;
}
}
return src[path[path.length-1]];
}
def setField(Map dest, String[] path, def value) {
for (int i=0; i<path.length-1; i++) {
dest = dest.computeIfAbsent(path[i], _ -> new HashMap());
}
dest[path[path.length-1]] = value;
}
for (entry in params.entrySet()) {
def srcField = entry.getKey();
def param = entry.getValue();
String oldVal = getField(ctx, srcField.splitOnToken('.'));
if (oldVal == null) continue;
def newVal = param.map?.getOrDefault(oldVal.toLowerCase(), null);
if (newVal != null) {
def dstField = param.getOrDefault('target', srcField);
setField(ctx, dstField.splitOnToken('.'), newVal);
}
}
- set:
if: "ctx.dns?.question?.type != null && ctx.dns?.response_code == null"
field: dns.response_code
value: NOERROR
- set:
if: 'ctx._temp_.cisco.message_id == "430001"'
field: event.action
value: intrusion-detected
- set:
if: 'ctx._temp_.cisco.message_id == "430002"'
field: event.action
value: connection-started
- set:
if: 'ctx._temp_.cisco.message_id == "430003"'
field: event.action
value: connection-finished
- set:
if: 'ctx._temp_.cisco.message_id == "430004"'
field: event.action
value: file-detected
- set:
if: 'ctx._temp_.cisco.message_id == "430005"'
field: event.action
value: malware-detected
#
# Handle event.duration
#
# It can be set from ConnectionDuration FTD field above. This field holds
# seconds as a string. Copy it to _temp_.duration_hms so that the following
# processor converts it to the right value and populates start and end.
- set:
field: "_temp_.duration_hms"
value: "{{event.duration}}"
ignore_empty_value: true
#
# Process the flow duration "hh:mm:ss" present in some messages
# This will fill event.start, event.end and event.duration
#
- script:
lang: painless
if: "ctx?._temp_?.duration_hms != null"
source: >
long parse_hms(String s) {
long cur = 0, total = 0;
for (char c: s.toCharArray()) {
if (c >= (char)'0' && c <= (char)'9') {
cur = (cur*10) + (long)c - (char)'0';
} else if (c == (char)':') {
total = (total + cur) * 60;
cur = 0;
} else if (c != (char)'h' && c == (char)'m' && c == (char)'s') {
return 0;
}
}
return total + cur;
}
if (ctx?.event == null) {
ctx['event'] = new HashMap();
}
String end = ctx['@timestamp'];
ctx.event['end'] = end;
long nanos = parse_hms(ctx._temp_.duration_hms) * 1000000000L;
ctx.event['duration'] = nanos;
ctx.event['start'] = ZonedDateTime.ofInstant(
Instant.parse(end).minusNanos(nanos),
ZoneOffset.UTC);
#
# Parse Source/Dest Username/Domain
#
- grok:
field: "_temp_.cisco.source_username"
if: 'ctx?._temp_?.cisco?.source_username != null'
ignore_failure: true
patterns:
- '%{CISCO_DOMAIN_USER:_temp_.cisco.source_username}%{CISCO_SGT}'
pattern_definitions:
CISCO_DOMAIN_USER: (%{CISCO_DOMAIN})?%{CISCO_USER}
CISCO_SGT: (, *%{NUMBER:_temp_.cisco.source_user_security_group_tag})?
CISCO_USER: "%{USERNAME}(@%{HOSTNAME})?"
CISCO_DOMAIN: (LOCAL\\)?(%{HOSTNAME}\\)?
- convert:
field: _temp_.cisco.source_user_security_group_tag
type: long
ignore_missing: true
- grok:
field: "_temp_.cisco.destination_username"
if: 'ctx?._temp_?.cisco?.destination_username != null'
ignore_failure: true
patterns:
- '%{CISCO_DOMAIN_USER:_temp_.cisco.destination_username}%{CISCO_SGT}'
pattern_definitions:
CISCO_DOMAIN_USER: (%{CISCO_DOMAIN})?%{CISCO_USER}
CISCO_SGT: (, *%{NUMBER:_temp_.cisco.destination_user_security_group_tag})?
CISCO_USER: "%{USERNAME}(@%{HOSTNAME})?"
CISCO_DOMAIN: (LOCAL\\)?(%{HOSTNAME}\\)?
- convert:
field: _temp_.cisco.destination_user_security_group_tag
type: long
ignore_missing: true
- set:
field: source.user.name
value: "{{{ _temp_.cisco.source_username }}}"
if: 'ctx?.source?.user?.name == null && ctx?._temp_?.cisco?.source_username != null'
- set:
field: destination.user.name
value: "{{{ _temp_.cisco.destination_username }}}"
if: 'ctx?.destination?.user?.name == null && ctx?._temp_?.cisco?.destination_username != null'
- grok:
field: "source.user.name"
if: 'ctx?.source?.user?.name != null'
ignore_failure: true
patterns:
- (%{CISCO_DOMAIN})?%{CISCO_USER}
pattern_definitions:
CISCO_USER: "%{USERNAME:source.user.name}(@%{HOSTNAME:source.user.domain})?"
CISCO_DOMAIN: (LOCAL\\)?(%{HOSTNAME:source.user.domain}\\)?
- grok:
field: "destination.user.name"
if: 'ctx?.destination?.user?.name != null'
ignore_failure: true
patterns:
- (%{CISCO_DOMAIN})?%{CISCO_USER}
pattern_definitions:
CISCO_USER: "%{USERNAME:destination.user.name}(@%{HOSTNAME:destination.user.domain})?"
CISCO_DOMAIN: (LOCAL\\)?(%{HOSTNAME:destination.user.domain}\\)?
#
# Normalize protocol names
#
- lowercase:
field: "network.transport"
ignore_failure: true
- lowercase:
field: "network.protocol"
ignore_failure: true
- lowercase:
field: "network.application"
ignore_failure: true
- lowercase:
field: "file.type"
ignore_failure: true
- lowercase:
field: "network.direction"
ignore_failure: true
- lowercase:
field: "network.type"
ignore_failure: true
#
# Populate network.iana_number from network.transport. Also does reverse
# mapping in case network.transport contains the iana_number.
#
- script:
if: "ctx?.network?.transport != null"
lang: painless
params:
icmp: 1
igmp: 2
ipv4: 4
tcp: 6
egp: 8
igp: 9
pup: 12
udp: 17
rdp: 27
irtp: 28
dccp: 33
idpr: 35
ipv6: 41
ipv6-route: 43
ipv6-frag: 44
rsvp: 46
gre: 47
esp: 50
ipv6-icmp: 58
ipv6-nonxt: 59
ipv6-opts: 60
source: >
def net = ctx.network;
def iana = params[net.transport];
if (iana != null) {
net['iana_number'] = iana;
return;
}
def reverse = new HashMap();
def[] arr = new def[] { null };
for (entry in params.entrySet()) {
arr[0] = entry.getValue();
reverse.put(String.format("%d", arr), entry.getKey());
}
def trans = reverse[net.transport];
if (trans != null) {
net['iana_number'] = net.transport;
net['transport'] = trans;
}
#
# Normalize event.outcome
#
- lowercase:
field: "event.outcome"
ignore_missing: true
- set:
field: "event.outcome"
if: 'ctx.event?.outcome == "est-allowed"'
value: "allowed"
- set:
field: "event.outcome"
if: 'ctx.event?.outcome == "permitted"'
value: "allowed"
- set:
field: "event.outcome"
if: 'ctx.event?.outcome == "allow"'
value: "allowed"
- set:
field: "event.outcome"
if: 'ctx.event?.outcome == "deny"'
value: denied
- set:
field: "network.transport"
if: 'ctx.network?.transport == "icmpv6"'
value: "ipv6-icmp"
#
# Convert numeric fields to integer or long, as output of dissect and kv processors is always a string
#
- convert:
field: "source.port"
type: integer
ignore_failure: true
ignore_missing: true
- convert:
field: "destination.port"
type: integer
ignore_failure: true
ignore_missing: true
- convert:
field: "source.bytes"
type: long
ignore_failure: true
ignore_missing: true
- convert:
field: "destination.bytes"
type: long
ignore_failure: true
ignore_missing: true
- convert:
field: "network.bytes"
type: long
ignore_failure: true
ignore_missing: true
- convert:
field: "source.packets"
type: integer
ignore_failure: true
ignore_missing: true
- convert:
field: "destination.packets"
type: integer
ignore_failure: true
ignore_missing: true
- convert:
field: "_temp_.cisco.mapped_source_port"
type: integer
ignore_failure: true
ignore_missing: true
- convert:
field: "_temp_.cisco.mapped_destination_port"
type: integer
ignore_failure: true
ignore_missing: true
- convert:
field: "_temp_.cisco.icmp_code"
type: integer
ignore_failure: true
ignore_missing: true
- convert:
field: "_temp_.cisco.icmp_type"
type: integer
ignore_failure: true
ignore_missing: true
- convert:
field: "network.iana_number"
type: integer
ignore_failure: true
ignore_missing: true
#
# Assign ECS .ip fields from .address is a valid IP address is found,
# otherwise set .domain field.
#
- grok:
field: source.address
patterns:
- "^(?:%{IP:source.ip}|%{GREEDYDATA:source.domain})$"
ignore_failure: true
- grok:
field: destination.address
patterns:
- "^(?:%{IP:destination.ip}|%{GREEDYDATA:destination.domain})$"
ignore_failure: true
- grok:
field: client.address
patterns:
- "^(?:%{IP:client.ip}|%{GREEDYDATA:client.domain})$"
ignore_failure: true
- grok:
field: server.address
patterns:
- "^(?:%{IP:server.ip}|%{GREEDYDATA:server.domain})$"
ignore_failure: true
#
# Geolocation for source and destination addresses
#
- geoip:
field: "source.ip"
target_field: "source.geo"
ignore_missing: true
- geoip:
field: "destination.ip"
target_field: "destination.geo"
ignore_missing: true
#
# IP Autonomous System (AS) Lookup
#
- geoip:
database_file: GeoLite2-ASN.mmdb
field: source.ip
target_field: source.as
properties:
- asn
- organization_name
ignore_missing: true
- geoip:
database_file: GeoLite2-ASN.mmdb
field: destination.ip
target_field: destination.as
properties:
- asn
- organization_name
ignore_missing: true
- rename:
field: source.as.asn
target_field: source.as.number
ignore_missing: true
- rename:
field: source.as.organization_name
target_field: source.as.organization.name
ignore_missing: true
- rename:
field: destination.as.asn
target_field: destination.as.number
ignore_missing: true
- rename:
field: destination.as.organization_name
target_field: destination.as.organization.name
ignore_missing: true
#
# Set mapped_{src|dst}_ip fields only if they consist of a valid IP address.
#
- grok:
field: _temp_.natsrcip
patterns:
- "^(?:%{IP:_temp_.cisco.mapped_source_ip}|%{GREEDYDATA:_temp_.cisco.mapped_source_host})$"
ignore_failure: true
- grok:
field: _temp_.natdstip
patterns:
- "^(?:%{IP:_temp_.cisco.mapped_destination_ip}|%{GREEDYDATA:_temp_.cisco.mapped_destination_host})$"
ignore_failure: true
#
# NAT fields
#
# The firewall always populates mapped ip and port even if there was no NAT.
# This populates both nat.ip and nat.port only when some translation is done.
# Fills nat.ip and nat.port even when only the ip or port changed.
- set:
field: source.nat.ip
value: "{{_temp_.cisco.mapped_source_ip}}"
if: "ctx?._temp_?.cisco?.mapped_source_ip != ctx?.source?.ip"
ignore_empty_value: true
- set:
field: source.nat.port
value: "{{_temp_.cisco.mapped_source_port}}"
if: "ctx?._temp_?.cisco?.mapped_source_port != ctx?.source?.port"
ignore_empty_value: true
- set:
field: destination.nat.ip
value: "{{_temp_.cisco.mapped_destination_ip}}"
if: "ctx?._temp_?.cisco.mapped_destination_ip != ctx?.destination?.ip"
ignore_empty_value: true
- set:
field: destination.nat.port
value: "{{_temp_.cisco.mapped_destination_port}}"
if: "ctx?._temp_?.cisco?.mapped_destination_port != ctx?.destination?.port"
ignore_empty_value: true
#
# Zone-based Network Directionality
#
# If external and internal zones are specified and our ingress/egress zones are
# populated, then we can classify traffic directionality based off of our defined
# zones rather than the logs.
- set:
field: network.direction
value: inbound
if: >
ctx?._temp_?.external_zones != null &&
ctx?._temp_?.internal_zones != null &&
ctx?.observer?.ingress?.zone != null &&
ctx?.observer?.egress?.zone != null &&
ctx._temp_.external_zones.contains(ctx.observer.ingress.zone) &&
ctx._temp_.internal_zones.contains(ctx.observer.egress.zone)
- set:
field: network.direction
value: outbound
if: >
ctx?._temp_?.external_zones != null &&
ctx?._temp_?.internal_zones != null &&
ctx?.observer?.ingress?.zone != null &&
ctx?.observer?.egress?.zone != null &&
ctx._temp_.external_zones.contains(ctx.observer.egress.zone) &&
ctx._temp_.internal_zones.contains(ctx.observer.ingress.zone)
- set:
field: network.direction
value: internal
if: >
ctx?._temp_?.external_zones != null &&
ctx?._temp_?.internal_zones != null &&
ctx?.observer?.ingress?.zone != null &&
ctx?.observer?.egress?.zone != null &&
ctx._temp_.internal_zones.contains(ctx.observer.egress.zone) &&
ctx._temp_.internal_zones.contains(ctx.observer.ingress.zone)
- set:
field: network.direction
value: external
if: >
ctx?._temp_?.external_zones != null &&
ctx?._temp_?.internal_zones != null &&
ctx?.observer?.ingress?.zone != null &&
ctx?.observer?.egress?.zone != null &&
ctx._temp_.external_zones.contains(ctx.observer.egress.zone) &&
ctx._temp_.external_zones.contains(ctx.observer.ingress.zone)
- set:
field: network.direction
value: unknown
if: >
ctx?._temp_?.external_zones != null &&
ctx?._temp_?.internal_zones != null &&
ctx?.observer?.egress?.zone != null &&
ctx?.observer?.ingress?.zone != null &&
(
(
!ctx._temp_.external_zones.contains(ctx.observer.egress.zone) &&
!ctx._temp_.internal_zones.contains(ctx.observer.egress.zone)
) ||
(
!ctx._temp_.external_zones.contains(ctx.observer.ingress.zone) &&
!ctx._temp_.internal_zones.contains(ctx.observer.ingress.zone)
)
)
- set:
field: _temp_.url_domain
value: "{{url.domain}}"
ignore_failure: true
if: ctx?.url?.domain != null
- uri_parts:
field: url.original
ignore_failure: true
if: ctx?.url?.original != null
- append:
field: url.domain
value: "{{_temp_.url_domain}}"
ignore_failure: true
allow_duplicates: false
if: ctx?._temp_?.url_domain != null
#
# Populate ECS event.code
#
- convert:
field: _temp_.cisco.message_id
target_field: event.code
type: integer
ignore_failure: true
- remove:
field:
- _temp_.cisco.message_id
- event.code
if: 'ctx._temp_.cisco.message_id == ""'
ignore_failure: true
#
# Copy _temp_.cisco to its final destination, cisco.asa or cisco.ftd.
#
- rename:
field: _temp_.cisco
target_field: "cisco.{< .internal_prefix >}"
ignore_failure: true
#
# Remove temporary fields
#
- remove:
field: _temp_
ignore_missing: true
#
# Rename some 7.x fields
#
- rename:
field: log.original
target_field: event.original
ignore_missing: true
- rename:
field: cisco.{< .internal_prefix >}.list_id
target_field: cisco.{< .internal_prefix >}.rule_name
ignore_missing: true
# ECS categorization
- script:
lang: painless
params:
connection-finished:
kind: event
category:
- network
type:
- end
connection-started:
kind: event
category:
- network
type:
- start
file-detected:
kind: alert
category:
- malware
type:
- info
firewall-rule:
kind: event
category:
- network
type: []
flow-creation:
kind: event
category:
- network
type:
- connection
- start
flow-expiration:
kind: event
category:
- network
type:
- connection
- end
intrusion-detected:
kind: alert
category:
- intrusion_detection
type:
- info
malware-detected:
kind: alert
category:
- malware
type:
- info
bypass:
kind: event
category:
- network
type:
- info
- change
error:
kind: event
outcome: failure
category:
- network
type:
- error
deleted:
kind: event
category:
- network
type:
- info
- deletion
- user
creation:
kind: event
category:
- network
type:
- info
- creation
- user
source: >-
if (ctx?.event?.action == null || !params.containsKey(ctx.event.action)) {
return;
}
ctx.event.kind = params.get(ctx.event.action).get('kind');
ctx.event.category = params.get(ctx.event.action).get('category').clone();
ctx.event.type = params.get(ctx.event.action).get('type').clone();
if (ctx?.event?.outcome == null || (!ctx.event.category.contains('network') && !ctx.event.category.contains('intrusion_detection'))) {
if (ctx?.event?.action == 'firewall-rule') {
ctx.event.type.add('info');
} else if (ctx?.event?.action.startsWith('connection-')) {
ctx.event.type.add('connection');
}
return;
}
if (ctx.event.outcome == 'allowed') {
ctx.event.outcome = 'success';
ctx.event.type.add('connection');
ctx.event.type.add('allowed');
} else if (ctx.event.outcome == 'denied' || ctx.event.outcome == 'block') {
ctx.event.outcome = 'success';
ctx.event.type.add('connection');
ctx.event.type.add('denied');
} else if (ctx.event.outcome == 'dropped') {
ctx.event.outcome = 'failure';
ctx.event.type.add('connection');
ctx.event.type.add('denied');
} else if (ctx?.event?.action == 'firewall-rule') {
ctx.event.type.add('info');
} else if (ctx?.event?.action.startsWith('connection-')) {
ctx.event.type.add('connection');
}
if (ctx.event.outcome == 'monitored') {
ctx.event.category.add('intrusion_detection');
ctx.event.outcome = 'success';
}
- set:
description: copy destination.user.name to user.name if it is not set
field: user.name
value: "{{destination.user.name}}"
ignore_empty_value: true
if: ctx?.user?.name == null
# Configures observer fields with a copy from cisco and host fields. Later on these might replace host.hostname.
- set:
field: observer.hostname
value: "{{ host.hostname }}"
ignore_empty_value: true
- set:
field: observer.vendor
value: "Cisco"
ignore_empty_value: true
- set:
field: observer.type
value: "firewall"
ignore_empty_value: true
- set:
field: observer.product
value: "{< .internal_prefix >}"
ignore_empty_value: true
- set:
field: observer.egress.interface.name
value: "{{ cisco.{< .internal_prefix >}.destination_interface }}"
ignore_empty_value: true
- set:
field: observer.ingress.interface.name
value: "{{ cisco.{< .internal_prefix >}.source_interface }}"
ignore_empty_value: true
- append:
field: related.ip
value: "{{source.ip}}"
if: "ctx?.source?.ip != null"
allow_duplicates: false
- append:
field: related.ip
value: "{{source.nat.ip}}"
if: "ctx?.source?.nat?.ip != null"
allow_duplicates: false
- append:
field: related.ip
value: "{{destination.ip}}"
if: "ctx?.destination?.ip != null"
allow_duplicates: false
- append:
field: related.ip
value: "{{destination.nat.ip}}"
if: "ctx?.destination?.nat?.ip != null"
allow_duplicates: false
- append:
field: related.user
value: "{{{user.name}}}"
if: ctx?.user?.name != null && ctx?.user?.name != ''
allow_duplicates: false
- append:
field: related.user
value: "{{{source.user.name}}}"
if: ctx?.source?.user?.name != null && ctx?.source?.user?.name != ''
allow_duplicates: false
- append:
field: related.user
value: "{{{destination.user.name}}}"
if: ctx?.destination?.user?.name != null && ctx?.destination?.user?.name != ''
allow_duplicates: false
- append:
field: related.hash
value: "{{file.hash.sha256}}"
if: "ctx?.file?.hash?.sha256 != null"
allow_duplicates: false
- append:
field: related.hosts
value: "{{host.hostname}}"
if: ctx.host?.hostname != null && ctx.host?.hostname != ''
allow_duplicates: false
- append:
field: related.hosts
value: "{{observer.hostname}}"
if: ctx.observer?.hostname != null && ctx.observer?.hostname != ''
allow_duplicates: false
- append:
field: related.hosts
value: "{{destination.domain}}"
if: ctx.destination?.domain != null && ctx.destination?.domain != ''
allow_duplicates: false
- append:
field: related.hosts
value: "{{source.domain}}"
if: ctx.source?.domain != null && ctx.source?.domain != ''
allow_duplicates: false
- append:
field: related.hosts
value: "{{source.user.domain}}"
if: ctx.source?.user?.domain != null && ctx.source?.user?.domain != ''
allow_duplicates: false
- append:
field: related.hosts
value: "{{destination.user.domain}}"
if: ctx.destination?.user?.domain != null && ctx.destination?.user?.domain != ''
allow_duplicates: false
- script:
lang: painless
description: This script processor iterates over the whole document to remove fields with null values.
source: |
void handleMap(Map map) {
for (def x : map.values()) {
if (x instanceof Map) {
handleMap(x);
} else if (x instanceof List) {
handleList(x);
}
}
map.values().removeIf(v -> v == null);
}
void handleList(List list) {
for (def x : list) {
if (x instanceof Map) {
handleMap(x);
} else if (x instanceof List) {
handleList(x);
}
}
}
handleMap(ctx);
- community_id:
ignore_missing: true
ignore_failure: true
on_failure:
# Copy any fields under _temp_.cisco to its final destination. Those can help
# with diagnosing the failure.
- rename:
field: _temp_.cisco
target_field: "cisco.{< .internal_prefix >}"
ignore_failure: true
# Remove _temp_ to avoid adding a lot of unnecessary fields to the index.
- remove:
field: _temp_
ignore_missing: true
- append:
field: "error.message"
value: "{{ _ingest.on_failure_message }}"