ruby-nessus 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,79 @@
1
+ module Nessus
2
+ module Version2
3
+
4
+ class Port
5
+
6
+ # Port Service
7
+ attr_reader :service
8
+ # Port number
9
+ attr_reader :number
10
+ # Port Protocol
11
+ attr_reader :protocol
12
+
13
+ #
14
+ # Creates A New Port Object
15
+ #
16
+ # @param [String] number The port number.
17
+ #
18
+ # @param [String] service The port service.
19
+ #
20
+ # @param [String] protocol The port protocol.
21
+ #
22
+ # @example
23
+ # Port.new(number, service, )
24
+ #
25
+ def initialize(number, service, protocol)
26
+ @number = number
27
+ @service = service
28
+ @protocol = protocol
29
+ end
30
+
31
+ #
32
+ # Return true if the port protocol is tcp.
33
+ #
34
+ # @return [Boolean]
35
+ # Return True If The Port Protocol Is TCP.
36
+ #
37
+ def tcp?
38
+ @protocol.to_s == 'tcp'
39
+ end
40
+
41
+ #
42
+ # Return true if the port protocol is udp.
43
+ #
44
+ # @return [Boolean]
45
+ # Return True If The Port Protocol Is UDP.
46
+ #
47
+ def udp?
48
+ @protocol.to_s == 'udp'
49
+ end
50
+
51
+ #
52
+ # Return true if the port protocol is icmp.
53
+ #
54
+ # @return [Boolean]
55
+ # Return True If The Port Protocol Is ICMP.
56
+ #
57
+ def icmp?
58
+ @protocol.to_s == 'icmp'
59
+ end
60
+
61
+ #
62
+ # Return the port as a string.
63
+ #
64
+ # @return [String]
65
+ # Return The Port As A String
66
+ #
67
+ # @example
68
+ # port.to_s #=> https (443/tcp)
69
+ #
70
+ def to_s
71
+ "#{@service} (#{@number}/#{@protocol})"
72
+ end
73
+
74
+
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,359 @@
1
+ require 'ruby-nessus/Version2/host'
2
+ require 'ruby-nessus/Version2/event'
3
+
4
+ module Nessus
5
+
6
+ # .Nessus Version 2 Schema
7
+ module Version2
8
+
9
+ # File to parse
10
+ attr_reader :file
11
+
12
+ class XML
13
+
14
+ include Enumerable
15
+
16
+ #
17
+ # Creates a new .Nessus (XML) object to be parser
18
+ #
19
+ # @param [String] file The Nessus xml results file to parse.
20
+ #
21
+ # @yield [prog] If a block is given, it will be passed the newly
22
+ # created XML object.
23
+ # @yieldparam [XML] prog The newly created XML object.
24
+ #
25
+ # @example
26
+ # Nessus::XML.new(nessus_scan_file) do |scan|
27
+ # scan.report_name
28
+ # end
29
+ #
30
+ def initialize(file)
31
+ @file = File.open(file)
32
+ @xml = Nokogiri::XML.parse(@file.read)
33
+ raise "Error: Not A Version 2.0 .Nessus file." unless @xml.at('NessusClientData_v2')
34
+ end
35
+
36
+ #
37
+ # Return the nessus report title.
38
+ #
39
+ # @return [String]
40
+ # The Nessus Report Title
41
+ #
42
+ # @example
43
+ # scan.report_name #=> "My Super Cool Nessus Report"
44
+ #
45
+ def title
46
+ @report_name ||= @xml.at('Report/@name').inner_text
47
+ end
48
+
49
+ #
50
+ # Return the nessus scan policy name. When creating a nessus policy this is usually the title field.
51
+ #
52
+ # @return [String]
53
+ # The Nessus Scan Policy Name
54
+ #
55
+ def policy_title
56
+ @policy_name ||= @xml.at("//Policy/policyName").inner_text
57
+ end
58
+
59
+ #
60
+ # Return the nessus scan policy comments. This is the description field when creating a new policy with the Nessus GUI client.
61
+ #
62
+ # @return [String]
63
+ # The Nessus Scan Policy Comments
64
+ #
65
+ def policy_notes
66
+ @policy_notes ||= @xml.at("//Policy/policyComments").inner_text
67
+ end
68
+
69
+ #
70
+ # Creates a new Host object to be parser
71
+ #
72
+ # @yield [prog] If a block is given, it will be passed the newly
73
+ # created Host object.
74
+ # @yieldparam [XML] prog The newly created Host object.
75
+ #
76
+ # @example
77
+ # scan.hosts do |host|
78
+ # puts host.hostname
79
+ # end
80
+ #
81
+ def each_host(&block)
82
+ hosts = []
83
+ @xml.xpath("//ReportHost").each do |host|
84
+ hosts << host['name'] if host['name']
85
+ block.call(Host.new(host)) if block
86
+ end
87
+ hosts
88
+ end
89
+
90
+ #
91
+ # Parses the hosts of the scan.
92
+ #
93
+ # @return [Array<String>]
94
+ # The Hosts of the scan.
95
+ #
96
+ def hosts
97
+ Enumerator.new(self,:each_host).to_a
98
+ end
99
+
100
+ #
101
+ # Return the nessus scan host count.
102
+ #
103
+ # @return [Integer]
104
+ # The Nessus Scan Host Count
105
+ #
106
+ # @example
107
+ # scan.host_count #=> 23
108
+ #
109
+ def host_count
110
+ each_host.size
111
+ end
112
+
113
+ #
114
+ # Retunrs an array of all unique ports.
115
+ #
116
+ # @return [Array]
117
+ #
118
+ # @example
119
+ # scan.unique_ports #=> 234
120
+ #
121
+ def unique_ports
122
+ unless @unique_ports
123
+ @unique_ports = []
124
+ @xml.xpath("//ReportItem").each do |port|
125
+ @unique_ports << port['port']
126
+ end
127
+ @unique_ports.uniq!
128
+ @unique_ports.sort!
129
+ end
130
+ end
131
+
132
+ #
133
+ # Return the Open Ports count.
134
+ #
135
+ # @return [Integer]
136
+ # The Open Ports Count
137
+ #
138
+ # @example
139
+ # scan.open_ports_count #=> 1203
140
+ #
141
+ def open_ports_count
142
+ count_stats[:open_ports].to_i
143
+ end
144
+
145
+ #
146
+ # Return the TCP Event Count.
147
+ #
148
+ # @return [Integer]
149
+ # The TCP Event Count
150
+ #
151
+ # @example
152
+ # scan.tcp_count #=> 3
153
+ #
154
+ def tcp_count
155
+ count_stats[:tcp].to_i
156
+ end
157
+
158
+ #
159
+ # Return the UDP Event Count.
160
+ #
161
+ # @return [Integer]
162
+ # The UDP Event Count
163
+ #
164
+ # @example
165
+ # scan.udp_count #=> 3
166
+ #
167
+ def udp_count
168
+ count_stats[:udp].to_i
169
+ end
170
+
171
+ #
172
+ # Return the ICMP Event Count.
173
+ #
174
+ # @return [Integer]
175
+ # The ICMP Event Count
176
+ #
177
+ # @example
178
+ # scan.icmp_count #=> 3
179
+ #
180
+ def icmp_count
181
+ count_stats[:icmp].to_i
182
+ end
183
+
184
+ #
185
+ # Return the informational severity count.
186
+ #
187
+ # @return [Integer]
188
+ # The Informational Severity Count
189
+ #
190
+ # @example
191
+ # scan.informational_severity_count #=> 1203
192
+ #
193
+ def informational_severity_count
194
+ count_stats[:informational].to_i
195
+ end
196
+
197
+ #
198
+ # Return the High severity count.
199
+ #
200
+ # @return [Integer]
201
+ # The High Severity Count
202
+ #
203
+ # @example
204
+ # scan.high_severity_count #=> 10
205
+ #
206
+ def high_severity_count
207
+ count_stats[:high].to_i
208
+ end
209
+
210
+ #
211
+ # Return the Medium severity count.
212
+ #
213
+ # @return [Integer]
214
+ # The Medium Severity Count
215
+ #
216
+ # @example
217
+ # scan.medium_severity_count #=> 234
218
+ #
219
+ def medium_severity_count
220
+ count_stats[:medium].to_i
221
+ end
222
+
223
+ #
224
+ # Return the Low severity count.
225
+ #
226
+ # @return [Integer]
227
+ # The Low Severity Count
228
+ #
229
+ # @example
230
+ # scan.low_severity_count #=> 114
231
+ #
232
+ def low_severity_count
233
+ count_stats[:low].to_i
234
+ end
235
+
236
+ #
237
+ # Return the Total severity count. [high, medium, low, informational]
238
+ #
239
+ # @param [true, false] argname only true or false
240
+ #
241
+ # @return [Integer]
242
+ # The Total Severity Count
243
+ #
244
+ # @example
245
+ # scan.total_event_count #=> 1561
246
+ #
247
+ def total_event_count(count_informational = false)
248
+ if count_informational
249
+ count_stats[:all].to_i + informational_severity_count
250
+ else
251
+ count_stats[:all].to_i
252
+ end
253
+ end
254
+
255
+ #
256
+ # Return the Total severity count.
257
+ #
258
+ # @param [String] severity the severity in which to calculate percentage for.
259
+ #
260
+ # @param [Boolean] round round the result to the nearest whole number.
261
+ #
262
+ # @raise [ExceptionClass] One of the following severity options must be passed. [high, medium, low, informational, all]
263
+ #
264
+ # @return [Integer]
265
+ # The Percentage Of Events For A Passed Severity
266
+ #
267
+ # @example
268
+ # scan.event_percentage_for("low", true) #=> 11%
269
+ #
270
+ def event_percentage_for(type, round_percentage=false)
271
+ @sc ||= count_stats
272
+ if %W(high medium low tcp udp icmp all).include?(type)
273
+ calc = ((@sc[:"#{type}"].to_f / (@sc[:all].to_f)) * 100)
274
+ if round_percentage
275
+ return "#{calc.round}"
276
+ else
277
+ return "#{calc}"
278
+ end
279
+ else
280
+ raise "Error: #{type} is not an acceptable severity. Possible options include: all, tdp, udp, icmp, high, medium and low."
281
+ end
282
+ end
283
+
284
+ #
285
+ # Creates a new Host object to be parser from a passed search param.
286
+ #
287
+ # @param [String] hostname the hostname to build a Host object for.
288
+ #
289
+ # @yield [prog] If a block is given, it will be passed the newly
290
+ # created Host object.
291
+ #
292
+ # @yieldparam [XML] prog The newly created Host object.
293
+ #
294
+ # @example
295
+ # scan.find_by_hostname('127.0.0.1') do |host|
296
+ # puts host.hostname
297
+ # end
298
+ #
299
+ def find_by_hostname(hostname, &block)
300
+ raise "Error: hostname can't be blank." if hostname.blank?
301
+ @xml.xpath('//ReportHost').each do |host|
302
+ next unless host['name'].match(hostname)
303
+ block.call(Host.new(host)) if block
304
+ end
305
+ end
306
+
307
+ private
308
+
309
+ #
310
+ # Calculates an event hash of totals for severity counts.
311
+ #
312
+ # @return [Hash]
313
+ # The Event Totals For Severity
314
+ #
315
+ def count_stats
316
+ unless @count
317
+ @count = {}
318
+ @open_ports, @tcp, @udp, @icmp, @informational, @low, @medium, @high = 0,0,0,0,0,0,0,0
319
+
320
+ @xml.xpath("//ReportItem").each do |s|
321
+ case s['severity'].to_i
322
+ when 0
323
+ @informational += 1
324
+ when 1
325
+ @low += 1
326
+ when 2
327
+ @medium += 1
328
+ when 3
329
+ @high += 1
330
+ end
331
+
332
+ unless s['severity'].to_i == 0
333
+ @tcp += 1 if s['protocol'] == 'tcp'
334
+ @udp += 1 if s['protocol'] == 'udp'
335
+ @icmp += 1 if s['protocol'] == 'icmp'
336
+ end
337
+
338
+ @open_ports += 1 if s['port'].to_i != 0
339
+ end
340
+
341
+ @count = {:open_ports => @open_ports,
342
+ :tcp => @tcp,
343
+ :udp => @udp,
344
+ :icmp => @icmp,
345
+ :informational => @informational,
346
+ :low => @low,
347
+ :medium => @medium,
348
+ :high => @high,
349
+ :all => (@low + @medium + @high)}
350
+ end
351
+
352
+ return @count
353
+ end
354
+
355
+ end
356
+
357
+
358
+ end
359
+ end
@@ -1,14 +1,6 @@
1
- require 'ruby-nessus/xml'
1
+ require 'ruby-nessus/parse'
2
2
  require 'ruby-nessus/core_ext/helpers'
3
3
 
4
4
  module Nessus
5
5
 
6
- class Parse
7
-
8
- def initialize(file, options={})
9
-
10
- end
11
-
12
- end
13
-
14
6
  end