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.
Files changed (44) hide show
  1. data/ChangeLog.rdoc +6 -0
  2. data/LICENSE.txt +1 -1
  3. data/README.md +72 -0
  4. data/example/{basic-example.rb → example.rb} +3 -2
  5. data/example/seeds/{unified2 → unified2.log} +0 -0
  6. data/gemspec.yml +2 -0
  7. data/lib/unified2/classification.rb +17 -3
  8. data/lib/unified2/config_file.rb +34 -10
  9. data/lib/unified2/constructor/construct.rb +83 -0
  10. data/lib/unified2/constructor/event_ip4.rb +47 -0
  11. data/lib/unified2/constructor/event_ip6.rb +44 -0
  12. data/lib/unified2/constructor/packet.rb +30 -0
  13. data/lib/unified2/constructor/primitive/ipv4.rb +31 -0
  14. data/lib/unified2/{primitive.rb → constructor/primitive.rb} +0 -0
  15. data/lib/unified2/constructor/record_header.rb +17 -0
  16. data/lib/unified2/constructor.rb +1 -0
  17. data/lib/unified2/core_ext/string.rb +10 -2
  18. data/lib/unified2/event.rb +250 -100
  19. data/lib/unified2/exceptions/file_not_found.rb +6 -3
  20. data/lib/unified2/exceptions/file_not_readable.rb +6 -3
  21. data/lib/unified2/exceptions/unknown_load_type.rb +6 -3
  22. data/lib/unified2/payload.rb +82 -13
  23. data/lib/unified2/protocol.rb +141 -0
  24. data/lib/unified2/sensor.rb +22 -0
  25. data/lib/unified2/signature.rb +28 -4
  26. data/lib/unified2/version.rb +2 -2
  27. data/lib/unified2.rb +84 -13
  28. data/spec/event_spec.rb +112 -0
  29. data/spec/spec_helper.rb +45 -1
  30. data/spec/unified2_spec.rb +87 -1
  31. metadata +45 -25
  32. data/README.rdoc +0 -60
  33. data/Rakefile.compiled.rbc +0 -775
  34. data/example/connect.rb +0 -20
  35. data/example/models.rb +0 -194
  36. data/example/mysql-example.rb +0 -73
  37. data/example/search.rb +0 -14
  38. data/example/untitled.rb +0 -31
  39. data/lib/unified2/construct.rb +0 -54
  40. data/lib/unified2/event_ip4.rb +0 -26
  41. data/lib/unified2/event_ip6.rb +0 -23
  42. data/lib/unified2/packet.rb +0 -16
  43. data/lib/unified2/primitive/ipv4.rb +0 -19
  44. data/lib/unified2/record_header.rb +0 -10
data/ChangeLog.rdoc CHANGED
@@ -1,3 +1,9 @@
1
+ === 0.5.0 / 2011-03-18
2
+
3
+ * major refactoring
4
+ * Added eth, ip, udp, icmp, and TCP header support
5
+ * Added basic specs and fully documented the source
6
+
1
7
  === 0.4.0 / 2011-03-14
2
8
 
3
9
  * added checksum support for sensor
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 mephux
1
+ Copyright (c) 2011 Dustin Willis Webber
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # unified2
2
+
3
+ * [Homepage](http://github.com/mephux/unified2)
4
+ * [Issues](http://github.com/mephux/unified2/issues)
5
+ * [Documentation](http://rubydoc.info/gems/unified2/frames)
6
+ * [Email](mailto:dustin.webber at gmail.com)
7
+
8
+ ## Description
9
+
10
+ A ruby interface for unified2 output. rUnified2 allows you to manipulate unified2 output for custom storage and/or analysis.
11
+
12
+ ## Features
13
+
14
+ * Monitor/Read unified2 logs & manipulate the data.
15
+ * Numerous connivence methods
16
+ * Simple & Intuitive to Use
17
+
18
+ ## Examples
19
+
20
+ require 'unified2'
21
+
22
+ #
23
+ # Load rules into memory
24
+ #
25
+
26
+ Unified2.configuration do
27
+ # Sensor Configurations
28
+ sensor :id => 1, :name => 'Test Sensor', :interface => 'en1'
29
+
30
+ # Load signatures, generators & classifications into memory
31
+ load :signatures, 'sid-msg.map'
32
+ load :generators, 'gen-msg.map'
33
+ load :classifications, 'classification.config'
34
+ end
35
+
36
+ #
37
+ # Unified2#watch
38
+ #
39
+ # Watch a unified2 file for changes and process the results.
40
+ #
41
+
42
+ Unified2.watch('/var/log/snort/merged.log', :last) do |event|
43
+ next if event.signature.name.blank?
44
+ puts event
45
+ end
46
+
47
+ # Unified2#read
48
+ # Parse a unified2 file and process the results.
49
+
50
+ Unified2.read('/var/log/snort/merged.log') do |event|
51
+
52
+ puts event.protocol #=> "TCP"
53
+
54
+ puts event.protocol.to_h #=> {:length=>379, :seq=>3934511163, :ack=>1584708129 ... }
55
+
56
+ end
57
+
58
+ ## Requirements
59
+
60
+ * bindata ~> 1.3.1
61
+ * hexdump: ~> 0.1.0
62
+ * packetfu: ~> 1.0.0
63
+
64
+ ## Install
65
+
66
+ `$ gem install unified2`
67
+
68
+ == Copyright
69
+
70
+ Copyright (c) 2011 Dustin Willis Webber
71
+
72
+ See LICENSE.txt for details.
@@ -1,6 +1,5 @@
1
1
  $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
2
  require 'unified2'
3
- require 'pp'
4
3
 
5
4
  # Unified2 Configuration
6
5
  Unified2.configuration do
@@ -10,7 +9,9 @@ Unified2.configuration do
10
9
 
11
10
  # Load signatures, generators & classifications into memory
12
11
  load :signatures, 'seeds/sid-msg.map'
12
+
13
13
  load :generators, 'seeds/gen-msg.map'
14
+
14
15
  load :classifications, 'seeds/classification.config'
15
16
 
16
17
  end
@@ -19,7 +20,7 @@ end
19
20
  # The second argument is the last event processed by
20
21
  # the sensor. If the last_event_id column is blank in the
21
22
  # sensor table it will begin at the first available event.
22
- Unified2.watch('seeds/unified2', :first) do |event|
23
+ Unified2.watch('seeds/unified2.log', :first) do |event|
23
24
  next if event.signature.blank?
24
25
 
25
26
  puts event
File without changes
data/gemspec.yml CHANGED
@@ -9,6 +9,8 @@ homepage: https://github.com/mephux/unified2
9
9
  dependencies:
10
10
  bindata: ~> 1.3.1
11
11
  hexdump: ~> 0.1.0
12
+ packetfu: ~> 1.0.0
13
+ pcaprub: ~> 0.9.2
12
14
 
13
15
  development_dependencies:
14
16
  ore-tasks: ~> 0.4
@@ -1,8 +1,21 @@
1
1
  module Unified2
2
+ #
3
+ # Classification
4
+ #
2
5
  class Classification
3
6
 
4
7
  attr_accessor :id, :name, :short, :severity
5
-
8
+
9
+ #
10
+ # Initialize classification
11
+ #
12
+ # @param [Hash] classification Classification attributes
13
+ #
14
+ # @option classification [Integer] :classification_id Classification id
15
+ # @option classification [String] :name Classification name
16
+ # @option classification [String] :short Classification short name
17
+ # @option classification [String] :severity Classification severity id
18
+ #
6
19
  def initialize(classification={})
7
20
  @id = classification[:classification_id]
8
21
  @name = classification[:name]
@@ -10,5 +23,6 @@ module Unified2
10
23
  @severity = classification[:severity]
11
24
  end
12
25
 
13
- end
14
- end
26
+ end # class Classification
27
+
28
+ end # module Unified2
@@ -1,8 +1,17 @@
1
1
  module Unified2
2
+ #
3
+ # Configuration file
4
+ #
2
5
  class ConfigFile
3
6
 
4
7
  attr_accessor :type, :path, :md5, :data
5
8
 
9
+ #
10
+ # Initialize configuration file
11
+ #
12
+ # @param [String, Symbol] type Configuration file type
13
+ # @param [String] path Configuration file path
14
+ #
6
15
  def initialize(type, path)
7
16
  @type = type
8
17
  @path = path
@@ -10,9 +19,24 @@ module Unified2
10
19
  @md5 = Digest::MD5.hexdigest(@path)
11
20
  import
12
21
  end
22
+
23
+ #
24
+ # Size
25
+ #
26
+ # @return [Integer] Configuration size
27
+ #
28
+ def size
29
+ @data.size
30
+ end
13
31
 
14
32
  private
15
-
33
+
34
+ #
35
+ # Configuration Import
36
+ #
37
+ # Parse the configuration files and store
38
+ # them in memory as a hash.
39
+ #
16
40
  def import
17
41
  file = File.open(@path)
18
42
 
@@ -25,9 +49,8 @@ module Unified2
25
49
  next unless line[/^config\s/]
26
50
  count += 1
27
51
 
28
- # attempted-dos,Attempted Denial of Service,2
29
52
  data = line.gsub!(/config classification: /, '')
30
- short, name, severity = data.to_s.split(',')
53
+ short, name, severity = data.to_s.split(',').map(&:strip)
31
54
 
32
55
  @data[count.to_s] = {
33
56
  :short => short,
@@ -40,13 +63,13 @@ module Unified2
40
63
 
41
64
  file.each_line do |line|
42
65
  next if line[/^\#/]
43
- generator_id, alert_id, name = line.split(' || ')
66
+ generator_id, alert_id, name = line.split(' || ').map(&:strip)
44
67
  id = "#{generator_id}.#{alert_id}"
45
68
 
46
69
  @data[id] = {
47
- :generator_id => generator_id,
70
+ :generator_id => generator_id.to_i,
48
71
  :name => name,
49
- :signature_id => alert_id
72
+ :signature_id => alert_id.to_i
50
73
  }
51
74
  end
52
75
 
@@ -54,7 +77,7 @@ module Unified2
54
77
 
55
78
  file.each_line do |line|
56
79
  next if line[/^\#/]
57
- id, body, *reference_data = line.split(' || ')
80
+ id, body, *reference_data = line.split(' || ').map(&:strip)
58
81
 
59
82
  references = {}
60
83
  reference_data.each do |line|
@@ -67,7 +90,7 @@ module Unified2
67
90
  end
68
91
 
69
92
  @data[id] = {
70
- :signature_id => id,
93
+ :signature_id => id.to_i,
71
94
  :name => body,
72
95
  :generator_id => 1
73
96
  }
@@ -76,5 +99,6 @@ module Unified2
76
99
  end
77
100
  end
78
101
 
79
- end
80
- end
102
+ end # class ConfigFile
103
+
104
+ end # module Unified2
@@ -0,0 +1,83 @@
1
+ require 'unified2/constructor/event_ip4'
2
+ require 'unified2/constructor/event_ip6'
3
+ require 'unified2/constructor/record_header'
4
+ require 'unified2/constructor/packet'
5
+
6
+ module Unified2
7
+ #
8
+ # Unified2 Constructor Namespace
9
+ #
10
+ module Constructor
11
+ #
12
+ # Unified2 Construction
13
+ #
14
+ class Construct < ::BinData::Record
15
+ #
16
+ # Rename record_header to header
17
+ # to simplify and cut down on verbosity
18
+ #
19
+ record_header :header
20
+
21
+ #
22
+ # Unified2 data types
23
+ #
24
+ # Currently rUnified2 only supports packet,
25
+ # event_ip4 and event_ip6.
26
+ #
27
+ choice :data, :selection => :type_selection do
28
+ packet "packet"
29
+ event_ip4 "ev4"
30
+ event_ip6 "ev6"
31
+ end
32
+
33
+ #
34
+ # String padding
35
+ #
36
+ string :read_length => :padding_length
37
+
38
+ #
39
+ # Type Selection
40
+ #
41
+ # Deterime and call data type based on
42
+ # the unified2 type attribute
43
+ #
44
+ def type_selection
45
+ case header.u2type.to_i
46
+ when 1
47
+ # define UNIFIED2_EVENT 1
48
+ when 2
49
+ # define UNIFIED2_PACKET 2
50
+ "packet"
51
+ when 7
52
+ # define UNIFIED2_IDS_EVENT 7
53
+ "ev4"
54
+ when 66
55
+ # define UNIFIED2_EVENT_EXTENDED 66
56
+ when 67
57
+ # define UNIFIED2_PERFORMANCE 67
58
+ when 68
59
+ # define UNIFIED2_PORTSCAN 68
60
+ when 72
61
+ # define UNIFIED2_IDS_EVENT_IPV6 72
62
+ "ev6"
63
+ else
64
+ "unknown type #{header.u2type}"
65
+ end
66
+ end
67
+
68
+ #
69
+ # Sometimes the data needs extra padding
70
+ #
71
+ def padding_length
72
+ if header.u2length > data.num_bytes
73
+ header.u2length - data.num_bytes
74
+ else
75
+ 0
76
+ end
77
+ end
78
+
79
+ end # class Construct
80
+
81
+ end # module Construct
82
+
83
+ end # module Unified2
@@ -0,0 +1,47 @@
1
+ require 'unified2/primitive/ipv4'
2
+
3
+ module Unified2
4
+
5
+ module Constructor
6
+ #
7
+ # Event IP Version 4
8
+ #
9
+ class EventIP4 < ::BinData::Record
10
+
11
+ endian :big
12
+
13
+ uint32 :sensor_id
14
+
15
+ uint32 :event_id
16
+
17
+ uint32 :event_second
18
+
19
+ uint32 :event_microsecond
20
+
21
+ uint32 :signature_id
22
+
23
+ uint32 :generator_id
24
+
25
+ uint32 :signature_revision
26
+
27
+ uint32 :classification_id
28
+
29
+ uint32 :priority_id
30
+
31
+ ipv4 :ip_source
32
+
33
+ ipv4 :ip_destination
34
+
35
+ uint16 :sport_itype
36
+
37
+ uint16 :dport_icode
38
+
39
+ uint8 :protocol
40
+
41
+ uint8 :packet_action
42
+
43
+ end # class EventIP4
44
+
45
+ end # module Constructor
46
+
47
+ end # module Unified2
@@ -0,0 +1,44 @@
1
+ module Unified2
2
+
3
+ module Constructor
4
+ #
5
+ # Event IP Version 6
6
+ #
7
+ class EventIP6 < ::BinData::Record
8
+ endian :big
9
+
10
+ uint32 :sensor_id
11
+
12
+ uint32 :event_id
13
+
14
+ uint32 :event_second
15
+
16
+ uint32 :event_microsecond
17
+
18
+ uint32 :signature_id
19
+
20
+ uint32 :generator_id
21
+
22
+ uint32 :signature_revision
23
+
24
+ uint32 :classification_id
25
+
26
+ uint32 :priority_id
27
+
28
+ uint128 :ip_source
29
+
30
+ uint128 :ip_destination
31
+
32
+ uint16 :sport_itype
33
+
34
+ uint16 :dport_icode
35
+
36
+ uint8 :protocol
37
+
38
+ uint8 :packet_action
39
+
40
+ end # class EventIP6
41
+
42
+ end # module Constructor
43
+
44
+ end # module Unified2
@@ -0,0 +1,30 @@
1
+ module Unified2
2
+
3
+ module Constructor
4
+ #
5
+ # Event Packet
6
+ #
7
+ class Packet < ::BinData::Record
8
+ endian :big
9
+
10
+ uint32 :sensor_id
11
+
12
+ uint32 :event_id
13
+
14
+ uint32 :event_second
15
+
16
+ uint32 :packet_second
17
+
18
+ uint32 :packet_microsecond
19
+
20
+ uint32 :linktype
21
+
22
+ uint32 :packet_length
23
+
24
+ string :packet_data, :read_length => :packet_length
25
+
26
+ end # class Packet
27
+
28
+ end # module Constructor
29
+
30
+ end # module Unified2
@@ -0,0 +1,31 @@
1
+ module Unified2
2
+
3
+ module Constructor
4
+ #
5
+ # Unified2 Primitive Namespace
6
+ #
7
+ module Primitive
8
+ #
9
+ # BinData Primitive IP4 Constructor
10
+ #
11
+ class IPV4 < ::BinData::Primitive
12
+ array :octets, :type => :uint8, :initial_length => 4
13
+
14
+ # IPV4#set
15
+ def set(value)
16
+ ints = value.split(/\./).collect { |int| int.to_i }
17
+ self.octets = ints
18
+ end
19
+
20
+ # IPV4#get
21
+ def get
22
+ self.octets.collect { |octet| "%d" % octet }.join(".")
23
+ end
24
+
25
+ end # class IPV4
26
+
27
+ end # class Primitive
28
+
29
+ end # module Constructor
30
+
31
+ end # module Unified2
@@ -0,0 +1,17 @@
1
+ module Unified2
2
+
3
+ module Constructor
4
+ #
5
+ # Unified2 Header
6
+ #
7
+ class RecordHeader < ::BinData::Record
8
+ endian :big
9
+
10
+ uint32 :u2type
11
+ uint32 :u2length
12
+
13
+ end # class RecordHeader
14
+
15
+ end # module Constructor
16
+
17
+ end # module Unified2
@@ -0,0 +1 @@
1
+ require 'unified2/constructor/construct'
@@ -1,8 +1,16 @@
1
+ #
2
+ # String monkeypatches
3
+ #
1
4
  class String
2
-
5
+ #
6
+ # Blank?
7
+ #
8
+ # @return [true, false] If the string
9
+ # is blank or empty return true.
10
+ #
3
11
  def blank?
4
12
  return true if (self.nil? || self == '')
5
13
  false
6
14
  end
7
15
 
8
- end
16
+ end # class String