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