ruby-nessus2 2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.drone.yml +51 -0
  3. data/.gitignore +5 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +4 -0
  6. data/.rubocop_todo.yml +124 -0
  7. data/.travis.yml +13 -0
  8. data/.yardopts +1 -0
  9. data/Gemfile +6 -0
  10. data/Gemfile.lock +75 -0
  11. data/LICENSE.txt +20 -0
  12. data/README.md +181 -0
  13. data/Rakefile +21 -0
  14. data/bin/recess +10 -0
  15. data/examples/example.rb +46 -0
  16. data/examples/example_bid.rb +28 -0
  17. data/examples/example_cpe.rb +28 -0
  18. data/examples/example_cve.rb +36 -0
  19. data/examples/example_v1.nessus +1 -0
  20. data/examples/example_v2.nessus +2076 -0
  21. data/examples/example_v3.nessus +7449 -0
  22. data/lib/ruby-nessus.rb +5 -0
  23. data/lib/ruby-nessus/cli.rb +126 -0
  24. data/lib/ruby-nessus/log.rb +84 -0
  25. data/lib/ruby-nessus/parse.rb +46 -0
  26. data/lib/ruby-nessus/ruby-nessus.rb +6 -0
  27. data/lib/ruby-nessus/version.rb +5 -0
  28. data/lib/ruby-nessus/version1/event.rb +85 -0
  29. data/lib/ruby-nessus/version1/host.rb +267 -0
  30. data/lib/ruby-nessus/version1/port.rb +84 -0
  31. data/lib/ruby-nessus/version1/scan.rb +404 -0
  32. data/lib/ruby-nessus/version2/event.rb +410 -0
  33. data/lib/ruby-nessus/version2/host.rb +522 -0
  34. data/lib/ruby-nessus/version2/port.rb +75 -0
  35. data/lib/ruby-nessus/version2/scan.rb +393 -0
  36. data/ruby-nessus.gemspec +28 -0
  37. data/spec/ruby-nessus/parse_spec.rb +40 -0
  38. data/spec/ruby-nessus/version1/event_spec.rb +69 -0
  39. data/spec/ruby-nessus/version1/host_spec.rb +75 -0
  40. data/spec/ruby-nessus/version1/scan_spec.rb +97 -0
  41. data/spec/ruby-nessus/version2/event_spec.rb +225 -0
  42. data/spec/ruby-nessus/version2/host_spec.rb +148 -0
  43. data/spec/ruby-nessus/version2/scan_spec.rb +96 -0
  44. data/spec/ruby-nessus/version_spec.rb +11 -0
  45. data/spec/spec_fixtures/example_v1.nessus +1 -0
  46. data/spec/spec_fixtures/example_v2.nessus +2080 -0
  47. data/spec/spec_fixtures/example_v_wrong.nessus +3 -0
  48. data/spec/spec_fixtures/xml.rb +15 -0
  49. data/spec/spec_helper.rb +7 -0
  50. metadata +190 -0
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'ruby-nessus2'
7
+ gem.version = '2.0'
8
+ gem.summary = 'Ruby-Nessus is a ruby interface for the popular Nessus vulnerability scanner.'
9
+ gem.description = 'Based on ruby-nessus. For internal testing only. Do not use this gem in production.'
10
+ gem.licenses = ['MIT']
11
+ gem.authors = ['Tamas']
12
+ gem.email = 'tamas@dxw.com'
13
+ gem.homepage = 'https://github.com/dxwcyber/ruby-nessus'
14
+
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
17
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ gem.require_paths = ['lib']
19
+ gem.required_ruby_version = '>= 2.3'
20
+
21
+ gem.add_dependency 'nokogiri', '~> 1.4'
22
+ gem.add_dependency 'rainbow', '>= 2.0'
23
+
24
+ gem.add_development_dependency 'rspec', '~> 3.7'
25
+ gem.add_development_dependency 'rubocop', '~> 0.51'
26
+ gem.add_development_dependency 'rubygems-tasks', '~> 0.1'
27
+ gem.add_development_dependency 'yard', '~> 0.9.11'
28
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper'
4
+ require_relative '../spec_fixtures/xml'
5
+
6
+ describe 'RubyNessus::Parse' do
7
+ it 'should parse a valid v1 .nessus file' do
8
+ expect { RubyNessus::Parse.new(Helpers::DOT_NESSUS_V1_PATH) }.not_to raise_error
9
+ end
10
+
11
+ it 'should parse a valid v2 .nessus file' do
12
+ expect { RubyNessus::Parse.new(Helpers::DOT_NESSUS_V2_PATH) }.not_to raise_error
13
+ end
14
+
15
+ it 'should parse a valid v1 .nessus string' do
16
+ options = { xml: Helpers::DOT_NESSUS_V1_DOC }
17
+ expect { RubyNessus::Parse.new(nil, options) }.not_to raise_error
18
+ end
19
+
20
+ it 'should parse a valid v2 .nessus string' do
21
+ options = { xml: Helpers::DOT_NESSUS_V2_DOC }
22
+ expect { RubyNessus::Parse.new(nil, options) }.not_to raise_error
23
+ end
24
+
25
+ it 'should not parse other versions .nessus string' do
26
+ options = { xml: Helpers::DOT_NESSUS_V2_DOC, version: 3 }
27
+ expect { RubyNessus::Parse.new(nil, options) }.to raise_error('Error: Supported .Nessus Version are 1 and 2.')
28
+ end
29
+
30
+ it 'should not parse other versions .nessus string' do
31
+ options = { xml: Helpers::DOT_NESSUS_VWRONG_DOC }
32
+ expect { RubyNessus::Parse.new(nil, options).detect_version }.to raise_error('Error: Supported .Nessus Version are 1 and 2.')
33
+ end
34
+
35
+ it 'should return the scan' do
36
+ options = { xml: Helpers::DOT_NESSUS_V2_DOC }
37
+ my_nessus = RubyNessus::Parse.new(nil, options)
38
+ expect(my_nessus.scan).to be_kind_of(RubyNessus::Version2::XML)
39
+ end
40
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'spec_fixtures/xml'
5
+
6
+ describe 'Nessus Version 1: Event' do
7
+ before(:all) do
8
+ @xml = RubyNessus::Version1::XML.new(Helpers::DOT_NESSUS_V1)
9
+ @host = @xml.hosts.first
10
+ @bad_event = @host.events.first
11
+ @good_event = @host.events.last
12
+ @bad_port_event = @host.events[25]
13
+ end
14
+
15
+ it 'should parse the event name' do
16
+ expect(@good_event.name).to eq 'Backported Security Patch Detection (WWW)'
17
+ end
18
+
19
+ it 'should parse the event port' do
20
+ expect(@good_event.port.to_s).to eq 'http (80/tcp)'
21
+ end
22
+
23
+ it 'should parse the event port number' do
24
+ expect(@good_event.port.number).to eq '80'
25
+ end
26
+
27
+ it 'should parse the event port service' do
28
+ expect(@good_event.port.service).to eq 'http'
29
+ end
30
+
31
+ it 'should parse the event port protocol' do
32
+ expect(@good_event.port.protocol).to eq 'tcp'
33
+ end
34
+
35
+ it 'should return true if the event port protocol is tcp' do
36
+ expect(@good_event.port.tcp?).to eq true
37
+ end
38
+
39
+ it 'should return false if the event port protocol is not udp' do
40
+ expect(@good_event.port.udp?).to eq false
41
+ end
42
+
43
+ it 'should parse the event severity' do
44
+ expect(@good_event.severity).to eq 1
45
+ end
46
+
47
+ it 'should return the event plugin output' do
48
+ expect(@good_event.data).not_to be nil
49
+ end
50
+
51
+ it 'should return falsey if not data' do
52
+ expect(@bad_event.data).to be_falsey
53
+ end
54
+
55
+ it 'should have a plugin_id' do
56
+ expect(@good_event.plugin_id).to eq 39_521
57
+ end
58
+
59
+ # Bad Event
60
+
61
+ it 'should return false if the event name is nil' do
62
+ expect(@bad_event.name).to eq false
63
+ end
64
+
65
+ it 'should use raw_string' do
66
+ expect(@bad_port_event.port.service).to be_falsey
67
+ expect(@bad_port_event.port.to_s).to eq 'general/tcp'
68
+ end
69
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'spec_fixtures/xml'
5
+
6
+ describe 'Nessus Version 1: Host' do
7
+ before(:all) do
8
+ @xml = RubyNessus::Version1::XML.new(Helpers::DOT_NESSUS_V1)
9
+ @host = @xml.hosts.first
10
+ end
11
+
12
+ it 'should parse the host hostname' do
13
+ expect(@host.hostname).to eq 'scanme.insecure.org'
14
+ end
15
+
16
+ it 'should parse the host start time' do
17
+ expect(@host.scan_start_time.to_s).to eq '2009-11-08T02:21:24+00:00'
18
+ end
19
+
20
+ it 'should parse the host stop time' do
21
+ expect(@host.scan_stop_time.to_s).to eq '2009-11-08T02:31:28+00:00'
22
+ end
23
+
24
+ it 'should parse the host runtime' do
25
+ expect(@host.scan_runtime).to eq '0 hours 10 minutes and 4 seconds'
26
+ end
27
+
28
+ it 'should parse the hosts open ports' do
29
+ expect(@host.open_ports).to eq 6
30
+ end
31
+
32
+ it 'should calculate the hosts informational event count' do
33
+ expect(@host.informational_events).to eq 5
34
+ end
35
+
36
+ it 'should calculate the hosts low severity event count' do
37
+ expect(@host.low_severity_events).to eq 19
38
+ end
39
+
40
+ it 'should calculate the hosts medium severity event count' do
41
+ expect(@host.medium_severity_events).to eq 3
42
+ end
43
+
44
+ it 'should calculate the hosts high severity event count' do
45
+ expect(@host.high_severity_events).to eq 0
46
+ end
47
+
48
+ it 'should calculate the hosts total event count' do
49
+ expect(@host.event_count).to eq 22
50
+ end
51
+
52
+ it 'should to_s return the ip' do
53
+ expect(@host.to_s).to eq @host.ip
54
+ end
55
+
56
+ it 'should ip return the hostname' do
57
+ expect(@host.ip).to eq 'scanme.insecure.org'
58
+ end
59
+
60
+ it 'should mac_addr return the mac address or unknown' do
61
+ expect(@host.mac_addr).to eq '(unknown)'
62
+ end
63
+
64
+ it 'should return the netbios_name' do
65
+ expect(@host.netbios_name).to eq '(unknown)'
66
+ end
67
+
68
+ it 'should return the dns_name' do
69
+ expect(@host.dns_name).to eq 'scanme.insecure.org.\\n'
70
+ end
71
+
72
+ it 'should return the os_name ' do
73
+ expect(@host.os_name).to eq 'Linux Kernel 2.6 on Red Hat Enterprise Linux 5'
74
+ end
75
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'spec_fixtures/xml'
5
+
6
+ describe 'Nessus Version 1: Scan' do
7
+ include Helpers
8
+
9
+ before(:all) do
10
+ @xml = RubyNessus::Version1::XML.new(Helpers::DOT_NESSUS_V1)
11
+ end
12
+
13
+ it 'should parse the scan title' do
14
+ expect(@xml.title).to eq 'Ruby-Nessus Example Policy'
15
+ end
16
+
17
+ it 'should parse the scan time' do
18
+ expect(@xml.time.to_s).to eq '2009-11-08T02:21:22+00:00'
19
+ end
20
+
21
+ it 'should parse the scan policy title' do
22
+ expect(@xml.policy_title).to eq 'Ruby-Nessus Example Policy'
23
+ end
24
+
25
+ it 'should parse the scan policy notes' do
26
+ expect(@xml.policy_notes).to eq 'This is an example .nessus file for testing the Ruby-Nessus gem.'
27
+ end
28
+
29
+ it 'should parse the scan start time' do
30
+ expect(@xml.start_time.to_s).to eq '2009-11-08T02:21:23+00:00'
31
+ end
32
+
33
+ it 'should parse the scan stop time' do
34
+ expect(@xml.stop_time.to_s).to eq '2009-11-08T02:31:29+00:00'
35
+ end
36
+
37
+ it 'should parse the scan runtime' do
38
+ expect(@xml.runtime).to eq '0 hours 10 minutes and 6 seconds'
39
+ end
40
+
41
+ it 'should parse the scan total host count' do
42
+ expect(@xml.host_count).to eq 1
43
+ end
44
+
45
+ it 'should calculate the percentage of low severity events' do
46
+ expect(@xml.event_percentage_for('low', true)).to eq '86'
47
+ end
48
+
49
+ it 'should calculate the low severity event total' do
50
+ expect(@xml.low_severity_count).to eq 19
51
+ end
52
+
53
+ it 'should calculate the percentage of medium severity events' do
54
+ expect(@xml.event_percentage_for('medium', true)).to eq '14'
55
+ end
56
+
57
+ it 'should calculate the medium severity event total' do
58
+ expect(@xml.medium_severity_count).to eq 3
59
+ end
60
+
61
+ it 'should calculate the percentage of high severity events' do
62
+ expect(@xml.event_percentage_for('high', true)).to eq '0'
63
+ end
64
+
65
+ it 'should calculate the high severity event total' do
66
+ expect(@xml.high_severity_count).to eq 0
67
+ end
68
+
69
+ it 'should calculate the total for all severity events' do
70
+ expect(@xml.total_event_count).to eq 22
71
+ end
72
+
73
+ it 'should target_hosts list the target' do
74
+ expect(@xml.target_hosts).to eq ['scanme.insecure.org']
75
+ end
76
+
77
+ it 'should be version 1' do
78
+ expect(@xml.version).to eq 1
79
+ end
80
+
81
+ it 'should return the plugin ids' do
82
+ expect(@xml.plugin_ids.length).to eq 31_507
83
+ end
84
+
85
+ it 'should return the plugins' do
86
+ expect(@xml.plugins).to be_kind_of(Array)
87
+ expect(@xml.plugins).not_to be_blank
88
+ end
89
+
90
+ it 'should parse the unique ports' do
91
+ expect(@xml.unique_ports).to eq ['arcp (7070/tcp)', 'domain (53/tcp)', 'domain (53/udp)', 'ftp (21/tcp)', 'general/tcp', 'general/udp', 'http (80/tcp)', 'rtsp (554/tcp)']
92
+ end
93
+
94
+ it 'should find_by_hotsname' do
95
+ @xml.find_by_hostname('scanme.insecure.org') { |host| expect(host.hostname).to eq 'scanme.insecure.org' }
96
+ end
97
+ end
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'spec_fixtures/xml'
5
+
6
+ describe 'Nessus Version 2: Event port' do
7
+ before(:all) do
8
+ @xml = RubyNessus::Version2::XML.new(Helpers::DOT_NESSUS_V2)
9
+ @host = @xml.hosts.first
10
+ @good_event = @host.events.last
11
+ end
12
+ it 'should parse the event name' do
13
+ expect(@good_event.name).to eq 'ICMP Timestamp Request Remote Date Disclosure'
14
+ end
15
+
16
+ it 'should parse the event port' do
17
+ expect(@good_event.port.to_s).to eq 'unknown (0/icmp)'
18
+ end
19
+
20
+ it 'should parse the event port number' do
21
+ expect(@good_event.port.number.to_s).to eq '0'
22
+ end
23
+
24
+ it 'should parse the event port service' do
25
+ expect(@good_event.port.service.to_s).to eq 'unknown'
26
+ end
27
+
28
+ it 'should parse the event port protocol' do
29
+ expect(@good_event.port.protocol.to_s).to eq 'icmp'
30
+ end
31
+
32
+ it 'should return true if the event port protocol is icmp' do
33
+ expect(@good_event.port.icmp?).to eq true
34
+ end
35
+
36
+ it 'should return false if the event port protocol is not udp' do
37
+ expect(@good_event.port.udp?).to eq false
38
+ end
39
+
40
+ it 'should return false if the event port protocol is not tcp' do
41
+ expect(@good_event.port.tcp?).to be_falsey
42
+ end
43
+ end
44
+
45
+ describe 'Nessus Version 2: Event' do
46
+ before(:all) do
47
+ @xml = RubyNessus::Version2::XML.new(Helpers::DOT_NESSUS_V2)
48
+ @host = @xml.hosts.first
49
+ @good_event = @host.events.last
50
+ @bad_event = @host.events.first
51
+ @medium_event = @host.medium_severity_events.first
52
+ @rich_event = @host.events[22]
53
+ end
54
+
55
+ it 'should return the event plugin output' do
56
+ expect(@good_event.data).not_to be_nil
57
+ end
58
+
59
+ it 'should return the event plugin type' do
60
+ expect(@good_event.plugin_type).to be_kind_of(String)
61
+ end
62
+
63
+ it 'should return the event synopsis' do
64
+ expect(@medium_event.synopsis).to eq 'The remote web server encrypts traffic using an obsolete protocol.'
65
+ end
66
+
67
+ it 'should return the event description' do
68
+ expect(@medium_event.description).to start_with 'The remote web server accepts connections encrypted using Secure'
69
+ end
70
+
71
+ it 'should return the event solution' do
72
+ expect(@medium_event.solution).to eq "Rare or obsolete code is often poorly tested. Thus, it would be\nsafer to disable support for S-HTTP and use HTTPS instead."
73
+ end
74
+
75
+ it 'should return the event risk' do
76
+ expect(@medium_event.risk).to eq 'Medium'
77
+ end
78
+
79
+ it 'should return the event output' do
80
+ expect(@good_event.output).to eq "The difference between the local and remote clocks is 1 second.\n"
81
+ end
82
+
83
+ it 'should return false for the event output' do
84
+ expect(@medium_event.output).to be_falsey
85
+ end
86
+
87
+ it 'should return false for the event plugin version' do
88
+ expect(@medium_event.version).to eq '$Revision: 1.9 $'
89
+ end
90
+
91
+ it 'should return the see_also information for the event' do
92
+ expect(@medium_event.see_also).to eq ['http://tools.ietf.org/html/rfc2660', 'http://cpe.mitre.org/']
93
+ end
94
+
95
+ it 'should return the vulnerability publication date' do
96
+ expect(@rich_event.vuln_publication_date).to eq Time.parse('2009-11-04')
97
+ end
98
+
99
+ it 'should return the patch publication date' do
100
+ expect(@rich_event.patch_publication_date).to eq Time.parse('2009-11-05')
101
+ end
102
+
103
+ it 'should return false if there is no patch publication date' do
104
+ expect(@medium_event.patch_publication_date).to be_falsey
105
+ end
106
+
107
+ it 'should return the cvss base score' do
108
+ expect(@medium_event.cvss_base_score).to eq 5.0
109
+ end
110
+
111
+ it 'should return the cvss temporal score' do
112
+ expect(@medium_event.cvss_temporal_score).to eq 5.0
113
+ end
114
+
115
+ it 'should return the cve score' do
116
+ expect(@rich_event.cve.first).to be_kind_of(String)
117
+ expect(@rich_event.cve.first).not_to be_blank
118
+ end
119
+
120
+ it 'should return falsey if no cve' do
121
+ expect(@medium_event.cve).to be_falsey
122
+ end
123
+
124
+ it 'should not return bid if its not here' do
125
+ expect(@medium_event.bid).to be_falsey
126
+ end
127
+
128
+ it 'should return the bid' do
129
+ expect(@rich_event.bid.first).to eq '36935'
130
+ end
131
+
132
+ it 'should retun an empty tab if there is not other ref' do
133
+ expect(@medium_event.xref).to be_empty
134
+ end
135
+
136
+ it 'should return other related references' do
137
+ expect(@rich_event.xref.first).to eq 'OSVDB:59968'
138
+ end
139
+
140
+ it 'should return cvss_vector' do
141
+ expect(@medium_event.cvss_vector).to eq 'CVSS2#AV:N/AC:L/Au:N/C:P/I:N/A:N'
142
+ end
143
+
144
+ it 'should have a plugin_id' do
145
+ expect(@good_event.plugin_id).to be_kind_of(Integer)
146
+ end
147
+
148
+ it 'should have a plugin_id' do
149
+ expect(@good_event.plugin_family).to be_kind_of(String)
150
+ expect(@good_event.plugin_family).not_to be_blank
151
+ end
152
+
153
+ it 'should have a cpe Array (empty if no cpe)' do
154
+ expect(@good_event.cpe).to be_kind_of(Array)
155
+ end
156
+
157
+ it 'should have a exploitability_ease' do
158
+ expect(@good_event.exploitability_ease).to be_kind_of(String)
159
+ end
160
+
161
+ it 'should have a exploit_available' do
162
+ expect(@good_event.exploit_available).to be_falsey
163
+ end
164
+
165
+ it 'should have a exploit_framework_canvas' do
166
+ expect(@good_event.exploit_framework_canvas).to be_blank
167
+ end
168
+
169
+ it 'should have a canvas_package' do
170
+ expect(@good_event.canvas_package).to be_blank
171
+ end
172
+
173
+ it 'should have a exploit_framework_metasploit' do
174
+ expect(@good_event.exploit_framework_metasploit).to be_blank
175
+ end
176
+
177
+ it 'should have a metasploit_name' do
178
+ expect(@good_event.metasploit_name).to be_blank
179
+ end
180
+
181
+ it 'should have a exploit_framework_core' do
182
+ expect(@good_event.exploit_framework_core).to be_blank
183
+ end
184
+
185
+ # Bad Event
186
+
187
+ it 'should return false if the event name is nil' do
188
+ expect(@bad_event.name).to be_falsey
189
+ end
190
+ end
191
+ describe 'Nessus Version 2: Event severity' do
192
+ before(:all) do
193
+ @xml = RubyNessus::Version2::XML.new(Helpers::DOT_NESSUS_V2)
194
+ @host = @xml.hosts.first
195
+ @medium_event = @host.medium_severity_events.first
196
+ end
197
+
198
+ it 'should not have a informational severity' do
199
+ expect(@medium_event.informational?).to be false
200
+ end
201
+
202
+ it 'should not have a low severity' do
203
+ expect(@medium_event.low?).to be false
204
+ end
205
+
206
+ it 'should have a medium severity' do
207
+ expect(@medium_event.medium?).to be true
208
+ end
209
+
210
+ it 'should have not have a high severity' do
211
+ expect(@medium_event.high?).to be false
212
+ end
213
+
214
+ it 'should have not have a high severity' do
215
+ expect(@medium_event.critical?).to be false
216
+ end
217
+
218
+ it 'should have not have a high severity' do
219
+ expect(@medium_event.critical?).to be false
220
+ end
221
+
222
+ it 'should parse the event severity' do
223
+ expect(@medium_event.severity).to eq 2
224
+ end
225
+ end