unified2 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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