Skip to content

Commit

Permalink
Wrap filter in [type] == "mod_security" condition
Browse files Browse the repository at this point in the history
Add type => "mod_security" for stdin input
  • Loading branch information
Lucas Bremgartner committed Nov 25, 2015
1 parent b982e1f commit c21a6d2
Show file tree
Hide file tree
Showing 23 changed files with 416 additions and 400 deletions.
2 changes: 2 additions & 0 deletions 1000_input_stdin_example.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
input {

stdin {
type => "mod_security"

codec => multiline {
pattern => "^--[a-fA-F0-9]{8}-Z--$"
negate => true
Expand Down
78 changes: 40 additions & 38 deletions 2000_filter_sections_split.conf
Original file line number Diff line number Diff line change
@@ -1,43 +1,45 @@
filter {
if [type] == "mod_security" {

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Due to the complexity of the collapsed single string
# we get from multiline and the variance of exactly
# which modsec sections (A-K) may or may not be in each
# log entry, we run some custom ruby code that will
# split on each modsec "section" and store each found in
# new fields named "rawSection[A-K]" as appropriate, the value
# of each of these fields contains the raw un-parsed data
# from that modsec section. Sections that are non-existant
# will not have a key in "fields"
#
# A bit long and crazy yes, but after spending many hours
# just doing this w/ grok patterns, this ended up being the
# most reliable way to break up this in-consistent format into
# more usable blocks
#
# @see https://github.com/SpiderLabs/ModSecurity/wiki/ModSecurity-2-Data-Formats
#
# READ the above to get a good understanding of the sections
# and which ones can actively contain data depending on your modsec
# version and environment!
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Due to the complexity of the collapsed single string
# we get from multiline and the variance of exactly
# which modsec sections (A-K) may or may not be in each
# log entry, we run some custom ruby code that will
# split on each modsec "section" and store each found in
# new fields named "rawSection[A-K]" as appropriate, the value
# of each of these fields contains the raw un-parsed data
# from that modsec section. Sections that are non-existant
# will not have a key in "fields"
#
# A bit long and crazy yes, but after spending many hours
# just doing this w/ grok patterns, this ended up being the
# most reliable way to break up this in-consistent format into
# more usable blocks
#
# @see https://github.com/SpiderLabs/ModSecurity/wiki/ModSecurity-2-Data-Formats
#
# READ the above to get a good understanding of the sections
# and which ones can actively contain data depending on your modsec
# version and environment!
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ruby {
code => "
if !event['message'].nil?
modSecSectionData = event['message'].split(/(?:--[a-fA-F0-9]{8}-([A-Z])--)/)
modSecSectionData.shift
for i in 0..((modSecSectionData.length-1)/2)
sectionName = 'rawSection'.concat(modSecSectionData.shift)
sectionData = modSecSectionData.shift
sectionName = sectionName.strip
if !sectionData.nil?
sectionData = sectionData.strip
end
event.to_hash.merge!(sectionName => sectionData)
end
end
"
ruby {
code => "
if !event['message'].nil?
modSecSectionData = event['message'].split(/(?:--[a-fA-F0-9]{8}-([A-Z])--)/)
modSecSectionData.shift
for i in 0..((modSecSectionData.length-1)/2)
sectionName = 'rawSection'.concat(modSecSectionData.shift)
sectionData = modSecSectionData.shift
sectionName = sectionName.strip
if !sectionData.nil?
sectionData = sectionData.strip
end
event.to_hash.merge!(sectionName => sectionData)
end
end
"
}
}
}
17 changes: 9 additions & 8 deletions 2010_filter_section_a_parse.conf
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
filter {
if [type] == "mod_security" {

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse out fields from Section A (general event basics)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grok {
match => {
"rawSectionA" => "\[%{L1_TIMESTAMP:modsec_timestamp}\] %{DATA:uniqueId} %{IP:sourceIp} %{INT:sourcePort} %{IP:destIp} %{INT:destPort}"
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse out fields from Section A (general event basics)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grok {
match => {
"rawSectionA" => "\[%{L1_TIMESTAMP:modsec_timestamp}\] %{DATA:uniqueId} %{IP:sourceIp} %{INT:sourcePort} %{IP:destIp} %{INT:destPort}"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}

}
40 changes: 20 additions & 20 deletions 2020_filter_section_b_parse_request_line.conf
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
filter {
if [type] == "mod_security" {
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse out fields from Section B (request related line 1)
# note line one could be garbage OR adhere to the
# httpMethod [space] uri [space] protocol pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse out fields from Section B (request related line 1)
# note line one could be garbage OR adhere to the
# httpMethod [space] uri [space] protocol pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# if a legit line... normal http request
if [rawSectionB] =~ /.*?\s\S+\s.+\n{1}/ {

# if a legit line... normal http request
if [rawSectionB] =~ /.*?\s\S+\s.+\n{1}/ {

grok {
match => {
"rawSectionB" => "%{DATA:httpMethod}\s(?<requestedUri>\S+)\s(?<incomingProtocol>.+?)\n{1}"
grok {
match => {
"rawSectionB" => "%{DATA:httpMethod}\s(?<requestedUri>\S+)\s(?<incomingProtocol>.+?)\n{1}"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}

# not a legit line.. invalid http request, grab first line and dump in the httpMethod
} else {
# not a legit line.. invalid http request, grab first line and dump in the httpMethod
} else {

grok {
match => {
"rawSectionB" => "(?<httpMethod>^(.*)$)"
grok {
match => {
"rawSectionB" => "(?<httpMethod>^(.*)$)"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
}

}
20 changes: 10 additions & 10 deletions 2021_filter_section_b_parse_headers.conf
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
filter {
if [type] == "mod_security" {

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse out fields from Section B (request headers, line 2+)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse out fields from Section B (request headers, line 2+)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if [rawSectionB] =~ /.+?\n(?m).+/ {
if [rawSectionB] =~ /.+?\n(?m).+/ {

grok {
match => {
"rawSectionB" => ".+?\n(?m)(?<raw_requestHeaders>.+)"
grok {
match => {
"rawSectionB" => ".+?\n(?m)(?<raw_requestHeaders>.+)"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}

}

}
46 changes: 23 additions & 23 deletions 2022_filter_section_b_headers_key-value.conf
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
filter {
if [type] == "mod_security" {
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Convert raw request headers into a key/value
# pair map
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Convert raw request headers into a key/value
# pair map
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if [raw_requestHeaders] =~ /.+/ {
kv {
source => "raw_requestHeaders"
field_split => "\n"
value_split => ":"
target => "requestHeaders"
}
if [raw_requestHeaders] =~ /.+/ {
kv {
source => "raw_requestHeaders"
field_split => "\n"
value_split => ":"
target => "requestHeaders"
}


# trim leading/trailing hack @see https://logstash.jira.com/browse/LOGSTASH-1369
ruby {
code => "
requestHeaders = event.to_hash['requestHeaders']
requestHeaders.each { |k, v|
if !v.nil? and v.is_a? String
requestHeaders[k] = v.strip
end
}
"
# trim leading/trailing hack @see https://logstash.jira.com/browse/LOGSTASH-1369
ruby {
code => "
requestHeaders = event.to_hash['requestHeaders']
requestHeaders.each { |k, v|
if !v.nil? and v.is_a? String
requestHeaders[k] = v.strip
end
}
"
}
}
}

}
21 changes: 11 additions & 10 deletions 2029_filter_section_b_example_header_Cookie.conf
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
filter {
if [type] == "mod_security" {

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Example of looking for a specific Cookie and promoting
# it to a first class field
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Example of looking for a specific Cookie and promoting
# it to a first class field
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if [raw_requestHeaders] =~ /Cookie/ and [raw_requestHeaders] =~ /myCookie=.+\b/ {
if [raw_requestHeaders] =~ /Cookie/ and [raw_requestHeaders] =~ /myCookie=.+\b/ {

grok {
match => {
"raw_requestHeaders" => "(?<myCookie>myCookie[^; \s]+)"
grok {
match => {
"raw_requestHeaders" => "(?<myCookie>myCookie[^; \s]+)"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
}

}
31 changes: 16 additions & 15 deletions 2029_filter_section_b_example_header_X-Forwarded-For.conf
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
filter {

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Promote real request IP to a field if it exists
# in the request headers section
#
# NOTE this is an example of promoting a custom header to a first
# class field that might be set by a app firewall or other
# upstream proxy
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [type] == "mod_security" {

if [raw_requestHeaders] =~ /X-Forwarded-For:/ {
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Promote real request IP to a field if it exists
# in the request headers section
#
# NOTE this is an example of promoting a custom header to a first
# class field that might be set by a app firewall or other
# upstream proxy
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

grok {
match => {
"raw_requestHeaders" => "X-Forwarded-For: %{IPORHOST:XForwardedFor}"
if [raw_requestHeaders] =~ /X-Forwarded-For:/ {

grok {
match => {
"raw_requestHeaders" => "X-Forwarded-For: %{IPORHOST:XForwardedFor}"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
}

}
25 changes: 13 additions & 12 deletions 2030_filter_section_c_parse.conf
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
filter {

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse out fields from Section C (post data)
# this is not always present
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [type] == "mod_security" {

if [rawSectionC] =~ /.+/ {
grok {
match => {
"rawSectionC" => "(?<requestBody>.+)"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Parse out fields from Section C (post data)
# this is not always present
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if [rawSectionC] =~ /.+/ {
grok {
match => {
"rawSectionC" => "(?<requestBody>.+)"
}
patterns_dir => "./patterns/logstash_modsecurity_patterns"
}
}
}

}
18 changes: 9 additions & 9 deletions 2040_filter_section_d_example.conf
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
filter {
if [type] == "mod_security" {
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Optionally deal w/ Section D (intended response headers)
# this section is NOT IMPLEMENTED by ModSecurity
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Optionally deal w/ Section D (intended response headers)
# this section is NOT IMPLEMENTED by ModSecurity
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#if [rawSectionD] =~ /.+/ {
# # you can deal w/ this if you want to here...
#}

#if [rawSectionD] =~ /.+/ {
# # you can deal w/ this if you want to here...
#}
}
}
Loading

0 comments on commit c21a6d2

Please sign in to comment.