nessus-xmlrpc 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Vlatko Kosturjak
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,84 @@
1
+ = nessus-xmlrpc
2
+
3
+ Nessus XML RPC library and Nessus Command Line interface to XML RPC
4
+
5
+ (C) Vlatko Kosturjak, Kost. Distributed under MIT.
6
+
7
+ Requirements
8
+ ============
9
+ Requirements are quite standard Ruby libraries for HTTPS and XML
10
+ parsing:
11
+ require 'uri'
12
+ require 'net/https'
13
+ require 'rexml/document'
14
+
15
+ nessus-cli.rb
16
+ =============
17
+ Nessus command line interface for XML-RPC.
18
+
19
+ Type ./nessus-cli.rb --help for command line options.
20
+
21
+ Examples:
22
+ ---------
23
+
24
+ ./nessus-cli.rb --user john --password doe --scan scan-localhost --wait --output report.xml --target localhost
25
+
26
+ ./nessus-cli.rb --user user --password pass --scan localhost-scan --wait 5 -D --output report-localhost.xml --target localhost --verbose
27
+
28
+ ./nessus-cli.rb --user user --password pass --scan localhost-scan --wait 5 -D --output report-localhost.xml --target 127.0.0.1 --verbose --policy mypolicy --url https://localhost:8834
29
+
30
+ Or if you want to have detached scans:
31
+ --------------------------------------
32
+
33
+ ./nessus-cli.rb --user user --password pass --scan localhost-scan --target 127.0.0.1 --policy mypolicy
34
+
35
+ ./nessus-cli.rb --user user --password pass --list-scans
36
+
37
+ ./nessus-cli.rb --user user --password pass --pause 5329fae9-fb1d-0c67-a401-a0db12637c0d5bcd67900d34e00e
38
+
39
+ ./nessus-cli.rb --user user --password pass --resume 5329fae9-fb1d-0c67-a401-a0db12637c0d5bcd67900d34e00e
40
+
41
+ ./nessus-cli.rb --user user --password pass --stop 5329fae9-fb1d-0c67-a401-a0db12637c0d5bcd67900d34e00e
42
+
43
+ ./nessus-cli.rb --user user --password pass --stop-all
44
+
45
+ ./nessus-cli.rb --user user --password pass --report 5329fae9-fb1d-0c67-a401-a0db12637c0d5bcd67900d34e00e --output report.xml
46
+
47
+ nessus-xmlrpc.rb
48
+ ================
49
+ communicate with Nessus(4.2+) over XML RPC interface
50
+
51
+ Simple example:
52
+
53
+ require 'nessus-xmlrpc'
54
+ n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
55
+ # n=NessusXMLRPC::NessusXMLRPC.new('','user','pass'); # it's same
56
+ if n.logged_in
57
+ id,name = n.policy_get_first
58
+ puts "using policy ID: " + id + " with name: " + name
59
+ uid=n.scan_new(id,"textxmlrpc","127.0.0.1")
60
+ puts "status: " + n.scan_status(uid)
61
+ while not n.scan_finished(uid)
62
+ sleep 10
63
+ end
64
+ content=n.report_file_download(uid)
65
+ File.open('report.xml', 'w') {|f| f.write(content) }
66
+ end
67
+
68
+ Take a look at nessus-cli.rb for more advanced examples.
69
+
70
+ == Contributing to nessus-xmlrpc
71
+
72
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
73
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
74
+ * Fork the project
75
+ * Start a feature/bugfix branch
76
+ * Commit and push until you are happy with your contribution
77
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
78
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
79
+
80
+ == Copyright
81
+
82
+ Copyright (c) 2010 Vlatko Kosturjak. See LICENSE.txt for
83
+ further details.
84
+
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "nessus-xmlrpc"
16
+ gem.homepage = "http://nessus-xmlrpc.rubyforge.org/"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Nessus XML RPC library and Nessus Command Line interface to XML RPC}
19
+ gem.description = %Q{Ruby library for Nessus XMLRPC interface and Nessus command line example of using Ruby library. This library is used for communication with Nessus over XML RPC interface. You can start, stop, pause and resume scan. Watch progress and status of scan, download report, etc. }
20
+ gem.email = "vlatko.kosturjak@gmail.com"
21
+ gem.authors = ["Vlatko Kosturjak"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ gem.rubyforge_project = "nessus-xmlrpc"
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ require 'rcov/rcovtask'
38
+ Rcov::RcovTask.new do |test|
39
+ test.libs << 'test'
40
+ test.pattern = 'test/**/test_*.rb'
41
+ test.verbose = true
42
+ end
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "nessus-xmlrpc #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/TODO ADDED
@@ -0,0 +1 @@
1
+ - Error handling, no puts
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.0
data/bin/nessus-cli.rb ADDED
@@ -0,0 +1,382 @@
1
+ #!/usr/bin/env ruby
2
+ # = nessus-cli.rb: Nessus command line interface for XML-RPC
3
+ # Author:: Vlatko Kosturjak
4
+ #
5
+ # (C) Vlatko Kosturjak, Kost. Distributed under GPL and BSD (dual licensed).
6
+
7
+ require 'nessus-xmlrpc'
8
+ require 'getoptlong'
9
+
10
+ verbose = 0
11
+ debug = 0
12
+ operation = ''
13
+ targets = ''
14
+ deletereport = false
15
+ user = ''
16
+ password = ''
17
+ scanname = ''
18
+ output = ''
19
+ output1 = ''
20
+ wait = ''
21
+ policy = ''
22
+ url = ''
23
+
24
+ def intro
25
+ $stderr.print $0 + ": Nessus command line interface for XML-RPC\n"
26
+ $stderr.print "(C) Vlatko Kosturjak, Kost. Distributed under GPL.\n"
27
+ $stderr.print "\n"
28
+ end
29
+
30
+ intro
31
+
32
+ def give_help
33
+ puts <<-EOF
34
+ --user <user> user for login to Nessus server
35
+ --password <p> password for login to Nessus server
36
+ --scan <name> start scan with name
37
+ --target <ip> specify list of targets, separated by comma
38
+ --policy <pol> specify policy to use (name of policy)
39
+ --url <url> url of Nessus server (default: localhost:8834)
40
+ --wait [t] wait scan to finish (ask in regular periods of <t> for status)
41
+ --output <f> output report XML to file <f>
42
+ --output1 <f> output report XML v1 to file <f>
43
+ --reportdelete delete report after finish or delete report by id (if alone)
44
+ --stop <id> stop scan identified by <id>
45
+ --stop-all stop all scans
46
+ --pause <id> pause scan identified by <id>
47
+ --pause-all pause all scans
48
+ --resume <id> resume scan identified by <id>
49
+ --resume-all resume all scans
50
+ --report <id> download report identified by <id>
51
+ --list-scans list scans
52
+ --list-policy list policies
53
+ --status <id> get status of scan by <id>
54
+ --verbose be verbose
55
+ --debug be even more verbose
56
+ --help this help
57
+
58
+ Examples:
59
+ #{$0} --user john --password doe --scan scan-localhost --wait --output report.xml --target localhost
60
+ EOF
61
+ exit 0
62
+ end
63
+
64
+ if ARGV.length < 1
65
+ give_help
66
+ end
67
+
68
+ opt = GetoptLong.new(
69
+ ["--help", "-h", GetoptLong::NO_ARGUMENT],
70
+ ["--verbose", "-v", GetoptLong::OPTIONAL_ARGUMENT],
71
+ ["--target", "-t", GetoptLong::REQUIRED_ARGUMENT],
72
+ ["--user", "-u", GetoptLong::REQUIRED_ARGUMENT],
73
+ ["--password", "-p", GetoptLong::REQUIRED_ARGUMENT],
74
+ ["--policy", "-P", GetoptLong::REQUIRED_ARGUMENT],
75
+ ["--url", "-U", GetoptLong::REQUIRED_ARGUMENT],
76
+ ["--deletereport", "-D", GetoptLong::OPTIONAL_ARGUMENT],
77
+ ["--wait", "-w", GetoptLong::OPTIONAL_ARGUMENT],
78
+ ["--scan", "-s", GetoptLong::REQUIRED_ARGUMENT],
79
+ ["--list-scans", "-l", GetoptLong::NO_ARGUMENT],
80
+ ["--list-policy", "-L", GetoptLong::NO_ARGUMENT],
81
+ ["--status", "-W", GetoptLong::REQUIRED_ARGUMENT],
82
+ ["--stop", "-S", GetoptLong::REQUIRED_ARGUMENT],
83
+ ["--stop-all", "-a", GetoptLong::NO_ARGUMENT],
84
+ ["--pause", "-q", GetoptLong::REQUIRED_ARGUMENT],
85
+ ["--pause-all", "-Q", GetoptLong::NO_ARGUMENT],
86
+ ["--resume", "-e", GetoptLong::REQUIRED_ARGUMENT],
87
+ ["--resume-all", "-E", GetoptLong::NO_ARGUMENT],
88
+ ["--report", "-r", GetoptLong::REQUIRED_ARGUMENT],
89
+ ["--output", "-o", GetoptLong::REQUIRED_ARGUMENT],
90
+ ["--output1", "-1", GetoptLong::REQUIRED_ARGUMENT]
91
+ )
92
+
93
+ def give_error
94
+ $stderr.print "You used incompatible options, probably you mixed --scan with --stop"
95
+ $stderr.print "or something similar."
96
+ exit 0
97
+ end
98
+
99
+ opt.each do |opt,arg|
100
+ case opt
101
+ when '--help'
102
+ give_help
103
+ when '--user'
104
+ user = arg
105
+ when '--password'
106
+ password = arg
107
+ when '--stop'
108
+ if operation == ''
109
+ operation = "stop"
110
+ scanname = arg
111
+ else
112
+ give_error
113
+ end
114
+ when '--pause'
115
+ if operation == ''
116
+ operation = "pause"
117
+ scanname = arg
118
+ else
119
+ give_error
120
+ end
121
+ when '--resume'
122
+ if operation == ''
123
+ operation = "resume"
124
+ scanname = arg
125
+ else
126
+ give_error
127
+ end
128
+ when '--stop-all'
129
+ if operation == ''
130
+ operation = "stop-all"
131
+ else
132
+ give_error
133
+ end
134
+ when '--pause-all'
135
+ if operation == ''
136
+ operation = "pause-all"
137
+ else
138
+ give_error
139
+ end
140
+ when '--resume-all'
141
+ if operation == ''
142
+ operation = "resume-all"
143
+ else
144
+ give_error
145
+ end
146
+ when '--report'
147
+ if operation == ''
148
+ operation = "report"
149
+ scanname = arg
150
+ else
151
+ give_error
152
+ end
153
+ when '--scan'
154
+ if operation == ''
155
+ operation = "scan"
156
+ scanname = arg
157
+ else
158
+ give_error
159
+ end
160
+ when '--target'
161
+ if arg[0..6] == 'file://'
162
+ f = File.open(arg[7..-1], "r")
163
+ f.each_line do |line|
164
+ line=line.chomp
165
+ line=line.strip
166
+ unless line == '' or line == nil
167
+ if targets == ''
168
+ targets = line
169
+ else
170
+ targets = targets + "," + line
171
+ end
172
+ end
173
+ end
174
+ f.close
175
+ else
176
+ # if there's multiple target options, add comma
177
+ if targets == ''
178
+ targets = arg
179
+
180
+ else
181
+ targets = targets + "," + arg
182
+ end
183
+ end
184
+ when '--wait'
185
+ if arg == ''
186
+ wait = 15
187
+ else
188
+ wait = arg.to_i
189
+ end
190
+ when '--reportdelete'
191
+ if arg = ''
192
+ deletereport=true
193
+ else
194
+ operation = "reportdelete"
195
+ scanname = arg
196
+ end
197
+
198
+ when '--output'
199
+ output = arg
200
+ when '--output1'
201
+ output1 = arg
202
+ when '--policy'
203
+ policy = arg
204
+ when '--status'
205
+ if operation == ''
206
+ operation = "status"
207
+ scanname = arg
208
+ else
209
+ give_error
210
+ end
211
+ when '--url'
212
+ url = arg
213
+ when '--verbose'
214
+ if arg == ''
215
+ verbose += 1
216
+ else
217
+ verbose = arg.to_i
218
+ end
219
+ when '--debug'
220
+ if arg == ''
221
+ debug += 1
222
+ else
223
+ debug = arg.to_i
224
+ end
225
+ when '--list-scans'
226
+ if operation == ''
227
+ operation = "list-scans"
228
+ scanname = arg
229
+ else
230
+ give_error
231
+ end
232
+ when '--list-policy'
233
+ if operation == ''
234
+ operation = "list-policy"
235
+ scanname = arg
236
+ else
237
+ give_error
238
+ end
239
+ end
240
+ end
241
+
242
+ if (user == '') or (password == '')
243
+ $stderr.print "User and password is required to login to Nessus server"
244
+ $stderr.print "Try --help!"
245
+ exit 1
246
+ end
247
+
248
+ $stderr.print "[i] Targets: " + targets +"\n" if verbose > 0
249
+ $stderr.print "[i] Connecting to nessus server: " if verbose > 0
250
+ n=NessusXMLRPC::NessusXMLRPC.new(url,user,password)
251
+ if n.logged_in
252
+ $stderr.print "OK!\n" if verbose > 0
253
+ else
254
+ $stderr.print "[e] Error connecting/logging to the server!\n"
255
+ exit 2
256
+ end
257
+
258
+ case operation
259
+ when "scan"
260
+ if policy == ''
261
+ $stderr.print "[w] Policy not defined, using first served from the server\n"
262
+ pid,name = n.policy_get_first
263
+ $stderr.print "[w] using policy id " + pid + " with name " + name + "\n"
264
+ else
265
+ pid=n.policy_get_id(policy)
266
+ if pid == ''
267
+ $stderr.print "[e] policy doesn't exit: " + policy + "\n"
268
+ exit 3
269
+ end
270
+ end
271
+ if targets == ''
272
+ $stderr.print "[w] Targets not defined, using localhost as target\n"
273
+ targets = '127.0.0.1'
274
+ end
275
+ $stderr.print "[i] Initiating scan with targets: "+targets+': ' if verbose > 0
276
+ uid=n.scan_new(pid,scanname,targets)
277
+ $stderr.print "done\n" if verbose > 0
278
+ unless wait == ''
279
+ while not n.scan_finished(uid)
280
+ $stderr.print "[v] Sleeping for " + wait.to_s() + ": " if verbose > 1
281
+ sleep wait
282
+ $stderr.print "done\n" if verbose > 1
283
+ stat = n.scan_status(uid)
284
+ print "\r" + stat if verbose > 0
285
+ end
286
+ else
287
+ puts uid
288
+ exit 0
289
+ end
290
+ unless output == ''
291
+ $stderr.print "[i] Output XML report to file: "+output if verbose > 0
292
+ content=n.report_file_download(uid)
293
+ File.open(output, 'w') {|f| f.write(content) }
294
+ $stderr.print ": done\n" if verbose > 0
295
+ end
296
+ unless output1 == ''
297
+ $stderr.print "[i] Output XML1 report to file: "+output1 if verbose > 0
298
+ content=n.report_file1_download(uid)
299
+ File.open(output, 'w') {|f| f.write(content) }
300
+ $stderr.print ": done\n" if verbose > 0
301
+ end
302
+ if deletereport
303
+ $stderr.print "[i] Deleting report: " if verbose > 0
304
+ n.report_delete(uid)
305
+ $stderr.print "done\n" if verbose > 0
306
+ end
307
+ when "report"
308
+ uid=scanname
309
+ if (output == '') and (output1 == '')
310
+ $stderr.print "[e] You want report, but specify filename with --output or output1\n"
311
+ end
312
+ unless output == ''
313
+ $stderr.print "[i] Output XML report to file: "+output if verbose > 0
314
+ content=n.report_file_download(uid)
315
+ File.open(output, 'w') {|f| f.write(content) }
316
+ $stderr.print ": done\n" if verbose > 0
317
+ end
318
+ unless output1 == ''
319
+ $stderr.print "[i] Output XML1 report to file: "+output1 if verbose > 0
320
+ content=n.report1_file_download(uid)
321
+ File.open(output, 'w') {|f| f.write(content) }
322
+ $stderr.print ": done\n" if verbose > 0
323
+ end
324
+ if deletereport
325
+ $stderr.print "[i] Deleting report: " if verbose > 0
326
+ n.report_delete(uid)
327
+ $stderr.print "done\n" if verbose > 0
328
+ end
329
+ when "stop"
330
+ $stderr.print "[i] Stopping scan: " + scanname if verbose > 0
331
+ n.scan_stop(scanname)
332
+ $stderr.print "done\n" if verbose > 0
333
+ when "stop-all"
334
+ $stderr.print "[i] Stopping all scans: " if verbose > 0
335
+ list=n.scan_stop_all
336
+ $stderr.print "done\n" if verbose > 0
337
+ if verbose > 1
338
+ list.each {|uuid| puts "[v] Stop all: " + uuid }
339
+ end
340
+ when "pause"
341
+ $stderr.print "[i] Pausing scan: " + scanname if verbose > 0
342
+ n.scan_pause(scanname)
343
+ $stderr.print "done\n" if verbose > 0
344
+ when "pause-all"
345
+ $stderr.print "[i] Pausing all scans: " if verbose > 0
346
+ list=n.scan_pause_all
347
+ $stderr.print "done\n" if verbose > 0
348
+ if verbose > 1
349
+ list.each {|uuid| puts "[v] Pause all: " + uuid }
350
+ end
351
+ when "resume"
352
+ $stderr.print "[i] Resuming scan: " + scanname if verbose > 0
353
+ n.scan_resume(scanname)
354
+ $stderr.print "done\n" if verbose > 0
355
+ when "resume-all"
356
+ $stderr.print "[i] Resuming all scans: " if verbose > 0
357
+ list=n.scan_resume_all
358
+ $stderr.print "done\n" if verbose > 0
359
+ if verbose > 1
360
+ list.each {|uuid| puts "[v] Resume all: " + uuid }
361
+ end
362
+ when "reportdelete"
363
+ $stderr.print "[i] Deleting report: " + scanname if verbose > 0
364
+ n.report_delete(scanname)
365
+ $stderr.print "done\n" if verbose > 0
366
+ when "status"
367
+ puts "status: " + n.scan_status(scanname)
368
+ when "list-scans"
369
+ list=n.scan_list_hash
370
+ list.each {|scan|
371
+ puts scan['id']+":"+scan['name']+":"+ \
372
+ scan['current']+"/"+scan['total']
373
+ }
374
+ when "list-policy"
375
+ list=n.policy_list_names
376
+ list.each {|policy|
377
+ puts policy
378
+ }
379
+
380
+ end
381
+
382
+ $stderr.print "[v] End reached.\n" if verbose > 1
@@ -0,0 +1,580 @@
1
+ #
2
+ # = nessus-xmlrpc.rb: communicate with Nessus(4.2+) over XML RPC interface
3
+ #
4
+ # Author:: Vlatko Kosturjak
5
+ #
6
+ # (C) Vlatko Kosturjak, Kost. Distributed under GPL and BSD license (dual).
7
+ #
8
+ # == What is this library?
9
+ #
10
+ # This library is used for communication with Nessus over XML RPC interface.
11
+ # You can start, stop, pause and resume scan. Watch progress and status of scan,
12
+ # download report, etc.
13
+ #
14
+ # == Requirements
15
+ #
16
+ # Required libraries are standard Ruby libraries: uri, net/https and rexml/document.
17
+ #
18
+ # == Optional
19
+ #
20
+ # Library is able to use nokogiri if available, but nokogiri is not required.
21
+ #
22
+ # == Usage:
23
+ #
24
+ # require 'nessus-xmlrpc'
25
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
26
+ # if n.logged_in
27
+ # id,name = n.policy_get_first
28
+ # puts "using policy ID: " + id + " with name: " + name
29
+ # uid=n.scan_new(id,"textxmlrpc","127.0.0.1")
30
+ # puts "status: " + n.scan_status(uid)
31
+ # while not n.scan_finished(uid)
32
+ # sleep 10
33
+ # end
34
+ # content=n.report_file_download(uid)
35
+ # File.open('report.xml', 'w') {|f| f.write(content) }
36
+ # end
37
+
38
+ require 'uri'
39
+ require 'net/https'
40
+ require 'rexml/document'
41
+
42
+ # NessusXMLRPC module
43
+ #
44
+ # Usage:
45
+ #
46
+ # require 'nessus-xmlrpc'
47
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
48
+ # if n.logged_in
49
+ # id,name = n.policy_get_first
50
+ # uid=n.scan_new(id,"textxmlrpc","127.0.0.1")
51
+ # puts "status: " + n.scan_status(uid)
52
+ # end
53
+ #
54
+ # Check NessusXMLRPCrexml for description of methods implemented
55
+ # (for both NessusXMLRPCnokogiri and NessusXMLRPCrexml).
56
+
57
+ module NessusXMLRPC
58
+
59
+ # Class which uses standard REXML to parse nessus XML RPC replies.
60
+ # It is adviseable to use NessusXMLRPC class, not this class directly.
61
+ # As NessusXMLRPC class will use nokogiri or rexml, depending on availability.
62
+ class NessusXMLRPCrexml
63
+ # initialize object: try to connect to Nessus Scanner using URL, user and password
64
+ #
65
+ # Usage:
66
+ #
67
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
68
+ def initialize(url,user,password)
69
+ if url == ''
70
+ @nurl="https://localhost:8834/"
71
+ else
72
+ if url =~ /\/$/
73
+ @nurl=url
74
+ else
75
+ @nurl=url + "/"
76
+ end
77
+ end
78
+ @token=''
79
+ login(user,password)
80
+ end
81
+
82
+ # checks if we're logged in correctly
83
+ #
84
+ # returns: true if logged in, false if not
85
+ #
86
+ # Usage:
87
+ #
88
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
89
+ # if n.logged_in
90
+ # puts "Logged in"
91
+ # else
92
+ # puts "Error"
93
+ # end
94
+ def logged_in
95
+ if @token == ''
96
+ return false
97
+ else
98
+ return true
99
+ end
100
+ end
101
+
102
+ # send standard Nessus XML request and check
103
+ #
104
+ # returns: rexml/document root
105
+ def nessus_request(uri, post_data)
106
+ body=nessus_http_request(uri, post_data)
107
+ # puts response.body
108
+ docxml = REXML::Document.new(body)
109
+ begin
110
+ status = docxml.root.elements['status'].text
111
+ rescue
112
+ puts "[e] error in XML parsing"
113
+ end
114
+ if status == "OK"
115
+ return docxml
116
+ else
117
+ return ''
118
+ end
119
+ end
120
+
121
+ # send standard Nessus HTTP request and check
122
+ #
123
+ # returns: body of response
124
+ def nessus_http_request(uri, post_data)
125
+ url = URI.parse(@nurl + uri)
126
+ request = Net::HTTP::Post.new( url.path )
127
+ request.set_form_data( post_data )
128
+ if not defined? @https
129
+ @https = Net::HTTP.new( url.host, url.port )
130
+ @https.use_ssl = true
131
+ @https.verify_mode = OpenSSL::SSL::VERIFY_NONE
132
+ end
133
+ # puts request
134
+ begin
135
+ response = @https.request( request )
136
+ rescue
137
+ puts "[e] error connecting to server: "+ @nurl + " with URI: " + uri
138
+
139
+ exit
140
+ end
141
+ # puts response.body
142
+ return response.body
143
+ end
144
+
145
+ # login with user & password and sets object-wide @token, @name and @admin
146
+ def login(user, password)
147
+ post = { "login" => user, "password" => password }
148
+ docxml=nessus_request('login', post)
149
+ if docxml == ''
150
+ @token=''
151
+ else
152
+ @token = docxml.root.elements['contents'].elements['token'].text
153
+ @name = docxml.root.elements['contents'].elements['user'].elements['name'].text
154
+ @admin = docxml.root.elements['contents'].elements['user'].elements['admin'].text
155
+ # puts "Got token:" + @token
156
+ end
157
+
158
+ end
159
+
160
+ # initiate new scan with policy id, descriptive name and list of targets
161
+ #
162
+ # returns: uuid of scan
163
+ #
164
+ # Usage:
165
+ #
166
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
167
+ # if n.logged_in
168
+ # id,name = n.policy_get_first
169
+ # puts "using policy ID: " + id + " with name: " + name
170
+ # uid=n.scan_new(id,"textxmlrpc","127.0.0.1")
171
+ # end
172
+ def scan_new(policy_id,scan_name,target)
173
+ post= { "token" => @token, "policy_id" => policy_id, "scan_name" => scan_name, "target" => target }
174
+ docxml=nessus_request('scan/new', post)
175
+ if docxml == ''
176
+ return ''
177
+ else
178
+ uuid=docxml.root.elements['contents'].elements['scan'].elements['uuid'].text
179
+ return uuid
180
+ end
181
+ end
182
+
183
+ # get uids of scans
184
+ #
185
+ # returns: array of uids of active scans
186
+ def scan_list_uids
187
+ post= { "token" => @token }
188
+ docxml=nessus_request('scan/list', post)
189
+ uuids=Array.new
190
+ docxml.root.elements['contents'].elements['scans'].elements['scanList'].each_element('//scan') {|scan| uuids.push(scan.elements['uuid'].text) }
191
+ return uuids
192
+ end
193
+
194
+ # get hash of active scan data
195
+ #
196
+ # returns: array of hash of active scans
197
+ def scan_list_hash
198
+ post= { "token" => @token }
199
+ docxml=nessus_request('scan/list', post)
200
+ scans=Array.new
201
+ docxml.root.elements['contents'].elements['scans'].elements['scanList'].each_element('//scan') {|scan|
202
+ entry=Hash.new
203
+ entry['id']=scan.elements['uuid'].text
204
+ entry['name']=scan.elements['readableName'].text
205
+ entry['current']=scan.elements['completion_current'].text;
206
+ entry['total']=scan.elements['completion_total'].text;
207
+ scans.push(entry)
208
+ }
209
+ return scans
210
+ end
211
+
212
+ # get policy by textname and return policyID
213
+ #
214
+ # returns: policyID
215
+ def policy_get_id(textname)
216
+ post= { "token" => @token }
217
+ docxml=nessus_request('policy/list', post)
218
+ docxml.root.elements['contents'].elements['policies'].each_element('//policy') {|policy|
219
+ if policy.elements['policyName'].text == textname
220
+ return policy.elements['policyID'].text
221
+ end
222
+ }
223
+ return ''
224
+ end
225
+
226
+ # get first policy from server and returns: policyID, policyName
227
+ #
228
+ # returns: policyID, policyName
229
+ def policy_get_first
230
+ post= { "token" => @token }
231
+ docxml=nessus_request('policy/list', post)
232
+ docxml.root.elements['contents'].elements['policies'].each_element('//policy') {|policy|
233
+ return policy.elements['policyID'].text, policy.elements['policyName'].text
234
+ }
235
+ end
236
+
237
+ # get list of policy IDs
238
+ #
239
+ # returns: array of all policy uids
240
+ def policy_list_uids
241
+ post= { "token" => @token }
242
+ docxml=nessus_request('policy/list', post)
243
+ pids=Array.new
244
+ docxml.root.elements['contents'].elements['policies'].each_element('//policy') { |policy|
245
+ pids.push(policy.elements['policyID'].text) }
246
+ return pids
247
+ end
248
+
249
+ # stop scan identified by scan_uuid
250
+ def scan_stop(uuid)
251
+ post= { "token" => @token, "scan_uuid" => uuid }
252
+ docxml=nessus_request('scan/stop', post)
253
+ return docxml
254
+ end
255
+ # stop all active scans
256
+ #
257
+ # Usage:
258
+ #
259
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
260
+ # if n.logged_in
261
+ # n.scan_stop_all
262
+ # end
263
+ def scan_stop_all
264
+ b=scan_list_uids
265
+ b.each {|uuid|
266
+ scan_stop(uuid)
267
+ }
268
+ return b
269
+ end
270
+ # pause scan identified by scan_uuid
271
+ def scan_pause(uuid)
272
+ post= { "token" => @token, "scan_uuid" => uuid }
273
+ docxml=nessus_request('scan/pause', post)
274
+ return docxml
275
+ end
276
+ # pause all active scans
277
+ #
278
+ # Usage:
279
+ #
280
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
281
+ # if n.logged_in
282
+ # n.scan_pause_all
283
+ # end
284
+ def scan_pause_all
285
+ b=scan_list_uids
286
+ b.each {|uuid|
287
+ scan_pause(uuid)
288
+ }
289
+ return b
290
+ end
291
+ # remove scan identified by uuid
292
+ def scan_resume(uuid)
293
+ post= { "token" => @token, "scan_uuid" => uuid }
294
+ docxml=nessus_request('scan/resume', post)
295
+ return docxml
296
+ end
297
+ # resume all active scans
298
+ #
299
+ # Usage:
300
+ #
301
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
302
+ # if n.logged_in
303
+ # n.scan_resume_all
304
+ # end
305
+ def scan_resume_all
306
+ b=scan_list_uids
307
+ b.each {|uuid|
308
+ scan_resume(uuid)
309
+ }
310
+ return b
311
+ end
312
+
313
+ # check status of scan identified by uuid
314
+ def scan_status(uuid)
315
+ post= { "token" => @token, "report" => uuid }
316
+ docxml=nessus_request('report/list', post)
317
+ docxml.root.elements['contents'].elements['reports'].each_element('//report') { |report|
318
+ if report.elements['name'].text == uuid
319
+ return (report.elements['status'].text)
320
+ end
321
+ }
322
+ return ''
323
+ end
324
+
325
+ # check if scan is finished (completed to be exact) identified by uuid
326
+ def scan_finished(uuid)
327
+ status=scan_status(uuid)
328
+ if status == "completed"
329
+ return true
330
+ else
331
+ return false
332
+ end
333
+ end
334
+
335
+ # get report by reportID and return XML file
336
+ #
337
+ # returns: XML file of report (nessus v2 format)
338
+ def report_file_download(report)
339
+ post= { "token" => @token, "report" => report }
340
+ file=nessus_http_request('file/report/download', post)
341
+ return file
342
+ end
343
+
344
+ # get report by reportID and return XML file (version 1)
345
+ #
346
+ # returns: XML file of report (nessus v1 format)
347
+ def report_file1_download(report)
348
+ post= { "token" => @token, "report" => report, "v1" => "true" }
349
+ file=nessus_http_request('file/report/download', post)
350
+ return file
351
+ end
352
+
353
+ # delete report by report ID
354
+ def report_delete(id)
355
+ post= { "token" => @token, "report" => id }
356
+ docxml=nessus_request('report/delete', post)
357
+ return docxml
358
+ end
359
+
360
+ # get list of names of policies
361
+ #
362
+ # returns: array of names
363
+ def policy_list_names
364
+ post= { "token" => @token }
365
+ docxml=nessus_request('policy/list', post)
366
+ list = Array.new
367
+ docxml.root.elements['contents'].elements['policies'].each_element('//policy') {|policy|
368
+ list.push policy.elements['policyName'].text
369
+ }
370
+ return list
371
+ end
372
+
373
+ # get hosts for particular report
374
+ #
375
+ # returns: array of hosts
376
+ def report_hosts(report_id)
377
+ post= { "token" => @token, "report" => report_id }
378
+ docxml=nessus_request('report/hosts', post)
379
+ list = Array.new
380
+ docxml.root.elements['contents'].elements['hostList'].each_element('//host') { |host|
381
+ list.push host.elements['hostname'].text
382
+ }
383
+ return list
384
+ end
385
+
386
+ # get host details for particular host identified by report id
387
+ #
388
+ # returns: severity, current, total
389
+ def report_get_host(report_id,host)
390
+ post= { "token" => @token, "report" => report_id }
391
+ docxml=nessus_request('report/hosts', post)
392
+ docxml.root.elements['contents'].elements['hostList'].each_element('//host') { |host|
393
+ if host.elements['hostname'].text == host
394
+ retval={}
395
+ retval["severity"] = host.elements['severity'].text
396
+ retval["current"] = host.elements['scanProgressCurrent'].text
397
+ retval["total"] = host.elements['scanProgressTotal'].text
398
+ return retval
399
+ end
400
+ }
401
+ end
402
+ #-- ToDo items
403
+ def plugins_list
404
+ post= { "token" => @token }
405
+ docxml=nessus_request('plugins/list', post)
406
+ return docxml
407
+ end
408
+ def users_list
409
+ post= { "token" => @token }
410
+ docxml=nessus_request('users/list', post)
411
+ return docxml
412
+ end
413
+ end # end of NessusXMLRPC::Class
414
+
415
+ # use nokogiri if available (it's faster!)
416
+ nokogiri=true
417
+ begin
418
+ require 'nokogiri'
419
+ rescue LoadError
420
+ nokogiri=false
421
+ end
422
+
423
+ # if found nokogiri
424
+ if nokogiri
425
+ # Class which uses nokogiri to parse nessus XML RPC replies.
426
+ # It is adviseable to use NessusXMLRPC class, not this class directly.
427
+ # As NessusXMLRPC class will use nokogiri or rexml, depending on availability.
428
+ #
429
+ # Documentation for this class documents only differences from NessusXMLRPCrexml.
430
+ # <b> So, check NessusXMLRPCrexml for method documentation </b>
431
+ class NessusXMLRPCnokogiri < NessusXMLRPCrexml
432
+ # send standard Nessus XML request and check
433
+ #
434
+ # return: nokogiri XML file
435
+ def nessus_request(uri, post_data)
436
+ body=nessus_http_request(uri, post_data)
437
+ docxml = Nokogiri::XML.parse(body)
438
+ begin
439
+ status = docxml.xpath("/reply/status").collect(&:text)[0]
440
+ rescue
441
+ puts "[e] error in XML parsing"
442
+ end
443
+ if status == "OK"
444
+ return docxml
445
+ else
446
+ return ''
447
+ end
448
+ end
449
+
450
+ def login(user, password)
451
+ post = { "login" => user, "password" => password }
452
+ docxml=nessus_request('login', post)
453
+ if docxml == ''
454
+ @token=''
455
+ else
456
+ @token = docxml.xpath("/reply/contents/token").collect(&:text)[0]
457
+ @name = docxml.xpath("/reply/contents/user/name").collect(&:text)[0]
458
+ @admin = docxml.xpath("/reply/contents/user/admin").collect(&:text)[0]
459
+ end
460
+
461
+ end
462
+
463
+ def scan_new(policy_id,scan_name,target)
464
+ post= { "token" => @token, "policy_id" => policy_id, "scan_name" => scan_name, "target" => target }
465
+ docxml=nessus_request('scan/new', post)
466
+ if docxml == ''
467
+ return ''
468
+ else
469
+ uuid=docxml.xpath("/reply/contents/scan/uuid").collect(&:text)[0]
470
+ return uuid
471
+ end
472
+ end
473
+
474
+ def scan_status(uuid)
475
+ post= { "token" => @token, "report" => uuid }
476
+ docxml=nessus_request('report/list', post)
477
+ return docxml.xpath("/reply/contents/reports/report/name[text()='"+uuid+"']/../status").collect(&:text)[0]
478
+ end
479
+
480
+ def scan_list_uids
481
+ post= { "token" => @token }
482
+ docxml=nessus_request('scan/list', post)
483
+ return docxml.xpath("/reply/contents/scans/scanList/scan/uuid").collect(&:text)
484
+ end
485
+
486
+ def scan_list_hash
487
+ post= { "token" => @token }
488
+ docxml=nessus_request('scan/list', post)
489
+ items = docxml.xpath("/reply/contents/scans/scanList/scan")
490
+ retval = items.collect do |item|
491
+ tmpitem = {}
492
+ [
493
+ [:id, 'uuid'],
494
+ [:name, 'readableName'],
495
+ [:current, 'completion_current'],
496
+ [:total, 'completion_total']
497
+ ].collect do |key, xpath|
498
+ tmpitem[key] = item.at_xpath(xpath).content
499
+ end
500
+ tmpitem
501
+ end
502
+ return retval
503
+ end
504
+
505
+ def policy_get_id(textname)
506
+ post= { "token" => @token }
507
+ docxml=nessus_request('policy/list', post)
508
+ return docxml.xpath("/reply/contents/policies/policy/policyName[text()='"+textname+"']/..policyID").collect(&:text)[0]
509
+ end
510
+
511
+ def policy_list_uids
512
+ post= { "token" => @token }
513
+ docxml=nessus_request('policy/list', post)
514
+ return docxml.xpath("/reply/contents/policies/policy/policyID").collect(&:text)
515
+ end
516
+
517
+ def policy_get_first
518
+ post= { "token" => @token }
519
+ docxml=nessus_request('policy/list', post)
520
+ id=docxml.xpath("/reply/contents/policies/policy/policyID").collect(&:text)[0]
521
+ name=docxml.xpath("/reply/contents/policies/policy/policyName").collect(&:text)[0]
522
+ return id, name
523
+ end
524
+
525
+ def policy_list_names
526
+ post= { "token" => @token }
527
+ docxml=nessus_request('policy/list', post)
528
+ return docxml.xpath("/reply/contents/policies/policy/policyName").collect(&:text)
529
+ end
530
+
531
+ def report_hosts(report_id)
532
+ post= { "token" => @token, "report" => report_id }
533
+ docxml=nessus_request('report/hosts', post)
534
+ return docxml.xpath("/reply/contents/hostList/host/hostname").collect(&:text)
535
+ end
536
+
537
+ def report_get_host(report_id,host)
538
+ post= { "token" => @token, "report" => report_id }
539
+ docxml=nessus_request('report/hosts', post)
540
+ items = docxml.xpath("/reply/contents/hostList/host/hostname[text()='"+host+"']")
541
+ retval = items.collect do |item|
542
+ tmpitem = {}
543
+ [
544
+ [:severity, 'severity'],
545
+ [:current, 'scanProgressCurrent'],
546
+ [:total, 'scanProgressTotal']
547
+ ].collect do |key, xpath|
548
+ tmpitem[key] = item.at_xpath(xpath).content
549
+ end
550
+ tmpitem
551
+ end
552
+ return retval
553
+ end
554
+
555
+ end # end of NessusXMLRPCnokogiri::Class
556
+ # Main class which controls Nessus using XMLRPC.
557
+ # It is adviseable to use this NessusXMLRPC class, and not NessusXMLRPCnokogiri or NessusXMLRPCrexml,
558
+ # As NessusXMLRPC class will use nokogiri or rexml, depending on availability.
559
+ # Of course, choosing nokogiri first because of speed.
560
+ #
561
+ # Example:
562
+ #
563
+ # n=NessusXMLRPC::NessusXMLRPC.new('https://localhost:8834','user','pass');
564
+ # if n.logged_in
565
+ # id,name = n.policy_get_first
566
+ # uid=n.scan_new(id,"textxmlrpc","127.0.0.1")
567
+ # puts "status: " + n.scan_status(uid)
568
+ # end
569
+ #
570
+ # Check NessusXMLRPCrexml for description of methods implemented
571
+ # (for both NessusXMLRPCnokogiri and NessusXMLRPCrexml).
572
+ class NessusXMLRPC < NessusXMLRPCnokogiri
573
+ end
574
+ else # nokogiri not found, use REXML
575
+ class NessusXMLRPC < NessusXMLRPCrexml
576
+ end
577
+ end # if nokogiri
578
+
579
+ end # of Module
580
+
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'nessus-xmlrpc'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,6 @@
1
+ require 'helper'
2
+
3
+ class TestNessusXmlrpc < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nessus-xmlrpc
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 4
8
+ - 0
9
+ version: 0.4.0
10
+ platform: ruby
11
+ authors:
12
+ - Vlatko Kosturjak
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-29 00:00:00 +00:00
18
+ default_executable: nessus-cli.rb
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: shoulda
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ prerelease: false
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 1
42
+ - 0
43
+ - 0
44
+ version: 1.0.0
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: jeweler
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 1
57
+ - 5
58
+ - 2
59
+ version: 1.5.2
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: rcov
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ type: :development
74
+ prerelease: false
75
+ version_requirements: *id004
76
+ description: "Ruby library for Nessus XMLRPC interface and Nessus command line example of using Ruby library. This library is used for communication with Nessus over XML RPC interface. You can start, stop, pause and resume scan. Watch progress and status of scan, download report, etc. "
77
+ email: vlatko.kosturjak@gmail.com
78
+ executables:
79
+ - nessus-cli.rb
80
+ extensions: []
81
+
82
+ extra_rdoc_files:
83
+ - LICENSE.txt
84
+ - README.rdoc
85
+ - TODO
86
+ files:
87
+ - .document
88
+ - Gemfile
89
+ - LICENSE.txt
90
+ - README.rdoc
91
+ - Rakefile
92
+ - TODO
93
+ - VERSION
94
+ - bin/nessus-cli.rb
95
+ - lib/nessus-xmlrpc.rb
96
+ - test/helper.rb
97
+ - test/test_nessus-xmlrpc.rb
98
+ has_rdoc: true
99
+ homepage: http://nessus-xmlrpc.rubyforge.org/
100
+ licenses:
101
+ - MIT
102
+ post_install_message:
103
+ rdoc_options: []
104
+
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 1047249299
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ segments:
122
+ - 0
123
+ version: "0"
124
+ requirements: []
125
+
126
+ rubyforge_project: nessus-xmlrpc
127
+ rubygems_version: 1.3.7
128
+ signing_key:
129
+ specification_version: 3
130
+ summary: Nessus XML RPC library and Nessus Command Line interface to XML RPC
131
+ test_files:
132
+ - test/helper.rb
133
+ - test/test_nessus-xmlrpc.rb