unified2 0.1.1

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/example/unified2 ADDED
Binary file
data/gemspec.yml ADDED
@@ -0,0 +1,14 @@
1
+ name: unified2
2
+ summary: "A ruby interface for unified2 output."
3
+ description: "A ruby interface for unified2 output. rUnified2 allows you to manipulate unified2 output for custom storage and/or analysis."
4
+ license: MIT
5
+ authors: Dustin Willis Webber
6
+ email: dustin.webber@gmail.com
7
+ homepage: https://github.com/mephux/unified2
8
+
9
+ development_dependencies:
10
+ bindata: ~> 1.3.1
11
+ hexdump: ~> 0.1.0
12
+ ore-tasks: ~> 0.4
13
+ rspec: ~> 2.4
14
+ yard: ~> 0.6.0
@@ -0,0 +1,14 @@
1
+ module Unified2
2
+ class Classification
3
+
4
+ attr_accessor :id, :name, :short, :priority
5
+
6
+ def initialize(classification={})
7
+ @id = classification[:classification_id]
8
+ @name = classification[:name]
9
+ @short = classification[:short]
10
+ @priority = classification[:priority]
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,54 @@
1
+ require 'unified2/event_ip4'
2
+ require 'unified2/event_ip6'
3
+ require 'unified2/record_header'
4
+ require 'unified2/packet'
5
+
6
+ module Unified2
7
+
8
+ class Construct < ::BinData::Record
9
+ record_header :header
10
+
11
+ choice :data, :selection => :type_selection do
12
+ packet "packet"
13
+ event_ip4 "ev4"
14
+ event_ip6 "ev6"
15
+ end
16
+
17
+ # padding
18
+ string :read_length => :padding_length
19
+
20
+ def type_selection
21
+ case header.u2type.to_i
22
+ when 1
23
+ # define UNIFIED2_EVENT 1
24
+ when 2
25
+ # define UNIFIED2_PACKET 2
26
+ "packet"
27
+ when 7
28
+ # define UNIFIED2_IDS_EVENT 7
29
+ "ev4"
30
+ when 66
31
+ # define UNIFIED2_EVENT_EXTENDED 66
32
+ when 67
33
+ # define UNIFIED2_PERFORMANCE 67
34
+ when 68
35
+ # define UNIFIED2_PORTSCAN 68
36
+ when 72
37
+ # define UNIFIED2_IDS_EVENT_IPV6 72
38
+ "ev6"
39
+ else
40
+ "unknown type #{header.u2type}"
41
+ end
42
+ end
43
+
44
+ # sometimes the data needs extra padding
45
+ def padding_length
46
+ if header.u2length > data.num_bytes
47
+ header.u2length - data.num_bytes
48
+ else
49
+ 0
50
+ end
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,8 @@
1
+ class String
2
+
3
+ def blank?
4
+ return true if (self.nil? || self == '')
5
+ false
6
+ end
7
+
8
+ end
@@ -0,0 +1 @@
1
+ require 'unified2/core_ext/string'
@@ -0,0 +1,315 @@
1
+ require 'ipaddr'
2
+ require 'json'
3
+ require 'unified2/classification'
4
+ require 'unified2/payload'
5
+ require 'unified2/sensor'
6
+ require 'unified2/signature'
7
+
8
+ module Unified2
9
+
10
+ class Event
11
+
12
+ attr_accessor :id, :metadata, :packet
13
+
14
+ def initialize(id)
15
+ @id = id
16
+ end
17
+
18
+ def packet_time
19
+ if @packet.has_key?(:packet_second)
20
+ @packet[:packet_second]
21
+ @timestamp = Time.at(@packet[:packet_second].to_i)
22
+ end
23
+ end
24
+
25
+ def event_time
26
+ if @packet.has_key?(:event_second)
27
+ @timestamp = Time.at(@packet[:event_second].to_i)
28
+ end
29
+ end
30
+ alias :timestamp :event_time
31
+
32
+ def microseconds
33
+ if @metadata.has_key?(:event_microsecond)
34
+ @microseconds = @metadata[:event_microsecond]
35
+ end
36
+ end
37
+
38
+ def sensor
39
+ @sensor ||= Unified2.sensor
40
+ end
41
+
42
+ def packet_action
43
+ if @metadata.has_key?(:event_second)
44
+ @packet_action = @metadata[:packet_action]
45
+ end
46
+ end
47
+
48
+ def protocol
49
+ if @metadata.has_key?(:protocol)
50
+ @protocol = determine_protocol(@metadata[:protocol])
51
+ end
52
+ end
53
+
54
+ def icmp?
55
+ return true if protocol == :ICMP
56
+ false
57
+ end
58
+
59
+ def tcp?
60
+ return true if protocol == :TCP
61
+ false
62
+ end
63
+
64
+ def udp?
65
+ return true if protocol == :UDP
66
+ false
67
+ end
68
+
69
+ def classification
70
+ if @metadata.is_a?(Hash)
71
+ @classification = Classification.new(@metadata[:classification]) if @metadata[:classification]
72
+ end
73
+ end
74
+
75
+ def signature
76
+ if @metadata.is_a?(Hash)
77
+ @signature = Signature.new(@metadata[:signature])
78
+ end
79
+ end
80
+
81
+ def generator_id
82
+ if @metadata.is_a?(Hash)
83
+ @metadata[:generator_id] if @metadata.has_key?(:generator_id)
84
+ end
85
+ end
86
+
87
+ def ip_source
88
+ if @metadata.is_a?(Hash)
89
+ @metadata[:ip_source] if @metadata.has_key?(:ip_source)
90
+ end
91
+ end
92
+ alias :source_ip :ip_source
93
+
94
+ # Add ICMP type
95
+ def source_port
96
+ return 0 if icmp?
97
+ @source_port = @metadata[:sport_itype] if @metadata.has_key?(:sport_itype)
98
+ end
99
+
100
+ def ip_destination
101
+ if @metadata.is_a?(Hash)
102
+ @metadata[:ip_destination] if @metadata.has_key?(:ip_destination)
103
+ end
104
+ end
105
+ alias :destination_ip :ip_destination
106
+
107
+ # Add ICMP code
108
+ def destination_port
109
+ return 0 if icmp?
110
+ @source_port = @metadata[:dport_icode] if @metadata.has_key?(:dport_icode)
111
+ end
112
+
113
+ def severity
114
+ @severity = @metadata[:priority_id] if @metadata.has_key?(:priority_id)
115
+ end
116
+
117
+ def payload
118
+ if @packet.is_a?(Hash)
119
+ Payload.new(@packet)
120
+ else
121
+ Payload.new
122
+ end
123
+ end
124
+
125
+ def load(event)
126
+ if event.data.respond_to?(:signature_id)
127
+ @metadata ||= build_event_metadata(event)
128
+ end
129
+
130
+ if event.data.respond_to?(:packet_data)
131
+ @packet ||= build_packet_metadata(event)
132
+ end
133
+ end
134
+
135
+ def to_h
136
+ if @metadata.is_a?(Hash)
137
+ if @packet.is_a?(Hash)
138
+ data = {}
139
+ data.merge!(@metadata)
140
+ data.merge!(@packet)
141
+ return data
142
+ end
143
+ else
144
+ if @packet.is_a?(Hash)
145
+ return @packet
146
+ end
147
+ end
148
+ end
149
+
150
+ def to_i
151
+ @id.to_i
152
+ end
153
+
154
+ def json
155
+ to_h.to_json
156
+ end
157
+
158
+ def to_s
159
+ data = %{
160
+ #############################################################################
161
+ Event ID: #{id}
162
+ Timestamp: #{timestamp}
163
+ Severity: #{severity}
164
+ Protocol: #{protocol}
165
+ Source IP: #{source_ip}:#{source_port}
166
+ Destination IP: #{destination_ip}:#{destination_port}
167
+ Signature: #{signature.name}
168
+ Payload:
169
+
170
+ }
171
+ if payload.blank?
172
+ data + '#############################################################################'
173
+ else
174
+ payload.dump(:width => 30, :output => data)
175
+ data + "#############################################################################"
176
+ end
177
+ end
178
+
179
+ private
180
+
181
+ def build_event_metadata(event)
182
+ @event_hash = {}
183
+
184
+ @event_hash = {
185
+ :ip_destination => event.data.ip_destination,
186
+ :priority_id => event.data.priority_id,
187
+ :signature_revision => event.data.signature_revision,
188
+ :event_id => event.data.event_id,
189
+ :protocol => event.data.protocol,
190
+ :sport_itype => event.data.sport_itype,
191
+ :event_second => event.data.event_second,
192
+ :packet_action => event.data.packet_action,
193
+ :dport_icode => event.data.dport_icode,
194
+ :sensor_id => event.data.sensor_id,
195
+ :generator_id => event.data.generator_id,
196
+ :ip_source => event.data.ip_source,
197
+ :event_microsecond => event.data.event_microsecond
198
+ }
199
+
200
+ build_classifications(event)
201
+
202
+ if event.data.generator_id.to_i == 1
203
+ build_signature(event)
204
+ else
205
+ build_generator(event)
206
+ end
207
+
208
+ @event_hash
209
+ end
210
+
211
+ def build_packet_metadata(event)
212
+ @packet_hash = {}
213
+ @packet_hash = {
214
+ :linktype => event.data.linktype,
215
+ :packet_microsecond => event.data.packet_microsecond,
216
+ :packet_second => event.data.packet_second,
217
+ :payload => event.data.packet_data,
218
+ :event_second => event.data.event_second,
219
+ :packet_length => event.data.packet_length
220
+ }
221
+
222
+ @packet_hash
223
+ end
224
+
225
+ def build_generator(event)
226
+ if Unified2.generators
227
+ if Unified2.generators.has_key?("#{event.data.generator_id}.#{event.data.signature_id}")
228
+ sig = Unified2.generators["#{event.data.generator_id}.#{event.data.signature_id}"]
229
+
230
+ @event_hash[:signature] = {
231
+ :signature_id => event.data.signature_id,
232
+ :revision => event.data.signature_revision,
233
+ :name => sig[:name],
234
+ :references => sig[:references],
235
+ :blank => false
236
+ }
237
+ end
238
+ end
239
+
240
+ unless @event_hash.has_key?(:signature)
241
+ @event_hash[:signature] = {
242
+ :signature_id => event.data.signature_id,
243
+ :revision => 0,
244
+ :name => "Unknown Signature #{event.data.signature_id}",
245
+ :references => [],
246
+ :blank => true
247
+ }
248
+ end
249
+ end
250
+
251
+ def build_signature(event)
252
+ if Unified2.signatures
253
+ if Unified2.signatures.has_key?(event.data.signature_id.to_s)
254
+ sig = Unified2.signatures[event.data.signature_id.to_s]
255
+
256
+ @event_hash[:signature] = {
257
+ :signature_id => event.data.signature_id,
258
+ :revision => event.data.signature_revision,
259
+ :name => sig[:name],
260
+ :references => sig[:references]
261
+ }
262
+ end
263
+ end
264
+
265
+ unless @event_hash.has_key?(:signature)
266
+ @event_hash[:signature] = {
267
+ :signature_id => event.data.signature_id,
268
+ :revision => 0,
269
+ :name => "Unknown Signature #{event.data.signature_id}",
270
+ :references => []
271
+ }
272
+ end
273
+ end
274
+
275
+ def build_classifications(event)
276
+ if Unified2.classifications
277
+ if Unified2.classifications.has_key?("#{event.data.classification_id}")
278
+ classification = Unified2.classifications["#{event.data.classification_id}"]
279
+
280
+ @event_hash[:classification] = {
281
+ :classification_id => event.data.classification_id,
282
+ :name => classification[:name],
283
+ :short => classification[:short],
284
+ :priority => classification[:priority]
285
+ }
286
+ end
287
+ end
288
+
289
+ unless @event_hash.has_key?(:classification)
290
+ @event_hash[:classification] = {
291
+ :classification_id => event.data.classification_id,
292
+ :name => 'Unknown',
293
+ :short => 'n/a',
294
+ :priority => 0
295
+ }
296
+ end
297
+ end
298
+
299
+ def determine_protocol(protocol)
300
+ case protocol.to_i
301
+ when 1
302
+ :ICMP # ICMP (Internet Control Message Protocol) packet type.
303
+ when 2
304
+ :IGMP # IGMP (Internet Group Message Protocol) packet type.
305
+ when 6
306
+ :TCP # TCP (Transmition Control Protocol) packet type.
307
+ when 17
308
+ :UDP # UDP (User Datagram Protocol) packet type.
309
+ else
310
+ :'N/A'
311
+ end
312
+ end
313
+
314
+ end
315
+ end
@@ -0,0 +1,26 @@
1
+ require 'unified2/primitive/ipv4'
2
+
3
+ module Unified2
4
+
5
+ class EventIP4 < ::BinData::Record
6
+
7
+ endian :big
8
+
9
+ uint32 :sensor_id
10
+ uint32 :event_id
11
+ uint32 :event_second
12
+ uint32 :event_microsecond
13
+ uint32 :signature_id
14
+ uint32 :generator_id
15
+ uint32 :signature_revision
16
+ uint32 :classification_id
17
+ uint32 :priority_id
18
+ ipv4 :ip_source
19
+ ipv4 :ip_destination
20
+ uint16 :sport_itype
21
+ uint16 :dport_icode
22
+ uint8 :protocol
23
+ uint8 :packet_action
24
+ end
25
+
26
+ end
@@ -0,0 +1,23 @@
1
+ module Unified2
2
+
3
+ class EventIP6 < ::BinData::Record
4
+ endian :big
5
+
6
+ uint32 :sensor_id
7
+ uint32 :event_id
8
+ uint32 :event_second
9
+ uint32 :event_microsecond
10
+ uint32 :signature_id
11
+ uint32 :generator_id
12
+ uint32 :signature_revision
13
+ uint32 :classification_id
14
+ uint32 :priority_id
15
+ uint128 :ip_source
16
+ uint128 :ip_destination
17
+ uint16 :sport_itype
18
+ uint16 :dport_icode
19
+ uint8 :protocol
20
+ uint8 :packet_action
21
+ end
22
+
23
+ end
@@ -0,0 +1,4 @@
1
+ module Unified2
2
+ class FileNotFound < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Unified2
2
+ class FileNotReadable < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Unified2
2
+ class UnknownLoadType < StandardError
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ require 'unified2/exceptions/file_not_found'
2
+ require 'unified2/exceptions/file_not_readable'
@@ -0,0 +1,16 @@
1
+ module Unified2
2
+
3
+ class Packet < ::BinData::Record
4
+ endian :big
5
+
6
+ uint32 :sensor_id
7
+ uint32 :event_id
8
+ uint32 :event_second
9
+ uint32 :packet_second
10
+ uint32 :packet_microsecond
11
+ uint32 :linktype
12
+ uint32 :packet_length
13
+ string :packet_data, :read_length => :packet_length
14
+ end
15
+
16
+ end
@@ -0,0 +1,32 @@
1
+ require 'hexdump'
2
+
3
+ module Unified2
4
+ class Payload
5
+
6
+ attr_accessor :linktype, :length
7
+
8
+ def initialize(payload={})
9
+ @payload = payload[:payload]
10
+ @length = payload[:packet_length].to_i
11
+ @linktype = payload[:linktype]
12
+ end
13
+
14
+ def blank?
15
+ return true unless @payload
16
+ false
17
+ end
18
+
19
+ def raw
20
+ @payload.to_s
21
+ end
22
+
23
+ def hex
24
+ @payload.to_s.unpack('H*')
25
+ end
26
+
27
+ def dump(options={})
28
+ Hexdump.dump(@payload, options)
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ module Unified2
2
+ module Primitive
3
+
4
+ class IPV4 < ::BinData::Primitive
5
+ array :octets, :type => :uint8, :initial_length => 4
6
+
7
+ def set(val)
8
+ ints = val.split(/\./).collect { |int| int.to_i }
9
+ self.octets = ints
10
+ end
11
+
12
+ def get
13
+ self.octets.collect { |octet| "%d" % octet }.join(".")
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ require 'primitive/ipv4'
@@ -0,0 +1,10 @@
1
+ module Unified2
2
+
3
+ class RecordHeader < ::BinData::Record
4
+ endian :big
5
+
6
+ uint32 :u2type
7
+ uint32 :u2length
8
+ end
9
+
10
+ end
@@ -0,0 +1,26 @@
1
+ module Unified2
2
+ class Sensor
3
+
4
+ attr_accessor :id, :hostname,
5
+ :interface, :name
6
+
7
+ def initialize(options={})
8
+ @id = options[:id] || 0
9
+ @name = options[:name] || ""
10
+ @hostname ||= Socket.gethostname
11
+ @interface ||= options[:interface] || nil
12
+ end
13
+
14
+ def update(attributes={})
15
+ return self if attributes.empty?
16
+
17
+ attributes.each do |key, value|
18
+ next unless self.respond_to?(key.to_sym)
19
+ instance_variable_set(:"@#{key}", value)
20
+ end
21
+
22
+ self
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ module Unified2
2
+
3
+ class Signature
4
+
5
+ attr_accessor :id, :revision, :name, :references
6
+
7
+ def initialize(signature={})
8
+ @id = signature[:signature_id] || 0
9
+ @revision = signature[:revision]
10
+ @name = signature[:name].strip
11
+ @references = signature[:references]
12
+ @blank = signature[:blank]
13
+ end
14
+
15
+ def blank?
16
+ @blank
17
+ end
18
+
19
+ def references
20
+ @references
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ module Unified2
2
+ # unified2 version
3
+ VERSION = "0.1.1"
4
+ end