prenus 0.0.3 → 0.0.4

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