ruby-nessus 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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