scandb 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,13 @@
1
- === 1.0.0 / 2008-07-31
1
+ === 0.1.1 / 2008-08-17
2
+
3
+ * Added a work-around to DataMappers current problem with lazy-loading
4
+ has-many relations.
5
+ * Added various convenience methods.
6
+ * Added the OSClass, OSClassGuess, OSMatch and OSMatchGuess models.
7
+ * Require dm-serializer by default.
8
+ * Added verbose and export options for the scandb utility.
9
+
10
+ === 0.1.0 / 2008-07-31
2
11
 
3
12
  * Fixed a bug where LibXML wasn't being included for ScanDB::Nmap.
4
13
 
data/Manifest.txt CHANGED
@@ -11,8 +11,10 @@ lib/scandb/model.rb
11
11
  lib/scandb/port.rb
12
12
  lib/scandb/service.rb
13
13
  lib/scandb/scanned_port.rb
14
- lib/scandb/os.rb
15
- lib/scandb/os_guess.rb
14
+ lib/scandb/os_class.rb
15
+ lib/scandb/os_class_guess.rb
16
+ lib/scandb/os_match.rb
17
+ lib/scandb/os_match_guess.rb
16
18
  lib/scandb/host_name.rb
17
19
  lib/scandb/host.rb
18
20
  lib/scandb/nmap.rb
data/Rakefile CHANGED
@@ -11,6 +11,7 @@ Hoe.new('scandb', ScanDB::VERSION) do |p|
11
11
  ['do_sqlite3', '>=0.9.3'],
12
12
  ['dm-core', '>=0.9.3'],
13
13
  ['dm-types', '>=0.9.3'],
14
+ ['dm-serializer','>=0.9.3'],
14
15
  'libxml-ruby'
15
16
  ]
16
17
  end
@@ -25,8 +25,10 @@ require 'scandb/exceptions/invalid_database_config'
25
25
  require 'scandb/config'
26
26
  require 'scandb/port'
27
27
  require 'scandb/service'
28
- require 'scandb/os'
29
- require 'scandb/os_guess'
28
+ require 'scandb/os_class'
29
+ require 'scandb/os_class_guess'
30
+ require 'scandb/os_match'
31
+ require 'scandb/os_match_guess'
30
32
  require 'scandb/host_name'
31
33
  require 'scandb/host'
32
34
 
@@ -52,17 +54,28 @@ module ScanDB
52
54
  # exist.
53
55
  #
54
56
  def Database.config
55
- if File.file?(CONFIG_FILE)
56
- conf = YAML.load(CONFIG_FILE)
57
+ unless class_variable_defined?('@@scandb_database_config')
58
+ @@scandb_database_config = DEFAULT_CONFIG
57
59
 
58
- unless (conf.kind_of?(Hash) || conf.kind_of?(String))
59
- raise(InvalidDatabaseConfig,"#{CONFIG_FILE} must contain either a Hash or a String",caller)
60
- end
60
+ if File.file?(CONFIG_FILE)
61
+ conf = YAML.load(CONFIG_FILE)
62
+
63
+ unless (conf.kind_of?(Hash) || conf.kind_of?(String))
64
+ raise(InvalidDatabaseConfig,"#{CONFIG_FILE} must contain either a Hash or a String",caller)
65
+ end
61
66
 
62
- return conf
67
+ @@scandb_database_config = conf
68
+ end
63
69
  end
64
70
 
65
- return DEFAULT_CONFIG
71
+ return @@scandb_database_config ||= DEFAULT_CONFIG
72
+ end
73
+
74
+ #
75
+ # Sets the Database configuration to the specified _configuration_.
76
+ #
77
+ def Database.config=(configuration)
78
+ @@scandb_database_config = configuration
66
79
  end
67
80
 
68
81
  #
@@ -88,12 +101,23 @@ module ScanDB
88
101
  # _configuration is not given, +DEFAULT_CONFIG+ will be used to setup
89
102
  # the Database.
90
103
  #
91
- def Database.setup(configuration=DEFAULT_CONFIG,&block)
104
+ def Database.setup(configuration=Database.config,&block)
92
105
  Database.setup_log
93
106
  DataMapper.setup(:default, configuration)
94
107
 
95
108
  block.call if block
96
109
 
110
+ # sourced from http://gist.github.com/3010
111
+ # in order to fix a has-many lazy-loading bug
112
+ # in dm-core <= 0.9.4
113
+ descendants = DataMapper::Resource.descendants.dup
114
+ descendants.each do |model|
115
+ descendants.merge(model.descendants) if model.respond_to?(:descendants)
116
+ end
117
+ descendants.each do |model|
118
+ model.relationships.each_value { |r| r.child_key if r.child_model == model }
119
+ end
120
+
97
121
  DataMapper.auto_upgrade!
98
122
  return nil
99
123
  end
data/lib/scandb/host.rb CHANGED
@@ -23,7 +23,8 @@
23
23
 
24
24
  require 'scandb/model'
25
25
  require 'scandb/host_name'
26
- require 'scandb/os_guess'
26
+ require 'scandb/os_class_guess'
27
+ require 'scandb/os_match_guess'
27
28
  require 'scandb/scanned_port'
28
29
 
29
30
  module ScanDB
@@ -31,12 +32,19 @@ module ScanDB
31
32
 
32
33
  include Model
33
34
 
35
+ # The IP address of the Host
34
36
  property :ip, String
35
37
 
38
+ # The host-names of the host
36
39
  has n, :names, :class_name => 'HostName'
37
40
 
38
- has n, :os_guesses, :order => [:accuracy.desc], :class_name => 'OSGuess'
41
+ # The OS Class guesses of the host
42
+ has n, :os_class_guesses, :class_name => 'OSClassGuess'
39
43
 
44
+ # The OS Match guesses of the host
45
+ has n, :os_match_guesses, :class_name => 'OSMatchGuess'
46
+
47
+ # The scanned ports of the host
40
48
  has n, :scanned_ports
41
49
 
42
50
  #
@@ -46,6 +54,60 @@ module ScanDB
46
54
  names.first
47
55
  end
48
56
 
57
+ #
58
+ # Returns the best OS Class guess.
59
+ #
60
+ def best_class_guess
61
+ os_class_guesses.first
62
+ end
63
+
64
+ #
65
+ # Returns the best OS Match guess.
66
+ #
67
+ def best_match_guess
68
+ os_match_guesses.first
69
+ end
70
+
71
+ #
72
+ # Returns all the open ports on the host.
73
+ #
74
+ def open_ports
75
+ scanned_ports.all(:status => :open)
76
+ end
77
+
78
+ #
79
+ # Returns all the filtered ports on the host.
80
+ #
81
+ def filtered_ports
82
+ scanned_ports.all(:status => :filtered)
83
+ end
84
+
85
+ #
86
+ # Returns all the closed ports on the host.
87
+ #
88
+ def closed_ports
89
+ scanned_ports.all(:status => :closed)
90
+ end
91
+
92
+ alias ports open_ports
93
+
94
+ #
95
+ # Returns the ports numbers of all open ports on the host.
96
+ #
97
+ def port_numbers
98
+ open_ports.map { |port| port.number }
99
+ end
100
+
101
+ #
102
+ # Returns the services of all open ports on the host.
103
+ #
104
+ def services
105
+ ports.service
106
+ end
107
+
108
+ #
109
+ # Returns the IP address of the host in String form.
110
+ #
49
111
  def to_s
50
112
  ip
51
113
  end
data/lib/scandb/model.rb CHANGED
@@ -22,6 +22,7 @@
22
22
  #
23
23
 
24
24
  require 'dm-core'
25
+ require 'dm-serializer'
25
26
 
26
27
  module ScanDB
27
28
  module Model
data/lib/scandb/nmap.rb CHANGED
@@ -32,12 +32,13 @@ module ScanDB
32
32
 
33
33
  #
34
34
  # Imports scan information from a Nmap XML scan file, specified by
35
- # the _path_. Returns an Array of Host objects.
35
+ # the _path_. Returns an Array of Host objects. If a _block_ is given
36
+ # it will be passed the newly created Host object.
36
37
  #
37
- # Nmap.from_xml('path/to/scan.xml')
38
+ # Nmap.import_xml('path/to/scan.xml')
38
39
  # # => [...]
39
40
  #
40
- def Nmap.from_xml(path)
41
+ def Nmap.import_xml(path,&block)
41
42
  doc = XML::Document.file(path)
42
43
  hosts = []
43
44
 
@@ -45,24 +46,36 @@ module ScanDB
45
46
  ip = host.find_first("address[@addr and @addrtype='ipv4']")['addr']
46
47
  new_host = Host.first_or_create(:ip => ip)
47
48
 
48
- host.find('hostname').each do |hostname|
49
+ host.find('hostnames/hostname').each do |hostname|
49
50
  new_host.names << HostName.first_or_create(
50
- :name => hostname['name'],
51
- :host_id => new_host.id
51
+ :name => hostname['name']
52
52
  )
53
53
  end
54
54
 
55
55
  host.find('os/osclass').each do |osclass|
56
- new_os = OS.first_or_create(
56
+ new_os_class = OSClass.first_or_create(
57
57
  :type => osclass['type'],
58
58
  :vendor => osclass['vendor'],
59
59
  :family => osclass['osfamily'],
60
60
  :version => osclass['osgen']
61
61
  )
62
62
 
63
- new_host.os_guesses << OSGuess.first_or_create(
64
- :os_id => new_os.id,
65
- :accuracy => osclass['accuracy'].to_i
63
+ new_host.os_class_guesses.first_or_create(
64
+ :accuracy => osclass['accuracy'].to_i,
65
+ :os_class_id => new_os_class.id,
66
+ :host_id => new_host.id
67
+ )
68
+ end
69
+
70
+ host.find('os/osmatch').each do |osmatch|
71
+ new_os_match = OSMatch.first_or_create(
72
+ :name => osmatch['name']
73
+ )
74
+
75
+ new_host.os_match_guesses.first_or_create(
76
+ :accuracy => osmatch['accuracy'].to_i,
77
+ :os_match_id => new_os_match.id,
78
+ :host_id => new_host.id
66
79
  )
67
80
  end
68
81
 
@@ -76,7 +89,7 @@ module ScanDB
76
89
  :name => port.find_first('service[@name]')['name']
77
90
  )
78
91
 
79
- new_host.scanned_ports << ScannedPort.first_or_create(
92
+ new_host.scanned_ports.first_or_create(
80
93
  :status => port.find_first('state[@state]')['state'].to_sym,
81
94
  :service_id => new_service.id,
82
95
  :port_id => new_port.id,
@@ -86,6 +99,7 @@ module ScanDB
86
99
 
87
100
  new_host.save
88
101
 
102
+ block.call(new_host) if block
89
103
  hosts << new_host
90
104
  end
91
105
 
@@ -0,0 +1,61 @@
1
+ #
2
+ #--
3
+ # ScanDB - A library for importing and analyzing information generated by
4
+ # various network scanning utilities.
5
+ #
6
+ # Copyright (c) 2008 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License along
19
+ # with this program; if not, write to the Free Software Foundation, Inc.,
20
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
+ #++
22
+ #
23
+
24
+ require 'scandb/model'
25
+
26
+ module ScanDB
27
+ class OSClass
28
+
29
+ include Model
30
+
31
+ # The type of OS
32
+ property :type, String
33
+
34
+ # The vendor of the OS
35
+ property :vendor, String
36
+
37
+ # The family the OS belongs to
38
+ property :family, String
39
+
40
+ # The version of the OS
41
+ property :version, String
42
+
43
+ # The guesses for the OS Class.
44
+ has n, :guesses, :class_name => 'OSClassGuess'
45
+
46
+ #
47
+ # Returns the String form of the OS Class.
48
+ #
49
+ def to_s
50
+ vars = []
51
+
52
+ vars << "type=#{type}" if type
53
+ vars << "vendor=#{vendor}" if vendor
54
+ vars << "family=#{family}" if family
55
+ vars << "version=#{version}" if version
56
+
57
+ return vars.join(' ')
58
+ end
59
+
60
+ end
61
+ end
@@ -21,20 +21,29 @@
21
21
  #++
22
22
  #
23
23
 
24
+ require 'scandb/os_class'
24
25
  require 'scandb/model'
25
- require 'scandb/os'
26
- require 'scandb/host'
27
26
 
28
27
  module ScanDB
29
- class OSGuess
28
+ class OSClassGuess
30
29
 
31
30
  include Model
32
31
 
32
+ # The accuracy of the guess
33
33
  property :accuracy, Integer
34
34
 
35
- belongs_to :os, :class_name => 'OS'
35
+ # The OS Class
36
+ belongs_to :os_class, :class_name => 'OSClass'
36
37
 
38
+ # The Host that the guess was made against
37
39
  belongs_to :host
38
40
 
41
+ #
42
+ # Returns the String form of the OS Class guess.
43
+ #
44
+ def to_s
45
+ "#{accuracy}%: #{os_class}"
46
+ end
47
+
39
48
  end
40
49
  end
@@ -24,19 +24,19 @@
24
24
  require 'scandb/model'
25
25
 
26
26
  module ScanDB
27
- class OS
27
+ class OSMatch
28
28
 
29
29
  include Model
30
30
 
31
- property :type, String
31
+ # The name of the OS match
32
+ property :name, String
32
33
 
33
- property :vendor, String
34
+ # The guesses for this OS match
35
+ has n, :guesses, :class_name => 'OSMatchGuess'
34
36
 
35
- property :family, String
36
-
37
- property :version, String
38
-
39
- has n, :guesses, :class_name => 'OSGuess'
37
+ def to_s
38
+ name
39
+ end
40
40
 
41
41
  end
42
42
  end
@@ -0,0 +1,49 @@
1
+ #
2
+ #--
3
+ # ScanDB - A library for importing and analyzing information generated by
4
+ # various network scanning utilities.
5
+ #
6
+ # Copyright (c) 2008 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License along
19
+ # with this program; if not, write to the Free Software Foundation, Inc.,
20
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
+ #++
22
+ #
23
+
24
+ require 'scandb/os_match'
25
+ require 'scandb/model'
26
+
27
+ module ScanDB
28
+ class OSMatchGuess
29
+
30
+ include Model
31
+
32
+ # The accuracy of the guess
33
+ property :accuracy, Integer
34
+
35
+ # The OS Match for the guess
36
+ belongs_to :os_match, :class_name => 'OSMatch'
37
+
38
+ # The Host that the guess was made against
39
+ belongs_to :host
40
+
41
+ #
42
+ # Returns the String form of the OS Match guess.
43
+ #
44
+ def to_s
45
+ "#{accuracy}%: #{os_match}"
46
+ end
47
+
48
+ end
49
+ end
data/lib/scandb/port.rb CHANGED
@@ -32,14 +32,20 @@ module ScanDB
32
32
 
33
33
  include Model
34
34
 
35
+ # The protocol that the port is runnin on
36
+ # (<tt>:tcp</tt>, <tt>:udp</tt>)
35
37
  property :protocol, Enum[:tcp, :udp]
36
38
 
39
+ # The port number
37
40
  property :number, Integer
38
41
 
42
+ # The scanned ports related to this port
39
43
  has n, :scanned, :class_name => 'ScannedPort'
40
44
 
45
+ # The hosts which were scanned for this port
41
46
  has n, :hosts, :through => :scanned
42
47
 
48
+ # The services that were found running on this port
43
49
  has n, :services, :through => :scanned
44
50
 
45
51
  #
data/lib/scandb/runner.rb CHANGED
@@ -36,7 +36,7 @@ module ScanDB
36
36
  options = OpenStruct.new
37
37
 
38
38
  opts = OptionParser.new do |opts|
39
- opts.banner = 'usage: scandb [-d URI] [--import-nmap FILE | -L | -p PORT | -s NAME]'
39
+ opts.banner = 'usage: scandb [-v] [-d URI] [--import-nmap FILE | -L | -p PORT | -s NAME]'
40
40
 
41
41
  opts.on('-d','--database URI','The URI for the Database.','Defaults to ~/.scandb/scandb.db') do |uri|
42
42
  options.database = uri
@@ -55,10 +55,41 @@ module ScanDB
55
55
  options.with_port = port.to_i
56
56
  end
57
57
 
58
+ opts.on('--with-open-ports','List hosts with open ports') do
59
+ options.with_port_status = :open
60
+ end
61
+
62
+ opts.on('--with-filtered-ports','List hosts with filtered ports') do
63
+ options.with_port_status = :filtered
64
+ end
65
+
66
+ opts.on('--with-closed-ports','List hosts with closed ports') do
67
+ options.with_port_status = :closed
68
+ end
69
+
58
70
  opts.on('-s','--with-service NAME','List hosts with the specified service') do |name|
59
71
  options.with_service = name
60
72
  end
61
73
 
74
+ opts.on('--export-yaml FILE','Exports hosts as a YAML file') do |path|
75
+ options.export = :yaml
76
+ options.export_path = path
77
+ end
78
+
79
+ opts.on('--export-xml FILE','Exports hosts as a XML file') do |path|
80
+ options.export = :xml
81
+ options.export_path = path
82
+ end
83
+
84
+ opts.on('-v','--verbose','Increase verbosity of output') do
85
+ options.verbose = true
86
+ end
87
+
88
+ opts.on('-V','--version','Print ScanDB version and exit') do
89
+ puts ScanDB::Version
90
+ exit
91
+ end
92
+
62
93
  opts.on('-h','--help','This cruft') do
63
94
  puts opts
64
95
  exit
@@ -70,8 +101,16 @@ module ScanDB
70
101
  if options.import
71
102
  case options.import
72
103
  when :nmap then
73
- hosts = Nmap.from_xml(options.import_file)
74
- puts "Success imported #{hosts.length} hosts."
104
+ hosts = Nmap.import_xml(options.import_file)
105
+
106
+ case hosts.length
107
+ when 0
108
+ puts "No hosts where imported."
109
+ when 1
110
+ puts "Imported #{hosts.length} host."
111
+ else
112
+ puts "Imported #{hosts.length} hosts."
113
+ end
75
114
  end
76
115
  else
77
116
  if options.with_port
@@ -82,7 +121,64 @@ module ScanDB
82
121
  hosts = Host.all
83
122
  end
84
123
 
85
- hosts.each { |host| puts host}
124
+ if options.export
125
+ File.open(options.export_path,'w') do |output|
126
+ case options.export
127
+ when :yaml
128
+ output.write(hosts.to_yaml)
129
+ when :xml
130
+ output.write(hosts.to_xml)
131
+ end
132
+ end
133
+ else
134
+ hosts.each do |host|
135
+ if options.verbose
136
+ print "[ #{host} ]\n\n"
137
+
138
+ unless host.names.empty?
139
+ puts ' Host names:'
140
+
141
+ host.names.each do |name|
142
+ puts " #{name}"
143
+ end
144
+
145
+ print "\n"
146
+ end
147
+
148
+ unless host.os_class_guesses.empty?
149
+ puts ' OS Classes:'
150
+
151
+ host.os_class_guesses.each do |guess|
152
+ puts " #{guess}"
153
+ end
154
+
155
+ print "\n"
156
+ end
157
+
158
+ unless host.os_match_guesses.empty?
159
+ puts ' OS Matches:'
160
+
161
+ host.os_match_guesses.each do |guess|
162
+ puts " #{guess}"
163
+ end
164
+
165
+ print "\n"
166
+ end
167
+
168
+ unless host.scanned_ports.empty?
169
+ puts " Scanned Ports:"
170
+
171
+ host.scanned_ports.each do |scanned_port|
172
+ puts " #{scanned_port}"
173
+ end
174
+
175
+ print "\n"
176
+ end
177
+ else
178
+ puts host
179
+ end
180
+ end
181
+ end
86
182
  end
87
183
 
88
184
  return true
@@ -33,12 +33,17 @@ module ScanDB
33
33
 
34
34
  include Model
35
35
 
36
+ # The scan status of the Port (<tt>:open</tt>, <tt>:filtered</tt>,
37
+ # <tt>:closed</tt>)
36
38
  property :status, Enum[:open, :filtered, :closed]
37
39
 
40
+ # The Service that is running on the scanned port
38
41
  belongs_to :service
39
42
 
43
+ # The Port
40
44
  belongs_to :port
41
45
 
46
+ # The Host that the scan was performed against
42
47
  belongs_to :host
43
48
 
44
49
  #
@@ -30,10 +30,13 @@ module ScanDB
30
30
 
31
31
  include Model
32
32
 
33
+ # Name of the service
33
34
  property :name, String
34
35
 
36
+ # Scanned ports that were found to be running the service
35
37
  has n, :scanned, :class_name => 'ScannedPort'
36
38
 
39
+ # Hosts that were found to be running the service
37
40
  has n, :hosts, :through => :scanned
38
41
 
39
42
  #
@@ -23,5 +23,5 @@
23
23
 
24
24
  module ScanDB
25
25
  # ScanDB version
26
- VERSION = '0.1.0'
26
+ VERSION = '0.1.1'
27
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scandb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Postmodern Modulus III
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-07-31 00:00:00 -07:00
12
+ date: 2008-08-17 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -42,6 +42,16 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: 0.9.3
44
44
  version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: dm-serializer
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.3
54
+ version:
45
55
  - !ruby/object:Gem::Dependency
46
56
  name: libxml-ruby
47
57
  type: :runtime
@@ -87,8 +97,10 @@ files:
87
97
  - lib/scandb/port.rb
88
98
  - lib/scandb/service.rb
89
99
  - lib/scandb/scanned_port.rb
90
- - lib/scandb/os.rb
91
- - lib/scandb/os_guess.rb
100
+ - lib/scandb/os_class.rb
101
+ - lib/scandb/os_class_guess.rb
102
+ - lib/scandb/os_match.rb
103
+ - lib/scandb/os_match_guess.rb
92
104
  - lib/scandb/host_name.rb
93
105
  - lib/scandb/host.rb
94
106
  - lib/scandb/nmap.rb