added Malcolm

This commit is contained in:
2021-08-06 10:35:01 +02:00
parent f043730066
commit 70f1922e80
751 changed files with 195277 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
input {
pipeline {
address => "log-enrichment"
}
}

View File

@@ -0,0 +1,444 @@
filter {
# todo: make added fields not zeek-specific? (see ECS topic branch)
# all the lookups are done here, but some of them are still zeek-specific which
# IMO isn't the cleanest. could be refactored/split.
######## MAC address OUI (manufacturer) lookup #################################################
# if OUI lookup is requested, enable it
mutate {
id => "mutate_add_field_env_logstash_oui_lookup"
add_field => { "[@metadata][ENV_LOGSTASH_OUI_LOOKUP]" => "${LOGSTASH_OUI_LOOKUP:false}" }
}
if ([@metadata][ENV_LOGSTASH_OUI_LOOKUP] == "true") {
# srcMac/dstMac are arrays at this point, as Arkime expects them to be
if ([srcMac]) and ([srcMac][0]) {
# attempt lookup of srcMac oui
ieee_oui {
id => "ieee_oui_srcMac"
source => "[srcMac][0]"
target => "[zeek][orig_l2_oui]"
ouifile => "/usr/share/logstash/config/oui-logstash.txt"
refresh_interval => 0
}
if ([zeek][orig_l2_oui]) {
# merge orig_l2_oui into srcOui array (with a count of 1)
mutate { id => "mutate_merge_field_srcOui"
merge => { "[srcOui]" => "[zeek][orig_l2_oui]" } }
mutate { id => "mutate_add_field_srcOuiCnt"
add_field => { "[srcOuiCnt]" => "1" } }
# if this is a DHCP log type, copy srcOui to dhcp.oui
if ([dhcp][mac]) {
mutate {
id => "mutate_add_fields_dhcp_oui"
add_field => { "[dhcp][oui]" => "%{[srcOui]}" }
}
mutate {
id => "mutate_add_fields_dhcp_ouiCnt"
add_field => { "[dhcp][ouiCnt]" => "%{[srcOuiCnt]}" }
}
}
}
} # end if [srcMac]
if ([dstMac]) and ([dstMac][0]) {
# attempt lookup of dstMac oui
ieee_oui {
id => "ieee_oui_dstMac"
source => "[dstMac][0]"
target => "[zeek][resp_l2_oui]"
ouifile => "/usr/share/logstash/config/oui-logstash.txt"
refresh_interval => 0
}
if ([zeek][resp_l2_oui]) {
# merge resp_l2_oui into dstOui array (with a count of 1)
mutate { id => "mutate_merge_field_dstOui"
merge => { "[dstOui]" => "[zeek][resp_l2_oui]" } }
mutate { id => "mutate_add_field_dstOuiCnt"
add_field => { "[dstOuiCnt]" => "1" } }
}
} # end if [dstMac]
} # end if ENV_LOGSTASH_OUI_LOOKUP
################################################################################################
######## IP address class tagging, GeoIP/ASN lookups, and reverse DNS ###########################
if ([srcIp]) {
cidr {
id => "cidr_add_tag_internal_source"
add_tag => [ "internal_source" ]
address => [ "%{srcIp}" ]
network => [ "0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.2.0/24",
"192.88.99.0/24", "192.168.0.0/16", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "224.0.0.0/4", "240.0.0.0/4",
"255.255.255.255/32", "::/0", "::/128", "::1/128", "fc00::/7", "fe80::/10", "ff00::/8"]
}
if (!("internal_source" in [tags])) {
mutate { id => "mutate_add_tag_external_source"
add_tag => [ "external_source" ] }
# map srcIp to GEO countries
geoip {
id => "geoip_srcIp_geo"
source => "[srcIp]"
target => "[zeek][source_geo]"
}
geoip {
id => "geoip_srcIp_asn"
default_database_type => "ASN"
source => "[srcIp]"
target => "[@metadata][orig_asn]"
}
if ([zeek][source_geo] and [zeek][source_geo][country_code2]) {
mutate { id => "mutate_add_field_srcGEO"
add_field => { "[srcGEO]" => "%{[zeek][source_geo][country_code2]}" } }
}
if ([@metadata][orig_asn] and [@metadata][orig_asn][as_org] and [@metadata][orig_asn][asn]) {
mutate { id => "mutate_add_field_srcASN"
add_field => { "[srcASN]" => "AS%{[@metadata][orig_asn][asn]} %{[@metadata][orig_asn][as_org]}" } }
}
# if reverse DNS for public IP addresses is enabled (via environment variable) do it
mutate {
add_field => { "[@metadata][ENV_LOGSTASH_REVERSE_DNS]" => "${LOGSTASH_REVERSE_DNS:false}" }
}
if ([@metadata][ENV_LOGSTASH_REVERSE_DNS] == "true") {
mutate {
id => "mutate_add_field_srcip_for_dns"
add_field => {
"[zeek][source_ip_reverse_dns]" => "%{[srcIp]}"
}
}
dns {
id => "dns_source_ip_reverse_dns"
reverse => [ "[zeek][source_ip_reverse_dns]" ]
action => "replace"
hit_cache_size => 8000
hit_cache_ttl => 300
failed_cache_size => 8000
failed_cache_ttl => 60
}
if ([srcIp] == [zeek][source_ip_reverse_dns]) {
mutate {
id => "mutate_remove_field_source_ip_reverse_dns"
remove_field => [ "[zeek][source_ip_reverse_dns]" ]
}
}
}
}
cidr {
id => "cidr_detect_network_type_ipv4_source"
add_field => { "[network][type]" => "ipv4" }
address => [ "%{srcIp}" ]
network => [ "0.0.0.0/0" ]
}
if (![network][type]) {
mutate { id => "mutate_add_network_type_ipv4_source"
add_field => { "[network][type]" => "ipv6" } }
}
} # if ([srcIp])
if ([dstIp]) {
cidr {
id => "cidr_add_tag_internal_destination"
add_tag => [ "internal_destination" ]
address => [ "%{dstIp}" ]
network => [ "0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.2.0/24",
"192.88.99.0/24", "192.168.0.0/16", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "224.0.0.0/4", "240.0.0.0/4",
"255.255.255.255/32", "::/0", "::/128", "::1/128", "fc00::/7", "fe80::/10", "ff00::/8"]
}
if (!("internal_destination" in [tags])) {
mutate { id => "mutate_add_tag_external_destination"
add_tag => [ "external_destination" ] }
# map dstIp to GEO countries
geoip {
id => "geoip_dstIp_geo"
source => "[dstIp]"
target => "[zeek][destination_geo]"
}
geoip {
id => "geoip_dstIp_asn"
default_database_type => "ASN"
source => "[dstIp]"
target => "[@metadata][resp_asn]"
}
if ([zeek][destination_geo] and [zeek][destination_geo][country_code2]) {
mutate { id => "mutate_add_field_dstGEO"
add_field => { "[dstGEO]" => "%{[zeek][destination_geo][country_code2]}" } }
}
if ([@metadata][resp_asn] and [@metadata][resp_asn][as_org] and [@metadata][resp_asn][asn]) {
mutate { id => "mutate_add_field_dstASN"
add_field => { "[dstASN]" => "AS%{[@metadata][resp_asn][asn]} %{[@metadata][resp_asn][as_org]}" } }
}
# if reverse DNS for public IP addresses is enabled (via environment variable) do it
if (![@metadata][ENV_LOGSTASH_REVERSE_DNS]) {
mutate {
add_field => { "[@metadata][ENV_LOGSTASH_REVERSE_DNS]" => "${LOGSTASH_REVERSE_DNS:false}" }
}
}
if ([@metadata][ENV_LOGSTASH_REVERSE_DNS] == "true") {
mutate {
id => "mutate_add_field_dstip_for_dns"
add_field => {
"[zeek][destination_ip_reverse_dns]" => "%{[dstIp]}"
}
}
dns {
id => "dns_destination_ip_reverse_dns"
reverse => [ "[zeek][destination_ip_reverse_dns]" ]
action => "replace"
hit_cache_size => 8000
hit_cache_ttl => 300
failed_cache_size => 8000
failed_cache_ttl => 60
}
if ([dstIp] == [zeek][destination_ip_reverse_dns]) {
mutate {
id => "mutate_remove_field_destination_ip_reverse_dns"
remove_field => [ "[zeek][destination_ip_reverse_dns]" ]
}
}
}
}
if (![network][type]) {
cidr {
id => "cidr_detect_network_type_ipv4_dest"
add_field => { "[network][type]" => "ipv4" }
address => [ "%{dstIp}" ]
network => [ "0.0.0.0/0" ]
}
if (![network][type]) {
mutate { id => "mutate_add_network_type_ipv4_dest"
add_field => { "[network][type]" => "ipv6" } }
}
}
} # if ([dstIp])
if ([dns][host]) {
# if requested, look up DNS queries using freq_server.py to get entropy scores
ruby {
id => "ruby_dns_freq_lookup"
init => "
require 'net/http'
require 'cgi'
$freqLookupEnabled = ENV['FREQ_LOOKUP'] || 'false'
"
# freq_server.py returns a string like: (2.9333, 3.6353)
code => "
if ($freqLookupEnabled == 'true') then
scoresv1 = Array.new
scoresv2 = Array.new
scoresTmp = Array.new
begin
event.get('[dns][host]').each { |query|
if (query.length >= 4) and (query !~ /(ip6\.int|ip6\.arpa|in-addr\.arpa|b32\.i2p)$/i) then
scoresTmp.clear
scoresTmp.concat(Net::HTTP.get_response(URI.parse('http://freq:10004/measure/' + CGI.escape(query))).body.gsub(/(^\(|\)$|\s+)/, '').split(',').map(&:to_f))
if (scoresTmp.length == 2) then
scoresv1 << scoresTmp[0]
scoresv2 << scoresTmp[1]
end
end
}
rescue Exception => e
event.set('ruby_exception', 'ruby_dns_freq_lookup: ' + e.message)
end
event.set('[zeek][freq_score_v1]', scoresv1) unless (scoresv1.length == 0)
event.set('[zeek][freq_score_v2]', scoresv2) unless (scoresv2.length == 0)
end"
}
} # end if dns.ip
if ([dns][ip]) and ([dns][ip][0]) {
# if this is a DNS record with an IP, GeoIP it as well
geoip {
id => "geoip_dns_ip_asn"
default_database_type => "ASN"
source => "[dns][ip][0]"
target => "[@metadata][dns_asn]"
}
if ([@metadata][dns_asn] and [@metadata][dns_asn][as_org] and [@metadata][dns_asn][asn]) {
# this is stupid, the %{} doesn't seem to be liked by mutate.merge
mutate { id => "mutate_add_field_dns_asn"
add_field => { "[@metadata][asn_str]" => "AS%{[@metadata][dns_asn][asn]} %{[@metadata][dns_asn][as_org]}" } }
mutate { id => "mutate_merge_dns_asn"
merge => { "[dns][ASN]" => "[@metadata][asn_str]" } }
}
geoip {
id => "geoip_dns_ip_geo"
source => "[dns][ip][0]"
target => "[@metadata][dns_geo]"
}
if ([@metadata][dns_geo] and [@metadata][dns_geo][country_code2]) {
mutate { id => "mutate_merge_dns_geo"
merge => { "[dns][GEO]" => "[@metadata][dns_geo][country_code2]" } }
}
} # end if dns.ip
if ([radius]) {
# if this is a Radius record with IP addresses, GeoIP them as well
if ([radius][framedIp]) and ([radius][framedIp][0]) {
geoip {
id => "geoip_radius_framedIp_asn"
default_database_type => "ASN"
source => "[radius][framedIp][0]"
target => "[@metadata][radius_asn]"
}
if ([@metadata][radius_asn] and [@metadata][radius_asn][as_org] and [@metadata][radius_asn][asn]) {
# this is stupid, the %{} doesn't seem to be liked by mutate.merge
mutate { id => "mutate_add_field_radius_asn"
add_field => { "[@metadata][asn_str]" => "AS%{[@metadata][radius_asn][asn]} %{[@metadata][radius_asn][as_org]}" } }
mutate { id => "mutate_merge_radius_asn"
merge => { "[radius][framedASN]" => "[@metadata][asn_str]" } }
}
geoip {
id => "geoip_radius_framedIp_geo"
source => "[radius][framedIp][0]"
target => "[@metadata][radius_geo]"
}
if ([@metadata][radius_geo] and [@metadata][radius_geo][country_code2]) {
mutate { id => "mutate_merge_radius_geo"
merge => { "[radius][framedGEO]" => "[@metadata][radius_geo][country_code2]" } }
}
} # end if radius.framedIp
if ([radius][endpointIp]) and ([radius][endpointIp][0]) {
geoip {
id => "geoip_radius_endpointIp_asn"
default_database_type => "ASN"
source => "[radius][endpointIp][0]"
target => "[@metadata][radius_asn]"
}
if ([@metadata][radius_asn] and [@metadata][radius_asn][as_org] and [@metadata][radius_asn][asn]) {
# this is stupid, the %{} doesn't seem to be liked by mutate.merge
mutate { id => "mutate_add_field_radius_endpoint_asn"
add_field => { "[@metadata][asn_str]" => "AS%{[@metadata][radius_asn][asn]} %{[@metadata][radius_asn][as_org]}" } }
mutate { id => "mutate_merge_radius_endpoint_asn"
merge => { "[radius][endpointASN]" => "[@metadata][asn_str]" } }
}
geoip {
id => "geoip_radius_endpointIp_geo"
source => "[radius][endpointIp][0]"
target => "[@metadata][radius_geo]"
}
if ([@metadata][radius_geo] and [@metadata][radius_geo][country_code2]) {
mutate { id => "mutate_merge_radius_endpoint_geo"
merge => { "[radius][endpointGEO]" => "[@metadata][radius_geo][country_code2]" } }
}
} # end if radius.endpointIp
} # end if radius
if ([zeek_cip_identity][socket_address]) {
# if this is a zeek_cip_identity record with socket_address, ASN/GeoIP it as well
geoip {
id => "geoip_zeek_cip_identity_socket_address"
default_database_type => "ASN"
source => "[zeek_cip_identity][socket_address]"
target => "[@metadata][zeek_cip_identity_asn]"
}
if ([@metadata][zeek_cip_identity_asn] and [@metadata][zeek_cip_identity_asn][as_org] and [@metadata][zeek_cip_identity_asn][asn]) {
# this is stupid, the %{} doesn't seem to be liked by mutate.merge
mutate { id => "mutate_add_field_zeek_cip_identity_asn"
add_field => { "[@metadata][cip_asn_str]" => "AS%{[@metadata][zeek_cip_identity_asn][asn]} %{[@metadata][zeek_cip_identity_asn][as_org]}" } }
mutate { id => "mutate_merge_zeek_cip_identity_asn"
merge => { "[zeek_cip_identity][socket_address_asn]" => "[@metadata][cip_asn_str]" } }
}
geoip {
id => "geoip_zeek_cip_identity_socket_address_geo"
source => "[zeek_cip_identity][socket_address]"
target => "[zeek_cip_identity][socket_address_geo]"
}
} # end if zeek_cip_identity.socket_address
if ([zeek_ssl][server_name]) {
mutate {
add_field => { "[@metadata][ENV_FREQ_LOOKUP]" => "${FREQ_LOOKUP:false}" }
}
if ([@metadata][ENV_FREQ_LOOKUP] == "true") {
# if requested, look up zeek_ssl.server_name queries using freq_server.py to get entropy scores
http {
id => "rest_zeek_ssl_server_name_freq_lookup"
url => "http://freq:10004/measure/%{[zeek_ssl][server_name]}"
target_body => "[@metadata][zeek_ssl_server_name_freq]"
}
if ([@metadata][zeek_ssl_server_name_freq]) {
grok {
id => "grok_zeek_ssl_server_name_freq_parse"
match => { "[@metadata][zeek_ssl_server_name_freq]" => [ "^\(%{NUMBER:[zeek][freq_score_v1]}, %{NUMBER:[zeek][freq_score_v2]}\)$" ] }
}
}
}
} # end if zeek_ssl.server_name
################################################################################################
######## JA3 community hashes lookup ###########################################################
# ja3/ja3s are arrays at this point, as Arkime expects them to be
if ([tls][ja3]) and ([tls][ja3][0]) {
translate {
id => "translate_ssl_ja3"
field => "[tls][ja3][0]"
destination => "[zeek_ssl][ja3_desc]"
dictionary_path => "/etc/ja3.yaml"
}
}
if ([tls][ja3s]) and ([tls][ja3s][0]) {
translate {
id => "translate_ssl_ja3s"
field => "[tls][ja3s][0]"
destination => "[zeek_ssl][ja3s_desc]"
dictionary_path => "/etc/ja3.yaml"
}
}
################################################################################################
# this identifies which node the log came from
if ([host][name]) {
mutate { id => "mutate_add_field_host_name_node"
add_field => { "[node]" => "%{[host][name]}" } }
} else {
mutate { id => "mutate_add_field_logstash_node"
add_field => { "[node]" => "logs" } }
}
if ([log][file][path]) {
# trim path portion of log.file.path
mutate { id => "mutate_gsub_field_zeek_log_file_path"
gsub => [ "[log][file][path]", "^.*/", "" ] }
}
# remove some useless beats-related fields
mutate {
id => "mutate_remove_field_beats_useless"
remove_field => [
"[beat]",
"[agent][ephemeral_id]",
"[log][offset]",
"[input][type]",
"[prospector]",
"[message]"
]
}
} # end Filter

View File

@@ -0,0 +1,79 @@
filter {
# set data types for fields that belong to multiple types of logs
# _dataconversion tag (for missing fields) will be removed in 18_tags_finalize.conf
mutate {
id => "mutate_convert_misc"
convert => {
"[certCnt]" => "integer"
"[dhcp][hostCnt]" => "integer"
"[dhcp][idCnt]" => "integer"
"[dhcp][macCnt]" => "integer"
"[dhcp][ouiCnt]" => "integer"
"[dns][hostCnt]" => "integer"
"[dns][ipCnt]" => "integer"
"[dns][opcodeCnt]" => "integer"
"[dns][qcCnt]" => "integer"
"[dns][qtCnt]" => "integer"
"[dstBytes]" => "integer"
"[dstDataBytes]" => "integer"
"[dstMacCnt]" => "integer"
"[dstOuiCnt]" => "integer"
"[dstPackets]" => "integer"
"[dstPort]" => "integer"
"[email][dstCnt]" => "integer"
"[email][idCnt]" => "integer"
"[email][srcCnt]" => "integer"
"[email][subjectCnt]" => "integer"
"[email][useragentCnt]" => "integer"
"[email][smtpHelloCnt]" => "integer"
"[firstPacket]" => "integer"
"[http][bodyMagicCnt]" => "integer"
"[http][clientVersionCnt]" => "integer"
"[http][hostCnt]" => "integer"
"[http][methodCnt]" => "integer"
"[http][statuscodeCnt]" => "integer"
"[http][uriCnt]" => "integer"
"[http][useragentCnt]" => "integer"
"[ipProtocol]" => "integer"
"[irc][channelCnt]" => "integer"
"[irc][nickCnt]" => "integer"
"[krb5][cnameCnt]" => "integer"
"[krb5][snameCnt]" => "integer"
"[lastPacket]" => "integer"
"[length]" => "integer"
"[protocolCnt]" => "integer"
"[quic][hostCnt]" => "integer"
"[quic][useragentCnt]" => "integer"
"[quic][versionCnt]" => "integer"
"[radius][endpointegerIpCnt]" => "integer"
"[radius][framedIpCnt]" => "integer"
"[radius][macCnt]" => "integer"
"[segmentCnt]" => "integer"
"[srcBytes]" => "integer"
"[srcDataBytes]" => "integer"
"[srcMacCnt]" => "integer"
"[srcOuiCnt]" => "integer"
"[srcPackets]" => "integer"
"[srcPort]" => "integer"
"[ssh][hasshCnt]" => "integer"
"[ssh][hasshServerCnt]" => "integer"
"[ssh][keyCnt]" => "integer"
"[ssh][versionCnt]" => "integer"
"[timestamp]" => "integer"
"[tls][cipherCnt]" => "integer"
"[tls][ja3Cnt]" => "integer"
"[tls][ja3sCnt]" => "integer"
"[tls][versionCnt]" => "integer"
"[totBytes]" => "integer"
"[totDataBytes]" => "integer"
"[totPackets]" => "integer"
"[userCnt]" => "integer"
"[vlan]" => "integer"
"[vlanCnt]" => "integer"
"[zeek][freq_score_v1]" => "float"
"[zeek][freq_score_v2]" => "float"
}
}
} # end Filter

View File

@@ -0,0 +1,12 @@
filter {
if ([zeek][resp_segment] and [zeek][orig_segment]) and
([zeek][resp_segment] != [zeek][orig_segment]) {
mutate {
id => "mutate_add_tag_cross_segment"
add_tag => [ "cross_segment" ]
}
}
} # filter

View File

@@ -0,0 +1,33 @@
filter {
# remove tags we'd rather not see
mutate { id => "mutate_enrichment_tags_remove"
remove_tag => [ "beats_input_codec_plain_applied",
"_dateparsefailure",
"_grokparsefailure",
"_jsonparsefailure",
"_dissectfailure",
"_ouilookupfailure",
"_geoip_lookup_failure" ] }
# deduplicate tags
ruby {
id => "ruby_zeek_tags_deduplicate"
code => "event.set('[tags]', event.get('[tags]').uniq)"
}
# count tags (for moloch)
ruby {
id => "ruby_enrichment_tagsCnt"
code => "event.set('[tagsCnt]', event.get('[tags]').length)"
}
mutate {
id => "mutate_convert_enrichment_tagsCnt"
convert => { "[tagsCnt]" => "integer" }
}
} # filter

View File

@@ -0,0 +1,69 @@
filter {
# Map enriched fields to ECS where possible (see https://github.com/idaholab/Malcolm/issues/16)
# For now I will add fields rather than rename them. This will preserve backwards compatibility
# but the records will be somewhat bigger. I'll have to address what (if anything) to do with upgrades.
# for now don't do anything unles an env explicitly enables it
mutate {
id => "mutate_add_field_env_logstash_enriched_to_ecs"
add_field => { "[@metadata][ENV_LOGSTASH_ENRICHED_TO_ECS]" => "${LOGSTASH_TO_ECS:false}" }
}
if ([@metadata][ENV_LOGSTASH_ENRICHED_TO_ECS] == "true") {
# 🗹 Network - Fields describing the communication path over which the event happened. - https://www.elastic.co/guide/en/ecs/current/ecs-network.html
# network.direction (from tags assigned during 11_lookups.conf)
if ("internal_source" in [tags]) and ("internal_destination" in [tags]) {
mutate { id => "mutate_add_field_metadata_network_direction_internal"
add_field => { "[@metadata][network_direction]" => "internal" } }
} else if ("external_source" in [tags]) and ("external_destination" in [tags]) {
mutate { id => "mutate_add_field_metadata_network_direction_external"
add_field => { "[@metadata][network_direction]" => "external" } }
} else if ("internal_source" in [tags]) and ("external_destination" in [tags]) {
mutate { id => "mutate_add_field_metadata_network_direction_outbound"
add_field => { "[@metadata][network_direction]" => "outbound" } }
} else if ("external_source" in [tags]) and ("internal_destination" in [tags]) {
mutate { id => "mutate_add_field_metadata_network_direction_inbound"
add_field => { "[@metadata][network_direction]" => "inbound" } }
}
if ([@metadata][network_direction]) {
mutate { id => "mutate_add_field_ecs_network_direction"
add_field => { "[network][direction]" => "%{[@metadata][network_direction]}" } }
}
# network.name (based on info from [zeek][resp_segment] and [zeek][orig_segment])
if ([zeek][resp_segment]) { mutate { id => "mutate_add_field_ecs_network_name_resp"
merge => { "[network][name]" => "[zeek][resp_segment]" } } }
if ([zeek][orig_segment]) { mutate { id => "mutate_add_field_ecs_network_name_orig"
merge => { "[network][name]" => "[zeek][orig_segment]" } } }
# Autonomous System and Geo are handled after enrichment in 20_enriched_to_ecs.conf
# ☐ Autonomous System - Fields describing an Autonomous System (Internet routing prefix). - https://www.elastic.co/guide/en/ecs/current/ecs-as.html
# ☐ Geo - Fields describing a location. - https://www.elastic.co/guide/en/ecs/current/ecs-geo.html
# ecs.version is required in all events - https://www.elastic.co/guide/en/ecs/current/ecs-ecs.html
if (![ecs][version]) { mutate { id => "mutate_add_field_ecs_version"
add_field => { "[ecs][version]" => "1.5.0" } } }
# event.ingested
if (![event][ingested]) {
ruby {
id => "ruby_event_ingested_now_zeek"
init => "require 'time'"
code => "event.set('[event][ingested]', Time.now.to_f)"
}
date {
id => "date_event_ingested_conv"
match => [ "[event][ingested]", "UNIX" ]
target => "[event][ingested]"
}
}
# event.provider
if (![event][provider]) { mutate { id => "mutate_add_field_event_provider_enrichment"
add_field => { "[event][provider]" => "malcolm" } } }
} # end if ENV_LOGSTASH_ENRICHED_TO_ECS
}

View File

@@ -0,0 +1,5 @@
output {
pipeline {
send_to => [_MALCOLM_ELASTICSEARCH_OUTPUT_PIPELINES_]
}
}

View File

@@ -0,0 +1,3 @@
queue.type: persisted
queue.max_bytes: 4gb
path.queue: "/logstash-persistent-queue"

View File

@@ -0,0 +1,6 @@
input {
pipeline {
address => "${ELASTICSEARCH_PIPELINE_ADDRESS_EXTERNAL:external-es}"
}
}

View File

@@ -0,0 +1,13 @@
output {
elasticsearch {
id => "output_external_elasticsearch_moloch"
hosts => "${ES_EXTERNAL_HOSTS}"
ssl => "${ES_EXTERNAL_SSL:true}"
ssl_certificate_verification => "${ES_EXTERNAL_SSL_CERTIFICATE_VERIFICATION:false}"
user => "${ES_EXTERNAL_USER:}"
password => "${ES_EXTERNAL_PASSWORD:}"
manage_template => false
index => "sessions2-%{+YYMMdd}"
document_id => "%{+YYMMdd}-%{zeekLogDocId}"
}
}

View File

@@ -0,0 +1,13 @@
input {
beats {
id => "input_beats"
host => "0.0.0.0"
port => 5044
ssl => "${BEATS_SSL:false}"
ssl_certificate_authorities => ["/certs/ca.crt"]
ssl_certificate => "/certs/server.crt"
ssl_key => "/certs/server.key"
ssl_verify_mode => "none"
}
}

View File

@@ -0,0 +1,5 @@
output {
pipeline {
send_to => [_MALCOLM_PARSE_PIPELINE_ADDRESSES_]
}
}

View File

@@ -0,0 +1,6 @@
input {
pipeline {
address => "${ELASTICSEARCH_PIPELINE_ADDRESS_INTERNAL:internal-es}"
}
}

View File

@@ -0,0 +1,9 @@
output {
elasticsearch {
id => "output_elasticsearch_moloch"
hosts => "${ES_HOSTS:elasticsearch:9200}"
manage_template => false
index => "sessions2-%{+YYMMdd}"
document_id => "%{+YYMMdd}-%{zeekLogDocId}"
}
}

View File

@@ -0,0 +1,6 @@
input {
pipeline {
address => "zeek-parse"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,967 @@
filter {
# Protocol/service version ##########################################################################################
# collect protocol version under the parent zeek.service_version array
if ([zeek_gquic][version]) { mutate { id => "mutate_merge_normalize_zeek_gquic_version"
merge => { "[zeek][service_version]" => "[zeek_gquic][version]" } } }
if ([zeek_http][version]) { mutate { id => "mutate_merge_normalize_zeek_http_version"
merge => { "[zeek][service_version]" => "[zeek_http][version]" } } }
if ([zeek_ipsec]) {
ruby {
id => "ruby_zeek_field_zeek_service_version_ipsec"
code => "
versions = Array.new
versions << [event.get('[zeek_ipsec][maj_ver]'),
event.get('[zeek_ipsec][min_ver]')].compact.join('.')
event.set('[zeek][service_version]', versions)"
}
}
if ([zeek_ldap][version]) { mutate { id => "mutate_merge_normalize_zeek_ldap_version"
merge => { "[zeek][service_version]" => "[zeek_ldap][version]" } } }
if ([zeek_ntp][version]) { mutate { id => "mutate_merge_normalize_zeek_ntp_version"
merge => { "[zeek][service_version]" => "[zeek_ntp][version]" } } }
if ([zeek_profinet][block_version]) { mutate { id => "mutate_merge_normalize_zeek_profinet_block_version"
merge => { "[zeek][service_version]" => "[zeek_profinet][block_version]" } } }
if ([zeek_profinet_dce_rpc][version]) { mutate { id => "mutate_merge_normalize_zeek_profinet_dce_rpc_version"
merge => { "[zeek][service_version]" => "[zeek_profinet_dce_rpc][version]" } } }
if ([zeek_rfb]) {
ruby {
id => "ruby_zeek_field_zeek_service_version_rfb"
code => '
versions = Array.new
clientMajorVersion = event.get("[zeek_rfb][client_major_version]").sub!(/^0*/, "")
clientMinorVersion = event.get("[zeek_rfb][client_minor_version]").sub!(/^0*/, "")
serverMajorVersion = event.get("[zeek_rfb][server_major_version]").sub!(/^0*/, "")
serverMinorVersion = event.get("[zeek_rfb][server_minor_version]").sub!(/^0*/, "")
if clientMajorVersion then
versions << [clientMajorVersion, clientMinorVersion].join(".")
end
if serverMajorVersion then
versions << [serverMajorVersion, serverMinorVersion].join(".")
end
event.set("[zeek][service_version]", versions.uniq)'
}
}
if ([zeek_rdp][client_build]) { mutate { id => "mutate_merge_normalize_zeek_rdp_client_build"
merge => { "[zeek][service_version]" => "[zeek_rdp][client_build]" } } }
if ([zeek_smtp][version]) { mutate { id => "mutate_merge_normalize_zeek_smtp_version"
merge => { "[zeek][service_version]" => "[zeek_smtp][version]" } } }
if ([zeek_smb_cmd][version]) { mutate { id => "mutate_merge_normalize_zeek_smb_cmd_version"
merge => { "[zeek][service_version]" => "[zeek_smb_cmd][version]" } } }
if ([zeek_snmp][version]) { mutate { id => "mutate_merge_normalize_zeek_snmp_version"
merge => { "[zeek][service_version]" => "[zeek_snmp][version]" } } }
if ([zeek_socks][version]) { mutate { id => "mutate_merge_normalize_zeek_socks_version"
merge => { "[zeek][service_version]" => "[zeek_socks][version]" } } }
if ([zeek_ssh][version]) { mutate { id => "mutate_merge_normalize_zeek_ssh_version"
merge => { "[zeek][service_version]" => "[zeek_ssh][version]" } } }
if ([zeek_ssl][ssl_version]) { mutate { id => "mutate_merge_normalize_zeek_ssl_ssl_version"
merge => { "[zeek][service_version]" => "[zeek_ssl][ssl_version]" } } }
if ([zeek][service_version]) {
ruby {
id => "ruby_zeek_service_version_uniq"
code => "event.set('[zeek][service_version]', event.get('[zeek][service_version]').uniq)"
}
}
# Action ############################################################################################################
# collect all actions/operations/commands under the parent [zeek][action] array
if ([zeek_bacnet][pdu_service]) { mutate { id => "mutate_merge_normalize_zeek_bacnet_pdu_service"
merge => { "[zeek][action]" => "[zeek_bacnet][pdu_service]" } } }
if ([zeek_bacnet_discovery][pdu_service]) { mutate { id => "mutate_merge_normalize_zeek_bacnet_discovery_pdu_service"
merge => { "[zeek][action]" => "[zeek_bacnet_discovery][pdu_service]" } } }
if ([zeek_bacnet_property][pdu_service]) { mutate { id => "mutate_merge_normalize_zeek_bacnet_property_pdu_service"
merge => { "[zeek][action]" => "[zeek_bacnet_property][pdu_service]" } } }
if ([zeek_bsap_ip_rdb]) {
ruby {
# action = zeek_bsap_ip_rdb.app_func_code:zeek_bsap_ip_rdb.func_code
id => "ruby_zeek_bsap_ip_rdb_generate_action"
code => "
actions = Array.new unless (actions = event.get('[zeek][action]'))
actions.append([event.get('[zeek_bsap_ip_rdb][app_func_code]'),
event.get('[zeek_bsap_ip_rdb][func_code]')].compact.join(':'))
event.set('[zeek][action]', actions)"
}
}
if ([zeek_bsap_serial_header][sfun]) { mutate { id => "mutate_merge_normalize_zeek_bsap_serial_header_sfun"
merge => { "[zeek][action]" => "[zeek_bsap_serial_header][sfun]" } } }
if ([zeek_bsap_serial_header][dfun]) { mutate { id => "mutate_merge_normalize_zeek_bsap_serial_header_dfun"
merge => { "[zeek][action]" => "[zeek_bsap_serial_header][dfun]" } } }
if ([zeek_bsap_serial_rdb][func_code]) { mutate { id => "mutate_merge_normalize_zeek_bsap_serial_rdb_func_code"
merge => { "[zeek][action]" => "[zeek_bsap_serial_rdb][func_code]" } } }
if ([zeek_bsap_serial_rdb_ext][sfun]) { mutate { id => "mutate_merge_normalize_zeek_bsap_serial_rdb_ext_sfun"
merge => { "[zeek][action]" => "[zeek_bsap_serial_rdb_ext][sfun]" } } }
if ([zeek_bsap_serial_rdb_ext][dfun]) { mutate { id => "mutate_merge_normalize_zeek_bsap_serial_rdb_ext_dfun"
merge => { "[zeek][action]" => "[zeek_bsap_serial_rdb_ext][dfun]" } } }
if ([zeek_bsap_serial_rdb_ext][extfun]) { mutate { id => "mutate_merge_normalize_zeek_bsap_serial_rdb_ext_extfun"
merge => { "[zeek][action]" => "[zeek_bsap_serial_rdb_ext][extfun]" } } }
if ([zeek_cip][cip_service]) { mutate { id => "mutate_merge_normalize_zeek_cip_cip_service"
merge => { "[zeek][action]" => "[zeek_cip][cip_service]" } } }
if ([zeek_dce_rpc][operation]) { mutate { id => "mutate_merge_normalize_zeek_dce_rpc_operation"
merge => { "[zeek][action]" => "[zeek_dce_rpc][operation]" } } }
if ([zeek_dhcp][msg_types]) { mutate { id => "mutate_merge_normalize_zeek_dhcp_msg_types"
merge => { "[zeek][action]" => "[zeek_dhcp][msg_types]" } } }
if ([zeek_dnp3][fc_request]) { mutate { id => "mutate_merge_normalize_zeek_dnp3_fc_request"
merge => { "[zeek][action]" => "[zeek_dnp3][fc_request]" } } }
if ([zeek_dnp3_control]) {
ruby {
# action = function_code:operation_type:trip_control_code
id => "ruby_zeek_dnp3_control_generate_action"
code => "
actions = Array.new unless (actions = event.get('[zeek][action]'))
actions.append([event.get('[zeek_dnp3_control][function_code]'),
event.get('[zeek_dnp3_control][operation_type]'),
event.get('[zeek_dnp3_control][trip_control_code]')].compact.join(':'))
event.set('[zeek][action]', actions)"
}
}
if ([zeek_dnp3_read_objects][function_code]) { mutate { id => "mutate_merge_normalize_zeek_dnp3_read_objects"
merge => { "[zeek][action]" => "[zeek_dnp3_read_objects][function_code]" } } }
if ([zeek_dns]) {
# action: query class and type
if ([zeek_dns][qclass_name]) and ([zeek_dns][qtype_name]) {
mutate { id => "mutate_add_field_metadata_dns_class_and_type"
add_field => { "[@metadata][dns_action]" => "%{[zeek_dns][qclass_name]} %{[zeek_dns][qtype_name]}" } }
} else if ([zeek_dns][qclass_name]) {
mutate { id => "mutate_add_field_metadata_dns_class"
add_field => { "[@metadata][dns_action]" => "%{[zeek_dns][qclass_name]}" } }
} else if ([zeek_dns][qtype_name]) {
mutate { id => "mutate_add_field_metadata_dns_type"
add_field => { "[@metadata][dns_action]" => "%{[zeek_dns][qtype_name]}" } }
} else {
mutate { id => "mutate_add_field_metadata_dns_query"
add_field => { "[@metadata][dns_action]" => "Query" } }
}
mutate { id => "mutate_merge_zeek_dns_action"
merge => { "[zeek][action]" => "[@metadata][dns_action]" } }
}
# TODO: convert zeek_ecat_foe_info.opcode and zeek_ecat_soe_info.opcode to operations
# zeek EtherCAT commands/operations
if ([zeek_ecat_aoe_info][command]) { mutate { id => "mutate_merge_normalize_zeek_ecat_aoe_info_command"
merge => { "[zeek][action]" => "[zeek_ecat_aoe_info][command]" } } }
if ([zeek_ecat_foe_info][opcode]) { mutate { id => "mutate_merge_normalize_zeek_ecat_foe_info_opcode"
merge => { "[zeek][action]" => "[zeek_ecat_foe_info][opcode]" } } }
if ([zeek_ecat_log_address][command]) { mutate { id => "mutate_merge_normalize_zeek_ecat_log_address"
merge => { "[zeek][action]" => "[zeek_ecat_log_address][command]" } } }
if ([zeek_ecat_registers][command]) { mutate { id => "mutate_merge_normalize_zeek_ecat_registers_command"
merge => { "[zeek][action]" => "[zeek_ecat_registers][command]" } } }
if ([zeek_ecat_soe_info][opcode]) { mutate { id => "mutate_merge_normalize_zeek_ecat_soe_info_opcode"
merge => { "[zeek][action]" => "[zeek_ecat_soe_info][opcode]" } } }
if ([zeek_ecat_arp_info][arp_type]) { mutate { id => "mutate_merge_normalize_zeek_ecat_arp_info_arp_type"
merge => { "[zeek][action]" => "[zeek_ecat_arp_info][arp_type]" } } }
if ([zeek_enip][enip_command]) { mutate { id => "mutate_merge_normalize_zeek_enip_enip_command"
merge => { "[zeek][action]" => "[zeek_enip][enip_command]" } } }
if ([zeek_ftp][command]) { mutate { id => "mutate_merge_normalize_zeek_ftp_command"
merge => { "[zeek][action]" => "[zeek_ftp][command]" } } }
if ([zeek_http]) {
if ([zeek_http][method]) {
mutate { id => "mutate_merge_normalize_zeek_http_method"
merge => { "[zeek][action]" => "[zeek_http][method]" } }
} else {
mutate { id => "mutate_add_field_zeek_http_request_action"
add_field => { "[@metadata][http_request_action]" => "Request" } }
mutate { id => "mutate_merge_field_zeek_http_request_action"
merge => { "[zeek][action]" => "[@metadata][http_request_action]" } }
}
}
if ([zeek_irc][command]) { mutate { id => "mutate_merge_normalize_zeek_irc_command"
merge => { "[zeek][action]" => "[zeek_irc][command]" } } }
if ([zeek_iso_cotp][pdu_type]) { mutate { id => "mutate_merge_normalize_zeek_iso_cotp_pdu_type"
merge => { "[zeek][action]" => "[zeek_iso_cotp][pdu_type]" } } }
if ([zeek_kerberos][request_type]) { mutate { id => "mutate_merge_normalize_zeek_kerberos_request_type"
merge => { "[zeek][action]" => "[zeek_kerberos][request_type]" } } }
if ([zeek_ldap][operation]) { mutate { id => "mutate_merge_normalize_zeek_ldap_operation"
merge => { "[zeek][action]" => "[zeek_ldap][operation]" } } }
if ([zeek_ldap_search]) {
if ([zeek_ldap_search][scope]) {
mutate { id => "mutate_add_field_zeek_ldap_search_scope_action"
add_field => { "[@metadata][zeek_ldap_search_action]" => "search %{[zeek_ldap_search][scope]}" } }
} else {
mutate { id => "mutate_add_field_zeek_ldap_search_action"
add_field => { "[@metadata][zeek_ldap_search_action]" => "search" } }
}
mutate { id => "mutate_merge_field_zeek_ldap_search_action"
merge => { "[zeek][action]" => "[@metadata][zeek_ldap_search_action]" } }
}
if ([zeek_modbus][func]) { mutate { id => "mutate_merge_normalize_zeek_modbus_func"
merge => { "[zeek][action]" => "[zeek_modbus][func]" } } }
if ([zeek_modbus_mask_write_register][func]) { mutate { id => "mutate_merge_normalize_zeek_modbus_mask_write_register_func"
merge => { "[zeek][action]" => "[zeek_modbus_mask_write_register][func]" } } }
if ([zeek_modbus_read_write_multiple_registers][func]) { mutate { id => "mutate_merge_normalize_zeek_modbus_read_write_multiple_registers"
merge => { "[zeek][action]" => "[zeek_modbus_read_write_multiple_registers][func]" } } }
if ([zeek_mqtt_connect][connect_status]) {
# this log entry implicitly means "connect"
mutate { id => "mutate_add_field_zeek_mqtt_connect_action"
add_field => { "[@metadata][zeek_mqtt_connect_action]" => "Connect" } }
mutate { id => "mutate_merge_zeek_mqtt_connect_action"
merge => { "[zeek][action]" => "[@metadata][zeek_mqtt_connect_action]" } }
}
if ([zeek_mqtt_publish]) {
if ([zeek_mqtt_publish][payload_dict][messageType]) {
# not sure if this is a standard or just the PCAPs I found :/
mutate { id => "mutate_merge_normalize_zeek_mqtt_publish_payload_dict_messageType"
merge => { "[zeek][action]" => "[zeek_mqtt_publish][payload_dict][messageType]" } }
} else {
mutate { id => "mutate_add_field_zeek_mqtt_publish_action"
add_field => { "[@metadata][zeek_mqtt_publish_action]" => "Publish" } }
mutate { id => "mutate_merge_zeek_mqtt_publish_action"
merge => { "[zeek][action]" => "[@metadata][zeek_mqtt_publish_action]" } }
}
}
if ([zeek_mqtt_subscribe][action]) { mutate { id => "mutate_merge_normalize_zeek_mqtt_subscribe_action"
merge => { "[zeek][action]" => "[zeek_mqtt_subscribe][action]" } } }
if ([zeek_mysql][cmd]) { mutate { id => "mutate_merge_normalize_zeek_mysql_cmd"
merge => { "[zeek][action]" => "[zeek_mysql][cmd]" } } }
if ([zeek_ntlm][success]) {
# this log entry implicitly means a login attempt
mutate { id => "mutate_add_field_zeek_ntlm_action"
add_field => { "[@metadata][zeek_ntlm_action]" => "Authenticate" } }
mutate { id => "mutate_merge_zeek_ntlm_action"
merge => { "[zeek][action]" => "[@metadata][zeek_ntlm_action]" } }
}
if ([zeek_ntp][mode_str]) { mutate { id => "mutate_merge_normalize_zeek_ntp_mode_str"
merge => { "[zeek][action]" => "[zeek_ntp][mode_str]" } } }
if ([zeek_profinet][operation_type]) { mutate { id => "mutate_merge_normalize_zeek_profinet_operation_type"
merge => { "[zeek][action]" => "[zeek_profinet][operation_type]" } } }
if ([zeek_profinet_dce_rpc][operation]) { mutate { id => "mutate_merge_normalize_zeek_profinet_dce_rpc_operation"
merge => { "[zeek][action]" => "[zeek_profinet_dce_rpc][operation]" } } }
if ([zeek_rfb][auth]) and ([zeek_rfb][authentication_method]) {
# if authentication was attempted, assign an "authenticate" action
mutate { id => "mutate_add_field_zeek_rfb_auth_action"
add_field => { "[@metadata][zeek_rfb_auth_action]" => "Authenticate" } }
mutate { id => "mutate_merge_zeek_rfb_auth_action"
merge => { "[zeek][action]" => "[@metadata][zeek_rfb_auth_action]" } }
}
if ([zeek_s7comm]) {
ruby {
# action = rosctr:mode:type:sub
id => "ruby_zeek_s7comm_generate_action"
code => "
actions = Array.new unless (actions = event.get('[zeek][action]'))
actions.append([event.get('[zeek_s7comm][rosctr]'),
event.get('[zeek_s7comm][parameters][mode]'),
event.get('[zeek_s7comm][parameters][type]'),
event.get('[zeek_s7comm][parameters][sub]')].compact.join(':'))
event.set('[zeek][action]', actions)"
}
}
if ([zeek_sip][method]) { mutate { id => "mutate_merge_normalize_zeek_sip_method"
merge => { "[zeek][action]" => "[zeek_sip][method]" } } }
if ([zeek_smtp]) {
# action depends on varios smtp headers' presence
if ([zeek_smtp][last_reply]) {
if ([zeek_smtp][msg_id]) {
mutate { id => "mutate_add_field_zeek_smtp_action_deliver"
add_field => { "[@metadata][zeek_smtp_action]" => "Deliver message" } }
} else if ([zeek_smtp][mailfrom]) {
mutate { id => "mutate_add_field_zeek_smtp_action_queue"
add_field => { "[@metadata][zeek_smtp_action]" => "Queue message" } }
} else {
mutate { id => "mutate_add_field_zeek_smtp_action_connect_reply"
add_field => { "[@metadata][zeek_smtp_action]" => "Connect" } }
}
} else {
mutate { id => "mutate_add_field_zeek_smtp_action_connect_no_reply"
add_field => { "[@metadata][zeek_smtp_action]" => "Connect" } }
}
if ([@metadata][zeek_smtp_action]) {
mutate { id => "mutate_merge_zeek_smtp_action"
merge => { "[zeek][action]" => "[@metadata][zeek_smtp_action]" } }
}
}
if ([zeek_socks]) {
# socks action is "Authenticate" or "Connect" based on user/password or not
if ([zeek_socks][user]) or ([zeek_socks][password]) {
mutate { id => "mutate_add_field_zeek_socks_action_authenticate"
add_field => { "[@metadata][zeek_socks_action]" => "Authenticate" } }
} else {
mutate { id => "mutate_add_field_zeek_socks_action_connect"
add_field => { "[@metadata][zeek_socks_action]" => "Connect" } }
}
if ([@metadata][zeek_socks_action]) {
mutate { id => "mutate_merge_zeek_socks_action"
merge => { "[zeek][action]" => "[@metadata][zeek_socks_action]" } }
}
}
if ([zeek_smb_cmd]) {
ruby {
# action = command:sub_command
id => "ruby_zeek_smb_cmd_generate_action"
code => "
cmd = event.get('[zeek_smb_cmd][command]')
subCmd = event.get('[zeek_smb_cmd][sub_command]')
actions = Array.new unless (actions = event.get('[zeek][action]'))
actions.append((cmd =~ /^\s*transaction\d*\s*$/i) ? subCmd : [cmd, subCmd].compact.join(':'))
event.set('[zeek][action]', actions)"
}
}
if ([zeek_smb_files][action]) { mutate { id => "mutate_merge_normalize_zeek_smb_files_action"
merge => { "[zeek][action]" => "[zeek_smb_files][action]" } } }
if ([zeek_smtp][method]) { mutate { id => "mutate_merge_normalize_zeek_smtp_method"
merge => { "[zeek][action]" => "[zeek_smtp][method]" } } }
if ([zeek_snmp]) {
# action based on > 0 values for variou get/set PDUs
if ([zeek_snmp][get_bulk_requests]) and ([zeek_snmp][get_bulk_requests] != "0") {
mutate { id => "mutate_add_field_zeek_snmp_get_bulk_requests_action"
add_field => { "[@metadata][snmp_get_bulk_requests_action]" => "GetBulkRequest" } }
mutate { id => "mutate_merge_zeek_snmp_action_get_bulk_requests"
merge => { "[zeek][action]" => "[@metadata][snmp_get_bulk_requests_action]" } }
}
if ([zeek_snmp][get_requests]) and ([zeek_snmp][get_requests] != "0") {
mutate { id => "mutate_add_field_zeek_snmp_get_requests_action"
add_field => { "[@metadata][snmp_get_requests_action]" => "GetRequest" } }
mutate { id => "mutate_merge_zeek_snmp_action_get_requests"
merge => { "[zeek][action]" => "[@metadata][snmp_get_requests_action]" } }
}
if ([zeek_snmp][get_responses]) and ([zeek_snmp][get_responses] != "0") {
mutate { id => "mutate_add_field_zeek_snmp_get_responses_action"
add_field => { "[@metadata][snmp_get_responses_action]" => "GetResponse" } }
mutate { id => "mutate_merge_zeek_snmp_action_get_responses"
merge => { "[zeek][action]" => "[@metadata][snmp_get_responses_action]" } }
}
if ([zeek_snmp][set_requests]) and ([zeek_snmp][set_requests] != "0") {
mutate { id => "mutate_add_field_zeek_snmp_set_requests_action"
add_field => { "[@metadata][snmp_set_requests_action]" => "SetRequest" } }
mutate { id => "mutate_merge_zeek_snmp_action_set_requests"
merge => { "[zeek][action]" => "[@metadata][snmp_set_requests_action]" } }
}
}
if ([zeek_ssh]) {
# ssh action is "Authenticate" or "Connect" based on auth_attempts
if ([zeek_ssh][auth_attempts]) {
mutate { id => "mutate_add_field_zeek_ssh_action_authenticate"
add_field => { "[@metadata][zeek_ssh_action]" => "Authenticate" } }
} else {
mutate { id => "mutate_add_field_zeek_ssh_action_connect"
add_field => { "[@metadata][zeek_ssh_action]" => "Connect" } }
}
if ([@metadata][zeek_ssh_action]) {
mutate { id => "mutate_merge_zeek_ssh_action"
merge => { "[zeek][action]" => "[@metadata][zeek_ssh_action]" } }
}
}
if ([zeek_ssl]) {
# SSL action will be either "connect", "validate", "resume"
if ([zeek_ssl][resumed] == "T") {
mutate { id => "mutate_add_field_zeek_ssl_resume"
add_field => { "[@metadata][zeek_ssl_action]" => "Resume" } }
} else if ([zeek_ssl][established] != "T") and ([zeek_ssl][validation_status]) and ([zeek_ssl][validation_status] != "ok") {
mutate { id => "mutate_add_field_zeek_ssl_validate"
add_field => { "[@metadata][zeek_ssl_action]" => "Validate Certificate" } }
} else {
mutate { id => "mutate_add_field_zeek_ssl_connect"
add_field => { "[@metadata][zeek_ssl_action]" => "Connect" } }
}
mutate { id => "mutate_merge_zeek_ssl_action"
merge => { "[zeek][action]" => "[@metadata][zeek_ssl_action]" } }
}
if ([zeek_tds][command]) { mutate { id => "mutate_merge_normalize_zeek_tds_command"
merge => { "[zeek][action]" => "[zeek_tds][command]" } } }
if ([zeek_tds_rpc][procedure_name]) {
mutate { id => "mutate_add_field_zeek_tds_rpc_procedure_name_tmp"
add_field => { "[@metadata][zeek_tds_rpc_procedure_name_tmp]" => "%{[zeek_tds_rpc][procedure_name]}" } }
# remove everything after the first $
mutate { id => "mutate_gsub_field_zeek_tds_rpc_procedure_name_tmp"
gsub => [ "[@metadata][zeek_tds_rpc_procedure_name_tmp]", "\$.*", "" ] }
mutate { id => "mutate_merge_normalize_zeek_tds_rpc_procedure_name"
merge => { "[zeek][action]" => "[@metadata][zeek_tds_rpc_procedure_name_tmp]" } }
}
if ([zeek_tftp][wrq]) {
if ([zeek_tftp][wrq] == "T") {
mutate { id => "mutate_add_field_zeek_tftp_wrq"
add_field => { "[@metadata][zeek_tftp_action]" => "Write" } }
} else {
mutate { id => "mutate_add_field_zeek_tftp_connect"
add_field => { "[@metadata][zeek_tftp_action]" => "Read" } }
}
mutate { id => "mutate_merge_zeek_tftp_action"
merge => { "[zeek][action]" => "[@metadata][zeek_tftp_action]" } }
}
if ([zeek_tunnel][action]) { mutate { id => "mutate_merge_normalize_zeek_tunnel_action"
merge => { "[zeek][action]" => "[zeek_tunnel][action]" } } }
# Result ############################################################################################################
# collect all result/status/response/errors under the parent [zeek][result] array
if ([zeek_bacnet]) {
if ([zeek_bacnet][result_code]) {
mutate { id => "mutate_merge_normalize_zeek_bacnet_result_code"
merge => { "[zeek][result]" => "[zeek_bacnet][result_code]" } }
} else if ([zeek_bacnet][pdu_service]) {
mutate { id => "mutate_add_field_zeek_bacnet_success"
add_field => { "[@metadata][zeek_bacnet_result]" => "Success" } }
mutate { id => "mutate_merge_field_zeek_bacnet_success"
merge => { "[zeek][result]" => "[@metadata][zeek_bacnet_result]" } }
}
}
if ([zeek_cip][cip_status]) { mutate { id => "mutate_merge_normalize_zeek_cip_status_result"
merge => { "[zeek][result]" => "[zeek_cip][cip_status]" } } }
if ([zeek_dhcp]) {
# dhcp server_message and client_message populate result, as do ACK and NAK message types
if ([zeek_dhcp][server_message]) { mutate { id => "mutate_merge_normalize_zeek_dhcp_server_message"
merge => { "[zeek][result]" => "[zeek_dhcp][server_message]" } } }
if ([zeek_dhcp][client_message]) { mutate { id => "mutate_merge_normalize_zeek_dhcp_client_message"
merge => { "[zeek][result]" => "[zeek_dhcp][client_message]" } } }
if ("ACK" in [zeek_dhcp][msg_types]) {
mutate { id => "mutate_add_field_zeek_dhcp_ack_result"
add_field => { "[@metadata][zeek_dhcp_result]" => "Success" } }
} else if ("NAK" in [zeek_dhcp][msg_types]) {
mutate { id => "mutate_add_field_zeek_dhcp_nak_result"
add_field => { "[@metadata][zeek_dhcp_result]" => "Failure" } }
}
if ([@metadata][zeek_dhcp_result]) {
mutate { id => "mutate_merge_zeek_dhcp_result"
merge => { "[zeek][result]" => "[@metadata][zeek_dhcp_result]" } }
}
}
# dnp3: fc_reply and iin_flags
if ([zeek_dnp3][fc_reply]) { mutate { id => "mutate_merge_zeek_dnp3_fc_reply"
merge => { "[zeek][result]" => "[zeek_dnp3][fc_reply]" } } }
if ([zeek_dnp3][iin_flags]) { mutate { id => "mutate_merge_zeek_dnp3_iin_flags"
merge => { "[zeek][result]" => "[zeek_dnp3][iin_flags]" } } }
# dnp3_control.status_code
if ([zeek_dnp3_control][status_code]) { mutate { id => "mutate_merge_zeek_dnp3_control_status_code"
merge => { "[zeek][result]" => "[zeek_dnp3_control][status_code]" } } }
if ([zeek_dns]) {
# DNS result is populated by rcode_name (with NOERROR being translated to Success), and rejected
if ([zeek_dns][rcode_name]) {
if ([zeek_dns][rcode_name] == 'NOERROR') {
mutate { id => "mutate_add_field_zeek_dns_noerror"
add_field => { "[@metadata][zeek_dns_result]" => "Success" } }
mutate { id => "mutate_merge_field_zeek_dns_noerror"
merge => { "[zeek][result]" => "[@metadata][zeek_dns_result]" } }
} else {
mutate { id => "mutate_merge_normalize_zeek_dns_rcode_name"
merge => { "[zeek][result]" => "[zeek_dns][rcode_name]" } }
}
}
if ([zeek_dns][rejected] == 'T') {
mutate { id => "mutate_add_field_zeek_dns_rejected"
add_field => { "[@metadata][zeek_dns_rejected_result]" => "Rejected" } }
mutate { id => "mutate_merge_field_zeek_dns_rejected"
merge => { "[zeek][result]" => "[@metadata][zeek_dns_rejected_result]" } }
}
}
# TODO: convert zeek_ecat_foe_info.error_code and zeek_ecat_soe_info.error to strings?
# zeek_ecat_foe_info.error_code and zeek_ecat_soe_info.error
if ([zeek_ecat_foe_info][error_code]) { mutate { id => "mutate_merge_normalize_zeek_ecat_foe_info_error_code"
merge => { "[zeek][result]" => "[zeek_ecat_foe_info][error_code]" } } }
if ([zeek_ecat_soe_info][error]) { mutate { id => "mutate_merge_normalize_zeek_ecat_soe_info_error"
merge => { "[zeek][result]" => "[zeek_ecat_soe_info][error]" } } }
# zeek_enip.enip_status
if ([zeek_enip][enip_status]) { mutate { id => "mutate_merge_normalize_zeek_enip_enip_status"
merge => { "[zeek][result]" => "[zeek_enip][enip_status]" } } }
if ([zeek_ftp][reply_code]) {
# normalized version of reply code (reply_msg is too unpredictable)
translate {
id => "translate_zeek_ftp_reply_code"
field => "[zeek_ftp][reply_code]"
destination => "[@metadata][zeek_ftp_mapped_result]"
dictionary_path => "/etc/ftp_result_codes.yaml"
}
if ([@metadata][zeek_ftp_mapped_result]) {
mutate { id => "mutate_merge_zeek_ftp_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_ftp_mapped_result]" } }
} else if ([zeek_ftp][reply_msg]) {
mutate { id => "mutate_merge_zeek_ftp_reply_msg_result"
merge => { "[zeek][result]" => "[zeek_ftp][reply_msg]" } }
} else {
mutate { id => "mutate_merge_zeek_ftp_reply_code_result"
merge => { "[zeek][result]" => "[zeek_ftp][reply_code]" } }
}
}
if ([zeek_http][status_code]) {
# normalized version of http reply code (status_msg is too unpredictable)
translate {
id => "translate_zeek_http_reply_code"
field => "[zeek_http][status_code]"
destination => "[@metadata][zeek_http_mapped_result]"
dictionary_path => "/etc/http_result_codes.yaml"
}
if ([@metadata][zeek_http_mapped_result]) {
mutate { id => "mutate_merge_zeek_http_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_http_mapped_result]" } }
} else if ([zeek_http][status_msg]) {
mutate { id => "mutate_merge_zeek_http_status_msg_result"
merge => { "[zeek][result]" => "[zeek_http][status_msg]" } }
} else {
mutate { id => "mutate_merge_zeek_http_status_code_result"
merge => { "[zeek][result]" => "[zeek_http][status_code]" } }
}
}
if ([zeek_kerberos]) {
# result populated from success and error_msg
if ([zeek_kerberos][success] == 'T') {
mutate { id => "mutate_add_field_zeek_zeek_kerberos_success"
add_field => { "[@metadata][zeek_kerberos_result]" => "Success" } }
} else if ([zeek_kerberos][error_msg]) {
mutate { id => "mutate_add_field_zeek_zeek_kerberos_error_msg"
add_field => { "[@metadata][zeek_kerberos_result]" => "%{[zeek_kerberos][error_msg]}" } }
} else {
mutate { id => "mutate_add_field_zeek_zeek_kerberos_failure"
add_field => { "[@metadata][zeek_kerberos_result]" => "Failure" } }
}
mutate { id => "mutate_merge_zeek_kerberos_result"
merge => { "[zeek][result]" => "[@metadata][zeek_kerberos_result]" } }
}
# (zeek_ldap|zeek_ldap_search).(result_code)
if ([zeek_ldap][result_code]) { mutate { id => "mutate_merge_normalize_zeek_ldap_result_code"
merge => { "[zeek][result]" => "[zeek_ldap][result_code]" } } }
if ([zeek_ldap_search][result_code]) { mutate { id => "mutate_merge_normalize_zeek_ldap_search_result_code"
merge => { "[zeek][result]" => "[zeek_ldap_search][result_code]" } } }
if ([zeek_modbus]) {
# result comes from exception, but if exception is missing and we have a func, then assume success
if ([zeek_modbus][exception]) {
mutate { id => "mutate_merge_normalize_zeek_modbus_exception"
merge => { "[zeek][result]" => "[zeek_modbus][exception]" } }
} else if ([zeek_modbus][func]) {
mutate { id => "mutate_add_field_zeek_modbus_success"
add_field => { "[@metadata][zeek_modbus_result]" => "Success" } }
mutate { id => "mutate_merge_field_zeek_modbus_success"
merge => { "[zeek][result]" => "[@metadata][zeek_modbus_result]" } }
}
}
# result for zeek_mqtt_connect: connect_status.'Connection Accepted' -> 'Success', else connect_status
if ([zeek_mqtt_connect][connect_status] == 'Connection Accepted') {
mutate { id => "mutate_add_field_zeek_mqtt_connect_success"
add_field => { "[@metadata][zeek_mqtt_connect_success]" => "Success" } }
mutate { id => "mutate_merge_field_zeek_mqtt_connect_success"
merge => { "[zeek][result]" => "[@metadata][zeek_mqtt_connect_success]" } }
} else if ([zeek_mqtt_connect][connect_status]) {
mutate { id => "mutate_merge_zeek_mqtt_connect_connect_status"
merge => { "[zeek][result]" => "[zeek_mqtt_connect][connect_status]" } }
}
# result for zeek_mqtt_publish: status.'ok' -> 'Success', else status
if ([zeek_mqtt_publish][status] == 'ok') {
mutate { id => "mutate_add_field_zeek_mqtt_publish_success"
add_field => { "[@metadata][zeek_mqtt_publish_success]" => "Success" } }
mutate { id => "mutate_merge_field_zeek_mqtt_publish_success"
merge => { "[zeek][result]" => "[@metadata][zeek_mqtt_publish_success]" } }
} else if ([zeek_mqtt_publish][status]) {
mutate { id => "mutate_merge_zeek_mqtt_publish_publish_status"
merge => { "[zeek][result]" => "[zeek_mqtt_publish][status]" } }
}
# zeek_mqtt_subscribe.ack.'T' -> 'Acknowledged'
if ([zeek_mqtt_subscribe][ack] == 'T') {
mutate { id => "mutate_add_field_zeek_mqtt_subscribe_ack"
add_field => { "[@metadata][zeek_mqtt_subscribe_acknowledged]" => "Acknowledged" } }
mutate { id => "mutate_merge_field_zeek_mqtt_subscribe_ack"
merge => { "[zeek][result]" => "[@metadata][zeek_mqtt_subscribe_acknowledged]" } }
}
if ([zeek_mysql]) {
# mysql result comes from success and response
if ([zeek_mysql][success] == "T") {
mutate { id => "mutate_add_field_zeek_mysql_success"
add_field => { "[@metadata][zeek_mysql_result]" => "Success" } }
} else if ([zeek_mysql][response] =~ /^Access denied/) {
mutate { id => "mutate_add_field_zeek_mysql_access"
add_field => { "[@metadata][zeek_mysql_result]" => "Access denied" } }
} else {
mutate { id => "mutate_add_field_zeek_mysql_failure"
add_field => { "[@metadata][zeek_mysql_result]" => "Failure" } }
}
mutate { id => "mutate_merge_zeek_mysql_result"
merge => { "[zeek][result]" => "[@metadata][zeek_mysql_result]" } }
}
if ([zeek_ntlm]) {
# ntlm result comes from .success
if ([zeek_ntlm][success] == "T") {
mutate { id => "mutate_add_field_zeek_ntlm_success"
add_field => { "[@metadata][zeek_ntlm_result]" => "Success" } }
} else {
mutate { id => "mutate_add_field_zeek_ntlm_failure"
add_field => { "[@metadata][zeek_ntlm_result]" => "Failure" } }
}
mutate { id => "mutate_merge_zeek_ntlm_result"
merge => { "[zeek][result]" => "[@metadata][zeek_ntlm_result]" } }
}
if ([zeek_radius][result]) {
if ([zeek_radius][result] =~ /^(?i)succ/) {
mutate { id => "mutate_add_field_zeek_radius_success"
add_field => { "[@metadata][zeek_radius_result]" => "Success" } }
} else if ([zeek_radius][result] =~ /^(?i)fail/) {
mutate { id => "mutate_add_field_zeek_radius_failure"
add_field => { "[@metadata][zeek_radius_result]" => "Failure" } }
} else {
mutate { id => "mutate_add_field_zeek_radius_result_fallback"
add_field => { "[@metadata][zeek_radius_result]" => "%{[zeek_radius][result]}" } }
}
mutate { id => "mutate_merge_zeek_radius_result"
merge => { "[zeek][result]" => "[@metadata][zeek_radius_result]" } }
# if authentication was attempted, also assign an "authenticate" action
mutate { id => "mutate_add_field_zeek_radius_auth_action"
add_field => { "[@metadata][zeek_radius_auth_action]" => "Authenticate" } }
mutate { id => "mutate_merge_zeek_radius_auth_action"
merge => { "[zeek][action]" => "[@metadata][zeek_radius_auth_action]" } }
}
if ([zeek_rdp][result]) { mutate { id => "mutate_merge_normalize_zeek_rdp_result"
merge => { "[zeek][result]" => "[zeek_rdp][result]" } } }
if ([zeek_s7comm][parameters][code]) {
# reference: https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-s7comm.c
translate {
id => "translate_zeek_s7comm_parameters_code"
field => "[zeek_s7comm][parameters][code]"
destination => "[@metadata][zeek_s7comm_mapped_result]"
dictionary_path => "/etc/s7comm_result_codes.yaml"
fallback => "%{[zeek_s7comm][parameters][code]}"
}
if ([@metadata][zeek_s7comm_mapped_result]) {
mutate { id => "mutate_merge_zeek_s7comm_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_s7comm_mapped_result]" } }
}
}
if ([zeek_sip][status_code]) {
# normalized version of sip reply code (status_msg may be unpredictable)
translate {
id => "translate_zeek_sip_reply_code"
field => "[zeek_sip][status_code]"
destination => "[@metadata][zeek_sip_mapped_result]"
dictionary_path => "/etc/sip_result_codes.yaml"
}
if ([@metadata][zeek_sip_mapped_result]) {
mutate { id => "mutate_merge_zeek_sip_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_sip_mapped_result]" } }
} else if ([zeek_sip][status_msg]) {
mutate { id => "mutate_merge_zeek_sip_status_msg_result"
merge => { "[zeek][result]" => "[zeek_sip][status_msg]" } }
} else {
mutate { id => "mutate_merge_zeek_sip_status_code_result"
merge => { "[zeek][result]" => "[zeek_sip][status_code]" } }
}
}
if ([zeek_smb_cmd][status]) {
# zeek_smb_cmd.status (SUCCESS, NO_SUCH_FILE, ACCESS_DENIED, OBJECT_NAME_COLLISION, etc.)
translate {
id => "translate_zeek_smb_cmd_status"
field => "[zeek_smb_cmd][status]"
destination => "[@metadata][zeek_smb_cmd_mapped_result]"
dictionary => {
"SUCCESS" => "Success"
# TODO... normalize other codes? or maybe just case-normalize and remove underscores/dashes?
# e.g., "ACCESS_DENIED".split(/[_-]/).collect(&:capitalize).join(' ')
}
fallback => "%{[zeek_smb_cmd][status]}"
}
if ([@metadata][zeek_smb_cmd_mapped_result]) {
mutate { id => "mutate_merge_zeek_smb_cmd_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_smb_cmd_mapped_result]" } }
}
}
if ([zeek_smtp]) {
if ([zeek_smtp][last_reply_code]) {
# normalized version of smtp reply code (last_reply may be unpredictable)
translate {
id => "translate_zeek_smtp_last_reply_code"
field => "[zeek_smtp][last_reply_code]"
destination => "[@metadata][zeek_smtp_mapped_result]"
dictionary_path => "/etc/smtp_result_codes.yaml"
}
}
if ([@metadata][zeek_smtp_mapped_result]) {
mutate { id => "mutate_merge_zeek_smtp_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_smtp_mapped_result]" } }
} else if ([zeek_smtp][last_reply]) {
mutate { id => "mutate_merge_zeek_smtp_last_reply_result"
merge => { "[zeek][result]" => "[zeek_smtp][last_reply]" } }
}
}
if ([zeek_socks][server_status]) {
translate {
id => "translate_zeek_socks_server_status"
field => "[zeek_socks][server_status]"
destination => "[@metadata][zeek_socks_mapped_result]"
dictionary => {
"succeeded" => "Success"
# TODO... normalize other codes (figure out what they are)
}
}
if ([@metadata][zeek_socks_mapped_result]) {
mutate { id => "mutate_merge_zeek_socks_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_socks_mapped_result]" } }
} else if ([zeek_socks][server_status]) {
mutate { id => "mutate_merge_zeek_socks_server_status_result"
merge => { "[zeek][result]" => "[zeek_socks][server_status]" } }
}
}
if ([zeek_ssh][auth_success]) {
translate {
id => "translate_zeek_ssh_auth_success"
field => "[zeek_ssh][auth_success]"
destination => "[@metadata][zeek_ssh_mapped_result]"
dictionary => {
"T" => "Success"
"F" => "Failure"
}
}
if ([@metadata][zeek_ssh_mapped_result]) {
mutate { id => "mutate_merge_zeek_ssh_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_ssh_mapped_result]" } }
}
}
if ([zeek_ssl]) {
if ([zeek_ssl][established] == "T") {
mutate { id => "mutate_add_field_zeek_ssl_result_success"
add_field => { "[@metadata][zeek_ssl_mapped_success_result]" => "Success" } }
} else if (![zeek_ssl][last_alert]) {
mutate { id => "mutate_add_field_zeek_ssl_result_failure"
add_field => { "[@metadata][zeek_ssl_mapped_success_result]" => "Failure" } }
}
if ([@metadata][zeek_ssl_mapped_success_result]) {
mutate { id => "mutate_merge_zeek_ssl_mapped_success_result"
merge => { "[zeek][result]" => "[@metadata][zeek_ssl_mapped_success_result]" } }
}
if ([zeek_ssl][last_alert]) {
mutate { id => "mutate_merge_field_zeek_ssl_result_last_alert"
merge => { "[zeek][result]" => "[zeek_ssl][last_alert]" } }
}
if ([zeek_ssl][validation_status]) and ([zeek_ssl][validation_status] != 'ok') {
mutate { id => "mutate_merge_field_zeek_ssl_result_validation_status"
merge => { "[zeek][result]" => "[zeek_ssl][validation_status]" } }
}
}
if ([zeek_tftp]) {
if (![zeek_tftp][error_code]) and (![zeek_tftp][error_msg]) {
# no error, set as "success"
mutate { id => "mutate_add_field_zeek_tftp_result_success"
add_field => { "[@metadata][zeek_tftp_result_success]" => "Success" } }
mutate { id => "mutate_merge_zeek_tftp_result_success"
merge => { "[zeek][result]" => "[@metadata][zeek_tftp_result_success]" } }
} else {
# normalized version of reply code
translate {
id => "translate_zeek_tftp_error_code"
field => "[zeek_tftp][error_code]"
destination => "[@metadata][zeek_tftp_mapped_result]"
dictionary_path => "/etc/tftp_result_codes.yaml"
}
if ([@metadata][zeek_tftp_mapped_result]) {
mutate { id => "mutate_merge_zeek_tftp_mapped_result"
merge => { "[zeek][result]" => "[@metadata][zeek_tftp_mapped_result]" } }
} else if ([zeek_tftp][error_msg]) {
mutate { id => "mutate_merge_zeek_tftp_error_msg_result"
merge => { "[zeek][result]" => "[zeek_tftp][error_msg]" } }
} else {
mutate { id => "mutate_merge_zeek_tftp_error_code_result"
merge => { "[zeek][result]" => "[zeek_tftp][error_code]" } }
}
}
}
#####################################################################################################################
# remove any duplicates from action and result
if ([zeek][action]) {
ruby {
id => "ruby_zeek_action_uniq"
code => "event.set('[zeek][action]', event.get('[zeek][action]').uniq)"
}
}
if ([zeek][result]) {
ruby {
id => "ruby_zeek_result_uniq"
code => "event.set('[zeek][result]', event.get('[zeek][result]').uniq)"
}
}
# FUIDs #############################################################################################################
# collect all other FUIDs under parent [zeek][fuid] array (some were already done at the root level in
# the "rename" in 11_zeek_logs.conf)
if ([zeek_files][parent_fuid]) { mutate { id => "mutate_merge_normalize_zeek_files_parent_fuid"
merge => { "[zeek][fuid]" => "[zeek_files][parent_fuid]" } } }
if ([zeek_http][orig_fuids]) { mutate { id => "mutate_merge_normalize_zeek_http_orig_fuids"
merge => { "[zeek][fuid]" => "[zeek_http][orig_fuids]" } } }
if ([zeek_http][resp_fuids]) { mutate { id => "mutate_merge_normalize_zeek_http_resp_fuids"
merge => { "[zeek][fuid]" => "[zeek_http][resp_fuids]" } } }
if ([zeek_kerberos][client_cert_fuid]) { mutate { id => "mutate_merge_normalize_zeek_kerberos_client_cert_fuid"
merge => { "[zeek][fuid]" => "[zeek_kerberos][client_cert_fuid]" } } }
if ([zeek_kerberos][server_cert_fuid]) { mutate { id => "mutate_merge_normalize_zeek_kerberos_server_cert_fuid"
merge => { "[zeek][fuid]" => "[zeek_kerberos][server_cert_fuid]" } } }
if ([zeek_ssl][cert_chain_fuids]) { mutate { id => "mutate_merge_normalize_zeek_ssl_cert_chain_fuids"
merge => { "[zeek][fuid]" => "[zeek_ssl][cert_chain_fuids]" } } }
if ([zeek_ssl][client_cert_chain_fuids]) { mutate { id => "mutate_merge_normalize_zeek_ssl_client_cert_chain_fuids"
merge => { "[zeek][fuid]" => "[zeek_ssl][client_cert_chain_fuids]" } } }
if ([zeek][fuid]) {
ruby {
id => "ruby_zeek_fuid_uniq"
code => "event.set('[zeek][fuid]', event.get('[zeek][fuid]').uniq)"
}
}
# File/MIME types ###################################################################################################
# collect all file/MIME types under the parent [zeek][filetype] array
if ([zeek_files][mime_type]) { mutate { id => "mutate_merge_normalize_zeek_files_mime_type"
merge => { "[zeek][filetype]" => "[zeek_files][mime_type]" } } }
if ([zeek_ftp][mime_type]) { mutate { id => "mutate_merge_normalize_zeek_ftp_mime_type"
merge => { "[zeek][filetype]" => "[zeek_ftp][mime_type]" } } }
if ([zeek_http][orig_mime_types]) { mutate { id => "mutate_merge_normalize_zeek_http_orig_mime_types"
merge => { "[zeek][filetype]" => "[zeek_http][orig_mime_types]" } } }
if ([zeek_http][resp_mime_types]) { mutate { id => "mutate_merge_normalize_zeek_http_resp_mime_types"
merge => { "[zeek][filetype]" => "[zeek_http][resp_mime_types]" } } }
if ([zeek_irc][dcc_mime_type]) { mutate { id => "mutate_merge_normalize_zeek_irc_dcc_mime_type"
merge => { "[zeek][filetype]" => "[zeek_irc][dcc_mime_type]" } } }
if ([zeek_intel][file_mime_type]) { mutate { id => "mutate_merge_normalize_zeek_intel_file_mime_type"
merge => { "[zeek][filetype]" => "[zeek_intel][file_mime_type]" } } }
if ([zeek_notice][file_mime_type]) { mutate { id => "mutate_merge_normalize_zeek_notice_file_mime_type"
merge => { "[zeek][filetype]" => "[zeek_notice][file_mime_type]" } } }
if ([zeek_sip][content_type]) { mutate { id => "mutate_merge_normalize_zeek_sip_content_type"
merge => { "[zeek][filetype]" => "[zeek_sip][content_type]" } } }
if ([zeek][filetype]) {
ruby {
id => "ruby_zeek_filetype_uniq"
code => "event.set('[zeek][filetype]', event.get('[zeek][filetype]').uniq)"
}
}
# Filenames #########################################################################################################
# collect all filenames under the parent [zeek][filename] array
if ([zeek_ecat_foe_info][filename]) { mutate { id => "mutate_merge_normalize_zeek_ecat_foe_info_filename"
merge => { "[zeek][filename]" => "[zeek_ecat_foe_info][filename]" } } }
if ([zeek_files][filename]) { mutate { id => "mutate_merge_normalize_zeek_files_filename"
merge => { "[zeek][filename]" => "[zeek_files][filename]" } } }
if ([zeek_files][extracted]) { mutate { id => "mutate_merge_normalize_zeek_files_extracted"
merge => { "[zeek][filename]" => "[zeek_files][extracted]" } } }
if ([zeek_http][orig_filenames]) { mutate { id => "mutate_merge_normalize_zeek_http_orig_filenames"
merge => { "[zeek][filename]" => "[zeek_http][orig_filenames]" } } }
if ([zeek_http][resp_filenames]) { mutate { id => "mutate_merge_normalize_zeek_http_resp_filenames"
merge => { "[zeek][filename]" => "[zeek_http][resp_filenames]" } } }
if ([zeek_irc][dcc_file_name]) { mutate { id => "mutate_merge_normalize_zeek_irc_dcc_file_name"
merge => { "[zeek][filename]" => "[zeek_irc][dcc_file_name]" } } }
if ([zeek_smb_files][name]) { mutate { id => "mutate_merge_normalize_zeek_smb_files_name"
merge => { "[zeek][filename]" => "[zeek_smb_files][name]" } } }
if ([zeek_smb_files][prev_name]) { mutate { id => "mutate_merge_normalize_zeek_smb_files_prev_name"
merge => { "[zeek][filename]" => "[zeek_smb_files][prev_name]" } } }
if ([zeek_tftp][fname]) { mutate { id => "mutate_merge_normalize_zeek_tftp_fname"
merge => { "[zeek][filename]" => "[zeek_tftp][fname]" } } }
if ([zeek][filename]) {
ruby {
id => "ruby_zeek_filename_uniq"
code => "event.set('[zeek][filename]', event.get('[zeek][filename]').uniq)"
}
}
}

View File

@@ -0,0 +1,299 @@
filter {
# set data types for fields that belong to various zeek logs
# todo
# "[zeek_ecat_dev_info][fmmucnt]" => "integer"
# "[zeek_ecat_dev_info][smcount]" => "integer"
mutate {
id => "mutate_convert_zeek_bulk"
convert => {
"[zeek_bacnet][invoke_id]" => "integer"
"[zeek_bacnet_discovery][instance_number]" => "integer"
"[zeek_bacnet_discovery][range_low]" => "integer"
"[zeek_bacnet_discovery][range_high]" => "integer"
"[zeek_bacnet_property][instance_number]" => "integer"
"[zeek_bacnet_property][array_index]" => "integer"
"[zeek_bsap_ip_header][type_name]" => "integer"
"[zeek_bsap_ip_rdb][data_len]" => "integer"
"[zeek_bsap_ip_rdb][header_size]" => "integer"
"[zeek_bsap_ip_rdb][mes_seq]" => "integer"
"[zeek_bsap_ip_rdb][node_status]" => "integer"
"[zeek_bsap_ip_rdb][res_seq]" => "integer"
"[zeek_bsap_ip_rdb][sequence]" => "integer"
"[zeek_bsap_serial_header][ctl]" => "integer"
"[zeek_bsap_serial_header][dadd]" => "integer"
"[zeek_bsap_serial_header][nsb]" => "integer"
"[zeek_bsap_serial_header][sadd]" => "integer"
"[zeek_bsap_serial_header][seq]" => "integer"
"[zeek_bsap_serial_rdb_ext][nsb]" => "integer"
"[zeek_bsap_serial_rdb_ext][seq]" => "integer"
"[zeek_cip][cip_sequence_count]" => "integer"
"[zeek_cip_identity][device_type_id]" => "integer"
"[zeek_cip_identity][encapsulation_version]" => "integer"
"[zeek_cip_identity][product_code]" => "integer"
"[zeek_cip_identity][socket_port]" => "integer"
"[zeek_cip_identity][vendor_id]" => "integer"
"[zeek_cip_io][data_length]" => "integer"
"[zeek_cip_io][sequence_number]" => "integer"
"[zeek_conn][duration]" => "float"
"[zeek_dce_rpc][rtt]" => "float"
"[zeek_dhcp][duration]" => "float"
"[zeek_dnp3_control][index_number]" => "integer"
"[zeek_dnp3_control][execute_count]" => "integer"
"[zeek_dnp3_control][on_time]" => "integer"
"[zeek_dnp3_control][off_time]" => "integer"
"[zeek_dnp3_objects][object_count]" => "integer"
"[zeek_dnp3_objects][range_high]" => "integer"
"[zeek_dnp3_objects][range_low]" => "integer"
"[zeek_dns][rtt]" => "float"
"[zeek_ecat_log_address][length]" => "integer"
"[zeek_enip][length]" => "integer"
"[zeek_ipsec][maj_ver]" => "integer"
"[zeek_ipsec][min_ver]" => "integer"
"[zeek_ipsec][exchange_type]" => "integer"
"[zeek_ipsec][ke_dh_groups]" => "integer"
"[zeek_ipsec][proposals]" => "integer"
"[zeek_ipsec][length]" => "integer"
"[zeek_ldap][version]" => "integer"
"[zeek_ldap_search][result_count]" => "integer"
"[zeek_modbus_detailed][unit_id]" => "integer"
"[zeek_modbus_detailed][address]" => "integer"
"[zeek_modbus_detailed][quantity]" => "integer"
"[zeek_modbus_mask_write_register][unit_id]" => "integer"
"[zeek_modbus_mask_write_register][address]" => "integer"
"[zeek_modbus_mask_write_register][and_mask]" => "integer"
"[zeek_modbus_mask_write_register][or_mask]" => "integer"
"[zeek_modbus_read_write_multiple_registers][unit_id]" => "integer"
"[zeek_modbus_read_write_multiple_registers][write_start_address]" => "integer"
"[zeek_modbus_read_write_multiple_registers][read_start_address]" => "integer"
"[zeek_modbus_read_write_multiple_registers][read_quantity]" => "integer"
"[zeek_modbus_register][delta]" => "float"
"[zeek_modbus_register][new_val]" => "integer"
"[zeek_modbus_register][old_val]" => "integer"
"[zeek_modbus_register][register]" => "integer"
"[zeek_mqtt_publish][payload_len]" => "integer"
"[zeek_mqtt_subscribe][granted_qos_level]" => "integer"
"[zeek_mqtt_subscribe][qos_levels]" => "integer"
"[zeek_ntp][num_exts]" => "integer"
"[zeek_ntp][poll]" => "float"
"[zeek_ntp][precision]" => "float"
"[zeek_ntp][root_delay]" => "float"
"[zeek_ntp][root_disp]" => "float"
"[zeek_ntp][version]" => "integer"
"[zeek_s7comm][item_count]" => "integer"
"[zeek_signatures][host_count]" => "integer"
"[zeek_signatures][signature_count]" => "integer"
"[zeek_smb_cmd][rtt]" => "float"
"[zeek_smb_files][data_len_req]" => "integer"
"[zeek_smb_files][data_len_rsp]" => "integer"
"[zeek_smb_files][data_offset_req]" => "integer"
"[zeek_tftp][size]" => "integer"
"[zeek_tftp][block_sent]" => "integer"
"[zeek_tftp][block_acked]" => "integer"
"[zeek_tftp][error_code]" => "integer"
"[zeek_wireguard][sender_index]" => "integer"
"[zeek_wireguard][receiver_index]" => "integer"
}
}
# convert all zeek "time" types (minus zeek.ts, which was done earlier)
# https://docs.zeek.org/en/current/script-reference/types.html#type-time
if ([zeek_kerberos][from]) {
if ([zeek_kerberos][from] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_kerberos_from_zero"
remove_field => [ "[zeek_kerberos][from]" ] }
} else {
date {
id => "date_zeek_kerberos_from"
match => [ "[zeek_kerberos][from]", "UNIX" ]
target => "[zeek_kerberos][from]"
}
}
}
if ([zeek_kerberos][till]) {
if ([zeek_kerberos][till] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_kerberos_till_zero"
remove_field => [ "[zeek_kerberos][till]" ] }
} else {
date {
id => "date_zeek_kerberos_till"
match => [ "[zeek_kerberos][till]", "UNIX" ]
target => "[zeek_kerberos][till]"
}
}
}
if ([zeek_ntp][org_time]) {
if ([zeek_ntp][org_time] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_ntp_org_time_zero"
remove_field => [ "[zeek_ntp][org_time]" ] }
} else {
date {
id => "date_zeek_ntp_org_time"
match => [ "[zeek_ntp][org_time]", "UNIX" ]
target => "[zeek_ntp][org_time]"
}
}
}
if ([zeek_ntp][rec_time]) {
if ([zeek_ntp][rec_time] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_ntp_rec_time_zero"
remove_field => [ "[zeek_ntp][rec_time]" ] }
} else {
date {
id => "date_zeek_ntp_rec_time"
match => [ "[zeek_ntp][rec_time]", "UNIX" ]
target => "[zeek_ntp][rec_time]"
}
}
}
if ([zeek_ntp][ref_time]) {
if ([zeek_ntp][ref_time] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_ntp_ref_time_zero"
remove_field => [ "[zeek_ntp][ref_time]" ] }
} else {
date {
id => "date_zeek_ntp_ref_time"
match => [ "[zeek_ntp][ref_time]", "UNIX" ]
target => "[zeek_ntp][ref_time]"
}
}
}
if ([zeek_ntp][xmt_time]) {
if ([zeek_ntp][xmt_time] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_ntp_xmt_time_zero"
remove_field => [ "[zeek_ntp][xmt_time]" ] }
} else {
date {
id => "date_zeek_ntp_xmt_time"
match => [ "[zeek_ntp][xmt_time]", "UNIX" ]
target => "[zeek_ntp][xmt_time]"
}
}
}
if ([zeek_pe][compile_ts]) {
if ([zeek_pe][compile_ts] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_pe_compile_ts_zero"
remove_field => [ "[zeek_pe][compile_ts]" ] }
} else {
date {
id => "date_zeek_pe_compile_ts"
match => [ "[zeek_pe][compile_ts]", "UNIX" ]
target => "[zeek_pe][compile_ts]"
}
}
}
if ([zeek_smb_files][times_accessed]) {
if ([zeek_smb_files][times_accessed] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_smb_files_times_accessed_zero"
remove_field => [ "[zeek_smb_files][times_accessed]" ] }
} else {
date {
id => "date_zeek_smb_files_times_accessed"
match => [ "[zeek_smb_files][times_accessed]", "UNIX" ]
target => "[zeek_smb_files][times_accessed]"
}
}
}
if ([zeek_smb_files][times_changed]) {
if ([zeek_smb_files][times_changed] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_smb_files_times_changed_zero"
remove_field => [ "[zeek_smb_files][times_changed]" ] }
} else {
date {
id => "date_zeek_smb_files_times_changed"
match => [ "[zeek_smb_files][times_changed]", "UNIX" ]
target => "[zeek_smb_files][times_changed]"
}
}
}
if ([zeek_smb_files][times_created]) {
if ([zeek_smb_files][times_created] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_smb_files_times_created_zero"
remove_field => [ "[zeek_smb_files][times_created]" ] }
} else {
date {
id => "date_zeek_smb_files_times_created"
match => [ "[zeek_smb_files][times_created]", "UNIX" ]
target => "[zeek_smb_files][times_created]"
}
}
}
if ([zeek_smb_files][times_modified]) {
if ([zeek_smb_files][times_modified] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_smb_files_times_modified_zero"
remove_field => [ "[zeek_smb_files][times_modified]" ] }
} else {
date {
id => "date_zeek_smb_files_times_modified"
match => [ "[zeek_smb_files][times_modified]", "UNIX" ]
target => "[zeek_smb_files][times_modified]"
}
}
}
if ([zeek_smb_files][ts]) {
if ([zeek_smb_files][ts] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_smb_files_ts_zero"
remove_field => [ "[zeek_smb_files][ts]" ] }
} else {
date {
id => "date_zeek_smb_files_ts"
match => [ "[zeek_smb_files][ts]", "UNIX" ]
target => "[zeek_smb_files][ts]"
}
}
}
if ([zeek_snmp][up_since]) {
if ([zeek_snmp][up_since] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_snmp_up_since_zero"
remove_field => [ "[zeek_snmp][up_since]" ] }
} else {
date {
id => "date_zeek_snmp_up_since"
match => [ "[zeek_snmp][up_since]", "UNIX" ]
target => "[zeek_snmp][up_since]"
}
}
}
if ([zeek_x509][certificate_not_valid_after]) {
if ([zeek_x509][certificate_not_valid_after] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_x509_certificate_not_valid_after_zero"
remove_field => [ "[zeek_x509][certificate_not_valid_after]" ] }
} else {
date {
id => "date_zeek_x509_certificate_not_valid_after"
match => [ "[zeek_x509][certificate_not_valid_after]", "UNIX" ]
target => "[zeek_x509][certificate_not_valid_after]"
}
}
}
if ([zeek_x509][certificate_not_valid_before]) {
if ([zeek_x509][certificate_not_valid_before] == "0.000000") {
mutate { id => "mutate_remove_field_zeek_x509_certificate_not_valid_before_zero"
remove_field => [ "[zeek_x509][certificate_not_valid_before]" ] }
} else {
date {
id => "date_zeek_x509_certificate_not_valid_before"
match => [ "[zeek_x509][certificate_not_valid_before]", "UNIX" ]
target => "[zeek_x509][certificate_not_valid_before]"
}
}
}
}

View File

@@ -0,0 +1,773 @@
filter {
# Map zeek fields to ECS where possible (see https://github.com/idaholab/Malcolm/issues/16)
# For now I will add fields rather than rename them. This will preserve backwards compatibility
# but the records will be somewhat bigger. I'll have to address what (if anything) to do with upgrades.
#
# Some fields (particularly AS and GEO fields) don't exist at this point in the pipeline, as they
# are added during enrichment. In that case, I will make a note of it here and handle it in
# ./pipelines/enrichment/20_enriched_to_ecs.conf:
#
# Autonomous System and Geo are handled after enrichment in 20_enriched_to_ecs.conf
# 🗹 Autonomous System - Fields describing an Autonomous System (Internet routing prefix). - https://www.elastic.co/guide/en/ecs/current/ecs-as.html
# 🗹 Geo - Fields describing a location. - https://www.elastic.co/guide/en/ecs/current/ecs-geo.html
#
# Risk/severity/priority/whatever will be done *after* enrichment based on normalized fields
# - event.severity, event.risk_score and event.risk_score_norm
#
# TODO: certain other fields that I'm already normalizing for moloch could maybe be moved out of
# here into enriched_to_ecs in the enrichment pipeline, but that kind of depends on what things
# look like when we add more data sources in the future, or if moloch tackles ECS, etc.
#
# for now don't do anything unles an env explicitly enables it
mutate {
id => "mutate_add_field_env_logstash_zeek_to_ecs"
add_field => { "[@metadata][ENV_LOGSTASH_ZEEK_TO_ECS]" => "${LOGSTASH_TO_ECS:false}" }
}
if ([@metadata][ENV_LOGSTASH_ZEEK_TO_ECS] == "true") {
# I will mark these ☐ off with a 🗹 or 🗷 as I address them or decide they don't need adressing
# 🗹 Network - Fields describing the communication path over which the event happened. - https://www.elastic.co/guide/en/ecs/current/ecs-network.html
# network.direction handled during enrichment pipeline
# network.name handled during enrichment pipeline
# network.type handled during enrichment pipeline
# TODO: some of these done here should probably be done after enrichment, too
# network.application and network.protocol (TODO: what's the difference as far as my logs go)
if ([zeek][service]) {
mutate { id => "mutate_add_field_ecs_network_application"
add_field => { "[network][application]" => "%{[zeek][service]}" } }
mutate { id => "mutate_add_field_ecs_network_protocol"
add_field => { "[network][protocol]" => "%{[zeek][service]}" } }
}
# network.packets
if ([totPackets]) { mutate { id => "mutate_add_field_ecs_network_packets"
add_field => { "[network][packets]" => "%{[totPackets]}" } } }
# network.bytes
if ([totBytes]) { mutate { id => "mutate_add_field_ecs_network_bytes"
add_field => { "[network][bytes]" => "%{[totBytes]}" } } }
# network.community_id
if ([zeek][community_id]) { mutate { id => "mutate_add_field_ecs_network_community_id"
add_field => { "[network][community_id]" => "%{[zeek][community_id]}" } } }
# network.iana_number
if ([ipProtocol]) { mutate { id => "mutate_add_field_ecs_network_iana_number"
add_field => { "[network][iana_number]" => "%{[ipProtocol]}" } } }
# network.transport
if ([zeek][proto]) { mutate { id => "mutate_add_field_ecs_network_transport"
add_field => { "[network][transport]" => "%{[zeek][proto]}" } } }
# 🗹 Client - Fields about the client side of a network connection, used with server. - https://www.elastic.co/guide/en/ecs/current/ecs-client.html
# client.ip / client.address
if ([zeek][orig_h]) {
mutate { id => "mutate_add_field_ecs_client_address"
add_field => { "[client][address]" => "%{[zeek][orig_h]}" } }
mutate { id => "mutate_add_field_ecs_client_ip"
add_field => { "[client][ip]" => "%{[zeek][orig_h]}" } }
}
# client.port
if ([zeek][orig_p]) { mutate { id => "mutate_add_field_ecs_client_port_orig_p"
add_field => { "[client][port]" => "%{[zeek][orig_p]}" } } }
# client.domain
if ([zeek][orig_hostname]) { mutate { id => "mutate_add_field_ecs_client_domain_orig_hostname"
add_field => { "[client][domain]" => "%{[zeek][orig_hostname]}" } } }
else if ([zeek_dhcp][host_name]) { mutate { id => "mutate_add_field_ecs_client_domain_dhcp_host_name"
add_field => { "[client][domain]" => "%{[zeek_dhcp][host_name]}" } } }
else if ([zeek_dhcp][domain]) { mutate { id => "mutate_add_field_ecs_client_domain_dhcp_domain"
add_field => { "[client][domain]" => "%{[zeek_dhcp][domain]}" } } }
else if ([zeek_ntlm][host]) { mutate { id => "mutate_add_field_ecs_client_domain_ntlm_host_name"
add_field => { "[client][domain]" => "%{[zeek_ntlm][host]}" } } }
else if ([zeek_ntlm][domain]) { mutate { id => "mutate_add_field_ecs_client_domain_ntlm_domain"
add_field => { "[client][domain]" => "%{[zeek_ntlm][domain]}" } } }
# client.mac
if ([zeek][orig_l2_addr]) { mutate { id => "mutate_add_field_ecs_client_mac_orig_l2_addr"
add_field => { "[client][mac]" => "%{[zeek][orig_l2_addr]}" } } }
else if ([zeek_dhcp][mac]) { mutate { id => "mutate_add_field_ecs_client_mac_dhcp_mac"
add_field => { "[client][mac]" => "%{[zeek_dhcp][mac]}" } } }
else if ([zeek_radius][mac]) { mutate { id => "mutate_add_field_ecs_client_mac_radius_mac"
add_field => { "[client][mac]" => "%{[zeek_radius][mac]}" } } }
# client.bytes
if ([zeek_conn][orig_ip_bytes]) { mutate { id => "mutate_add_field_ecs_client_bytes_conn_orig_ip_bytes"
add_field => { "[client][bytes]" => "%{[zeek_conn][orig_ip_bytes]}" } } }
else if ([zeek_conn][orig_bytes]) { mutate { id => "mutate_add_field_ecs_client_bytes_conn_orig_bytes"
add_field => { "[client][bytes]" => "%{[zeek_conn][orig_bytes]}" } } }
else if ([zeek_http][request_body_len]) { mutate { id => "mutate_add_field_ecs_client_bytes_http_request_body_len"
add_field => { "[client][bytes]" => "%{[zeek_http][request_body_len]}" } } }
else if ([zeek_mqtt_publish][payload_len]) { mutate { id => "mutate_add_field_ecs_client_bytes_mqtt_publish_payload_len"
add_field => { "[client][bytes]" => "%{[zeek_mqtt_publish][payload_len]}" } } }
else if ([zeek_sip][request_body_len]) { mutate { id => "mutate_add_field_ecs_client_bytes_sip_request_body_len"
add_field => { "[client][bytes]" => "%{[zeek_sip][request_body_len]}" } } }
# client.packets
if ([zeek_conn][orig_pkts]) { mutate { id => "mutate_add_field_ecs_client_packets_conn_orig_pkts"
add_field => { "[client][packets]" => "%{[zeek_conn][orig_pkts]}" } } }
# 🗹 Server - Fields about the server side of a network connection, used with client. - https://www.elastic.co/guide/en/ecs/current/ecs-server.html
# server.ip / server.address
if ([zeek][resp_h]) {
mutate { id => "mutate_add_field_ecs_server_address"
add_field => { "[server][address]" => "%{[zeek][resp_h]}" } }
mutate { id => "mutate_add_field_ecs_server_ip"
add_field => { "[server][ip]" => "%{[zeek][resp_h]}" } }
}
# server.port
if ([zeek][resp_p]) { mutate { id => "mutate_add_field_ecs_server_port_resp_p"
add_field => { "[server][port]" => "%{[zeek][resp_p]}" } } }
# server.domain
if ([zeek][resp_hostname]) { mutate { id => "mutate_add_field_ecs_server_domain_resp_hostname"
add_field => { "[server][domain]" => "%{[zeek][resp_hostname]}" } } }
# server.mac
if ([zeek][resp_l2_addr]) { mutate { id => "mutate_add_field_ecs_server_mac_resp_l2_addr"
add_field => { "[server][mac]" => "%{[zeek][resp_l2_addr]}" } } }
# server.bytes
if ([zeek_conn][resp_ip_bytes]) { mutate { id => "mutate_add_field_ecs_server_bytes_conn_resp_ip_bytes"
add_field => { "[server][bytes]" => "%{[zeek_conn][resp_ip_bytes]}" } } }
else if ([zeek_conn][resp_bytes]) { mutate { id => "mutate_add_field_ecs_server_bytes_conn_resp_bytes"
add_field => { "[server][bytes]" => "%{[zeek_conn][resp_bytes]}" } } }
else if ([zeek_http][response_body_len]) { mutate { id => "mutate_add_field_ecs_server_bytes_http_response_body_len"
add_field => { "[server][bytes]" => "%{[zeek_http][response_body_len]}" } } }
else if ([zeek_sip][response_body_len]) { mutate { id => "mutate_add_field_ecs_server_bytes_sip_response_body_len"
add_field => { "[server][bytes]" => "%{[zeek_sip][response_body_len]}" } } }
# server.packets
if ([zeek_conn][resp_pkts]) { mutate { id => "mutate_add_field_ecs_server_packets_conn_resp_pkts"
add_field => { "[server][packets]" => "%{[zeek_conn][resp_pkts]}" } } }
# ☐ Event - Fields breaking down the event details. - https://www.elastic.co/guide/en/ecs/current/ecs-event.html
# event.action from zeek.action
if ([zeek][action]) { mutate { id => "mutate_add_field_ecs_event_action"
add_field => { "[event][action]" => "%{[zeek][action]}" } } }
# event.dataset from zeek.logtype
mutate { id => "mutate_add_field_ecs_event_dataset"
add_field => { "[event][dataset]" => "zeek.%{[zeek][logType]}" } }
# event.duration
if ([zeek_conn][duration]) {
# convert duration (floating-point seconds) to nanoseconds
ruby {
id => "ruby_zeek_duration_to_ecs_event_duration"
code => "event.set('[event][duration]', (1000000000 * event.get('[zeek_conn][duration]').to_f).round(0))"
}
}
# for event.start/event.end, we'll the moloch firstPacket/lastPacket field as we already did the math
if ([firstPacket]) { mutate { id => "mutate_add_field_ecs_event_start"
add_field => { "[event][start]" => "%{[firstPacket]}" } } }
if ([lastPacket]) { mutate { id => "mutate_add_field_ecs_event_end"
add_field => { "[event][end]" => "%{[lastPacket]}" } } }
# UIDs and FUIDs constitude unique IDs
if ([zeek][uid]) { mutate { id => "mutate_add_field_ecs_id_uid"
merge => { "[event][id]" => "[zeek][uid]" } } }
if ([zeek][fuid]) { mutate { id => "mutate_add_field_ecs_id_fuid"
merge => { "[event][id]" => "[zeek][fuid]" } } }
# event.provider
if (![event][provider]) { mutate { id => "mutate_add_field_event_provider_zeek"
add_field => { "[event][provider]" => "zeek" } } }
# event.kind - https://www.elastic.co/guide/en/ecs/current/ecs-allowed-values-event-kind.html
if ([zeek_notice]) or ([zeek_signatures]) or ([zeek_weird]) {
mutate { id => "mutate_add_field_ecs_event_kind_alert"
add_field => { "[event][kind]" => "alert" } }
} else {
mutate { id => "mutate_add_field_ecs_event_kind_event"
add_field => { "[event][kind]" => "event" } }
}
# event.category - https://www.elastic.co/guide/en/ecs/current/ecs-allowed-values-event-category.html
translate {
id => "translate_zeek_ecs_event_category"
field => "[zeek][logType]"
destination => "[event][category]"
dictionary_path => "/etc/zeek_log_ecs_categories.yaml"
}
# TODO: this gets very granular and varies wildly per protocol, not sure I can translate these 100% from zeek.action and zeek.result
# event.type - https://www.elastic.co/guide/en/ecs/current/ecs-allowed-values-event-type.html
# event.outcome - https://www.elastic.co/guide/en/ecs/current/ecs-allowed-values-event-outcome.html
# Eeesh, this is a swag...
# if ([zeek][result]) {
# ruby {
# id => "ruby_ecs_event_outcome_zeek_result"
# code => "
# event.get('[zeek][result]').each { |zeekResult|
# zeekResult.downcase!
# if zeekResult =~ /(abo?rt|bad|busy|close|conflict|crit|declin|denied|deny|disabl|discon|down|err|exceed|exhaust|expir|fail|forbid|illeg|imposs|inappr|incorr|insuff|interrupt|misdirected|nak|no[ _-]*such|overload|problem|refus|reject|terminat|timeout|violat|wrong|(im|dis|mis|un|un|not)[ _-]*(avail|allow|assign|auth|deciph|process|permit|found|support|exist|enough|implem|known|ok|okay|reach|respond|consist|access|satis|succes|valid|want)|too[ _-]*(large|long|small|short|early|late|many|few))/
# event.set('[event][outcome]', 'failure')
# break
# elsif zeekResult =~ /(ok|okay|success|ack|complet|correct|good|ready|finish|valid)/
# event.set('[event][outcome]', 'success')
# break
# end
# }
# "
# }
# }
# ☐ DNS - Fields describing DNS queries and answers. - https://www.elastic.co/guide/en/ecs/current/ecs-dns.html
if ([zeek_dns]) {
# dns.resolved_ip
if ([dns][ip]) { mutate { id => "mutate_merge_ecs_dhs_resolved_ip"
merge => { "[dns][resolved_ip]" => "[dns][ip]" } } }
# dns.answers and dns.type:answer
if ([zeek_dns][answers]) {
ruby {
id => "ruby_zeek_dns_answers_to_ecs"
code => '
event.set("[dns][answers]", [Array(event.get("[zeek_dns][answers]")), Array(event.get("[zeek_dns][TTLs]"))].transpose.map{ |d| Hash[[:data, :ttl].zip(d)] })
'}
mutate { id => "mutate_add_field_ecs_dns_type_answer"
add_field => { "[dns][type]" => "answer" } }
}
# dns.op_code
if ([dns][opcode]) { mutate { id => "mutate_add_field_ecs_dns_opcode"
add_field => { "[dns][op_code]" => "%{[dns][opcode]}" } } }
# dns.question.class
if ([zeek_dns][qclass_name]) { mutate { id => "mutate_add_field_ecs_dns_qclass"
add_field => { "[dns][question][class]" => "%{[zeek_dns][qclass_name]}" } } }
# dns.question.type
if ([zeek_dns][qtype_name]) { mutate { id => "mutate_add_field_ecs_dns_qtype"
add_field => { "[dns][question][type]" => "%{[zeek_dns][qtype_name]}" } } }
# dns.question.name and dns.type:query
if ([zeek_dns][query]) {
mutate { id => "mutate_add_field_ecs_dns_query"
add_field => { "[dns][question][name]" => "%{[zeek_dns][query]}" } }
if (![dns][type]) { mutate { id => "mutate_add_field_ecs_dns_type_query"
add_field => { "[dns][type]" => "query" } } }
}
if ([dns][type]) {
# dns.header_flags
if ([zeek][AA] == "T") { mutate { id => "mutate_add_field_ecs_dns_header_flag_aa"
add_field => { "[dns][header_flags]" => "AA" } } }
if ([zeek][TC] == "T") { mutate { id => "mutate_add_field_ecs_dns_header_flag_tc"
add_field => { "[dns][header_flags]" => "TC" } } }
if ([zeek][RD] == "T") { mutate { id => "mutate_add_field_ecs_dns_header_flag_rd"
add_field => { "[dns][header_flags]" => "RD" } } }
if ([zeek][RA] == "T") { mutate { id => "mutate_add_field_ecs_dns_header_flag_ra"
add_field => { "[dns][header_flags]" => "RA" } } }
}
# dns.response_code
if ([zeek_dns][rcode_name]) { mutate { id => "mutate_add_field_ecs_dns_response_code"
add_field => { "[dns][response_code]" => "%{[zeek_dns][rcode_name]}" } } }
# dns.id
if ([zeek_dns][trans_id]) { mutate { id => "mutate_add_field_ecs_dns_id"
add_field => { "[dns][id]" => "%{[zeek_dns][trans_id]}" } } }
# TODO: domain stuff (dns.question.registered_domain, dns.question.subdomain, dns.question.top_level_domain)
# perhaps use something like https://github.com/plutonbacon/logstash-filter-publicsuffix
}
# 🗹 File - Fields describing files. - https://www.elastic.co/guide/en/ecs/current/ecs-file.html
if ([zeek_files]) {
# file.type
mutate { id => "mutate_add_field_ecs_file_type"
add_field => { "[file][type]" => "file" } }
# file.directory, file.name, file.path
if ([zeek_files][filename]) {
mutate { id => "mutate_add_field_ecs_file_path"
add_field => { "[file][path]" => "%{[zeek_files][filename]}" } }
grok {
id => "grok_zeek_files_filename_ecs"
match => { "[zeek_files][filename]" => [ "%{GREEDYDATA:[file][directory]}[\\\/]%{DATA:[file][name]}" ] }
}
}
# file.mime_type
if ([zeek_files][mime_type]) { mutate { id => "mutate_add_field_ecs_files_mime_type"
add_field => { "[file][mime_type]" => "%{[zeek_files][mime_type]}" } } }
# file.size
if ([zeek_files][total_bytes]) { mutate { id => "mutate_add_field_ecs_files_size"
add_field => { "[file][size]" => "%{[zeek_files][total_bytes]}" } } }
# 🗹 Hash - Hashes, usually file hashes. - https://www.elastic.co/guide/en/ecs/current/ecs-hash.html
# file.hash.md5,sha1,sha256
if ([zeek_files][md5]) { mutate { id => "mutate_add_field_ecs_files_hash_md5"
add_field => { "[file][hash][md5]" => "%{[zeek_files][md5]}" } } }
if ([zeek_files][sha1]) { mutate { id => "mutate_add_field_ecs_files_hash_sha1"
add_field => { "[file][hash][sha1]" => "%{[zeek_files][sha1]}" } } }
if ([zeek_files][sha256]) { mutate { id => "mutate_add_field_ecs_files_hash_sha256"
add_field => { "[file][hash][sha256]" => "%{[zeek_files][sha256]}" } } }
}
if ([zeek_smb_files]) {
# from smb_files, file.created,accessed,ctime,mtime,size
if ([zeek_smb_files][times_created]) { mutate { id => "mutate_add_field_ecs_smb_created"
add_field => { "[file][created]" => "%{[zeek_smb_files][times_created]}" } } }
if ([zeek_smb_files][times_accessed]) { mutate { id => "mutate_add_field_ecs_smb_accessed"
add_field => { "[file][accessed]" => "%{[zeek_smb_files][times_accessed]}" } } }
if ([zeek_smb_files][times_changed]) { mutate { id => "mutate_add_field_ecs_smb_changed"
add_field => { "[file][ctime]" => "%{[zeek_smb_files][times_changed]}" } } }
if ([zeek_smb_files][times_modified]) { mutate { id => "mutate_add_field_ecs_smb_modified"
add_field => { "[file][mtime]" => "%{[zeek_smb_files][times_modified]}" } } }
if ([zeek_smb_files][size]) { mutate { id => "mutate_add_field_ecs_smb_size"
add_field => { "[file][size]" => "%{[zeek_smb_files][size]}" } } }
# file.name from smb_files.name
if (![file][name]) and ([zeek_smb_files][name]) {
mutate { id => "mutate_add_field_ecs_file_smb_files_name"
add_field => { "[file][name]" => "%{[zeek_smb_files][name]}" } }
}
}
# file.directory from zeek_smb_files.smb_path
if ([@metadata][smb_path]) {
if (![file][type]) { mutate { id => "mutate_add_field_ecs_file_type_smb_path"
add_field => { "[file][type]" => "file" } } }
mutate { id => "mutate_add_field_ecs_file_directory_from_smb"
add_field => { "[file][directory]" => "%{[@metadata][smb_path]}" } }
}
# file.path from file.directory and file.name, if present and not already populated
if ([file][directory]) and (![file][path]) {
if ([file][name]) {
mutate { id => "mutate_add_field_ecs_path_from_dir_and_name"
add_field => { "[file][path]" => "%{[file][directory]}/%{[file][name]}" } }
} else {
mutate { id => "mutate_add_field_ecs_path_from_dir_only"
add_field => { "[file][path]" => "%{[file][directory]}" } }
}
}
if ([file][name]) {
if (![file][type]) { mutate { id => "mutate_add_field_ecs_file_type_name"
add_field => { "[file][type]" => "file" } } }
# file.extension
grok {
id => "grok_zeek_files_fileext_ecs"
match => { "[file][name]" => [ "%{GREEDYDATA}\.%{DATA:[file][extension]}" ] }
}
}
# 🗹 HTTP - Fields describing an HTTP request. - https://www.elastic.co/guide/en/ecs/current/ecs-http.html
if ([zeek_http]) {
if ([zeek_http][request_body_len]) { mutate { id => "mutate_add_field_ecs_http_request_body_bytes"
add_field => { "[http][request][body][bytes]" => "%{[zeek_http][request_body_len]}" } } }
if ([zeek_http][method]) { mutate { id => "mutate_add_field_ecs_http_request_method"
add_field => { "[http][request][method]" => "%{[zeek_http][method]}" } } }
if ([zeek_http][referrer]) { mutate { id => "mutate_add_field_ecs_http_request_referrer"
add_field => { "[http][request][referrer]" => "%{[zeek_http][referrer]}" } } }
if ([zeek_http][response_body_len]) { mutate { id => "mutate_add_field_ecs_http_response_body_bytes"
add_field => { "[http][response][body][bytes]" => "%{[zeek_http][response_body_len]}" } } }
if ([zeek_http][status_code]) { mutate { id => "mutate_add_field_ecs_http_response_status_cocde"
add_field => { "[http][response][status_cocde]" => "%{[zeek_http][status_code]}" } } }
if ([zeek_http][version]) { mutate { id => "mutate_add_field_ecs_http_version"
add_field => { "[http][version]" => "%{[zeek_http][version]}" } } }
# ☐ URL - Fields that let you store URLs in various forms. - https://www.elastic.co/guide/en/ecs/current/ecs-url.html
# todo: handle URIs from other protocols (SIP, FTP, ...)
if ([zeek_http][uri]) or ([zeek_http][host]) {
ruby {
id => "ruby_ecs_uri_parse_from_zeek_http"
init => "require 'uri'"
code => "
scheme = 'http'
user = event.get('[zeek][user]')
password = event.get('[zeek][password]')
host = event.get('[zeek_http][host]')
port = event.get('[zeek][resp_p]')
uri = event.get('[zeek_http][uri]')
ext = (uri.nil? || !(uri.include? '/')) ? nil : File.extname(uri).partition('.').last.split(/[\?#]/)[0]
fragment = uri.nil? ? nil : uri.partition('#').last
query = uri.nil? ? nil : uri.partition('?').last
event.set('[url][scheme]', scheme)
event.set('[url][original]', scheme + '://' + (host.nil? ? '' : host) + (uri.nil? ? '' : uri))
event.set('[url][full]', scheme + '://' + (user.nil? ? '' : Array(user).first) + (password.nil? ? '' : ':' + password) + ((user.nil? && password.nil?) ? '' : '@') + (host.nil? ? '' : host) + (port.nil? ? '' : ':' + port) + (uri.nil? ? '' : uri))
event.set('[url][domain]', host) unless host.nil?
event.set('[url][extension]', ext) unless ext.nil? || ext.empty?
event.set('[url][fragment]', fragment) unless fragment.nil? || fragment.empty?
event.set('[url][password]', password) unless password.nil?
event.set('[url][path]', uri) unless uri.nil?
event.set('[url][port]', port) unless port.nil?
event.set('[url][query]', query) unless query.nil? || query.empty?
event.set('[url][user]', Array(user).first) unless user.nil?
"
# TODO: domain stuff (url.registered_domain, url.top_level_domain)
# perhaps use something like https://github.com/plutonbacon/logstash-filter-publicsuffix
}
}
}
# 🗹 Related - Fields meant to facilitate pivoting around a piece of data. - https://www.elastic.co/guide/en/ecs/current/ecs-related.html
# related.user (zeek.user is already the array we want)
if ([zeek][user]) { mutate { id => "mutate_merge_field_related_zeek_user"
merge => { "[related][user]" => "[zeek][user]" } } }
# related.hash (accumulate all hash/fingerprint fields into related.hash)
if ([zeek_files][md5]) { mutate { id => "mutate_merge_field_related_hash_files_md5"
merge => { "[related][hash]" => "[zeek_files][md5]" } } }
if ([zeek_files][sha1]) { mutate { id => "mutate_merge_field_related_hash_files_sha1"
merge => { "[related][hash]" => "[zeek_files][sha1]" } } }
if ([zeek_files][sha256]) { mutate { id => "mutate_merge_field_related_hash_files_sha256"
merge => { "[related][hash]" => "[zeek_files][sha256]" } } }
if ([zeek_ssh][hassh]) { mutate { id => "mutate_merge_field_related_hash_ssh_hassh"
merge => { "[related][hash]" => "[zeek_ssh][hassh]" } } }
if ([zeek_ssh][hasshServer]) { mutate { id => "mutate_merge_field_related_hash_ssh_hasshServer"
merge => { "[related][hash]" => "[zeek_ssh][hasshServer]" } } }
if ([zeek_ssl][ja3]) { mutate { id => "mutate_merge_field_related_hash_ssl_ja3"
merge => { "[related][hash]" => "[zeek_ssl][ja3]" } } }
if ([zeek_ssl][ja3s]) { mutate { id => "mutate_merge_field_related_hash_zeek_ssl_ja3s"
merge => { "[related][hash]" => "[zeek_ssl][ja3s]" } } }
# related.ip (all IP-type fields get rolled up into related.ip)
if ([zeek][destination_geo][ip]) { mutate { id => "mutate_merge_field_related_ip_zeek_destination_geo_ip"
merge => { "[related][ip]" => "[zeek][destination_geo][ip]" } } }
if ([zeek][orig_h]) { mutate { id => "mutate_merge_field_related_ip_zeek_orig_h"
merge => { "[related][ip]" => "[zeek][orig_h]" } } }
if ([zeek][resp_h]) { mutate { id => "mutate_merge_field_related_ip_zeek_resp_h"
merge => { "[related][ip]" => "[zeek][resp_h]" } } }
if ([zeek][source_geo][ip]) { mutate { id => "mutate_merge_field_related_ip_zeek_source_geo_ip"
merge => { "[related][ip]" => "[zeek][source_geo][ip]" } } }
if ([zeek_dhcp][assigned_ip]) { mutate { id => "mutate_merge_field_related_ip_zeek_dhcp_assigned_ip"
merge => { "[related][ip]" => "[zeek_dhcp][assigned_ip]" } } }
if ([zeek_dhcp][requested_ip]) { mutate { id => "mutate_merge_field_related_ip_zeek_dhcp_requested_ip"
merge => { "[related][ip]" => "[zeek_dhcp][requested_ip]" } } }
if ([zeek_enip_list_identity][device_ip]) { mutate { id => "mutate_merge_field_related_ip_zeek_enip_list_identity_device_ip"
merge => { "[related][ip]" => "[zeek_enip_list_identity][device_ip]" } } }
if ([zeek_files][rx_hosts]) { mutate { id => "mutate_merge_field_related_ip_zeek_files_rx_hosts"
merge => { "[related][ip]" => "[zeek_files][rx_hosts]" } } }
if ([zeek_files][tx_hosts]) { mutate { id => "mutate_merge_field_related_ip_zeek_files_tx_hosts"
merge => { "[related][ip]" => "[zeek_files][tx_hosts]" } } }
if ([zeek_ftp][data_channel_orig_h]) { mutate { id => "mutate_merge_field_related_ip_zeek_ftp_data_channel_orig_h"
merge => { "[related][ip]" => "[zeek_ftp][data_channel_orig_h]" } } }
if ([zeek_ftp][data_channel_resp_h]) { mutate { id => "mutate_merge_field_related_ip_zeek_ftp_data_channel_resp_h"
merge => { "[related][ip]" => "[zeek_ftp][data_channel_resp_h]" } } }
if ([zeek_notice][dst]) { mutate { id => "mutate_merge_field_related_ip_zeek_notice_dst"
merge => { "[related][ip]" => "[zeek_notice][dst]" } } }
if ([zeek_notice][src]) { mutate { id => "mutate_merge_field_related_ip_zeek_notice_src"
merge => { "[related][ip]" => "[zeek_notice][src]" } } }
if ([zeek_radius][framed_addr]) { mutate { id => "mutate_merge_field_related_ip_zeek_radius_framed_addr"
merge => { "[related][ip]" => "[zeek_radius][framed_addr]" } } }
if ([zeek_smtp][path]) { mutate { id => "mutate_merge_field_related_ip_zeek_smtp_path"
merge => { "[related][ip]" => "[zeek_smtp][path]" } } }
if ([zeek_smtp][x_originating_ip]) { mutate { id => "mutate_merge_field_related_ip_zeek_smtp_x_originating_ip"
merge => { "[related][ip]" => "[zeek_smtp][x_originating_ip]" } } }
if ([zeek_socks][bound_host]) { mutate { id => "mutate_merge_field_related_ip_zeek_socks_bound_host"
merge => { "[related][ip]" => "[zeek_socks][bound_host]" } } }
if ([zeek_socks][request_host]) { mutate { id => "mutate_merge_field_related_ip_zeek_socks_request_host"
merge => { "[related][ip]" => "[zeek_socks][request_host]" } } }
if ([zeek_x509][san_ip]) { mutate { id => "mutate_merge_field_related_ip_zeek_x509_san_ip"
merge => { "[related][ip]" => "[zeek_x509][san_ip]" } } }
if ([related][ip]) {
ruby {
id => "ruby_related_ip_uniq"
code => "event.set('[related][ip]', event.get('[related][ip]').uniq)"
}
}
# 🗹 Rule - Fields to capture details about rules used to generate alerts or other notable events. - https://www.elastic.co/guide/en/ecs/current/ecs-rule.html
# - signatures
# - engine - >rule.author
# - signature_id -> rule.name
# - event_msg -> rule.description
# - notice
# - category -> rule.category, rule.author (mapped), rule.reference (mapped), rule.license (mapped)
# - sub_category -> rule.name
# - weird
# - name -> rule.name
if ([zeek_signatures]) {
if ([zeek_signatures][engine]) { mutate { id => "mutate_merge_field_ecs_rule_author_signatures_engine"
merge => { "[rule][author]" => "[zeek_signatures][engine]" } } }
if ([zeek_signatures][signature_id]) { mutate { id => "mutate_add_field_ecs_rule_id_signature_name"
merge => { "[rule][name]" => "[zeek_signatures][signature_id]" } } }
if ([zeek_signatures][event_msg]) { mutate { id => "mutate_add_field_ecs_rule_id_signature_event_msg" merge => { "[rule][description]" => "[zeek_signatures][event_msg]" } } }
}
if ([zeek_notice]) {
mutate { id => "mutate_add_field_ecs_rule_ruleset_notice_zeek"
add_field => { "[rule][ruleset]" => "Zeek Notices" } }
if ([zeek_notice][category]) { mutate { id => "mutate_add_field_ecs_rule_category_notice_category"
add_field => { "[rule][category]" => "%{[zeek_notice][category]}" } } }
if ([zeek_notice][sub_category]) { mutate { id => "mutate_add_field_ecs_rule_category_notice_sub_category"
add_field => { "[rule][name]" => "%{[zeek_notice][sub_category]}" } } }
translate {
id => "translate_zeek_notice_author"
field => "[zeek_notice][category]"
destination => "[@metadata][zeek_noticed_mapped_author]"
dictionary_path => "/etc/notice_authors.yaml"
fallback => "Zeek"
}
if ([@metadata][zeek_noticed_mapped_author]) {
mutate { id => "mutate_merge_zeek_noticed_mapped_author"
merge => { "[rule][author]" => "[@metadata][zeek_noticed_mapped_author]" } }
}
translate {
id => "translate_zeek_notice_reference"
field => "[zeek_notice][category]"
destination => "[@metadata][zeek_noticed_mapped_reference]"
dictionary_path => "/etc/notice_reference.yaml"
fallback => "https://docs.zeek.org/en/current/zeek-noticeindex.html"
}
if ([@metadata][zeek_noticed_mapped_reference]) {
mutate { id => "mutate_merge_zeek_noticed_mapped_reference"
merge => { "[rule][reference]" => "[@metadata][zeek_noticed_mapped_reference]" } }
}
translate {
id => "translate_zeek_notice_license"
field => "[zeek_notice][category]"
destination => "[@metadata][zeek_noticed_mapped_license]"
dictionary_path => "/etc/notice_license.yaml"
fallback => "https://raw.githubusercontent.com/zeek/zeek/master/COPYING"
}
if ([@metadata][zeek_noticed_mapped_license]) {
mutate { id => "mutate_merge_zeek_noticed_mapped_license"
merge => { "[rule][license]" => "[@metadata][zeek_noticed_mapped_license]" } }
}
}
if ([zeek_weird][name]) {
mutate { id => "mutate_add_field_ecs_rule_author_zeek_weird"
add_field => { "[rule][author]" => "Zeek" } }
mutate { id => "mutate_add_field_ecs_rule_ruleset_zeek_weird"
add_field => { "[rule][ruleset]" => "Zeek Weird Logs" } }
mutate { id => "mutate_add_field_ecs_rule_reference_zeek_weird"
add_field => { "[rule][reference]" => "https://docs.zeek.org/en/current/scripts/base/frameworks/notice/weird.zeek.html" } }
mutate { id => "mutate_add_field_ecs_rule_name_weird_name"
add_field => { "[rule][name]" => "%{[zeek_weird][name]}" } }
}
# 🗹 Threat - Fields to classify events and alerts according to a threat taxonomy. - https://www.elastic.co/guide/en/ecs/current/ecs-threat.html
if ([zeek_notice]) {
if ([zeek_notice][category] == "ATTACK") {
# populate threat information for MITRE ATT&CK notices from mitre-attack/bzar plugin
mutate { id => "mutate_add_field_ecs_threat_framework_mitre_attack"
add_field => { "[threat][framework]" => "MITRE ATT&CK" } }
if ([zeek_notice][sub_category]) {
mutate { id => "mutate_add_field_ecs_threat_tactic_name_mitre"
add_field => { "[threat][tactic][name]" => "%{[zeek_notice][sub_category]}" } }
mutate { id => "mutate_gsub_ecs_threat_tactic_name_notice_sub"
gsub => [ "[threat][tactic][name]", "_,", " " ] }
translate {
id => "translate_zeek_mitre_attack_tactic_name_to_id"
field => "[zeek_notice][sub_category]"
destination => "[threat][tactic][id]"
dictionary_path => "/etc/mitre_attack_tactic_ids.yaml"
}
translate {
id => "translate_zeek_mitre_attack_tactic_name_to_reference"
field => "[zeek_notice][sub_category]"
destination => "[threat][tactic][reference]"
dictionary_path => "/etc/mitre_attack_tactic_reference.yaml"
fallback => "https://attack.mitre.org/tactics/enterprise/"
}
}
if ([zeek_notice][sub]) and ([zeek_notice][sub] =~ /^T/) {
# eg., T1077 Windows Admin Shares + T1105 Remote File Copy
ruby {
id => "ruby_ecs_threat_technique_from_attack"
code => "
idArray = Array.new
nameArray = Array.new
event.get('[zeek_notice][sub]').split('+').each do |technique|
id, name = technique.strip.match(/(^T.*?)\s+(.+$)/).captures
idArray.push(id) unless id.nil?
nameArray.push(name) unless name.nil?
end
event.set('[threat][technique][id]', idArray)
event.set('[threat][technique][name]', nameArray)
event.set('[threat][technique][reference]', idArray.clone.map(&:clone).map{|x| x.prepend('https://attack.mitre.org/techniques/')})
"
}
}
} else if ([zeek_notice][category] == "EternalSafety") {
# populate threat information for EternalSafety from 0xl3x1/zeek-EternalSafety plugin
mutate { id => "mutate_add_field_ecs_threat_framework_eternal_safety"
add_field => { "[threat][framework]" => "EternalSafety" } }
if ([zeek_notice][sub_category]) { mutate { id => "mutate_add_field_ecs_threat_technique_name_eternal"
add_field => { "[threat][technique][name]" => "%{[zeek_notice][sub_category]}" } } }
if ([rule][reference]) { mutate { id => "mutate_add_field_ecs_threat_technique_reference_eternal"
add_field => { "[threat][technique][reference]" => "%{[rule][reference]}" } } }
}
}
# 🗹 TLS - Fields describing a TLS connection. - https://www.elastic.co/guide/en/ecs/current/ecs-tls.html
if ([zeek_ssl]) {
if ([zeek_ssl][ssl_version]) {
# turn TLSv10, TLSv13, TSLv12, etc. to 'tls' and '1.2', etc.
# TODO: tls.cipher already exists as a Arkime field, will this conflict/duplicate that?
# EDIT: it won't duplicate it, but it will replace it. I guess that's okay for now.
ruby {
id => "ruby_ecs_ssl_version_parse"
code => "
verMatch = event.get('[zeek_ssl][ssl_version]').tr('.', '').match(/(.+)\s*[v-]\s*([\d\.]+)/i)
verParts = verMatch.nil? ? nil : verMatch.captures
unless verParts.nil?
event.set('[tls][version_protocol]', verParts[0].downcase)
event.set('[tls][version]', verParts[1].split(//).join('.'))
end
"
}
}
if ([zeek_ssl][established]) { mutate { id => "mutate_add_field_ecs_zeek_tls_established"
add_field => { "[tls][established]" => "%{[zeek_ssl][established]}" } } }
if ([zeek_ssl][resumed]) { mutate { id => "mutate_add_field_ecs_zeek_tls_resumed"
add_field => { "[tls][resumed]" => "%{[zeek_ssl][resumed]}" } } }
if ([zeek_ssl][next_protocol]) {
mutate { id => "mutate_add_field_ecs_zeek_tls_next_protocol"
add_field => { "[tls][next_protocol]" => "%{[zeek_ssl][next_protocol]}" } }
mutate { id => "mutate_lowercase_field_ecs_zeek_tls_next_protocol"
lowercase => [ "[tls][next_protocol]" ] }
}
# TODO: tls.cipher already exists as a Arkime field, will this conflict/duplicate that?
# EDIT: apparently it does duplicate the value, so I'm commenting this out for now...
#if ([zeek_ssl][cipher]) { mutate { id => "mutate_add_field_ecs_zeek_tls_cipher"
# add_field => { "[tls][cipher]" => "%{[zeek_ssl][cipher]}" } } }
if ([zeek_ssl][curve]) { mutate { id => "mutate_add_field_ecs_zeek_tls_client_curve"
add_field => { "[tls][curve]" => "%{[zeek_ssl][curve]}" } } }
if ([zeek_ssl][ja3]) { mutate { id => "mutate_add_field_ecs_zeek_tls_client_ja3"
add_field => { "[tls][client][ja3]" => "%{[zeek_ssl][ja3]}" } } }
if ([zeek_ssl][client_issuer_full]) { mutate { id => "mutate_add_field_ecs_zeek_tls_client_issuer_full"
add_field => { "[tls][client][issuer]" => "%{[zeek_ssl][client_issuer_full]}" } } }
if ([zeek_ssl][client_subject_full]) { mutate { id => "mutate_add_field_ecs_zeek_tls_client_subject_full"
add_field => { "[tls][client][subject]" => "%{[zeek_ssl][client_subject_full]}" } } }
if ([zeek_ssl][server_name]) {
mutate { id => "mutate_add_field_ecs_zeek_tls_client_server_name"
add_field => { "[tls][client][server_name]" => "%{[zeek_ssl][server_name]}" } }
mutate { id => "mutate_add_field_ecs_zeek_tls_client_server_name_destination_domain"
add_field => { "[destination][domain]" => "%{[zeek_ssl][server_name]}" } }
}
if ([zeek_ssl][issuer_full]) { mutate { id => "mutate_add_field_ecs_zeek_tls_issuer_full"
add_field => { "[tls][server][issuer]" => "%{[zeek_ssl][issuer_full]}" } } }
if ([zeek_ssl][ja3s]) { mutate { id => "mutate_add_field_ecs_zeek_tls_server_ja3s"
add_field => { "[tls][server][ja3s]" => "%{[zeek_ssl][ja3s]}" } } }
if ([zeek_ssl][subject_full]) { mutate { id => "mutate_add_field_ecs_zeek_tls_subject_full"
add_field => { "[tls][server][subject]" => "%{[zeek_ssl][subject_full]}" } } }
}
# ☐ User agent - Fields to describe a browser user_agent string. - https://www.elastic.co/guide/en/ecs/current/ecs-user_agent.html
# - TODO: potentially more parsing could be done for user agent strings (.name, .device.name, .version)
if ([zeek_gquic][user_agent]) { mutate { id => "mutate_add_field_metadata_http_ecs_useragent_gquic"
add_field => { "[@metadata][generic_user_agent]" => "%{[zeek_gquic][user_agent]}" } } }
if ([zeek_http][user_agent]) { mutate { id => "mutate_add_field_metadata_http_ecs_useragent_http"
add_field => { "[@metadata][generic_user_agent]" => "%{[zeek_http][user_agent]}" } } }
if ([zeek_sip][user_agent]) { mutate { id => "mutate_add_field_metadata_http_ecs_useragent_sip"
add_field => { "[@metadata][generic_user_agent]" => "%{[zeek_sip][user_agent]}" } } }
if ([zeek_smtp][user_agent]) { mutate { id => "mutate_add_field_metadata_http_ecs_useragent_smtp"
add_field => { "[@metadata][generic_user_agent]" => "%{[zeek_smtp][user_agent]}" } } }
if ([@metadata][generic_user_agent]) {
mutate { id => "mutate_add_field_ecs_user_agent_original_zeek"
add_field => { "[user_agent][original]" => "%{[@metadata][generic_user_agent]}" } }
}
# ☐ Agent - Fields about the monitoring agent. - https://www.elastic.co/guide/en/ecs/current/ecs-agent.html
# - agent will be set for logs coming from a sensor (hedgehog)
# - double-check agent set for local Malcolm filebeat Zeek logs to ensure it's set correctly, too
# ☐ Observer - Fields describing an entity observing the event from outside the host. - https://www.elastic.co/guide/en/ecs/current/ecs-observer.html
# - anything useful we could get here from either Malcolm or Hedgehog?
# ☐ Destination - Fields about the destination side of a network connection, used with source. - https://www.elastic.co/guide/en/ecs/current/ecs-destination.html
# ☐ Source - Fields about the source side of a network connection, used with destination. - https://www.elastic.co/guide/en/ecs/current/ecs-source.html
# - I have client/server, do I need to do anything with this as well?
# ☐ Error - Fields about errors of any kind. - https://www.elastic.co/guide/en/ecs/current/ecs-error.html
# - There could be a lot of cases where there are errors, do we lump them all in here? we'd need to idenfity
# instances of error, error_msg, reply, status code, etc...
# ☐ User - Fields to describe the user relevant to the event. - https://www.elastic.co/guide/en/ecs/current/ecs-user.html
# - a *lot* of the details ECS wants for the user (client, destination, email, domain, etc.) aren't provided by Zeek
# also, it appears that there is an issue with type mismatch between Arkime's "user" field and ECS "user.name", etc.
# ☐ Vulnerability - Fields to describe the vulnerability relevant to an event. - https://www.elastic.co/guide/en/ecs/current/ecs-vulnerability.html
# - There are some CVE zeek plugins, they may be mappable to this (?)
# ☐ VLAN - Fields to describe observed VLAN information. - https://www.elastic.co/guide/en/ecs/current/ecs-vlan.html
# - conflicts with Arkime's VLAN field:
# Can't merge a non object mapping [vlan] with an object mapping [vlan]", "caused_by"=>{"type"=>"illegal_argument_exception",
# "reason"=>"Can't merge a non object mapping [vlan] with an object mapping [vlan]
# 🗷 Base - All fields defined directly at the top level - https://www.elastic.co/guide/en/ecs/current/ecs-base.html
# 🗷 Cloud - Fields about the cloud resource. - https://www.elastic.co/guide/en/ecs/current/ecs-cloud.html
# 🗷 Code Signature - These fields contain information about binary code signatures. - https://www.elastic.co/guide/en/ecs/current/ecs-code_signature.html
# 🗷 Container - Fields describing the container that generated this event. - https://www.elastic.co/guide/en/ecs/current/ecs-container.html
# 🗷 DLL - These fields contain information about code libraries dynamically loaded into processes. - https://www.elastic.co/guide/en/ecs/current/ecs-dll.html
# 🗷 ECS - Meta-information specific to ECS. - https://www.elastic.co/guide/en/ecs/current/ecs-ecs.html
# 🗷 Group - User's group relevant to the event. - https://www.elastic.co/guide/en/ecs/current/ecs-group.html
# 🗷 Host - Fields describing the relevant computing instance. - https://www.elastic.co/guide/en/ecs/current/ecs-host.html
# 🗷 Interface - Fields to describe observer interface information. - https://www.elastic.co/guide/en/ecs/current/ecs-interface.html
# 🗷 Log - Details about the event's logging mechanism. - https://www.elastic.co/guide/en/ecs/current/ecs-log.html
# 🗷 Operating System - OS fields contain information about the operating system. - https://www.elastic.co/guide/en/ecs/current/ecs-os.html
# 🗷 Organization - Fields describing the organization or company the event is associated with. - https://www.elastic.co/guide/en/ecs/current/ecs-organization.html
# 🗷 Package - These fields contain information about an installed software package. - https://www.elastic.co/guide/en/ecs/current/ecs-package.html
# - I almost mapped "software" to this but it doesn't really line up (installed packages vs. software network traffic observed)
# 🗷 PE Header - These fields contain Windows Portable Executable (PE) metadata. - https://www.elastic.co/guide/en/ecs/current/ecs-pe.html
# - You would think zeek_pe would line up here, but this is just header stuff specific to windows executables and there's not much that lines up
# 🗷 Process - These fields contain information about a process. - https://www.elastic.co/guide/en/ecs/current/ecs-process.html
# 🗷 Registry - Fields related to Windows Registry operations. - https://www.elastic.co/guide/en/ecs/current/ecs-registry.html
# 🗷 Service - Fields describing the service for or from which the data was collected. - https://www.elastic.co/guide/en/ecs/current/ecs-service.html
# 🗷 Tracing - Fields related to distributed tracing. - https://www.elastic.co/guide/en/ecs/current/ecs-tracing.html
} # end if ENV_LOGSTASH_ZEEK_TO_ECS
}

View File

@@ -0,0 +1,5 @@
output {
pipeline {
send_to => ["log-enrichment"]
}
}