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/example/connect.rb
DELETED
@@ -1,20 +0,0 @@
|
|
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/models.rb
DELETED
@@ -1,194 +0,0 @@
|
|
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 :event_id, Integer, :index => true
|
10
|
-
|
11
|
-
property :sensor_id, Integer, :index => true
|
12
|
-
|
13
|
-
property :source_ip, String, :index => true
|
14
|
-
|
15
|
-
property :source_port, Integer
|
16
|
-
|
17
|
-
property :destination_ip, String, :index => true
|
18
|
-
|
19
|
-
property :destination_port, Integer
|
20
|
-
|
21
|
-
property :severity_id, Integer, :index => true
|
22
|
-
|
23
|
-
property :classification_id, Integer, :index => true
|
24
|
-
|
25
|
-
property :category_id, Integer, :index => true
|
26
|
-
|
27
|
-
property :user_id, Integer, :index => true
|
28
|
-
|
29
|
-
property :protocol, String, :index => true
|
30
|
-
|
31
|
-
property :link_type, Integer
|
32
|
-
|
33
|
-
property :packet_length, Integer
|
34
|
-
|
35
|
-
property :packet, Text
|
36
|
-
|
37
|
-
belongs_to :sensor
|
38
|
-
|
39
|
-
belongs_to :classification
|
40
|
-
|
41
|
-
belongs_to :signature
|
42
|
-
|
43
|
-
validates_uniqueness_of :uid
|
44
|
-
|
45
|
-
def update_sensor
|
46
|
-
sensor.update(:last_event_id => self.event_id)
|
47
|
-
sensor.save
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
class Sensor
|
53
|
-
include DataMapper::Resource
|
54
|
-
timestamps :created_at, :updated_at
|
55
|
-
|
56
|
-
property :id, Serial, :index => true
|
57
|
-
|
58
|
-
property :hostname, Text, :index => true
|
59
|
-
|
60
|
-
property :interface, String
|
61
|
-
|
62
|
-
property :name, String, :index => true
|
63
|
-
|
64
|
-
property :last_event_id, Integer, :index => true
|
65
|
-
|
66
|
-
property :signatures_md5, String, :length => 32, :index => true
|
67
|
-
|
68
|
-
property :generators_md5, String, :length => 32, :index => true
|
69
|
-
|
70
|
-
property :classifications_md5, String, :length => 32, :index => true
|
71
|
-
|
72
|
-
has n, :events
|
73
|
-
|
74
|
-
validates_uniqueness_of :hostname, :name
|
75
|
-
|
76
|
-
def events_count
|
77
|
-
last_event_id
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.find(object)
|
81
|
-
name = object.name ? object.name : object.hostname
|
82
|
-
|
83
|
-
sensor = first_or_create({:hostname => object.hostname, :interface => object.interface}, {
|
84
|
-
:hostname => object.hostname,
|
85
|
-
:interface => object.interface,
|
86
|
-
:name => name,
|
87
|
-
})
|
88
|
-
|
89
|
-
sensor
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
class Signature
|
95
|
-
include DataMapper::Resource
|
96
|
-
storage_names[:default] = "signatures"
|
97
|
-
|
98
|
-
timestamps :created_at, :updated_at
|
99
|
-
|
100
|
-
property :id, Serial, :index => true
|
101
|
-
|
102
|
-
property :signature_id, Integer, :index => true
|
103
|
-
|
104
|
-
property :generator_id, Integer, :index => true
|
105
|
-
|
106
|
-
property :name, Text
|
107
|
-
|
108
|
-
has n, :events
|
109
|
-
|
110
|
-
validates_uniqueness_of :name
|
111
|
-
|
112
|
-
def self.import(options={})
|
113
|
-
|
114
|
-
if options.has_key?(:signatures)
|
115
|
-
|
116
|
-
options[:signatures].each do |key, value|
|
117
|
-
signature = Signature.get(:signature_id => key)
|
118
|
-
next if signature && options[:force]
|
119
|
-
|
120
|
-
if signature
|
121
|
-
signature.update(value)
|
122
|
-
else
|
123
|
-
value.merge!(:signature_id => key, :generator_id => 1)
|
124
|
-
Signature.create(value)
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
130
|
-
|
131
|
-
if options.has_key?(:generators)
|
132
|
-
|
133
|
-
options[:generators].each do |key, value|
|
134
|
-
genid, sid = key.split('.')
|
135
|
-
signature = Signature.get(:signature_id => sid, :generator_id => genid)
|
136
|
-
next if signature && options[:force]
|
137
|
-
|
138
|
-
if signature
|
139
|
-
signature.update(value)
|
140
|
-
else
|
141
|
-
value.merge!(:signature_id => sid, :generator_id => genid)
|
142
|
-
Signature.create(value)
|
143
|
-
end
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
class Classification
|
153
|
-
include DataMapper::Resource
|
154
|
-
|
155
|
-
storage_names[:default] = "classifications"
|
156
|
-
|
157
|
-
timestamps :created_at, :updated_at
|
158
|
-
|
159
|
-
property :id, Serial, :index => true
|
160
|
-
|
161
|
-
property :classification_id, Integer, :index => true
|
162
|
-
|
163
|
-
property :name, Text
|
164
|
-
|
165
|
-
property :short, String
|
166
|
-
|
167
|
-
property :severity_id, Integer, :index => true
|
168
|
-
|
169
|
-
has n, :events
|
170
|
-
|
171
|
-
# belongs_to :severity
|
172
|
-
|
173
|
-
validates_uniqueness_of :name, :classification_id
|
174
|
-
|
175
|
-
def self.import(options={})
|
176
|
-
|
177
|
-
if options.has_key?(:classifications)
|
178
|
-
|
179
|
-
options[:classifications].each do |key,value|
|
180
|
-
classification = Classification.get(:classification_id => key)
|
181
|
-
next if classification && options[:force]
|
182
|
-
|
183
|
-
if classification
|
184
|
-
classification.update(value)
|
185
|
-
else
|
186
|
-
value.merge!(:classification_id => key)
|
187
|
-
Classification.create(value)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
end
|
data/example/mysql-example.rb
DELETED
@@ -1,73 +0,0 @@
|
|
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
|
-
# Initialize Database Connection
|
9
|
-
Connect.setup
|
10
|
-
|
11
|
-
# Unified2 Configuration
|
12
|
-
Unified2.configuration do
|
13
|
-
|
14
|
-
# Sensor Configurations
|
15
|
-
sensor :interface => 'en1', :name => 'Example Sensor'
|
16
|
-
|
17
|
-
# Load signatures, generators & classifications into memory
|
18
|
-
load :signatures, 'seeds/sid-msg.map'
|
19
|
-
load :generators, 'seeds/gen-msg.map'
|
20
|
-
load :classifications, 'seeds/classification.config'
|
21
|
-
end
|
22
|
-
|
23
|
-
# Locate the sensor in the database using
|
24
|
-
# the hostname and interface. If this fails
|
25
|
-
# rUnified2 will create a new sensor record.
|
26
|
-
sensor = Sensor.find(Unified2.sensor)
|
27
|
-
Unified2.sensor.id = sensor.id
|
28
|
-
|
29
|
-
# Load the classifications, generators &
|
30
|
-
# signatures into the database and store the
|
31
|
-
# md5 in the sensor record. This will only
|
32
|
-
# update if the md5s DO NOT match.
|
33
|
-
[[Classification,:classifications], [Signature, :signatures], [Signature, :generators]].each do |klass, method|
|
34
|
-
unless sensor.send(:"#{method}_md5") == Unified2.send(method).send(:md5)
|
35
|
-
klass.send(:import, { method => Unified2.send(method).send(:data), :force => true })
|
36
|
-
sensor.update(:"#{method}_md5" => Unified2.send(method).send(:md5))
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Monitor the unfied2 log and process the data.
|
41
|
-
# The second argument is the last event processed by
|
42
|
-
# the sensor. If the last_event_id column is blank in the
|
43
|
-
# sensor table it will begin at the first available event.
|
44
|
-
Unified2.watch('seeds/unified2', sensor ? sensor.last_event_id + 1 : :first) do |event|
|
45
|
-
next if event.signature.blank?
|
46
|
-
|
47
|
-
puts event
|
48
|
-
|
49
|
-
insert_event = Event.new({
|
50
|
-
:event_id => event.id,
|
51
|
-
:checksum => event.checksum,
|
52
|
-
:created_at => event.timestamp,
|
53
|
-
:sensor_id => event.sensor.id,
|
54
|
-
:source_ip => event.source_ip,
|
55
|
-
:source_port => event.source_port,
|
56
|
-
:destination_ip => event.destination_ip,
|
57
|
-
:destination_port => event.destination_port,
|
58
|
-
:severity_id => event.severity,
|
59
|
-
:protocol => event.protocol,
|
60
|
-
:link_type => event.payload.linktype,
|
61
|
-
:packet_length => event.payload.length,
|
62
|
-
:packet => event.payload.hex,
|
63
|
-
:classification_id => event.classification.id,
|
64
|
-
:signature_id => event.signature.id
|
65
|
-
})
|
66
|
-
|
67
|
-
if insert_event.save
|
68
|
-
insert_event.update_sensor
|
69
|
-
else
|
70
|
-
STDERR.puts "VALIDATION ERROR OR RECORD ALREADY EXISTS #{insert_event.errors}"
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
data/example/search.rb
DELETED
@@ -1,14 +0,0 @@
|
|
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
|
data/example/untitled.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# http://192.168.1.254/xslt?PAGE=A06&THISPAGE=&NEXTPAGE=A06
|
4
|
-
|
5
|
-
@file = File.open('/Users/mephux/Source/passwords/wpa.txt')
|
6
|
-
|
7
|
-
require 'rubygems'
|
8
|
-
require 'mechanize'
|
9
|
-
|
10
|
-
a = Mechanize.new
|
11
|
-
|
12
|
-
a.get('http://192.168.1.254/xslt?PAGE=A06&THISPAGE=&NEXTPAGE=A06') do |page|
|
13
|
-
|
14
|
-
@file.each_line do |password|
|
15
|
-
next unless password[/^e/]
|
16
|
-
|
17
|
-
puts password
|
18
|
-
login_form = page.form_with(:action => '/xslt', :method => 'POST')
|
19
|
-
login_form['PASSWORD'] = password
|
20
|
-
page = a.submit login_form
|
21
|
-
|
22
|
-
if page.body =~ /The password is incorrect./
|
23
|
-
puts 'FAIL'
|
24
|
-
else
|
25
|
-
puts 'W0ots'
|
26
|
-
puts password
|
27
|
-
exit -1
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
data/lib/unified2/construct.rb
DELETED
@@ -1,54 +0,0 @@
|
|
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
|
data/lib/unified2/event_ip4.rb
DELETED
@@ -1,26 +0,0 @@
|
|
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
|
data/lib/unified2/event_ip6.rb
DELETED
@@ -1,23 +0,0 @@
|
|
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
|
data/lib/unified2/packet.rb
DELETED
@@ -1,16 +0,0 @@
|
|
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
|
@@ -1,19 +0,0 @@
|
|
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
|