ruby-nessus 0.1.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.
@@ -0,0 +1,6 @@
1
+ require 'ruby-nessus/xml'
2
+ require 'ruby-nessus/core_ext/helpers'
3
+
4
+ module Nessus
5
+
6
+ end
@@ -0,0 +1,86 @@
1
+ module Nessus
2
+ class Port
3
+
4
+ # Port Service
5
+ attr_reader :service
6
+ # Port number
7
+ attr_reader :number
8
+ # Port Protocol
9
+ attr_reader :protocol
10
+ # Raw output string from nessus
11
+ attr_reader :raw_string
12
+
13
+ # Creates A New Port Object
14
+ # @param [String] service The Port Service.
15
+ # @param [Integer] number The Port number.
16
+ # @param [String] protocol The Port protocol.
17
+ # @param [String] raw output string from nessus.
18
+ # @example
19
+ # Port.new("ssh",22,"tcp", str)
20
+ def initialize(service,number,protocol,raw_string)
21
+ @service = service
22
+ @number = number
23
+ @protocol = protocol
24
+ @raw_string = raw_string
25
+ end
26
+
27
+ # Parse A passed port string and return a Port Object.
28
+ # @return [Object]
29
+ # New Port Object
30
+ # @example
31
+ # Port.parse(port)
32
+ def Port.parse(str)
33
+ begin
34
+ @full_port = str
35
+ components = str.match(/^([^\(]+)\((\d+)\/([^\)]+)\)/)
36
+
37
+ if components
38
+ return Port.new(components[1].strip, components[2].strip, components[3].strip, str)
39
+ else
40
+ return Port.new(false, false, false, str)
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ # Return true iF port protocol Ii tcp.
48
+ # @return [Boolean]
49
+ # Return True If The Port Protocol Is TCP.
50
+ def tcp?
51
+ @protocol == 'tcp'
52
+ end
53
+
54
+ # Return true iF port protocol Ii udp.
55
+ # @return [Boolean]
56
+ # Return True If The Port Protocol Is UDP.
57
+ def udp?
58
+ @protocol == 'udp'
59
+ end
60
+
61
+ # Return the port as a string.
62
+ # @return [String]
63
+ # Return The Port As A String
64
+ # @example
65
+ # port.to_s #=> https (443/tcp)
66
+ def to_s
67
+ if @service && @number && @protocol
68
+ "#{@service} (#{@number}/#{@protocol})"
69
+ else
70
+ "#{@raw_string}"
71
+ end
72
+ end
73
+
74
+ # Return false if the port object number is nil
75
+ # @return [Boolean]
76
+ # Return false if the port object number is nil
77
+ def number
78
+ if @number
79
+ return @number
80
+ else
81
+ false
82
+ end
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,5 @@
1
+ module Nessus
2
+ # Ruby-Nessus
3
+ # Copyright (c) 2009 Dustin Willis Webber
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,285 @@
1
+ require 'ruby-nessus/host'
2
+ require 'ruby-nessus/event'
3
+ require 'nokogiri'
4
+ require 'time'
5
+
6
+ module Nessus
7
+ # File to parse
8
+ attr_reader :file
9
+
10
+ class XML
11
+
12
+ # Creates a new .Nessus (XML) object to be parser
13
+ # @param [String] file The Nessus xml results file to parse.
14
+ # @yield [prog] If a block is given, it will be passed the newly
15
+ # created XML object.
16
+ # @yieldparam [XML] prog The newly created XML object.
17
+ # @example
18
+ # Nessus::XML.new(nessus_scan_file) do |scan|
19
+ # scan.report_name
20
+ # end
21
+ def initialize(file, &block)
22
+
23
+ @file = File.open(file)
24
+ @xml = Nokogiri::XML.parse(@file.read)
25
+
26
+ block.call(self) if block
27
+ end
28
+
29
+ # Return the nessus report title.
30
+ # @return [String]
31
+ # The Nessus Report Title
32
+ # @example
33
+ # scan.report_name #=> "My Super Cool Nessus Report"
34
+ def report_name
35
+ @report_name ||= @xml.xpath("//NessusClientData//Report//ReportName").inner_text
36
+ end
37
+
38
+ # Return the scan start time.
39
+ # @return [DateTime]
40
+ # The Nessus Scan Start Time
41
+ # @example
42
+ # scan.start_time #=> 'Fri Nov 11 23:36:54 1985'
43
+ def start_time
44
+ @start_time = @xml.xpath("//NessusClientData//Report//StartTime").inner_text
45
+ end
46
+
47
+ # Return the scan stop time.
48
+ # @return [DateTime]
49
+ # The Nessus Scan Stop Time
50
+ # @example
51
+ # scan.stop_time #=> 'Mon Nov 11 23:36:54 1985'
52
+ def stop_time
53
+ @stop_time = @xml.xpath("//NessusClientData//Report//StopTime").inner_text
54
+ end
55
+
56
+ # Return the scan run time.
57
+ # @return [String]
58
+ # The Nessus Scan Run Time
59
+ # @example
60
+ # scan.runtime #=> '2 hours 5 minutes and 16 seconds'
61
+ def runtime
62
+ h = ("#{Time.parse(stop_time).strftime('%H').to_i - Time.parse(start_time).strftime('%H').to_i}").gsub('-', '')
63
+ m = ("#{Time.parse(stop_time).strftime('%M').to_i - Time.parse(start_time).strftime('%M').to_i}").gsub('-', '')
64
+ s = ("#{Time.parse(stop_time).strftime('%S').to_i - Time.parse(start_time).strftime('%S').to_i}").gsub('-', '')
65
+ return "#{h} hours #{m} minutes and #{s} seconds"
66
+ end
67
+
68
+ # Return the nessus scan policy name. When creating a nessus policy this is usually the title field.
69
+ # @return [String]
70
+ # The Nessus Scan Policy Name
71
+ def policy_name
72
+ @policy_name ||= @xml.xpath("//NessusClientData//Report//policyName").inner_text
73
+ end
74
+
75
+ # Return the nessus scan policy comments. This is the description field when creating a new policy with the Nessus GUI client.
76
+ # @return [String]
77
+ # The Nessus Scan Policy Comments
78
+ def policy_comments
79
+ @policy_comments ||= @xml.xpath("//NessusClientData//Report//policyComments").inner_text
80
+ end
81
+
82
+ # Returns and array of the plugin ids userd for the passed .nessus scan.
83
+ # @return [Array]
84
+ # The Nessus Scan Plugin Ids
85
+ # @example
86
+ # scan.policy_name #=> [1234,2343,9742,5452,5343,2423,1233]
87
+ def plugin_ids
88
+ unless @plugin_ids
89
+ @plugin_ids = []
90
+
91
+ @xml.xpath("//PluginSelection").last.text.split(';').each do |id|
92
+ @plugin_ids << id
93
+ end
94
+ end
95
+
96
+ @plugin_ids
97
+ end
98
+
99
+ # Returns and array of the plugin names userd for the passed .nessus scan.
100
+ # @return [Array]
101
+ # The Nessus Scan Plugin Names
102
+ # @example
103
+ # scan.policy_name #=> ["PHP < 5.2.1 Multiple Vulnerabilities", "PHP < 4.4.1 / 5.0.6 Multiple Vulnerabilities"]
104
+ def plugins
105
+ unless @plugins
106
+ # get elements with attribute:
107
+ @plugins = []
108
+
109
+ @xml.xpath("//pluginName").each do |x|
110
+ @plugins << x.inner_text unless x.inner_text.empty?
111
+ end
112
+
113
+ @plugins.uniq!
114
+ @plugins.sort!
115
+ end
116
+
117
+ return @plugins
118
+ end
119
+
120
+ # Creates a new Host object to be parser
121
+ # @yield [prog] If a block is given, it will be passed the newly
122
+ # created Host object.
123
+ # @yieldparam [XML] prog The newly created Host object.
124
+ # @example
125
+ # scan.hosts do |host|
126
+ # puts host.hostname
127
+ # end
128
+ def hosts(&block)
129
+ hosts = []
130
+ @xml.xpath("//ReportHost").each do |host|
131
+ hosts << host.at('HostName').inner_text if host.at('HostName').inner_text
132
+ block.call(Host.new(host)) if block
133
+ end
134
+ hosts
135
+ end
136
+
137
+ # Return the nessus scan host count.
138
+ # @return [Integer]
139
+ # The Nessus Scan Host Count
140
+ # @example
141
+ # scan.host_count #=> 23
142
+ def host_count
143
+ hosts.size
144
+ end
145
+
146
+ # Retunrs an array of all unique ports.
147
+ # @return [Array]
148
+ # @example
149
+ # scan.unique_ports #=> 234
150
+ def unique_ports
151
+ unless @unique_ports
152
+ @unique_ports = []
153
+ @xml.xpath("//ReportItem//port").each do |port|
154
+ @unique_ports << port.inner_text
155
+ end
156
+ @unique_ports.uniq!
157
+ @unique_ports.sort!
158
+ end
159
+ end
160
+
161
+ # Return the informational severity count.
162
+ # @return [Integer]
163
+ # The Informational Severity Count
164
+ # @example
165
+ # scan.informational_severity_count #=> 1203
166
+ def informational_severity_count
167
+ count_severity[:informational].to_i
168
+ end
169
+
170
+ # Return the High severity count.
171
+ # @return [Integer]
172
+ # The High Severity Count
173
+ # @example
174
+ # scan.high_severity_count #=> 10
175
+ def high_severity_count
176
+ count_severity[:high].to_i
177
+ end
178
+
179
+ # Return the Medium severity count.
180
+ # @return [Integer]
181
+ # The Medium Severity Count
182
+ # @example
183
+ # scan.medium_severity_count #=> 234
184
+ def medium_severity_count
185
+ count_severity[:medium].to_i
186
+ end
187
+
188
+ # Return the Low severity count.
189
+ # @return [Integer]
190
+ # The Low Severity Count
191
+ # @example
192
+ # scan.low_severity_count #=> 114
193
+ def low_severity_count
194
+ count_severity[:low].to_i
195
+ end
196
+
197
+ # Return the Total severity count. [high, medium, low, informational]
198
+ # @return [Integer]
199
+ # The Total Severity Count
200
+ # @example
201
+ # scan.total_event_count #=> 1561
202
+ def total_event_count
203
+ count_severity[:all].to_i
204
+ end
205
+
206
+ # Return the Total severity count.
207
+ # @param [String] severity the severity in which to calculate percentage for.
208
+ # @param [Boolean] round round the result to the nearest whole number.
209
+ # @raise [ExceptionClass] One of the following severity options must be passed. [high, medium, low, informational, all]
210
+ # @return [Integer]
211
+ # The Percentage Of Events For A Passed Severity
212
+ # @example
213
+ # scan.event_percentage_for("low", true) #=> 11%
214
+ def event_percentage_for(type, round_percentage=false)
215
+ @sc ||= count_severity
216
+ if %W(high medium low informational all).include?(type)
217
+ c = @sc[:"#{type}"].to_f
218
+ t = @sc[:all].to_f
219
+ c1 = (c / t) * 100
220
+ if round_percentage
221
+ return "#{c1.round}"
222
+ else
223
+ return "#{c1}"
224
+ end
225
+ else
226
+ raise "Error: #{type} is not an acceptable severity. Possible options include: all, high, medium, low and informational."
227
+ end
228
+ end
229
+
230
+ # Creates a new Host object to be parser from a passed search param.
231
+ # @param [String] hostname the hostname to build a Host object for.
232
+ # @yield [prog] If a block is given, it will be passed the newly
233
+ # created Host object.
234
+ # @yieldparam [XML] prog The newly created Host object.
235
+ # @example
236
+ # scan.find_by_hostname('127.0.0.1') do |host|
237
+ # puts host.hostname
238
+ # end
239
+ def find_by_hostname(hostname, &block)
240
+ raise "Error: hostname can't be blank." if hostname.blank?
241
+ @xml.xpath('//ReportHost[HostName]').each do |host|
242
+ next unless host.inner_text.match(hostname)
243
+ block.call(Host.new(host)) if block
244
+ end
245
+ end
246
+
247
+ private
248
+
249
+ # Calculates an event hash of totals for severity counts.
250
+ # @return [hash]
251
+ # The Event Totals For Severity
252
+ def count_severity
253
+ unless @count
254
+ @count = {}
255
+ @informational = 0
256
+ @low = 0
257
+ @medium = 0
258
+ @high = 0
259
+ @all = 0
260
+
261
+ @xml.xpath("//ReportItem//severity").each do |s|
262
+ case s.inner_text.to_i
263
+ when 0
264
+ @informational += 1
265
+ when 1
266
+ @low += 1
267
+ when 2
268
+ @medium += 1
269
+ when 3
270
+ @high += 1
271
+ end
272
+ end
273
+
274
+ @count[:informational] = @informational
275
+ @count[:low] = @low
276
+ @count[:medium] = @medium
277
+ @count[:high] = @high
278
+ @count[:all] = (@informational + @low + @medium + @high)
279
+ end
280
+
281
+ return @count
282
+ end
283
+
284
+ end
285
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe "RubyNessus" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,8 @@
1
+ require 'ruby-nessus'
2
+
3
+ require 'spec'
4
+ require 'spec/autorun'
5
+
6
+ Spec::Runner.configure do |config|
7
+
8
+ end
data/tasks/rdoc.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'rake/rdoctask'
2
+ Rake::RDocTask.new do |rdoc|
3
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
4
+
5
+ rdoc.rdoc_dir = 'rdoc'
6
+ rdoc.title = "ruby-nessus #{version}"
7
+ rdoc.rdoc_files.include('README*')
8
+ rdoc.rdoc_files.include('lib/**/*.rb')
9
+ end
data/tasks/spec.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'spec/rake/spectask'
2
+ Spec::Rake::SpecTask.new(:spec) do |spec|
3
+ spec.libs << 'lib' << 'spec'
4
+ spec.spec_files = FileList['spec/**/*_spec.rb']
5
+ end
6
+
7
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
8
+ spec.libs << 'lib' << 'spec'
9
+ spec.pattern = 'spec/**/*_spec.rb'
10
+ spec.rcov = true
11
+ end
12
+
13
+ task :spec => :check_dependencies
14
+ task :default => :spec
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-nessus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dustin Willis Webber
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-08 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: nokogiri
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: yard
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.2.3.5
44
+ version:
45
+ description: Ruby-Nessus aims to deliver an easy yet powerful interface for interacting and manipulating Nessus scan results and configurations.
46
+ email: dustin.webber@gmail.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.rdoc
54
+ files:
55
+ - .gitignore
56
+ - LICENSE
57
+ - README.rdoc
58
+ - Rakefile
59
+ - VERSION
60
+ - examples/example.nessus
61
+ - examples/example.rb
62
+ - lib/ruby-nessus.rb
63
+ - lib/ruby-nessus/core_ext/helpers.rb
64
+ - lib/ruby-nessus/event.rb
65
+ - lib/ruby-nessus/host.rb
66
+ - lib/ruby-nessus/nessus.rb
67
+ - lib/ruby-nessus/port.rb
68
+ - lib/ruby-nessus/version.rb
69
+ - lib/ruby-nessus/xml.rb
70
+ - spec/ruby-nessus_spec.rb
71
+ - spec/spec.opts
72
+ - spec/spec_helper.rb
73
+ - tasks/rdoc.rb
74
+ - tasks/spec.rb
75
+ has_rdoc: true
76
+ homepage: http://github.com/mephux/ruby-nessus
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --charset=UTF-8
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ version:
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ version:
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.3.5
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Ruby-Nessus is a ruby interface for the popular Nessus vulnerability scanner.
103
+ test_files:
104
+ - spec/ruby-nessus_spec.rb
105
+ - spec/spec_helper.rb
106
+ - examples/example.rb