nessus-xmlrpc 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +84 -0
- data/Rakefile +54 -0
- data/TODO +1 -0
- data/VERSION +1 -0
- data/bin/nessus-cli.rb +382 -0
- data/lib/nessus-xmlrpc.rb +580 -0
- data/test/helper.rb +18 -0
- data/test/test_nessus-xmlrpc.rb +6 -0
- metadata +133 -0
data/.document
ADDED
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/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
|
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
|