ruby-nessus 1.0.0 → 1.0.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/.gitignore +2 -1
- data/README.rdoc +59 -1
- data/Rakefile +28 -3
- data/{tasks/yard.rb → bin/recess} +6 -7
- data/examples/example.rb +15 -44
- data/lib/ruby-nessus.rb +1 -0
- data/lib/ruby-nessus/Version1/event.rb +0 -2
- data/lib/ruby-nessus/Version1/host.rb +22 -9
- data/lib/ruby-nessus/Version1/version1.rb +7 -4
- data/lib/ruby-nessus/Version2/event.rb +0 -2
- data/lib/ruby-nessus/Version2/host.rb +48 -28
- data/lib/ruby-nessus/Version2/version2.rb +8 -4
- data/lib/ruby-nessus/cli.rb +128 -0
- data/lib/ruby-nessus/log.rb +82 -0
- data/lib/ruby-nessus/parse.rb +22 -16
- data/lib/ruby-nessus/version.rb +3 -0
- data/spec/helpers/xml.rb +4 -2
- data/spec/ruby-nessus_spec.rb +8 -0
- metadata +19 -8
- data/VERSION +0 -1
- data/tasks/spec.rb +0 -10
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -20,6 +20,8 @@ The below example illustrates how easy it really is to iterate of result data.
|
|
20
20
|
require 'ruby-nessus'
|
21
21
|
|
22
22
|
Nessus::Parse.new("example_v1.nessus", :version => 1) do |scan|
|
23
|
+
# OR: Nessus::Parse.new("example_v2.nessus") do |scan| <-- Ruby-Nessus will figured out the correct Nessus file version.
|
24
|
+
|
23
25
|
puts scan.title # The Nessus Report Title.
|
24
26
|
puts scan.runtime # The Scan Runtime. #=> 2 hours 23 minutes 12 seconds
|
25
27
|
puts scan.host_count # Host Count.
|
@@ -60,7 +62,7 @@ You also have the ability to search for particular hostnames. In the near future
|
|
60
62
|
|
61
63
|
There are a bunch of convenient methods (maybe more then needed) added to make reporting a bit easier to produce quickly from a raw scan file. If you do not pass :version as an option it will default to the 2.0 .nessus schema.
|
62
64
|
|
63
|
-
Nessus::Parse.new("example_v2.nessus"
|
65
|
+
Nessus::Parse.new("example_v2.nessus") do |scan|
|
64
66
|
|
65
67
|
puts scan.event_percentage_for('low', true) #=> 8%
|
66
68
|
|
@@ -94,6 +96,62 @@ There are a bunch of convenient methods (maybe more then needed) added to make r
|
|
94
96
|
|
95
97
|
end
|
96
98
|
|
99
|
+
Ruby-Nessus also ships with a POC CLI application for the lib called 'recess':
|
100
|
+
|
101
|
+
Recess 0.1.1
|
102
|
+
usage: recess FILE [OPTIONS]
|
103
|
+
-f, --file FILE The .nessus file to parse.
|
104
|
+
-h, --help This help summary page.
|
105
|
+
-v, --version Recess Version.
|
106
|
+
|
107
|
+
Below is example output generated by recess:
|
108
|
+
|
109
|
+
$> recess examples/example_v2.nessus
|
110
|
+
Recess - Ruby-Nessus CLI
|
111
|
+
Version: 0.1.1
|
112
|
+
|
113
|
+
-> SCAN Metadata:
|
114
|
+
|
115
|
+
Scan Title: Ruby-Nessus
|
116
|
+
Policy Title: Ruby-Nessus
|
117
|
+
|
118
|
+
-> SCAN Statistics:
|
119
|
+
|
120
|
+
Host Count: 2
|
121
|
+
Open Port Count: 51
|
122
|
+
TCP Count: 38
|
123
|
+
UDP Count: 11
|
124
|
+
ICMP Count: 1
|
125
|
+
|
126
|
+
-> EVENT Statistics:
|
127
|
+
|
128
|
+
Informational Severity Count: 19
|
129
|
+
Low Severity Count: 47
|
130
|
+
Medium Severity Count: 3
|
131
|
+
High Severity Count: 0
|
132
|
+
Total Event Count: 50
|
133
|
+
|
134
|
+
|
135
|
+
Low Event Percentage: 94
|
136
|
+
Medium Event Percentage: 6
|
137
|
+
High Event Percentage: 0
|
138
|
+
|
139
|
+
-> HOSTS:
|
140
|
+
|
141
|
+
Hostname: snorby.org
|
142
|
+
- IP Address:: 173.45.230.150
|
143
|
+
- Informational Count: 12
|
144
|
+
- Low Count: 34
|
145
|
+
- Medium Count: 1
|
146
|
+
- High Count: 0
|
147
|
+
|
148
|
+
Hostname: scanme.insecure.org
|
149
|
+
- IP Address:: 64.13.134.52
|
150
|
+
- Informational Count: 7
|
151
|
+
- Low Count: 13
|
152
|
+
- Medium Count: 2
|
153
|
+
- High Count: 0
|
154
|
+
|
97
155
|
== Requirements
|
98
156
|
* Ruby 1.8 or 1.9
|
99
157
|
* Nokogiri http://github.com/tenderlove/nokogiri
|
data/Rakefile
CHANGED
@@ -1,23 +1,48 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
3
|
|
4
|
-
require './
|
5
|
-
require './tasks/yard.rb'
|
4
|
+
require './lib/ruby-nessus/version.rb'
|
6
5
|
|
7
6
|
begin
|
8
7
|
require 'jeweler'
|
9
8
|
Jeweler::Tasks.new do |gem|
|
10
9
|
gem.name = "ruby-nessus"
|
10
|
+
gem.version = Nessus::VERSION
|
11
11
|
gem.summary = "Ruby-Nessus is a ruby interface for the popular Nessus vulnerability scanner."
|
12
12
|
gem.description = "Ruby-Nessus aims to deliver an easy yet powerful interface for interacting and manipulating Nessus scan results and configurations."
|
13
13
|
gem.email = "dustin.webber@gmail.com"
|
14
14
|
gem.homepage = "http://github.com/mephux/ruby-nessus"
|
15
15
|
gem.authors = ["Dustin Willis Webber"]
|
16
16
|
gem.add_dependency "nokogiri", ">= 1.4.0"
|
17
|
+
gem.add_dependency "rainbow", ">= 1.0.4"
|
17
18
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
18
19
|
gem.add_development_dependency "yard", ">=0.2.3.5"
|
19
20
|
end
|
20
21
|
Jeweler::GemcutterTasks.new
|
21
22
|
rescue LoadError
|
22
23
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
23
|
-
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'spec/rake/spectask'
|
27
|
+
|
28
|
+
desc "Run all specifications"
|
29
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
30
|
+
t.libs += ['lib', 'spec']
|
31
|
+
t.spec_opts = ['--colour', '--format', 'specdoc']
|
32
|
+
end
|
33
|
+
|
34
|
+
task :test => :spec
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
lib_dir = File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
|
38
|
+
unless $LOAD_PATH.include?(lib_dir)
|
39
|
+
$LOAD_PATH.unshift(lib_dir)
|
40
|
+
end
|
41
|
+
|
42
|
+
require 'yard'
|
43
|
+
|
44
|
+
YARD::Rake::YardocTask.new do |t|
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
task :docs => :yardoc
|
@@ -1,12 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
1
3
|
lib_dir = File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
|
2
4
|
unless $LOAD_PATH.include?(lib_dir)
|
3
|
-
$LOAD_PATH
|
5
|
+
$LOAD_PATH << lib_dir
|
4
6
|
end
|
5
|
-
|
6
|
-
require 'yard'
|
7
|
-
|
8
|
-
YARD::Rake::YardocTask.new do |t|
|
9
7
|
|
10
|
-
|
8
|
+
require 'ruby-nessus/cli'
|
9
|
+
require 'ruby-nessus/version'
|
11
10
|
|
12
|
-
|
11
|
+
Nessus::CLI.run
|
data/examples/example.rb
CHANGED
@@ -6,65 +6,36 @@ require 'ruby-nessus'
|
|
6
6
|
|
7
7
|
# Ruby-Nessus Example
|
8
8
|
|
9
|
-
Nessus::Parse.new('
|
10
|
-
|
11
|
-
# puts scan.title
|
12
|
-
# puts scan.policy_title
|
13
|
-
# puts scan.policy_notes
|
14
|
-
#
|
15
|
-
# puts scan.total_event_count(true)
|
16
|
-
#
|
17
|
-
# puts scan.tcp_count
|
18
|
-
# puts scan.udp_count
|
19
|
-
# puts scan.icmp_count
|
20
|
-
#
|
21
|
-
# puts scan.informational_severity_count
|
22
|
-
# puts scan.high_severity_count
|
23
|
-
# puts scan.medium_severity_count
|
24
|
-
# puts scan.low_severity_count
|
25
|
-
|
26
|
-
# scan.find_by_hostname('snorby') do |host|
|
27
|
-
#
|
28
|
-
# puts host.hostname
|
29
|
-
# puts host.ip
|
30
|
-
#
|
31
|
-
# puts host.ports.inspect
|
32
|
-
#
|
33
|
-
# host.medium_severity_events do |event|
|
34
|
-
# puts event.family
|
35
|
-
#
|
36
|
-
# puts event.synopsis
|
37
|
-
#
|
38
|
-
# puts event.links.inspect
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# end
|
42
|
-
|
9
|
+
Nessus::Parse.new('example_v1.nessus') do |scan|
|
43
10
|
|
44
11
|
scan.each_host do |host|
|
45
|
-
|
46
12
|
puts host.ip
|
47
13
|
puts host.hostname
|
48
14
|
puts host.os_name
|
49
|
-
puts host.
|
50
|
-
|
51
|
-
puts "\n"
|
15
|
+
puts host.runtime
|
52
16
|
|
17
|
+
#puts host.mac_addr
|
18
|
+
# puts host.event_percentage_for('icmp', true)
|
19
|
+
# puts host.ports.inspect
|
20
|
+
#
|
21
|
+
# puts "\n"
|
22
|
+
#
|
53
23
|
host.each_event do |event|
|
54
24
|
|
55
|
-
next if event.informational?
|
56
|
-
|
57
25
|
puts "=> #{event.name}" if event.name
|
58
|
-
|
26
|
+
# puts event.synopsis if event.synopsis
|
27
|
+
# puts "\n"
|
28
|
+
# puts event.output
|
29
|
+
# puts "\n"
|
59
30
|
# puts event.patch_publication_date.pretty if event.patch_publication_data
|
60
31
|
# puts event.see_also unless event.see_also.empty?
|
61
32
|
# puts event.synopsis if event.synopsis
|
62
33
|
# puts event.solution if event.solution
|
63
34
|
|
64
35
|
end
|
65
|
-
|
66
|
-
puts "\n"
|
67
|
-
puts "\n"
|
36
|
+
#
|
37
|
+
# puts "\n"
|
38
|
+
# puts "\n"
|
68
39
|
|
69
40
|
|
70
41
|
end
|
data/lib/ruby-nessus.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
1
|
module Nessus
|
2
2
|
module Version1
|
3
|
-
|
3
|
+
|
4
4
|
class Host
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
-
# Host
|
8
|
-
attr_reader :host
|
9
|
-
|
10
7
|
# Creates A New Host Object
|
11
8
|
# @param [Object] Host Object
|
12
9
|
# @example
|
@@ -15,6 +12,10 @@ module Nessus
|
|
15
12
|
@host = host
|
16
13
|
end
|
17
14
|
|
15
|
+
def to_s
|
16
|
+
"#{ip}"
|
17
|
+
end
|
18
|
+
|
18
19
|
# Return the Host Object hostname.
|
19
20
|
# @return [String]
|
20
21
|
# The Host Object Hostname
|
@@ -57,11 +58,9 @@ module Nessus
|
|
57
58
|
# @example
|
58
59
|
# scan.scan_run_time #=> '2 hours 5 minutes and 16 seconds'
|
59
60
|
def scan_runtime
|
60
|
-
|
61
|
-
m = ("#{Time.parse(scan_stop_time.to_s).strftime('%M').to_i - Time.parse(scan_start_time.to_s).strftime('%M').to_i}").gsub('-', '')
|
62
|
-
s = ("#{Time.parse(scan_stop_time.to_s).strftime('%S').to_i - Time.parse(scan_start_time.to_s).strftime('%S').to_i}").gsub('-', '')
|
63
|
-
return "#{h} hours #{m} minutes and #{s} seconds"
|
61
|
+
get_runtime
|
64
62
|
end
|
63
|
+
alias runtime scan_runtime
|
65
64
|
|
66
65
|
# Return the Host Netbios Name.
|
67
66
|
# @return [String]
|
@@ -253,8 +252,22 @@ module Nessus
|
|
253
252
|
Enumerator.new(self,:each_event).to_a
|
254
253
|
end
|
255
254
|
|
255
|
+
|
256
|
+
private
|
257
|
+
|
258
|
+
def get_runtime
|
259
|
+
if scan_start_time && scan_stop_time
|
260
|
+
h = ("#{Time.parse(scan_stop_time.to_s).strftime('%H').to_i - Time.parse(scan_start_time.to_s).strftime('%H').to_i}").gsub('-', '')
|
261
|
+
m = ("#{Time.parse(scan_stop_time.to_s).strftime('%M').to_i - Time.parse(scan_start_time.to_s).strftime('%M').to_i}").gsub('-', '')
|
262
|
+
s = ("#{Time.parse(scan_stop_time.to_s).strftime('%S').to_i - Time.parse(scan_start_time.to_s).strftime('%S').to_i}").gsub('-', '')
|
263
|
+
return "#{h} hours #{m} minutes and #{s} seconds"
|
264
|
+
else
|
265
|
+
false
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
256
269
|
end
|
257
|
-
|
270
|
+
|
258
271
|
end
|
259
272
|
|
260
273
|
end
|
@@ -28,12 +28,15 @@ module Nessus
|
|
28
28
|
# scan.report_name
|
29
29
|
# end
|
30
30
|
#
|
31
|
-
def initialize(
|
32
|
-
@
|
33
|
-
@xml = Nokogiri::XML.parse(@file.read)
|
31
|
+
def initialize(xml)
|
32
|
+
@xml = xml
|
34
33
|
raise "Error: Not A Version 1.0 .Nessus file." unless @xml.at('NessusClientData')
|
35
34
|
end
|
36
35
|
|
36
|
+
def version
|
37
|
+
1
|
38
|
+
end
|
39
|
+
|
37
40
|
#
|
38
41
|
# Return the nessus report title.
|
39
42
|
#
|
@@ -297,7 +300,7 @@ module Nessus
|
|
297
300
|
def total_event_count
|
298
301
|
count_severity[:all].to_i
|
299
302
|
end
|
300
|
-
|
303
|
+
|
301
304
|
#
|
302
305
|
# Return the Total severity count.
|
303
306
|
#
|
@@ -4,9 +4,6 @@ module Nessus
|
|
4
4
|
class Host
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
-
# Host
|
8
|
-
attr_reader :host
|
9
|
-
|
10
7
|
#
|
11
8
|
# Creates A New Host Object
|
12
9
|
#
|
@@ -19,6 +16,10 @@ module Nessus
|
|
19
16
|
@host = host
|
20
17
|
end
|
21
18
|
|
19
|
+
def to_s
|
20
|
+
"#{ip}"
|
21
|
+
end
|
22
|
+
|
22
23
|
#
|
23
24
|
# Return the Host Object hostname.
|
24
25
|
#
|
@@ -29,7 +30,9 @@ module Nessus
|
|
29
30
|
# host.hostname #=> "example.com"
|
30
31
|
#
|
31
32
|
def hostname
|
32
|
-
|
33
|
+
if (host = @host.at('tag[name=host-fqdn]'))
|
34
|
+
host.inner_text
|
35
|
+
end
|
33
36
|
end
|
34
37
|
alias name hostname
|
35
38
|
alias fqdn hostname
|
@@ -45,7 +48,9 @@ module Nessus
|
|
45
48
|
# host.ip #=> "127.0.0.1"
|
46
49
|
#
|
47
50
|
def ip
|
48
|
-
|
51
|
+
if (ip = @host.at('tag[name=host-ip]'))
|
52
|
+
ip.inner_text
|
53
|
+
end
|
49
54
|
end
|
50
55
|
|
51
56
|
#
|
@@ -58,10 +63,10 @@ module Nessus
|
|
58
63
|
# scan.scan_start_time #=> 'Fri Nov 11 23:36:54 1985'
|
59
64
|
#
|
60
65
|
def start_time
|
61
|
-
if @host.at('tag[name=HOST_START]')
|
62
|
-
|
66
|
+
if (start_time = @host.at('tag[name=HOST_START]'))
|
67
|
+
DateTime.strptime(start_time.inner_text, fmt='%a %b %d %H:%M:%S %Y')
|
63
68
|
else
|
64
|
-
|
69
|
+
false
|
65
70
|
end
|
66
71
|
end
|
67
72
|
|
@@ -75,10 +80,10 @@ module Nessus
|
|
75
80
|
# scan.scan_start_time #=> 'Fri Nov 11 23:36:54 1985'
|
76
81
|
#
|
77
82
|
def stop_time
|
78
|
-
if @host.at('tag[name=HOST_END]')
|
79
|
-
|
83
|
+
if (stop_time = @host.at('tag[name=HOST_END]'))
|
84
|
+
DateTime.strptime(stop_time.inner_text, fmt='%a %b %d %H:%M:%S %Y')
|
80
85
|
else
|
81
|
-
|
86
|
+
false
|
82
87
|
end
|
83
88
|
end
|
84
89
|
|
@@ -92,11 +97,9 @@ module Nessus
|
|
92
97
|
# scan.scan_run_time #=> '2 hours 5 minutes and 16 seconds'
|
93
98
|
#
|
94
99
|
def runtime
|
95
|
-
|
96
|
-
m = ("#{Time.parse(stop_time.to_s).strftime('%M').to_i - Time.parse(start_time.to_s).strftime('%M').to_i}").gsub('-', '')
|
97
|
-
s = ("#{Time.parse(stop_time.to_s).strftime('%S').to_i - Time.parse(start_time.to_s).strftime('%S').to_i}").gsub('-', '')
|
98
|
-
return "#{h} hours #{m} minutes and #{s} seconds"
|
100
|
+
get_runtime
|
99
101
|
end
|
102
|
+
alias scan_runtime runtime
|
100
103
|
|
101
104
|
#
|
102
105
|
# Return the Host Netbios Name.
|
@@ -108,7 +111,9 @@ module Nessus
|
|
108
111
|
# host.netbios_name #=> "SOMENAME4243"
|
109
112
|
#
|
110
113
|
def netbios_name
|
111
|
-
|
114
|
+
if (netbios = @host.at('tag[name=netbios-name]'))
|
115
|
+
netbios.inner_text
|
116
|
+
end
|
112
117
|
end
|
113
118
|
|
114
119
|
#
|
@@ -121,7 +126,9 @@ module Nessus
|
|
121
126
|
# host.mac_addr #=> "00:11:22:33:44:55"
|
122
127
|
#
|
123
128
|
def mac_addr
|
124
|
-
|
129
|
+
if (mac_addr = @host.at('tag[name=mac-addr]'))
|
130
|
+
mac_addr.inner_text
|
131
|
+
end
|
125
132
|
end
|
126
133
|
alias mac_address mac_addr
|
127
134
|
|
@@ -135,7 +142,9 @@ module Nessus
|
|
135
142
|
# host.dns_name #=> "Microsoft Windows 2000, Microsoft Windows Server 2003"
|
136
143
|
#
|
137
144
|
def os_name
|
138
|
-
|
145
|
+
if (os_name = @host.at('tag[name=operating-system]'))
|
146
|
+
os_name.inner_text
|
147
|
+
end
|
139
148
|
end
|
140
149
|
alias os os_name
|
141
150
|
alias operating_system os_name
|
@@ -244,7 +253,7 @@ module Nessus
|
|
244
253
|
|
245
254
|
@medium_severity_events.each(&block)
|
246
255
|
end
|
247
|
-
|
256
|
+
|
248
257
|
def medium_severity
|
249
258
|
Enumerator.new(self,:medium_severity_events).to_a
|
250
259
|
end
|
@@ -479,9 +488,20 @@ module Nessus
|
|
479
488
|
raise "Error: #{type} is not an acceptable severity. Possible options include: all, tdp, udp, icmp, high, medium and low."
|
480
489
|
end
|
481
490
|
end
|
482
|
-
|
491
|
+
|
483
492
|
private
|
484
493
|
|
494
|
+
def get_runtime
|
495
|
+
if stop_time && start_time
|
496
|
+
h = ("#{Time.parse(stop_time.to_s).strftime('%H').to_i - Time.parse(start_time.to_s).strftime('%H').to_i}").gsub('-', '')
|
497
|
+
m = ("#{Time.parse(stop_time.to_s).strftime('%M').to_i - Time.parse(start_time.to_s).strftime('%M').to_i}").gsub('-', '')
|
498
|
+
s = ("#{Time.parse(stop_time.to_s).strftime('%S').to_i - Time.parse(start_time.to_s).strftime('%S').to_i}").gsub('-', '')
|
499
|
+
return "#{h} hours #{m} minutes and #{s} seconds"
|
500
|
+
else
|
501
|
+
false
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
485
505
|
def host_stats
|
486
506
|
|
487
507
|
unless @host_stats
|
@@ -510,14 +530,14 @@ module Nessus
|
|
510
530
|
end
|
511
531
|
|
512
532
|
@host_stats = {:open_ports => @open_ports,
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
533
|
+
:tcp => @tcp,
|
534
|
+
:udp => @udp,
|
535
|
+
:icmp => @icmp,
|
536
|
+
:informational => @informational,
|
537
|
+
:low => @low,
|
538
|
+
:medium => @medium,
|
539
|
+
:high => @high,
|
540
|
+
:all => (@low + @medium + @high)}
|
521
541
|
|
522
542
|
end
|
523
543
|
@host_stats
|
@@ -27,12 +27,16 @@ module Nessus
|
|
27
27
|
# scan.report_name
|
28
28
|
# end
|
29
29
|
#
|
30
|
-
def initialize(
|
31
|
-
@
|
32
|
-
@xml = Nokogiri::XML.parse(@file.read)
|
30
|
+
def initialize(xml)
|
31
|
+
@xml = xml
|
33
32
|
raise "Error: Not A Version 2.0 .Nessus file." unless @xml.at('NessusClientData_v2')
|
34
33
|
end
|
35
|
-
|
34
|
+
|
35
|
+
|
36
|
+
def version
|
37
|
+
2
|
38
|
+
end
|
39
|
+
|
36
40
|
#
|
37
41
|
# Return the nessus report title.
|
38
42
|
#
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ruby-nessus/nessus'
|
3
|
+
require 'ruby-nessus/log'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
module Nessus
|
9
|
+
|
10
|
+
class CLI
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@file = nil
|
14
|
+
@nessus_version = nil
|
15
|
+
@args = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def CLI.run
|
19
|
+
self.new.run(*ARGV)
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(*args)
|
23
|
+
optparse(*args)
|
24
|
+
|
25
|
+
Log.it "Recess - Ruby-Nessus CLI"
|
26
|
+
Log.it "Version: #{Nessus::VERSION}"
|
27
|
+
Log.it
|
28
|
+
|
29
|
+
Nessus::Parse.new("#{@file}") do |scan|
|
30
|
+
|
31
|
+
Log.h1 "SCAN Metadata"
|
32
|
+
Log.it
|
33
|
+
Log.h2 "Scan Title", scan.title
|
34
|
+
Log.h2 "Policy Title", scan.policy_title
|
35
|
+
Log.it
|
36
|
+
Log.h1 "SCAN Statistics"
|
37
|
+
Log.it
|
38
|
+
Log.h2 "Host Count", scan.host_count
|
39
|
+
Log.h2 "Open Port Count", scan.open_ports_count
|
40
|
+
|
41
|
+
unless scan.version == 1
|
42
|
+
Log.h2 "TCP Count", scan.tcp_count
|
43
|
+
Log.h2 "UDP Count", scan.udp_count
|
44
|
+
Log.h2 "ICMP Count", scan.icmp_count
|
45
|
+
end
|
46
|
+
|
47
|
+
Log.it
|
48
|
+
Log.h1 "EVENT Statistics"
|
49
|
+
Log.it
|
50
|
+
|
51
|
+
unless scan.version == 1
|
52
|
+
Log.informational "Informational Severity Count", scan.informational_severity_count
|
53
|
+
end
|
54
|
+
Log.low "Low Severity Count", scan.low_severity_count
|
55
|
+
Log.medium "Medium Severity Count", scan.medium_severity_count
|
56
|
+
Log.high "High Severity Count", scan.high_severity_count
|
57
|
+
Log.h3 "Total Event Count", scan.total_event_count
|
58
|
+
Log.break
|
59
|
+
Log.it! "Low Event Percentage: #{scan.event_percentage_for('low', true)}"
|
60
|
+
Log.it! "Medium Event Percentage: #{scan.event_percentage_for('medium', true)}"
|
61
|
+
Log.it! "High Event Percentage: #{scan.event_percentage_for('high', true)}"
|
62
|
+
Log.it
|
63
|
+
|
64
|
+
Log.h1 "HOSTS"
|
65
|
+
Log.it
|
66
|
+
|
67
|
+
scan.each_host do |host|
|
68
|
+
Log.h2 "Hostname", host.hostname
|
69
|
+
Log.h5 "IP Address:", host.ip
|
70
|
+
Log.h5 "Informational Count", host.informational_severity_count
|
71
|
+
Log.h5 "Low Count", host.low_severity_count
|
72
|
+
Log.h5 "Medium Count", host.medium_severity_count
|
73
|
+
Log.h5 "High Count", host.high_severity_count
|
74
|
+
Log.it
|
75
|
+
end
|
76
|
+
|
77
|
+
Log.end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
def optparse(*args)
|
86
|
+
opts = OptionParser.new
|
87
|
+
opts.program_name = "recess"
|
88
|
+
opts.banner = "Recess #{Nessus::VERSION}"
|
89
|
+
opts.separator "usage: recess FILE [OPTIONS]"
|
90
|
+
|
91
|
+
opts.on('-f','--file FILE','The .nessus file to parse.') do |file|
|
92
|
+
@file = file
|
93
|
+
end
|
94
|
+
|
95
|
+
opts.on('-f','--file FILE','The .nessus file to parse.') do |file|
|
96
|
+
@file = file
|
97
|
+
end
|
98
|
+
|
99
|
+
opts.on('-h','--help','This help summary page.') do |help|
|
100
|
+
Log.it opts
|
101
|
+
Log.it
|
102
|
+
exit -1
|
103
|
+
end
|
104
|
+
|
105
|
+
opts.on('-v','--version','Recess Version.') do |version|
|
106
|
+
Log.it Nessus::VERSION
|
107
|
+
Log.it
|
108
|
+
exit -1
|
109
|
+
end
|
110
|
+
|
111
|
+
begin
|
112
|
+
@args = opts.parse!(args)
|
113
|
+
@file ||= @args[0]
|
114
|
+
if @file.nil?
|
115
|
+
Log.it opts
|
116
|
+
Log.it
|
117
|
+
exit -1
|
118
|
+
end
|
119
|
+
rescue => e
|
120
|
+
Log.error e.message
|
121
|
+
Log.it opts
|
122
|
+
Log.it
|
123
|
+
exit -1
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rainbow'
|
2
|
+
module Nessus
|
3
|
+
|
4
|
+
class Log
|
5
|
+
|
6
|
+
#
|
7
|
+
# Formatting
|
8
|
+
#
|
9
|
+
def self.it(msg=nil)
|
10
|
+
STDERR.puts "#{msg}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.it!(msg=nil)
|
14
|
+
STDERR.puts "\t#{msg}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.break
|
18
|
+
STDERR.puts "\t"
|
19
|
+
STDERR.puts ""
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.end
|
23
|
+
STDERR.puts "\n\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Headers
|
28
|
+
#
|
29
|
+
def self.h1(title, msg=nil)
|
30
|
+
STDERR.puts "-> #{title}: ".foreground(:green).bright + "#{msg}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.h2(title, msg=nil)
|
34
|
+
STDERR.puts "\t#{title}: ".foreground(:blue).bright + "#{msg}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.h3(title, msg=nil)
|
38
|
+
STDERR.puts "\t#{title}: " + "#{msg}".foreground(:blue).underline
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.h4(msg=nil)
|
42
|
+
STDERR.puts "\t\t- #{msg}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.h5(title, msg=nil)
|
46
|
+
STDERR.puts "\t\t- #{title}: #{msg}"
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Errors
|
51
|
+
#
|
52
|
+
def self.error(msg=nil)
|
53
|
+
STDERR.puts "ERROR: ".foreground(:red).bright + "#{msg}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.warn(msg=nil)
|
57
|
+
STDERR.puts "WARNING: ".foreground(:yellow).bright + "#{msg}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.info(msg=nil)
|
61
|
+
STDERR.puts "INFO: ".foreground(:green).bright + "#{msg}"
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Event Severities
|
66
|
+
#
|
67
|
+
def self.informational(title, msg=nil)
|
68
|
+
STDERR.puts "\t#{title}: ".foreground(:magenta).bright + "#{msg}"
|
69
|
+
end
|
70
|
+
def self.low(title, msg=nil)
|
71
|
+
STDERR.puts "\t#{title}: ".foreground(:green) + "#{msg}"
|
72
|
+
end
|
73
|
+
def self.medium(title, msg=nil)
|
74
|
+
STDERR.puts "\t#{title}: ".foreground(:yellow).bright + "#{msg}"
|
75
|
+
end
|
76
|
+
def self.high(title, msg=nil)
|
77
|
+
STDERR.puts "\t#{title}: ".foreground(:red).bright + "#{msg}"
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/lib/ruby-nessus/parse.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'ruby-nessus/log'
|
1
2
|
require 'ruby-nessus/Version1/version1'
|
2
3
|
require 'ruby-nessus/Version2/version2'
|
3
4
|
|
4
5
|
require 'nokogiri'
|
6
|
+
require 'date'
|
5
7
|
require 'enumerator'
|
6
8
|
require 'time'
|
7
9
|
|
@@ -9,27 +11,31 @@ module Nessus
|
|
9
11
|
|
10
12
|
class Parse
|
11
13
|
|
12
|
-
def initialize(file,
|
13
|
-
@file = file
|
14
|
-
@version =
|
14
|
+
def initialize(file, options={}, &block)
|
15
|
+
@file = File.open(file)
|
16
|
+
@version = options[:version]
|
17
|
+
@xml = Nokogiri::XML.parse(@file.read)
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
block.call(Version2::XML.new(file)) if block
|
19
|
+
if @version
|
20
|
+
case @version
|
21
|
+
when 1
|
22
|
+
block.call(Version1::XML.new(@xml)) if block
|
23
|
+
when 2
|
24
|
+
block.call(Version2::XML.new(@xml)) if block
|
25
|
+
else
|
26
|
+
raise "Error: Supported .Nessus Version are 1 and 2."
|
25
27
|
end
|
26
28
|
else
|
27
|
-
|
29
|
+
if @xml.at('NessusClientData')
|
30
|
+
block.call(Version1::XML.new(@xml)) if block
|
31
|
+
elsif @xml.at('NessusClientData_v2')
|
32
|
+
block.call(Version2::XML.new(@xml)) if block
|
33
|
+
else
|
34
|
+
raise "Error: Supported .Nessus Version are 1 and 2."
|
35
|
+
end
|
28
36
|
end
|
29
|
-
|
30
|
-
end
|
31
37
|
|
32
|
-
|
38
|
+
end
|
33
39
|
|
34
40
|
end
|
35
41
|
end
|
data/spec/helpers/xml.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Helpers
|
2
|
-
|
3
|
-
|
2
|
+
v1 = File.join(File.dirname(__FILE__),'example_v1.nessus')
|
3
|
+
v2 = File.join(File.dirname(__FILE__),'example_v2.nessus')
|
4
|
+
DOT_NESSUS_V1 = Nokogiri::XML.parse(File.open(v1).read)
|
5
|
+
DOT_NESSUS_V2 = Nokogiri::XML.parse(File.open(v2).read)
|
4
6
|
end
|
data/spec/ruby-nessus_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-nessus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dustin Willis Webber
|
@@ -9,8 +9,8 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
13
|
-
default_executable:
|
12
|
+
date: 2010-03-29 00:00:00 -04:00
|
13
|
+
default_executable: recess
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: nokogiri
|
@@ -22,6 +22,16 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: 1.4.0
|
24
24
|
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rainbow
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.4
|
34
|
+
version:
|
25
35
|
- !ruby/object:Gem::Dependency
|
26
36
|
name: rspec
|
27
37
|
type: :development
|
@@ -44,8 +54,8 @@ dependencies:
|
|
44
54
|
version:
|
45
55
|
description: Ruby-Nessus aims to deliver an easy yet powerful interface for interacting and manipulating Nessus scan results and configurations.
|
46
56
|
email: dustin.webber@gmail.com
|
47
|
-
executables:
|
48
|
-
|
57
|
+
executables:
|
58
|
+
- recess
|
49
59
|
extensions: []
|
50
60
|
|
51
61
|
extra_rdoc_files:
|
@@ -56,7 +66,7 @@ files:
|
|
56
66
|
- LICENSE
|
57
67
|
- README.rdoc
|
58
68
|
- Rakefile
|
59
|
-
-
|
69
|
+
- bin/recess
|
60
70
|
- examples/example.rb
|
61
71
|
- examples/example_v1.nessus
|
62
72
|
- examples/example_v2.nessus
|
@@ -70,9 +80,12 @@ files:
|
|
70
80
|
- lib/ruby-nessus/Version2/host.rb
|
71
81
|
- lib/ruby-nessus/Version2/port.rb
|
72
82
|
- lib/ruby-nessus/Version2/version2.rb
|
83
|
+
- lib/ruby-nessus/cli.rb
|
73
84
|
- lib/ruby-nessus/core_ext/helpers.rb
|
85
|
+
- lib/ruby-nessus/log.rb
|
74
86
|
- lib/ruby-nessus/nessus.rb
|
75
87
|
- lib/ruby-nessus/parse.rb
|
88
|
+
- lib/ruby-nessus/version.rb
|
76
89
|
- spec/Version1/event_spec.rb
|
77
90
|
- spec/Version1/host_spec.rb
|
78
91
|
- spec/Version1/scan_spec.rb
|
@@ -84,8 +97,6 @@ files:
|
|
84
97
|
- spec/helpers/xml.rb
|
85
98
|
- spec/ruby-nessus_spec.rb
|
86
99
|
- spec/spec_helper.rb
|
87
|
-
- tasks/spec.rb
|
88
|
-
- tasks/yard.rb
|
89
100
|
has_rdoc: true
|
90
101
|
homepage: http://github.com/mephux/ruby-nessus
|
91
102
|
licenses: []
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.0.0
|
data/tasks/spec.rb
DELETED