unified2 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog.rdoc +6 -0
- data/LICENSE.txt +1 -1
- data/README.md +72 -0
- data/example/{basic-example.rb → example.rb} +3 -2
- data/example/seeds/{unified2 → unified2.log} +0 -0
- data/gemspec.yml +2 -0
- data/lib/unified2/classification.rb +17 -3
- data/lib/unified2/config_file.rb +34 -10
- data/lib/unified2/constructor/construct.rb +83 -0
- data/lib/unified2/constructor/event_ip4.rb +47 -0
- data/lib/unified2/constructor/event_ip6.rb +44 -0
- data/lib/unified2/constructor/packet.rb +30 -0
- data/lib/unified2/constructor/primitive/ipv4.rb +31 -0
- data/lib/unified2/{primitive.rb → constructor/primitive.rb} +0 -0
- data/lib/unified2/constructor/record_header.rb +17 -0
- data/lib/unified2/constructor.rb +1 -0
- data/lib/unified2/core_ext/string.rb +10 -2
- data/lib/unified2/event.rb +250 -100
- data/lib/unified2/exceptions/file_not_found.rb +6 -3
- data/lib/unified2/exceptions/file_not_readable.rb +6 -3
- data/lib/unified2/exceptions/unknown_load_type.rb +6 -3
- data/lib/unified2/payload.rb +82 -13
- data/lib/unified2/protocol.rb +141 -0
- data/lib/unified2/sensor.rb +22 -0
- data/lib/unified2/signature.rb +28 -4
- data/lib/unified2/version.rb +2 -2
- data/lib/unified2.rb +84 -13
- data/spec/event_spec.rb +112 -0
- data/spec/spec_helper.rb +45 -1
- data/spec/unified2_spec.rb +87 -1
- metadata +45 -25
- data/README.rdoc +0 -60
- data/Rakefile.compiled.rbc +0 -775
- data/example/connect.rb +0 -20
- data/example/models.rb +0 -194
- data/example/mysql-example.rb +0 -73
- data/example/search.rb +0 -14
- data/example/untitled.rb +0 -31
- data/lib/unified2/construct.rb +0 -54
- data/lib/unified2/event_ip4.rb +0 -26
- data/lib/unified2/event_ip6.rb +0 -23
- data/lib/unified2/packet.rb +0 -16
- data/lib/unified2/primitive/ipv4.rb +0 -19
- data/lib/unified2/record_header.rb +0 -10
data/ChangeLog.rdoc
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# unified2
|
2
|
+
|
3
|
+
* [Homepage](http://github.com/mephux/unified2)
|
4
|
+
* [Issues](http://github.com/mephux/unified2/issues)
|
5
|
+
* [Documentation](http://rubydoc.info/gems/unified2/frames)
|
6
|
+
* [Email](mailto:dustin.webber at gmail.com)
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
A ruby interface for unified2 output. rUnified2 allows you to manipulate unified2 output for custom storage and/or analysis.
|
11
|
+
|
12
|
+
## Features
|
13
|
+
|
14
|
+
* Monitor/Read unified2 logs & manipulate the data.
|
15
|
+
* Numerous connivence methods
|
16
|
+
* Simple & Intuitive to Use
|
17
|
+
|
18
|
+
## Examples
|
19
|
+
|
20
|
+
require 'unified2'
|
21
|
+
|
22
|
+
#
|
23
|
+
# Load rules into memory
|
24
|
+
#
|
25
|
+
|
26
|
+
Unified2.configuration do
|
27
|
+
# Sensor Configurations
|
28
|
+
sensor :id => 1, :name => 'Test Sensor', :interface => 'en1'
|
29
|
+
|
30
|
+
# Load signatures, generators & classifications into memory
|
31
|
+
load :signatures, 'sid-msg.map'
|
32
|
+
load :generators, 'gen-msg.map'
|
33
|
+
load :classifications, 'classification.config'
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Unified2#watch
|
38
|
+
#
|
39
|
+
# Watch a unified2 file for changes and process the results.
|
40
|
+
#
|
41
|
+
|
42
|
+
Unified2.watch('/var/log/snort/merged.log', :last) do |event|
|
43
|
+
next if event.signature.name.blank?
|
44
|
+
puts event
|
45
|
+
end
|
46
|
+
|
47
|
+
# Unified2#read
|
48
|
+
# Parse a unified2 file and process the results.
|
49
|
+
|
50
|
+
Unified2.read('/var/log/snort/merged.log') do |event|
|
51
|
+
|
52
|
+
puts event.protocol #=> "TCP"
|
53
|
+
|
54
|
+
puts event.protocol.to_h #=> {:length=>379, :seq=>3934511163, :ack=>1584708129 ... }
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
## Requirements
|
59
|
+
|
60
|
+
* bindata ~> 1.3.1
|
61
|
+
* hexdump: ~> 0.1.0
|
62
|
+
* packetfu: ~> 1.0.0
|
63
|
+
|
64
|
+
## Install
|
65
|
+
|
66
|
+
`$ gem install unified2`
|
67
|
+
|
68
|
+
== Copyright
|
69
|
+
|
70
|
+
Copyright (c) 2011 Dustin Willis Webber
|
71
|
+
|
72
|
+
See LICENSE.txt for details.
|
@@ -1,6 +1,5 @@
|
|
1
1
|
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
2
|
require 'unified2'
|
3
|
-
require 'pp'
|
4
3
|
|
5
4
|
# Unified2 Configuration
|
6
5
|
Unified2.configuration do
|
@@ -10,7 +9,9 @@ Unified2.configuration do
|
|
10
9
|
|
11
10
|
# Load signatures, generators & classifications into memory
|
12
11
|
load :signatures, 'seeds/sid-msg.map'
|
12
|
+
|
13
13
|
load :generators, 'seeds/gen-msg.map'
|
14
|
+
|
14
15
|
load :classifications, 'seeds/classification.config'
|
15
16
|
|
16
17
|
end
|
@@ -19,7 +20,7 @@ end
|
|
19
20
|
# The second argument is the last event processed by
|
20
21
|
# the sensor. If the last_event_id column is blank in the
|
21
22
|
# sensor table it will begin at the first available event.
|
22
|
-
Unified2.watch('seeds/unified2', :first) do |event|
|
23
|
+
Unified2.watch('seeds/unified2.log', :first) do |event|
|
23
24
|
next if event.signature.blank?
|
24
25
|
|
25
26
|
puts event
|
File without changes
|
data/gemspec.yml
CHANGED
@@ -1,8 +1,21 @@
|
|
1
1
|
module Unified2
|
2
|
+
#
|
3
|
+
# Classification
|
4
|
+
#
|
2
5
|
class Classification
|
3
6
|
|
4
7
|
attr_accessor :id, :name, :short, :severity
|
5
|
-
|
8
|
+
|
9
|
+
#
|
10
|
+
# Initialize classification
|
11
|
+
#
|
12
|
+
# @param [Hash] classification Classification attributes
|
13
|
+
#
|
14
|
+
# @option classification [Integer] :classification_id Classification id
|
15
|
+
# @option classification [String] :name Classification name
|
16
|
+
# @option classification [String] :short Classification short name
|
17
|
+
# @option classification [String] :severity Classification severity id
|
18
|
+
#
|
6
19
|
def initialize(classification={})
|
7
20
|
@id = classification[:classification_id]
|
8
21
|
@name = classification[:name]
|
@@ -10,5 +23,6 @@ module Unified2
|
|
10
23
|
@severity = classification[:severity]
|
11
24
|
end
|
12
25
|
|
13
|
-
end
|
14
|
-
|
26
|
+
end # class Classification
|
27
|
+
|
28
|
+
end # module Unified2
|
data/lib/unified2/config_file.rb
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
module Unified2
|
2
|
+
#
|
3
|
+
# Configuration file
|
4
|
+
#
|
2
5
|
class ConfigFile
|
3
6
|
|
4
7
|
attr_accessor :type, :path, :md5, :data
|
5
8
|
|
9
|
+
#
|
10
|
+
# Initialize configuration file
|
11
|
+
#
|
12
|
+
# @param [String, Symbol] type Configuration file type
|
13
|
+
# @param [String] path Configuration file path
|
14
|
+
#
|
6
15
|
def initialize(type, path)
|
7
16
|
@type = type
|
8
17
|
@path = path
|
@@ -10,9 +19,24 @@ module Unified2
|
|
10
19
|
@md5 = Digest::MD5.hexdigest(@path)
|
11
20
|
import
|
12
21
|
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Size
|
25
|
+
#
|
26
|
+
# @return [Integer] Configuration size
|
27
|
+
#
|
28
|
+
def size
|
29
|
+
@data.size
|
30
|
+
end
|
13
31
|
|
14
32
|
private
|
15
|
-
|
33
|
+
|
34
|
+
#
|
35
|
+
# Configuration Import
|
36
|
+
#
|
37
|
+
# Parse the configuration files and store
|
38
|
+
# them in memory as a hash.
|
39
|
+
#
|
16
40
|
def import
|
17
41
|
file = File.open(@path)
|
18
42
|
|
@@ -25,9 +49,8 @@ module Unified2
|
|
25
49
|
next unless line[/^config\s/]
|
26
50
|
count += 1
|
27
51
|
|
28
|
-
# attempted-dos,Attempted Denial of Service,2
|
29
52
|
data = line.gsub!(/config classification: /, '')
|
30
|
-
short, name, severity = data.to_s.split(',')
|
53
|
+
short, name, severity = data.to_s.split(',').map(&:strip)
|
31
54
|
|
32
55
|
@data[count.to_s] = {
|
33
56
|
:short => short,
|
@@ -40,13 +63,13 @@ module Unified2
|
|
40
63
|
|
41
64
|
file.each_line do |line|
|
42
65
|
next if line[/^\#/]
|
43
|
-
generator_id, alert_id, name = line.split(' || ')
|
66
|
+
generator_id, alert_id, name = line.split(' || ').map(&:strip)
|
44
67
|
id = "#{generator_id}.#{alert_id}"
|
45
68
|
|
46
69
|
@data[id] = {
|
47
|
-
:generator_id => generator_id,
|
70
|
+
:generator_id => generator_id.to_i,
|
48
71
|
:name => name,
|
49
|
-
:signature_id => alert_id
|
72
|
+
:signature_id => alert_id.to_i
|
50
73
|
}
|
51
74
|
end
|
52
75
|
|
@@ -54,7 +77,7 @@ module Unified2
|
|
54
77
|
|
55
78
|
file.each_line do |line|
|
56
79
|
next if line[/^\#/]
|
57
|
-
id, body, *reference_data = line.split(' || ')
|
80
|
+
id, body, *reference_data = line.split(' || ').map(&:strip)
|
58
81
|
|
59
82
|
references = {}
|
60
83
|
reference_data.each do |line|
|
@@ -67,7 +90,7 @@ module Unified2
|
|
67
90
|
end
|
68
91
|
|
69
92
|
@data[id] = {
|
70
|
-
:signature_id => id,
|
93
|
+
:signature_id => id.to_i,
|
71
94
|
:name => body,
|
72
95
|
:generator_id => 1
|
73
96
|
}
|
@@ -76,5 +99,6 @@ module Unified2
|
|
76
99
|
end
|
77
100
|
end
|
78
101
|
|
79
|
-
end
|
80
|
-
|
102
|
+
end # class ConfigFile
|
103
|
+
|
104
|
+
end # module Unified2
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'unified2/constructor/event_ip4'
|
2
|
+
require 'unified2/constructor/event_ip6'
|
3
|
+
require 'unified2/constructor/record_header'
|
4
|
+
require 'unified2/constructor/packet'
|
5
|
+
|
6
|
+
module Unified2
|
7
|
+
#
|
8
|
+
# Unified2 Constructor Namespace
|
9
|
+
#
|
10
|
+
module Constructor
|
11
|
+
#
|
12
|
+
# Unified2 Construction
|
13
|
+
#
|
14
|
+
class Construct < ::BinData::Record
|
15
|
+
#
|
16
|
+
# Rename record_header to header
|
17
|
+
# to simplify and cut down on verbosity
|
18
|
+
#
|
19
|
+
record_header :header
|
20
|
+
|
21
|
+
#
|
22
|
+
# Unified2 data types
|
23
|
+
#
|
24
|
+
# Currently rUnified2 only supports packet,
|
25
|
+
# event_ip4 and event_ip6.
|
26
|
+
#
|
27
|
+
choice :data, :selection => :type_selection do
|
28
|
+
packet "packet"
|
29
|
+
event_ip4 "ev4"
|
30
|
+
event_ip6 "ev6"
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# String padding
|
35
|
+
#
|
36
|
+
string :read_length => :padding_length
|
37
|
+
|
38
|
+
#
|
39
|
+
# Type Selection
|
40
|
+
#
|
41
|
+
# Deterime and call data type based on
|
42
|
+
# the unified2 type attribute
|
43
|
+
#
|
44
|
+
def type_selection
|
45
|
+
case header.u2type.to_i
|
46
|
+
when 1
|
47
|
+
# define UNIFIED2_EVENT 1
|
48
|
+
when 2
|
49
|
+
# define UNIFIED2_PACKET 2
|
50
|
+
"packet"
|
51
|
+
when 7
|
52
|
+
# define UNIFIED2_IDS_EVENT 7
|
53
|
+
"ev4"
|
54
|
+
when 66
|
55
|
+
# define UNIFIED2_EVENT_EXTENDED 66
|
56
|
+
when 67
|
57
|
+
# define UNIFIED2_PERFORMANCE 67
|
58
|
+
when 68
|
59
|
+
# define UNIFIED2_PORTSCAN 68
|
60
|
+
when 72
|
61
|
+
# define UNIFIED2_IDS_EVENT_IPV6 72
|
62
|
+
"ev6"
|
63
|
+
else
|
64
|
+
"unknown type #{header.u2type}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Sometimes the data needs extra padding
|
70
|
+
#
|
71
|
+
def padding_length
|
72
|
+
if header.u2length > data.num_bytes
|
73
|
+
header.u2length - data.num_bytes
|
74
|
+
else
|
75
|
+
0
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end # class Construct
|
80
|
+
|
81
|
+
end # module Construct
|
82
|
+
|
83
|
+
end # module Unified2
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'unified2/primitive/ipv4'
|
2
|
+
|
3
|
+
module Unified2
|
4
|
+
|
5
|
+
module Constructor
|
6
|
+
#
|
7
|
+
# Event IP Version 4
|
8
|
+
#
|
9
|
+
class EventIP4 < ::BinData::Record
|
10
|
+
|
11
|
+
endian :big
|
12
|
+
|
13
|
+
uint32 :sensor_id
|
14
|
+
|
15
|
+
uint32 :event_id
|
16
|
+
|
17
|
+
uint32 :event_second
|
18
|
+
|
19
|
+
uint32 :event_microsecond
|
20
|
+
|
21
|
+
uint32 :signature_id
|
22
|
+
|
23
|
+
uint32 :generator_id
|
24
|
+
|
25
|
+
uint32 :signature_revision
|
26
|
+
|
27
|
+
uint32 :classification_id
|
28
|
+
|
29
|
+
uint32 :priority_id
|
30
|
+
|
31
|
+
ipv4 :ip_source
|
32
|
+
|
33
|
+
ipv4 :ip_destination
|
34
|
+
|
35
|
+
uint16 :sport_itype
|
36
|
+
|
37
|
+
uint16 :dport_icode
|
38
|
+
|
39
|
+
uint8 :protocol
|
40
|
+
|
41
|
+
uint8 :packet_action
|
42
|
+
|
43
|
+
end # class EventIP4
|
44
|
+
|
45
|
+
end # module Constructor
|
46
|
+
|
47
|
+
end # module Unified2
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Unified2
|
2
|
+
|
3
|
+
module Constructor
|
4
|
+
#
|
5
|
+
# Event IP Version 6
|
6
|
+
#
|
7
|
+
class EventIP6 < ::BinData::Record
|
8
|
+
endian :big
|
9
|
+
|
10
|
+
uint32 :sensor_id
|
11
|
+
|
12
|
+
uint32 :event_id
|
13
|
+
|
14
|
+
uint32 :event_second
|
15
|
+
|
16
|
+
uint32 :event_microsecond
|
17
|
+
|
18
|
+
uint32 :signature_id
|
19
|
+
|
20
|
+
uint32 :generator_id
|
21
|
+
|
22
|
+
uint32 :signature_revision
|
23
|
+
|
24
|
+
uint32 :classification_id
|
25
|
+
|
26
|
+
uint32 :priority_id
|
27
|
+
|
28
|
+
uint128 :ip_source
|
29
|
+
|
30
|
+
uint128 :ip_destination
|
31
|
+
|
32
|
+
uint16 :sport_itype
|
33
|
+
|
34
|
+
uint16 :dport_icode
|
35
|
+
|
36
|
+
uint8 :protocol
|
37
|
+
|
38
|
+
uint8 :packet_action
|
39
|
+
|
40
|
+
end # class EventIP6
|
41
|
+
|
42
|
+
end # module Constructor
|
43
|
+
|
44
|
+
end # module Unified2
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Unified2
|
2
|
+
|
3
|
+
module Constructor
|
4
|
+
#
|
5
|
+
# Event Packet
|
6
|
+
#
|
7
|
+
class Packet < ::BinData::Record
|
8
|
+
endian :big
|
9
|
+
|
10
|
+
uint32 :sensor_id
|
11
|
+
|
12
|
+
uint32 :event_id
|
13
|
+
|
14
|
+
uint32 :event_second
|
15
|
+
|
16
|
+
uint32 :packet_second
|
17
|
+
|
18
|
+
uint32 :packet_microsecond
|
19
|
+
|
20
|
+
uint32 :linktype
|
21
|
+
|
22
|
+
uint32 :packet_length
|
23
|
+
|
24
|
+
string :packet_data, :read_length => :packet_length
|
25
|
+
|
26
|
+
end # class Packet
|
27
|
+
|
28
|
+
end # module Constructor
|
29
|
+
|
30
|
+
end # module Unified2
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Unified2
|
2
|
+
|
3
|
+
module Constructor
|
4
|
+
#
|
5
|
+
# Unified2 Primitive Namespace
|
6
|
+
#
|
7
|
+
module Primitive
|
8
|
+
#
|
9
|
+
# BinData Primitive IP4 Constructor
|
10
|
+
#
|
11
|
+
class IPV4 < ::BinData::Primitive
|
12
|
+
array :octets, :type => :uint8, :initial_length => 4
|
13
|
+
|
14
|
+
# IPV4#set
|
15
|
+
def set(value)
|
16
|
+
ints = value.split(/\./).collect { |int| int.to_i }
|
17
|
+
self.octets = ints
|
18
|
+
end
|
19
|
+
|
20
|
+
# IPV4#get
|
21
|
+
def get
|
22
|
+
self.octets.collect { |octet| "%d" % octet }.join(".")
|
23
|
+
end
|
24
|
+
|
25
|
+
end # class IPV4
|
26
|
+
|
27
|
+
end # class Primitive
|
28
|
+
|
29
|
+
end # module Constructor
|
30
|
+
|
31
|
+
end # module Unified2
|
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Unified2
|
2
|
+
|
3
|
+
module Constructor
|
4
|
+
#
|
5
|
+
# Unified2 Header
|
6
|
+
#
|
7
|
+
class RecordHeader < ::BinData::Record
|
8
|
+
endian :big
|
9
|
+
|
10
|
+
uint32 :u2type
|
11
|
+
uint32 :u2length
|
12
|
+
|
13
|
+
end # class RecordHeader
|
14
|
+
|
15
|
+
end # module Constructor
|
16
|
+
|
17
|
+
end # module Unified2
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'unified2/constructor/construct'
|
@@ -1,8 +1,16 @@
|
|
1
|
+
#
|
2
|
+
# String monkeypatches
|
3
|
+
#
|
1
4
|
class String
|
2
|
-
|
5
|
+
#
|
6
|
+
# Blank?
|
7
|
+
#
|
8
|
+
# @return [true, false] If the string
|
9
|
+
# is blank or empty return true.
|
10
|
+
#
|
3
11
|
def blank?
|
4
12
|
return true if (self.nil? || self == '')
|
5
13
|
false
|
6
14
|
end
|
7
15
|
|
8
|
-
end
|
16
|
+
end # class String
|