ruby-nessus2 2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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