prenus 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -58,7 +58,7 @@ By default this is html
58
58
 
59
59
  === Severity
60
60
 
61
- This option doesn't apply to the html output, but, for all other output types, this sets the bottom severity which will be included for output. For example, if severity is 0, then all vulnerabilities identified as informational, low, medium, high and critical will be included. If severity is 3 then only high and critical will be included.
61
+ This sets the bottom severity which will be included for output. For example, if severity is 0, then all vulnerabilities identified as informational, low, medium, high and critical will be included. If severity is 3 then only high and critical will be included.
62
62
 
63
63
  By default this is 3.
64
64
 
@@ -96,6 +96,7 @@ This will only work if you're in the Circos Tools tableviewer folder (in my inst
96
96
  This will dump the png into the img/ folder.
97
97
 
98
98
  == Changes
99
+ * Version 0.0.8 - Default HTML output directory - plus - can filter out severity issues for HTML. Updated gemspec, removed internal gem
99
100
  * Version 0.0.7 - Included push update for XLS output - and updated version statements
100
101
  * Version 0.0.6 - Updated the version in the prenus file
101
102
  * Version 0.0.5 - FUUUU Did it again. Botched the gem push #facepalm. This is identical to 0.0.4
data/bin/prenus CHANGED
@@ -19,9 +19,9 @@ require 'lib/input'
19
19
  require 'lib/gemcache/ruby-nessus/ruby-nessus'
20
20
 
21
21
  #Versioning and .. those things
22
- $verstring = "Version 0.0.7 - 22nd of June, 2013 - Created by Christian \"xntrik\" Frichot.\n\n"
22
+ $verstring = "Version 0.0.8 - 1st of October, 2013 - Created by Christian \"xntrik\" Frichot.\n\n"
23
23
  $verstring += "Copyright 2013 Christian Frichot\n\n"
24
- $verstring += "See LICENSE.txt for more details"
24
+ $verstring += "See LICENSE.txt for more details\n"
25
25
 
26
26
  class OptsConsole
27
27
  def self.parse(args)
@@ -87,7 +87,13 @@ class Htmlout < Baseout
87
87
  low_total += 1 if v[:severity] == 1
88
88
  end
89
89
 
90
- pie_js(f,"pie_graph","Vuln Breakdown","Vuln Breakdown",[['Low',low_total.to_i],['Medium',med_total.to_i],['High',high_total.to_i],['Critical',crit_total.to_i]],"document.location.href = 'vuln_overview.html';")
90
+ pie_data = []
91
+ pie_data << ['Low',low_total.to_i] if @options[:severity] <= 1
92
+ pie_data << ['Medium',med_total.to_i] if @options[:severity] <= 2
93
+ pie_data << ['High',high_total.to_i] if @options[:severity] <= 3
94
+ pie_data << ['Critical',crit_total.to_i] if @options[:severity] <= 4
95
+
96
+ pie_js(f,"pie_graph","Vuln Breakdown","Vuln Breakdown",pie_data,"document.location.href = 'vuln_overview.html';")
91
97
 
92
98
  target_lookup = "var target_lookup = {"
93
99
  @hosts.each_with_index do |host,index|
@@ -115,7 +121,7 @@ class Htmlout < Baseout
115
121
  ips << host[1][:ip]
116
122
  end
117
123
 
118
- body += '<table id="hosts_table" class="display"><thead><tr><th>IP</th><th>Hostname</th><th>OS</th><th>Number of vulns</th></tr></thead><tbody>'
124
+ body += '<table id="hosts_table" class="display"><thead><tr><th>IP</th><th>Hostname</th><th>OS</th><th>Number of vulns (Low to Critical)</th></tr></thead><tbody>'
119
125
  ips.sort_by{|ip| ip.split('.').map{|octet| octet.to_i}}.each do |ip|
120
126
  @hosts.select{|k,v| v[:ip] == ip}.each do |k,v|
121
127
  body += '<tr><td><a href="host_' + k.to_s + '.html">' + ip + '</a></td><td>' + v[:hostname] + '</td><td>' + v[:os] + '</td><td>' + v[:total_excl_info].to_s + '</td></tr>'
@@ -153,6 +159,7 @@ class Htmlout < Baseout
153
159
 
154
160
  body += '<table id="vulns_table" class="display"><thead><tr><th>Nessus ID</th><th>Severity</th><th>Name</th><th>Family</th><th>Ports</th><th>Number of impacted hosts</th></tr></thead><tbody>'
155
161
  @events.each do |k,v|
162
+ next if v[:severity].to_i < @options[:severity].to_i
156
163
  body += '<tr><td><a href="vuln_' + k.to_s + '.html">' + k.to_s
157
164
  body += '</a></td><td>' + v[:severity].to_s + '<td>' + v[:plugin_name] + '</td>'
158
165
  body += '<td>' + v[:family].to_s + '</td><td>'
@@ -188,6 +195,7 @@ class Htmlout < Baseout
188
195
  #
189
196
  def print_vulns
190
197
  @events.each do |id,values|
198
+ next if values[:severity].to_i < @options[:severity].to_i
191
199
  File.open(@options[:output] + "/vuln_" + id.to_s + ".html", 'w') do |f|
192
200
  html_header(f,id.to_s)
193
201
 
@@ -258,7 +266,12 @@ class Htmlout < Baseout
258
266
  if values[:total_excl_info] == 0
259
267
  pie_js(f,"pie_graph","Criticality Breakdown","Criticality Breakdown",[['Informational ONLY',values[:info].to_i]])
260
268
  else
261
- pie_js(f,"pie_graph","Criticality Breakdown","Criticality Breakdown",[['Low',values[:low].to_i],['Medium',values[:med].to_i],['High',values[:high].to_i],['Critical',values[:crit].to_i]],"document.location.href = '#' + event.point.name;")
269
+ pie_data = []
270
+ pie_data << ['Low',values[:low].to_i] if @options[:severity] <= 1
271
+ pie_data << ['Medium',values[:med].to_i] if @options[:severity] <= 2
272
+ pie_data << ['High',values[:high].to_i] if @options[:severity] <= 3
273
+ pie_data << ['Critical',values[:crit].to_i] if @options[:severity] <= 4
274
+ pie_js(f,"pie_graph","Criticality Breakdown","Criticality Breakdown",pie_data,"document.location.href = '#' + event.point.name;")
262
275
  end
263
276
 
264
277
  close_html_header(f)
@@ -271,87 +284,99 @@ class Htmlout < Baseout
271
284
  body += '<div id="vulns"><h2>Vulns</h2>'
272
285
 
273
286
 
274
- body += '<div id="critical"><a name="Critical"></a><h3>Critical</h3>'
287
+ if @options[:severity] <= 4
288
+ body += '<div id="critical"><a name="Critical"></a><h3>Critical</h3>'
275
289
 
276
- body += '<table id="critical_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
277
- @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
278
- vuln_data[:ports].each {|k,v|
290
+ body += '<table id="critical_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
291
+ @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
292
+ vuln_data[:ports].each {|k,v|
279
293
 
280
- v[:hosts].each do |h,v2|
281
- if h == id and vuln_data[:severity] == 4
282
- body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
294
+ v[:hosts].each do |h,v2|
295
+ if h == id and vuln_data[:severity] == 4
296
+ body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
297
+ end
283
298
  end
284
- end
285
- }
299
+ }
300
+ end
301
+ body += '</tbody></table></div>'
286
302
  end
287
- body += '</tbody></table></div>'
288
303
 
304
+ if @options[:severity] <= 3
289
305
 
290
- body += '<div id="high"><a name="High"></a><h3>High</h3>'
306
+ body += '<div id="high"><a name="High"></a><h3>High</h3>'
291
307
 
292
- body += '<table id="high_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
293
- @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
294
- vuln_data[:ports].each {|k,v|
295
- v[:hosts].each do |h,v2|
296
- if h == id and vuln_data[:severity] == 3
297
- body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
308
+ body += '<table id="high_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
309
+ @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
310
+ vuln_data[:ports].each {|k,v|
311
+ v[:hosts].each do |h,v2|
312
+ if h == id and vuln_data[:severity] == 3
313
+ body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
314
+ end
298
315
  end
299
- end
300
- }
316
+ }
317
+ end
318
+ body += '</tbody></table></div>'
301
319
  end
302
- body += '</tbody></table></div>'
303
320
 
321
+ if @options[:severity] <= 2
304
322
 
305
- body += '<div id="medium"><a name="Medium"></a><h3>Medium</h3>'
323
+ body += '<div id="medium"><a name="Medium"></a><h3>Medium</h3>'
306
324
 
307
- body += '<table id="medium_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
308
- @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
309
- vuln_data[:ports].each {|k,v|
310
- v[:hosts].each do |h,v2|
311
- if h == id and vuln_data[:severity] == 2
312
- body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
325
+ body += '<table id="medium_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
326
+ @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
327
+ vuln_data[:ports].each {|k,v|
328
+ v[:hosts].each do |h,v2|
329
+ if h == id and vuln_data[:severity] == 2
330
+ body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
331
+ end
313
332
  end
314
- end
315
- }
333
+ }
334
+ end
335
+ body += '</tbody></table></div>'
336
+
316
337
  end
317
- body += '</tbody></table></div>'
318
338
 
339
+ if @options[:severity] <= 1
319
340
 
320
- body += '<div id="low"><a name="Low"></a><h3>Low</h3>'
341
+ body += '<div id="low"><a name="Low"></a><h3>Low</h3>'
321
342
 
322
- body += '<table id="low_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
323
- @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
324
- vuln_data[:ports].each {|k,v|
325
- v[:hosts].each do |h,v2|
326
- if h == id and vuln_data[:severity] == 1
327
- body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
343
+ body += '<table id="low_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
344
+ @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
345
+ vuln_data[:ports].each {|k,v|
346
+ v[:hosts].each do |h,v2|
347
+ if h == id and vuln_data[:severity] == 1
348
+ body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
349
+ end
328
350
  end
329
- end
330
- }
351
+ }
352
+ end
353
+ body += '</tbody></table></div>'
331
354
  end
332
- body += '</tbody></table></div>'
333
355
 
356
+ if @options[:severity] <= 0
334
357
 
335
- body += '<div id="informational"><a name="Informational"></a><h3>Informational</h3>'
358
+ body += '<div id="informational"><a name="Informational"></a><h3>Informational</h3>'
336
359
 
337
- body += '<table id="informational_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
338
- @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
339
- vuln_data[:ports].each {|k,v|
340
- v[:hosts].each do |h,v2|
341
- if h == id and vuln_data[:severity] == 0
342
- body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
360
+ body += '<table id="informational_table" class="display"><thead><tr><th>Nessus ID</th><th>Name</th><th>Synopsis</th><th>Result</th><th>Family</th><th>Port</th></tr></thead><tbody>'
361
+ @events.sort_by{|k,v| v[:port].to_s}.each do |vuln_id,vuln_data|
362
+ vuln_data[:ports].each {|k,v|
363
+ v[:hosts].each do |h,v2|
364
+ if h == id and vuln_data[:severity] == 0
365
+ body += '<tr><td><a href="vuln_' + vuln_id.to_s + '.html">' + vuln_id.to_s + '</a></td><td>' + vuln_data[:plugin_name] + '</td><td>' + vuln_data[:synopsis] + '</td><td>' + v2.to_s.gsub(/<\/?[^>]*>/, "").gsub("\n","<br />") + '</td><td>' + vuln_data[:family] + '</td><td>' + k.to_s + '</td></tr>'
366
+ end
343
367
  end
344
- end
345
- }
368
+ }
369
+ end
370
+ body += '</tbody></table></div>'
346
371
  end
347
- body += '</tbody></table></div>'
348
372
 
349
373
 
350
- body += "<script>$(document).ready(function() {\n $('#critical_table').dataTable({\"bPaginate\": false});\n"
351
- body += "$('#high_table').dataTable({\"bPaginate\": false});\n"
352
- body += "$('#medium_table').dataTable({\"bPaginate\": false});\n"
353
- body += "$('#low_table').dataTable({\"bPaginate\": false});\n"
354
- body += "$('#informational_table').dataTable({\"bPaginate\": false});\n"
374
+ body += "<script>$(document).ready(function() {\n ";
375
+ body += "$('#critical_table').dataTable({\"bPaginate\": false});\n" if @options[:severity] > 4
376
+ body += "$('#high_table').dataTable({\"bPaginate\": false});\n" if @options[:severity] > 3
377
+ body += "$('#medium_table').dataTable({\"bPaginate\": false});\n" if @options[:severity] > 2
378
+ body += "$('#low_table').dataTable({\"bPaginate\": false});\n" if @options[:severity] > 1
379
+ body += "$('#informational_table').dataTable({\"bPaginate\": false});\n" if @options[:severity] > 0
355
380
  body += "});</script>"
356
381
 
357
382
  body += '</div></div>'
@@ -581,61 +606,69 @@ class Htmlout < Baseout
581
606
  }
582
607
  }
583
608
  },
584
- series: [{
609
+ series: [
585
610
  eos
586
611
 
587
- fp.puts "name: 'Critical',"
588
- fp.puts "color: 'purple',"
589
- tmpline = "data: ["
612
+ if @options[:severity] <= 4
613
+ fp.puts "{name: 'Critical',"
614
+ fp.puts "color: 'purple',"
615
+ tmpline = "data: ["
590
616
 
591
- data.each_with_index do |entry,index|
592
- tmpline += entry[1][:crit].to_s
593
- tmpline += "," unless index == data.length - 1
617
+ data.each_with_index do |entry,index|
618
+ tmpline += entry[1][:crit].to_s
619
+ tmpline += "," unless index == data.length - 1
620
+ end
621
+ tmpline += "]"
622
+ fp.puts tmpline
623
+ fp.puts "}"
594
624
  end
595
- tmpline += "]"
596
- fp.puts tmpline
597
- fp.puts "},{"
598
625
 
599
- fp.puts "name: 'High',"
600
- fp.puts "color: 'red',"
601
- tmpline = "data: ["
626
+ if @options[:severity] <= 3
627
+ fp.puts ",{name: 'High',"
628
+ fp.puts "color: 'red',"
629
+ tmpline = "data: ["
602
630
 
603
- data.each_with_index do |entry,index|
604
- tmpline += entry[1][:high].to_s
605
- tmpline += "," unless index == data.length - 1
631
+ data.each_with_index do |entry,index|
632
+ tmpline += entry[1][:high].to_s
633
+ tmpline += "," unless index == data.length - 1
634
+ end
635
+ tmpline += "]"
636
+ fp.puts tmpline
637
+ fp.puts "}"
606
638
  end
607
- tmpline += "]"
608
- fp.puts tmpline
609
- fp.puts "},{"
610
639
 
640
+ if @options[:severity] <= 2
641
+ fp.puts ",{name: 'Medium',"
642
+ fp.puts "color: 'orange',"
643
+ tmpline = "data: ["
611
644
 
612
- fp.puts "name: 'Medium',"
613
- fp.puts "color: 'orange',"
614
- tmpline = "data: ["
615
-
616
- data.each_with_index do |entry,index|
617
- tmpline += entry[1][:med].to_s
618
- tmpline += "," unless index == data.length - 1
645
+ data.each_with_index do |entry,index|
646
+ tmpline += entry[1][:med].to_s
647
+ tmpline += "," unless index == data.length - 1
648
+ end
649
+ tmpline += "]"
650
+ fp.puts tmpline
651
+ fp.puts "}"
619
652
  end
620
- tmpline += "]"
621
- fp.puts tmpline
622
- fp.puts "},{"
623
653
 
654
+ if @options[:severity] <= 1
624
655
 
625
- fp.puts "name: 'Low',"
626
- fp.puts "color: 'green',"
627
- tmpline = "data: ["
656
+ fp.puts ",{name: 'Low',"
657
+ fp.puts "color: 'green',"
658
+ tmpline = "data: ["
628
659
 
629
- data.each_with_index do |entry,index|
630
- tmpline += entry[1][:low].to_s
631
- tmpline += "," unless index == data.length - 1
660
+ data.each_with_index do |entry,index|
661
+ tmpline += entry[1][:low].to_s
662
+ tmpline += "," unless index == data.length - 1
663
+ end
664
+ tmpline += "]"
665
+ fp.puts tmpline
666
+ fp.puts "}"
632
667
  end
633
- tmpline += "]"
634
- fp.puts tmpline
635
668
 
636
669
  fp.puts <<-eos
637
670
 
638
- }]
671
+ ]
639
672
  });
640
673
  });
641
674
 
@@ -18,8 +18,11 @@ module Output
18
18
  @options = options
19
19
 
20
20
  if @options[:type] == "html" #Therefore, the output should be a folder name, not a file
21
+
22
+ @options[:output] = "." if @options[:output].nil?
23
+
21
24
  #Check if the output dir exists
22
- Dir.mkdir(options[:output]) unless File.exists?(options[:output])
25
+ Dir.mkdir(@options[:output]) unless File.exists?(@options[:output])
23
26
  else
24
27
  @oFile = File.new(@options[:output],'w') unless @options[:output].nil?
25
28
  @oFile = STDOUT if @oFile.nil?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prenus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-22 00:00:00.000000000Z
13
- dependencies: []
12
+ date: 2013-01-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rainbow
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 1.1.0
14
30
  description: Pretty Nessus = Prenus
15
31
  email: xntrik@gmail.com
16
32
  executables:
@@ -83,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
99
  version: 1.8.0
84
100
  requirements: []
85
101
  rubyforge_project:
86
- rubygems_version: 1.8.10
102
+ rubygems_version: 1.8.24
87
103
  signing_key:
88
104
  specification_version: 3
89
105
  summary: Prenus - The Pretty Nessus Parser