unified2 0.1.2 → 0.2.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/README.rdoc CHANGED
@@ -9,10 +9,9 @@ A ruby interface for unified2 output. rUnified2 allows you to manipulate unified
9
9
 
10
10
  == Features
11
11
 
12
- * Monitor unified2 logs and manipulate the data.
13
- * Modular adaptor support (monogdb, mysql, postgresql, sguil etc..)
14
- * Parse unified2 log files
15
- * Numerous connivence methods for statistical analysis
12
+ * Monitor/Read unified2 logs & manipulate the data.
13
+ * Numerous connivence methods
14
+ * Simple & Intuitive to Use
16
15
 
17
16
  == Examples
18
17
 
@@ -34,9 +33,8 @@ A ruby interface for unified2 output. rUnified2 allows you to manipulate unified
34
33
  Unified2.watch('/var/log/snort/merged.log', :last) do |event|
35
34
  next if event.signature.name.blank?
36
35
 
37
- puts "#{event.id} | #{event.ip_destination} | #{event.ip_source} | #{event.signature.name}"
38
- puts event.payload.dump(:width => 30)
39
- puts event.classification.name
36
+ puts event
37
+
40
38
  end
41
39
 
42
40
  # Unified2#read
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'datamapper'
3
+ require 'dm-mysql-adapter'
4
+ require 'models'
5
+
6
+ class Connect
7
+
8
+ def self.setup
9
+ @connection = DataMapper.setup(:default, {
10
+ :adapter => "mysql",
11
+ :host => "localhost",
12
+ :database => "rUnified2",
13
+ :username => "rUnified2",
14
+ :password => "password"
15
+ })
16
+ DataMapper.finalize
17
+ DataMapper.auto_upgrade!
18
+ end
19
+
20
+ end
data/example/example.rb CHANGED
@@ -1,43 +1,74 @@
1
1
  $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift File.join(File.dirname(__FILE__), "..", "example")
3
+
2
4
  require 'unified2'
5
+ require 'connect'
3
6
  require 'pp'
4
7
 
8
+ # Initialize Database Connection
9
+ Connect.setup
10
+
5
11
  # Unified2 Configuration
6
12
  Unified2.configuration do
7
- # Sensor Configurations
8
- sensor :id => 200, :name => 'Hello Sensor', :interface => 'en1'
9
13
 
14
+ # Sensor Configurations
15
+ sensor :interface => 'en1', :name => 'Example Sensor'
16
+
10
17
  # Load signatures, generators & classifications into memory
11
- load :signatures, 'sid-msg.map'
12
- load :generators, 'gen-msg.map'
13
- load :classifications, 'classification.config'
18
+ load :signatures, 'seeds/sid-msg.map'
19
+ load :generators, 'seeds/gen-msg.map'
20
+ load :classifications, 'seeds/classification.config'
21
+
14
22
  end
15
23
 
16
- # Unified2#watch will continuously monitor
17
- # the unified output for modifications and
18
- # process the data accordingly.
24
+ # Locate the sensor in the database using
25
+ # the hostname and interface. If this fails
26
+ # rUnified2 will create a new sensor record.
27
+ sensor = Sensor.find(Unified2.sensor)
28
+ Unified2.sensor.id = sensor.id
19
29
 
20
- Unified2.watch('unified2', 1) do |event|
30
+ # Load the classifications, generators &
31
+ # signatures into the database and store the
32
+ # md5 in the sensor record. This will only
33
+ # update if the md5s DO NOT match.
34
+ [[Classification,:classifications], [Signature, :signatures], [Signature, :generators]].each do |klass, method|
35
+ unless sensor.send(:"#{method}_md5") == Unified2.send(method).send(:md5)
36
+ klass.send(:import, { method => Unified2.send(method).send(:data), :force => true })
37
+ sensor.update(:"#{method}_md5" => Unified2.send(method).send(:md5))
38
+ end
39
+ end
40
+
41
+ # Monitor the unfied2 log and process the data.
42
+ # The second argument is the last event processed by
43
+ # the sensor. If the last_event_id column is blank in the
44
+ # sensor table it will begin at the first available event.
45
+ Unified2.watch('/var/log/snort/merged.log', sensor.last_event_id + 1 || :first) do |event|
21
46
  next if event.signature.blank?
22
47
 
23
- puts event.signature.name
48
+ #puts event
24
49
 
25
- # puts "#{event.sensor.name} #{event.timestamp} || #{event.source_port} #{event.destination_port} | #{event.protocol}"
26
-
27
- # #{event.source_port} #{event.destination_port}
28
- # puts "#{event.id} | #{event.ip_destination} | #{event.ip_source} | #{event.signature.name}"
29
- # {event.generator_id} || #{event.signature.id}
30
- end
50
+ insert_event = Event.new({
51
+ :event_id => event.id,
52
+ :uid => event.uid,
53
+ :created_at => event.timestamp,
54
+ :sensor_id => event.sensor.id,
55
+ :source_ip => event.source_ip,
56
+ :source_port => event.source_port,
57
+ :destination_ip => event.destination_ip,
58
+ :destination_port => event.destination_port,
59
+ :severity_id => event.severity,
60
+ :protocol => event.protocol,
61
+ :link_type => event.payload.linktype,
62
+ :packet_length => event.payload.length,
63
+ :packet => event.payload.hex,
64
+ :classification_id => event.classification.id,
65
+ :signature_id => event.signature.id
66
+ })
67
+
68
+ if insert_event.save
69
+ insert_event.update_sensor
70
+ else
71
+ STDERR.puts "VALIDATION ERROR OR RECORD ALREADY EXISTS #{insert_event.errors}"
72
+ end
31
73
 
32
- # Unified2#read will parse the supplied
33
- # unified2 output and return records untill EOF.
34
-
35
- # @signatures = []
36
- # Unified2.watch('unified2', 101) do |event|
37
- # next if event.signature.name.blank?
38
- # next if @signatures.include?(event.signature.id)
39
- #
40
- # @signatures.push event.signature.id
41
- #
42
- # puts "#{event.id} | #{event.ip_destination} | #{event.ip_source} | #{event.signature.name}"
43
- # end
74
+ end
data/example/models.rb ADDED
@@ -0,0 +1,196 @@
1
+ class Event
2
+ include DataMapper::Resource
3
+ storage_names[:default] = "events"
4
+
5
+ timestamps :created_at, :updated_at
6
+
7
+ property :id, Serial, :index => true
8
+
9
+ property :uid, String, :index => true
10
+
11
+ property :event_id, Integer, :index => true
12
+
13
+ property :sensor_id, Integer, :index => true
14
+
15
+ property :source_ip, String, :index => true
16
+
17
+ property :source_port, Integer
18
+
19
+ property :destination_ip, String, :index => true
20
+
21
+ property :destination_port, Integer
22
+
23
+ property :severity_id, Integer, :index => true
24
+
25
+ property :classification_id, Integer, :index => true
26
+
27
+ property :category_id, Integer, :index => true
28
+
29
+ property :user_id, Integer, :index => true
30
+
31
+ property :protocol, String, :index => true
32
+
33
+ property :link_type, Integer
34
+
35
+ property :packet_length, Integer
36
+
37
+ property :packet, Text
38
+
39
+ belongs_to :sensor
40
+
41
+ belongs_to :classification
42
+
43
+ belongs_to :signature
44
+
45
+ validates_uniqueness_of :uid
46
+
47
+ def update_sensor
48
+ sensor.update(:last_event_id => self.event_id)
49
+ sensor.save
50
+ end
51
+
52
+ end
53
+
54
+ class Sensor
55
+ include DataMapper::Resource
56
+ timestamps :created_at, :updated_at
57
+
58
+ property :id, Serial, :index => true
59
+
60
+ property :hostname, Text, :index => true
61
+
62
+ property :interface, String
63
+
64
+ property :name, String, :index => true
65
+
66
+ property :last_event_id, Integer, :index => true
67
+
68
+ property :signatures_md5, String, :length => 32, :index => true
69
+
70
+ property :generators_md5, String, :length => 32, :index => true
71
+
72
+ property :classifications_md5, String, :length => 32, :index => true
73
+
74
+ has n, :events
75
+
76
+ validates_uniqueness_of :hostname, :name
77
+
78
+ def events_count
79
+ last_event_id
80
+ end
81
+
82
+ def self.find(object)
83
+ name = object.name ? object.name : object.hostname
84
+
85
+ sensor = first_or_create({:hostname => object.hostname, :interface => object.interface}, {
86
+ :hostname => object.hostname,
87
+ :interface => object.interface,
88
+ :name => name,
89
+ })
90
+
91
+ sensor
92
+ end
93
+
94
+ end
95
+
96
+ class Signature
97
+ include DataMapper::Resource
98
+ storage_names[:default] = "signatures"
99
+
100
+ timestamps :created_at, :updated_at
101
+
102
+ property :id, Serial, :index => true
103
+
104
+ property :signature_id, Integer, :index => true
105
+
106
+ property :generator_id, Integer, :index => true
107
+
108
+ property :name, Text
109
+
110
+ has n, :events
111
+
112
+ validates_uniqueness_of :name
113
+
114
+ def self.import(options={})
115
+
116
+ if options.has_key?(:signatures)
117
+
118
+ options[:signatures].each do |key, value|
119
+ signature = Signature.get(:signature_id => key)
120
+ next if signature && options[:force]
121
+
122
+ if signature
123
+ signature.update(value)
124
+ else
125
+ value.merge!(:signature_id => key, :generator_id => 1)
126
+ Signature.create(value)
127
+ end
128
+
129
+ end
130
+
131
+ end
132
+
133
+ if options.has_key?(:generators)
134
+
135
+ options[:generators].each do |key, value|
136
+ genid, sid = key.split('.')
137
+ signature = Signature.get(:signature_id => sid, :generator_id => genid)
138
+ next if signature && options[:force]
139
+
140
+ if signature
141
+ signature.update(value)
142
+ else
143
+ value.merge!(:signature_id => sid, :generator_id => genid)
144
+ Signature.create(value)
145
+ end
146
+
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+ end
153
+
154
+ class Classification
155
+ include DataMapper::Resource
156
+
157
+ storage_names[:default] = "classifications"
158
+
159
+ timestamps :created_at, :updated_at
160
+
161
+ property :id, Serial, :index => true
162
+
163
+ property :classification_id, Integer, :index => true
164
+
165
+ property :name, Text
166
+
167
+ property :short, String
168
+
169
+ property :severity_id, Integer, :index => true
170
+
171
+ has n, :events
172
+
173
+ # belongs_to :severity
174
+
175
+ validates_uniqueness_of :name, :classification_id
176
+
177
+ def self.import(options={})
178
+
179
+ if options.has_key?(:classifications)
180
+
181
+ options[:classifications].each do |key,value|
182
+ classification = Classification.get(:classification_id => key)
183
+ next if classification && options[:force]
184
+
185
+ if classification
186
+ classification.update(value)
187
+ else
188
+ value.merge!(:classification_id => key)
189
+ Classification.create(value)
190
+ end
191
+ end
192
+
193
+ end
194
+ end
195
+
196
+ end
data/example/search.rb ADDED
@@ -0,0 +1,14 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift File.join(File.dirname(__FILE__), "..", "example")
3
+
4
+ require 'unified2'
5
+ require 'connect'
6
+ require 'pp'
7
+
8
+ Connect.setup
9
+
10
+ @sensor = Sensor.first
11
+
12
+ @sensor.events.each do |event|
13
+ puts event.signature.name
14
+ end
File without changes