risu 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/KNOWNISSUES.markdown +50 -0
  2. data/LICENSE +25 -0
  3. data/NEWS.markdown +112 -0
  4. data/README.markdown +126 -0
  5. data/Rakefile +37 -0
  6. data/TODO.markdown +69 -0
  7. data/bin/risu +12 -0
  8. data/lib/nessusdb.rb +38 -0
  9. data/lib/nessusdb/cli.rb +9 -0
  10. data/lib/nessusdb/cli/application.rb +402 -0
  11. data/lib/nessusdb/cli/banner.rb +25 -0
  12. data/lib/nessusdb/exceptions.rb +8 -0
  13. data/lib/nessusdb/exceptions/invaliddocument.rb +10 -0
  14. data/lib/nessusdb/listener.rb +274 -0
  15. data/lib/nessusdb/models.rb +18 -0
  16. data/lib/nessusdb/models/familyselection.rb +12 -0
  17. data/lib/nessusdb/models/host.rb +359 -0
  18. data/lib/nessusdb/models/individualpluginselection.rb +14 -0
  19. data/lib/nessusdb/models/item.rb +183 -0
  20. data/lib/nessusdb/models/plugin.rb +98 -0
  21. data/lib/nessusdb/models/pluginspreference.rb +12 -0
  22. data/lib/nessusdb/models/policy.rb +17 -0
  23. data/lib/nessusdb/models/reference.rb +13 -0
  24. data/lib/nessusdb/models/report.rb +26 -0
  25. data/lib/nessusdb/models/serverpreference.rb +13 -0
  26. data/lib/nessusdb/models/version.rb +12 -0
  27. data/lib/nessusdb/nessusdocument.rb +66 -0
  28. data/lib/nessusdb/parsers.rb +8 -0
  29. data/lib/nessusdb/prawn_templater.rb +38 -0
  30. data/lib/nessusdb/schema.rb +145 -0
  31. data/lib/nessusdb/templates/assets.rb +21 -0
  32. data/lib/nessusdb/templates/cover_sheet.rb +42 -0
  33. data/lib/nessusdb/templates/data/nessuslogo.jpg +0 -0
  34. data/lib/nessusdb/templates/exec_summary.rb +56 -0
  35. data/lib/nessusdb/templates/executive_summary.rb +182 -0
  36. data/lib/nessusdb/templates/finding_statistics.rb +23 -0
  37. data/lib/nessusdb/templates/findings_host.rb +49 -0
  38. data/lib/nessusdb/templates/findings_summary.rb +68 -0
  39. data/lib/nessusdb/templates/findings_summary_with_pluginid.rb +68 -0
  40. data/lib/nessusdb/templates/graphs.rb +33 -0
  41. data/lib/nessusdb/templates/host_summary.rb +40 -0
  42. data/lib/nessusdb/templates/ms_patch_summary.rb +37 -0
  43. data/lib/nessusdb/templates/ms_update_summary.rb +43 -0
  44. data/lib/nessusdb/templates/pci_compliance.rb +66 -0
  45. data/lib/nessusdb/templates/technical_findings.rb +116 -0
  46. data/risu.gemspec +44 -0
  47. metadata +247 -0
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+
6
+ # IndividualPluginSelection Model
7
+ #
8
+ # @author Jacob Hammack
9
+ class IndividualPluginSelection < ActiveRecord::Base
10
+ belongs_to :policy
11
+ has_many :plugins
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,183 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+
6
+ # Item Model
7
+ #
8
+ # @author Jacob Hammack <jacob.hammack@hammackj.com>
9
+ class Item < ActiveRecord::Base
10
+ belongs_to :host
11
+ belongs_to :plugin
12
+
13
+ class << self
14
+
15
+ # Queries for all risks in the database
16
+ #
17
+ # @return [ActiveRecord::Relation] with the query results
18
+ def risks
19
+ where(:severity => [0,1,2,3])
20
+ end
21
+
22
+ # Queries for all the high risks in the database
23
+ #
24
+ # @return [ActiveRecord::Relation] with the query results
25
+ def high_risks
26
+ where(:severity => 3)
27
+ end
28
+
29
+ # Queries for all the medium risks in the database
30
+ #
31
+ # @return [ActiveRecord::Relation] with the query results
32
+ def medium_risks
33
+ where(:severity => 2)
34
+ end
35
+
36
+ # Queries for all the low risks in the database
37
+ #
38
+ # @return [ActiveRecord::Relation] with the query results
39
+ def low_risks
40
+ where(:severity => 1)
41
+ end
42
+
43
+ # Queries for all the info risks in the database
44
+ #
45
+ # @return [ActiveRecord::Relation] with the query results
46
+ def info_risks
47
+ where(:severity => 0)
48
+ end
49
+
50
+ # Queries for all the unique high risks in the database
51
+ #
52
+ # @return [ActiveRecord::Relation] with the query results
53
+ def high_risks_unique
54
+ where(:severity => 3).joins(:plugin).order("plugins.cvss_base_score").group(:plugin_id)
55
+ end
56
+
57
+ # Queries for all the unique high findings and sorts them by count
58
+ #
59
+ # @return [ActiveRecord::Relation] with the query results
60
+ def high_risks_unique_sorted
61
+ select("items.*").select("count(*) as count_all").where(:severity => 3).group(:plugin_id).order("count_all DESC")
62
+ end
63
+
64
+ # Queries for all the unique medium risks in the database
65
+ #
66
+ # @return [ActiveRecord::Relation] with the query results
67
+ def medium_risks_unique
68
+ where(:severity => 2).joins(:plugin).order(:cvss_base_score).group(:plugin_id)
69
+ end
70
+
71
+ # Queries for all the unique medium findings and sorts them by count
72
+ #
73
+ # @return [ActiveRecord::Relation] with the query results
74
+ def medium_risks_unique_sorted
75
+ select("items.*").select("count(*) as count_all").where(:severity => 2).group(:plugin_id).order("count_all DESC")
76
+ end
77
+
78
+ # Queries for all the unique low risks in the database
79
+ #
80
+ # @return [ActiveRecord::Relation] with the query results
81
+ def low_risks_unique
82
+ where(:severity => 1).joins(:plugin).order(:cvss_base_score).group(:plugin_id)
83
+ end
84
+
85
+ # Queries for all the unique low findings and sorts them by count
86
+ #
87
+ # @return [ActiveRecord::Relation] with the query results
88
+ def low_risks_unique_sorted
89
+ select("items.*").select("count(*) as count_all").where(:severity => 1).group(:plugin_id).order("count_all DESC")
90
+ end
91
+
92
+ # Queries for all the unique info risks in the database
93
+ #
94
+ # @return [ActiveRecord::Relation] with the query results
95
+ def info_risks_unique
96
+ where(:severity => 0).joins(:plugin).order(:cvss_base_score).group(:plugin_id)
97
+ end
98
+
99
+ # Queries for all the unique info findings and sorts them by count
100
+ #
101
+ # @return [ActiveRecord::Relation] with the query results
102
+ def info_risks_unique_sorted
103
+ select("items.*").select("count(*) as count_all").where(:severity => 0).group(:plugin_id).order("count_all DESC")
104
+ end
105
+
106
+ # Queries for all the risks grouped by service type, used for the Vulnerbilities by Service graph
107
+ #
108
+ # @return [ActiveRecord::Relation] with the query results
109
+ def risks_by_service(limit=10)
110
+ select("items.*").select("count(*) as count_all").where("svc_name != 'unknown' and svc_name != 'general'").group(:svc_name).order("count_all DESC").limit(limit)
111
+ end
112
+
113
+ # Queries for all the high risks by plugin
114
+ #
115
+ # @todo update this
116
+ #
117
+ # @return [ActiveRecord::Relation] with the query results
118
+ def risks_by_plugin(limit=10)
119
+ select("items.*").select("count(*) as count_all").joins(:plugin).where("plugin_id != 1").where(:severity => 3).group(:plugin_id).order("count_all DESC").limit(limit)
120
+ end
121
+
122
+ # Queries for all the risks by host
123
+ #
124
+ # @return [ActiveRecord::Relation] with the query results
125
+ def risks_by_host(limit=10)
126
+ select("items.*").select("count(*) as count_all").joins(:host).where("plugin_id != 1").where(:severity => [3, 2]).group(:host_id).order("count_all DESC").limit(limit)
127
+ end
128
+
129
+ # Queries for all the hosts with the Microsoft patch summary plugin (38153)
130
+ #
131
+ # @return [ActiveRecord::Relation] with the query results
132
+ def ms_patches
133
+ where(:plugin_id => 38153).joins(:host)
134
+ end
135
+
136
+ # Queries for all host with the Microsoft Update Summary plugin(12028)
137
+ #
138
+ # @return [ActiveRecord::Relation] with the query results
139
+ def ms_update
140
+ where(:plugin_id => 12028).joins(:host)
141
+ end
142
+
143
+ # Generates a Graph of all the risks by service
144
+ #
145
+ # @return [StringIO] Object containing the generated PNG image
146
+ def risks_by_service_graph(limit=10)
147
+ g = Gruff::Pie.new(GRAPH_WIDTH)
148
+ g.title = sprintf "Top %d Findings By Service", Item.risks_by_service(limit).all.count
149
+ g.sort = false
150
+ g.theme = {
151
+ :colors => %w(red green blue orange yellow purple black grey brown pink),
152
+ :background_colors => %w(white white)
153
+ }
154
+
155
+ Item.risks_by_service(limit).all.each { |service|
156
+ g.data(service.svc_name, Item.find(:all, :conditions => {:svc_name => service.svc_name}).count)
157
+ }
158
+
159
+ StringIO.new(g.to_blob)
160
+ end
161
+
162
+ # Generates a Graph of all the risks by severity
163
+ #
164
+ # @return [StringIO] Object containing the generated PNG image
165
+ def risks_by_severity_graph
166
+ g = Gruff::Bar.new(GRAPH_WIDTH)
167
+ g.title = "Findings By Severity"
168
+ g.sort = false
169
+ g.theme = {
170
+ :background_colors => %w(white white)
171
+ }
172
+
173
+ g.data("High", Item.high_risks.count, "red") unless Item.high_risks.count == 0
174
+ g.data("Medium", Item.medium_risks.count, "orange") unless Item.medium_risks.count == 0
175
+ g.data("Low", Item.low_risks.count, "yellow") unless Item.low_risks.count == 0
176
+ g.data("Info", Item.info_risks.count, "blue") unless Item.info_risks.count == 0
177
+
178
+ StringIO.new(g.to_blob)
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,98 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+
6
+ # Plugin Model
7
+ #
8
+ # @author Jacob Hammack
9
+ class Plugin < ActiveRecord::Base
10
+ has_many :items
11
+ belongs_to :family
12
+ has_many :references
13
+ has_many :individual_plugin_selections
14
+
15
+ class << self
16
+
17
+ # Queries for all risks based on Plugin.risk_factor
18
+ #
19
+ # @return [Array] of all risks
20
+ def risks
21
+ critical_risks + high_risks + medium_risks + low_risks + none_risks
22
+ end
23
+
24
+ # Queries for all the critical risks based on Plugin.risk_factor
25
+ #
26
+ # @return [ActiveRelation] of Critical Risks
27
+ def critical_risks
28
+ where(:risk_factor => "Critical")
29
+ end
30
+
31
+ #Queries for all the critical risks based on Plugin.risk_factor
32
+ #
33
+ # @return [ActiveRelation] of High Risks
34
+ def high_risks
35
+ where(:risk_factor => "High")
36
+ end
37
+
38
+ # Queries for all the critical risks based on Plugin.risk_factor
39
+ #
40
+ # @return [ActiveRelation] of Medium Risks
41
+ def medium_risks
42
+ where(:risk_factor => "Medium")
43
+ end
44
+
45
+ # Queries for all the critical risks based on Plugin.risk_factor
46
+ #
47
+ # @return [ActiveRelation] of Low Risks
48
+ def low_risks
49
+ where(:risk_factor => "Low")
50
+ end
51
+
52
+ # Queries for all the critical risks based on Plugin.risk_factor
53
+ #
54
+ # @return [ActiveRelation] of None Risks
55
+ def none_risks
56
+ where(:risk_factor => "None")
57
+ end
58
+
59
+ # Creates a graph based on the top plugins sorted by count
60
+ #
61
+ # @return Filename of the created graph
62
+ def top_by_count_graph(limit=10)
63
+ g = Gruff::Bar.new(GRAPH_WIDTH)
64
+ g.title = sprintf "Top %d High Findings By Plugin", Item.risks_by_plugin(limit).all.count
65
+ g.sort = false
66
+ g.theme = {
67
+ :colors => %w(red green blue orange yellow purple black grey brown pink),
68
+ :background_colors => %w(white white)
69
+ }
70
+
71
+ Item.risks_by_plugin(limit).all.each do |plugin|
72
+ plugin_name = Plugin.find_by_id(plugin.plugin_id).plugin_name
73
+
74
+ #We need to filter the names a little to make everything look nice on the graph
75
+ plugin_name = case plugin.plugin_id
76
+ when 35362 then plugin_name.split(":")[0]
77
+ when 34477 then plugin_name.split(":")[0]
78
+ when 35635 then plugin_name.split(":")[0]
79
+ when 21564 then "VNC Remote Authentication Bypass"
80
+ when 38664 then "Intel Common Base Agent Remote Command Execution"
81
+ when 42411 then "Windows SMB Shares Unprivileged Access"
82
+ else
83
+ plugin_name = Plugin.find_by_id(plugin.plugin_id).plugin_name
84
+ end
85
+
86
+ if plugin_name =~ /^(MS\d{2}-\d{3}):/
87
+ plugin_name = $1
88
+ end
89
+
90
+ g.data(plugin_name, Item.where(:plugin_id => plugin.plugin_id).count)
91
+ end
92
+
93
+ StringIO.new(g.to_blob)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+ # PluginPreference Model
6
+ #
7
+ # @author Jacob Hammack
8
+ class PluginsPreference < ActiveRecord::Base
9
+ belongs_to :policy
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+
6
+ # Policy Model
7
+ #
8
+ # @author Jacob Hammack
9
+ class Policy < ActiveRecord::Base
10
+ has_many :family_selections
11
+ has_many :individual_plugin_selections
12
+ has_many :reports
13
+ has_many :plugins_preferences
14
+ has_many :server_preferences
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+
6
+ # Reference Model
7
+ #
8
+ # @author Jacob Hammack
9
+ class Reference < ActiveRecord::Base
10
+ has_many :plugins
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+
6
+ # Report Model
7
+ #
8
+ # @author Jacob Hammack <jacob.hammack@hammackj.com>
9
+ class Report < ActiveRecord::Base
10
+ has_many :hosts
11
+ belongs_to :policy
12
+
13
+ class << self
14
+
15
+ attr_accessor :title, :author, :company, :classification
16
+
17
+ #
18
+ #@scan_date = Host.where("start is not null").first[:start].to_s
19
+ #
20
+ def scan_date
21
+ Host.where("start is not null").first[:start].to_s
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+
6
+ # ServerPreference Model
7
+ #
8
+ # @author Jacob Hammack
9
+ class ServerPreference < ActiveRecord::Base
10
+ belongs_to :policy
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+ module Models
5
+
6
+ # Version Model for the DB
7
+ #
8
+ # @author Jacob Hammack
9
+ class Version < ActiveRecord::Base
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ module NessusDB
4
+
5
+ # A Object to represet the Nessus xml file in memory
6
+ #
7
+ # @author Jacob Hammack <jacob.hammack@hammackj.com>
8
+ class NessusDocument
9
+
10
+ # Creates a instance of the NessusDocument class
11
+ #
12
+ def initialize document
13
+ @document = document
14
+ end
15
+
16
+ # Checks the validness of a NessusDocument
17
+ #
18
+ # @return [Boolean] True if valid, False if invalid
19
+ def valid?
20
+ if File.exist?(@document)
21
+ @parser = LibXML::XML::Parser.file @document
22
+ doc = @parser.parse
23
+
24
+ if doc.root.name == nil
25
+ return false
26
+ end
27
+
28
+ if doc.root.name == "NessusClientData_v2"
29
+ return true
30
+ elsif doc.root.name == "NessusClientData"
31
+ return false
32
+ else
33
+ return false
34
+ end
35
+ else
36
+ return false
37
+ end
38
+ end
39
+
40
+ # Invokes the SAX parser on the XML document
41
+ #
42
+ def parse
43
+ @parser = LibXML::XML::SaxParser.file @document
44
+ @parser.callbacks = NessusSaxListener.new
45
+ @parser.parse
46
+ end
47
+
48
+ # Fixes the ip field if nil and replaces it with the name if its an ip
49
+ #
50
+ def fix_ips
51
+ @hosts = Host.all
52
+
53
+ @hosts.each do |host|
54
+ if host.ip == nil
55
+ begin
56
+ ip = IPAddr.new host.name
57
+ host.ip = ip.to_string
58
+ host.save
59
+ rescue ArgumentError => ae
60
+ next
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end