ruby-nessus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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