Skip to content

Instantly share code, notes, and snippets.

@Ana06
Created April 8, 2020 15:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ana06/89b63a37302bd268bda2bf7539237399 to your computer and use it in GitHub Desktop.
Save Ana06/89b63a37302bd268bda2bf7539237399 to your computer and use it in GitHub Desktop.
Ruby script that parses a Snort log and prints statistics
# Copyright (C) 2020 Ana Maria Martinez Gomez <anamaria@martinezgomez.name>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# See <https://www.gnu.org/licenses>.
#
# SPDX-License-Identifier: GPLv3-or-later
# INSTRUCTIONS
# To run it just execute (tried with Ruby 2.6):
# ruby snort-log-report.rb FILE_NAME
#
# It parses a log file generated with the following Snort command and print statistics:
# sudo snort -A full -u snort -g snort -c /etc/snort/snort.conf -i wlan0 -k none
#
# EXAMPLES OF Snort logs:
# [**] [1:2402000:5461] ET DROP Dshield Block Listed Source group 1 [**]
# [Classification: Misc Attack] [Priority: 2]·
# 02/27-13:44:36.706131 223.71.167.165:36143 -> 129.236.182.85:8161
# TCP TTL:107 TOS:0x28 ID:3723 IpLen:20 DgmLen:44
# ******S* Seq: 0xD7F69FC8 Ack: 0x0 Win: 0x7210 TcpLen: 24
# TCP Options (1) => MSS: 1386·
# [Xref => http://feeds.dshield.org/block.txt]
#
# [**] [122:3:1] (portscan) TCP Portsweep [**]
# [Classification: Attempted Information Leak] [Priority: 2]
# 02/27-13:44:41.989455 129.236.182.85 -> 192.3.204.74
# PROTO:255 TTL:243 TOS:0x28 ID:55003 IpLen:20 DgmLen:164
require 'resolv'
$max_alerts = 5
$max_ips = 9
$tab = ' '
$ignored_alerts = ['[1:10000001:1] ICMP test detected', '[1:10000002:1] Port 902 detected']
$my_ips = ['192.168.1.13', '129.236.182.85']
def hostname(ip)
begin
hostname = Resolv.getname ip
"|| Hostname: #{hostname}"
rescue
end
end
def str_out_of(t, n)
return "(#{t})" if t <= n
"(#{n} out of #{t})"
end
def print_ips(label, ips_hash)
return if ips_hash.empty?
puts "#{$tab * 3}#{label} #{str_out_of(ips_hash.size, $max_ips)}:"
top_ips = ips_hash.sort_by { |_key, value| -value}[0..($max_ips - 1)]
top_ips.each { |ip, n| puts ($tab * 4) + "Number: #{n} || IP: #{ip} #{hostname(ip)}" }
end
file_name = ARGV[0]
file = File.open(file_name)
alerts = Hash.new()
entries = 0
file.read.split(/\n\n/).each do |alert|
/\[\*\*\] (?<rule>.*) \[\*\*\]/ =~ alert
next if $ignored_alerts.include?(rule)
entries += 1
# IPv4
/(?<ip_from>(\d{1,3}\.){3}\d{1,5}).* (?<ip_to>(\d{1,3}\.){3}\d{1,5})/ =~ alert
#IPv6
/(?<ip_from>(([0-9a-z]{1,5}(\:)+){3,5})[0-9a-z]{1,5})(\:)+\d{1,5}.* (?<ip_to>(([0-9a-z]{1,5}(\:)+){3,5})[0-9a-z]{1,5})(\:)+\d{1,5}/ =~ alert unless ip_from && ip_to
alerts[rule] ||= [0, Hash.new(0), Hash.new(0)]
alerts[rule][0] += 1
(alerts[rule][1][ip_from] += 1) unless $my_ips.include? ip_from
alerts[rule][2][ip_to] += 1 unless $my_ips.include? ip_to
end
puts "#{entries} ATTACKS DETECTED\n\n"
puts "TOP MOST PREVALENT ATTACK TYPES #{str_out_of(alerts.size, $max_alerts)}:"
top_alerts = alerts.sort_by { |_key, value| -value[0] }[0..($max_alerts-1)]
digits_longest = "#{top_alerts[0][1][0].digits.length}"
top_alerts.each.with_index(1) do |(rule, data), index|
printf $tab + "%s. Number: %-#{digits_longest}s || Rule: %s\n", index, data[0], rule
print_ips('From', data[1])
print_ips('To', data[2])
end
alerts_once = alerts.select { |_key, value| value[0] == 1 }
puts "\n\nALERTS WHICH ONLY HAPPENED ONCE (#{alerts_once.size}):"
alerts_once.each do |rule, data|
puts $tab + rule
ip = (data[1] || data[2]).keys[0]
puts "#{$tab * 2}IP: #{ip} #{hostname(ip)}"
end
puts "\n\nALL ALERT TYPES: (#{alerts.size}):"
alerts.sort.each do |rule, _data|
puts $tab + rule
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment