nexpose 0.0.9 → 0.0.91

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.
@@ -0,0 +1,122 @@
1
+ module Nexpose
2
+ module NexposeAPI
3
+ include XMLUtils
4
+
5
+ def device_delete(param)
6
+ r = execute(make_xml('DeviceDeleteRequest', {'device-id' => param}))
7
+ r.success
8
+ end
9
+
10
+ def asset_group_delete(connection, id, debug = false)
11
+ r = execute(make_xml('AssetGroupDeleteRequest', {'group-id' => param}))
12
+ r.success
13
+ end
14
+
15
+ #-------------------------------------------------------------------------
16
+ # Returns all asset group information
17
+ #-------------------------------------------------------------------------
18
+ def asset_groups_listing()
19
+ r = execute(make_xml('AssetGroupListingRequest'))
20
+
21
+ if r.success
22
+ res = []
23
+ r.res.elements.each('//AssetGroupSummary') do |group|
24
+ res << {
25
+ :asset_group_id => group.attributes['id'].to_i,
26
+ :name => group.attributes['name'].to_s,
27
+ :description => group.attributes['description'].to_s,
28
+ :risk_score => group.attributes['riskscore'].to_f,
29
+ }
30
+ end
31
+ res
32
+ else
33
+ false
34
+ end
35
+ end
36
+
37
+ #-------------------------------------------------------------------------
38
+ # Returns an asset group configuration information for a specific group ID
39
+ #-------------------------------------------------------------------------
40
+ def asset_group_config(group_id)
41
+ r = execute(make_xml('AssetGroupConfigRequest', {'group-id' => group_id}))
42
+
43
+ if r.success
44
+ res = []
45
+ r.res.elements.each('//Devices/device') do |device_info|
46
+ res << {
47
+ :device_id => device_info.attributes['id'].to_i,
48
+ :site_id => device_info.attributes['site-id'].to_i,
49
+ :address => device_info.attributes['address'].to_s,
50
+ :riskfactor => device_info.attributes['riskfactor'].to_f,
51
+ }
52
+ end
53
+ res
54
+ else
55
+ false
56
+ end
57
+ end
58
+
59
+ #
60
+ # Lists all the users for the NSC along with the user details.
61
+ #
62
+ def list_users
63
+ r = execute(make_xml('UserListingRequest'))
64
+ if r.success
65
+ res = []
66
+ r.res.elements.each('//UserSummary') do |user_summary|
67
+ res << {
68
+ :auth_source => user_summary.attributes['authSource'],
69
+ :auth_module => user_summary.attributes['authModule'],
70
+ :user_name => user_summary.attributes['userName'],
71
+ :full_name => user_summary.attributes['fullName'],
72
+ :email => user_summary.attributes['email'],
73
+ :is_admin => user_summary.attributes['isAdmin'].to_s.chomp.eql?('1'),
74
+ :is_disabled => user_summary.attributes['disabled'].to_s.chomp.eql?('1'),
75
+ :site_count => user_summary.attributes['siteCount'],
76
+ :group_count => user_summary.attributes['groupCount']
77
+ }
78
+ end
79
+ res
80
+ else
81
+ false
82
+ end
83
+ end
84
+
85
+
86
+ def console_command(cmd_string)
87
+ xml = make_xml('ConsoleCommandRequest', {})
88
+ cmd = REXML::Element.new('Command')
89
+ cmd.text = cmd_string
90
+ xml << cmd
91
+
92
+ r = execute(xml)
93
+
94
+ if (r.success)
95
+ res = ""
96
+ r.res.elements.each("//Output") do |out|
97
+ res << out.text.to_s
98
+ end
99
+
100
+ res
101
+ else
102
+ false
103
+ end
104
+ end
105
+
106
+ def system_information
107
+ r = execute(make_xml('SystemInformationRequest', {}))
108
+
109
+ if (r.success)
110
+ res = {}
111
+ r.res.elements.each("//Statistic") do |stat|
112
+ res[stat.attributes['name'].to_s] = stat.text.to_s
113
+ end
114
+
115
+ res
116
+ else
117
+ false
118
+ end
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,570 @@
1
+ module Nexpose
2
+ module NexposeAPI
3
+ include XMLUtils
4
+
5
+ #
6
+ #
7
+ #
8
+ def report_generate(param)
9
+ r = execute(make_xml('ReportGenerateRequest', {'report-id' => param}))
10
+ r.success
11
+ end
12
+
13
+ #
14
+ #
15
+ #
16
+ def report_last(param)
17
+ r = execute(make_xml('ReportHistoryRequest', {'reportcfg-id' => param}))
18
+ res = nil
19
+ if (r.success)
20
+ stk = []
21
+ r.res.elements.each("//ReportSummary") do |rep|
22
+ stk << [rep.attributes['id'].to_i, rep.attributes['report-URI']]
23
+ end
24
+ if (stk.length > 0)
25
+ stk.sort! { |a, b| b[0] <=> a[0] }
26
+ res = stk[0][1]
27
+ end
28
+ end
29
+ res
30
+ end
31
+
32
+ #
33
+ #
34
+ #
35
+ def report_history(param)
36
+ execute(make_xml('ReportHistoryRequest', {'reportcfg-id' => param}))
37
+ end
38
+
39
+ #
40
+ #
41
+ #
42
+ def report_config_delete(param)
43
+ r = execute(make_xml('ReportDeleteRequest', {'reportcfg-id' => param}))
44
+ r.success
45
+ end
46
+
47
+ #
48
+ #
49
+ #
50
+ def report_delete(param)
51
+ r = execute(make_xml('ReportDeleteRequest', {'report-id' => param}))
52
+ r.success
53
+ end
54
+
55
+ #
56
+ #
57
+ #
58
+ def report_template_listing
59
+ r = execute(make_xml('ReportTemplateListingRequest', {}))
60
+
61
+ if (r.success)
62
+ res = []
63
+ r.res.elements.each("//ReportTemplateSummary") do |template|
64
+ desc = ''
65
+ template.elements.each("//description") do |ent|
66
+ desc = ent.text
67
+ end
68
+
69
+ res << {
70
+ :template_id => template.attributes['id'].to_s,
71
+ :name => template.attributes['name'].to_s,
72
+ :description => desc.to_s
73
+ }
74
+ end
75
+ res
76
+ else
77
+ false
78
+ end
79
+ end
80
+ end
81
+
82
+ # === Description
83
+ # Object that represents the summary of a Report Configuration.
84
+ #
85
+ class ReportConfigSummary
86
+ # The Report Configuration ID
87
+ attr_reader :id
88
+ # A unique name for the Report
89
+ attr_reader :name
90
+ # The report format
91
+ attr_reader :format
92
+ # The date of the last report generation
93
+ attr_reader :last_generated_on
94
+ # Relative URI of the last generated report
95
+ attr_reader :last_generated_uri
96
+
97
+ # Constructor
98
+ # ReportConfigSummary(id, name, format, last_generated_on, last_generated_uri)
99
+ def initialize(id, name, format, last_generated_on, last_generated_uri)
100
+
101
+ @id = id
102
+ @name = name
103
+ @format = format
104
+ @last_generated_on = last_generated_on
105
+ @last_generated_uri = last_generated_uri
106
+
107
+ end
108
+ end
109
+
110
+ # === Description
111
+ # Object that represents the schedule on which to automatically generate new reports.
112
+ class ReportHistory
113
+
114
+ # true if an error condition exists; false otherwise
115
+ attr_reader :error
116
+ # Error message string
117
+ attr_reader :error_msg
118
+ # The last XML request sent by this object
119
+ attr_reader :request_xml
120
+ # The last XML response received by this object
121
+ attr_reader :response_xml
122
+ # The NSC Connection associated with this object
123
+ attr_reader :connection
124
+ # The report definition (report config) ID
125
+ # Report definition ID
126
+ attr_reader :config_id
127
+ # Array (ReportSummary*)
128
+ attr_reader :report_summaries
129
+
130
+
131
+ def initialize(connection, config_id)
132
+
133
+ @error = false
134
+ @connection = connection
135
+ @config_id = config_id
136
+ @report_summaries = []
137
+
138
+ reportHistory_request = APIRequest.new('<ReportHistoryRequest session-id="' + "#{connection.session_id}" + '" reportcfg-id="' + "#{@config_id}" + '"/>', @connection.url)
139
+ reportHistory_request.execute()
140
+ @response_xml = reportHistory_request.response_xml
141
+ @request_xml = reportHistory_request.request_xml
142
+
143
+ end
144
+
145
+ def xml_parse(response)
146
+ response = REXML::Document.new(response.to_s)
147
+ status = response.root.attributes['success']
148
+ if (status == '1')
149
+ response.elements.each('ReportHistoryResponse/ReportSummary') do |r|
150
+ @report_summaries.push(ReportSummary.new(r.attributes["id"], r.attributes["cfg-id"], r.attributes["status"], r.attributes["generated-on"], r.attributes['report-uri']))
151
+ end
152
+ else
153
+ @error = true
154
+ @error_msg = 'Error ReportHistoryReponse'
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+ # === Description
161
+ # Object that represents the summary of a single report.
162
+ class ReportSummary
163
+
164
+ # The Report ID
165
+ attr_reader :id
166
+ # The Report Configuration ID
167
+ attr_reader :cfg_id
168
+ # The status of this report
169
+ # available | generating | failed
170
+ attr_reader :status
171
+ # The date on which this report was generated
172
+ attr_reader :generated_on
173
+ # The relative URI of the report
174
+ attr_reader :report_uri
175
+
176
+ def initialize(id, cfg_id, status, generated_on, report_uri)
177
+
178
+ @id = id
179
+ @cfg_id = cfg_id
180
+ @status = status
181
+ @generated_on = generated_on
182
+ @report_uri = report_uri
183
+
184
+ end
185
+
186
+ end
187
+
188
+ # === Description
189
+ #
190
+ class ReportAdHoc
191
+ include XMLUtils
192
+
193
+ attr_reader :error
194
+ attr_reader :error_msg
195
+ attr_reader :connection
196
+ # Report Template ID strong e.g. full-audit
197
+ attr_reader :template_id
198
+ # pdf|html|xml|text|csv|raw-xml
199
+ attr_reader :format
200
+ # Array of (ReportFilter)*
201
+ attr_reader :filters
202
+ attr_reader :request_xml
203
+ attr_reader :response_xml
204
+ attr_reader :report_decoded
205
+
206
+
207
+ def initialize(connection, template_id = 'full-audit', format = 'raw-xml')
208
+
209
+ @error = false
210
+ @connection = connection
211
+ @filters = Array.new()
212
+ @template_id = template_id
213
+ @format = format
214
+
215
+ end
216
+
217
+ def addFilter(filter_type, id)
218
+
219
+ # filter_type can be site|group|device|scan
220
+ # id is the ID number. For scan, you can use 'last' for the most recently run scan
221
+ filter = ReportFilter.new(filter_type, id)
222
+ filters.push(filter)
223
+
224
+ end
225
+
226
+ def generate()
227
+ request_xml = '<ReportAdhocGenerateRequest session-id="' + @connection.session_id + '">'
228
+ request_xml += '<AdhocReportConfig template-id="' + @template_id + '" format="' + @format + '">'
229
+ request_xml += '<Filters>'
230
+ @filters.each do |f|
231
+ request_xml += '<filter type="' + f.type + '" id="'+ f.id.to_s + '"/>'
232
+ end
233
+ request_xml += '</Filters>'
234
+ request_xml += '</AdhocReportConfig>'
235
+ request_xml += '</ReportAdhocGenerateRequest>'
236
+
237
+ ad_hoc_request = APIRequest.new(request_xml, @connection.url)
238
+ ad_hoc_request.execute()
239
+
240
+ content_type_response = ad_hoc_request.raw_response.header['Content-Type']
241
+ if content_type_response =~ /multipart\/mixed;\s*boundary=([^\s]+)/
242
+ # NeXpose sends an incorrect boundary format which breaks parsing
243
+ # Eg: boundary=XXX; charset=XXX
244
+ # Fix by removing everything from the last semi-colon onward
245
+ last_semi_colon_index = content_type_response.index(/;/, content_type_response.index(/boundary/))
246
+ content_type_response = content_type_response[0, last_semi_colon_index]
247
+
248
+ data = "Content-Type: " + content_type_response + "\r\n\r\n" + ad_hoc_request.raw_response_data
249
+ doc = Rex::MIME::Message.new data
250
+ doc.parts.each do |part|
251
+ if /.*base64.*/ =~ part.header.to_s
252
+ return parse_xml(part.content.unpack("m*")[0])
253
+ end
254
+ end
255
+ end
256
+ end
257
+
258
+ end
259
+
260
+ # === Description
261
+ # Object that represents the configuration of a report definition.
262
+ #
263
+ class ReportConfig
264
+
265
+ # true if an error condition exists; false otherwise
266
+ attr_reader :error
267
+ # Error message string
268
+ attr_reader :error_msg
269
+ # The last XML request sent by this object
270
+ attr_reader :request_xml
271
+ # The last XML response received by this object
272
+ attr_reader :response_xml
273
+ # The NSC Connection associated with this object
274
+ attr_reader :connection
275
+ # The ID for this report definition
276
+ attr_reader :config_id
277
+ # A unique name for this report definition
278
+ attr_reader :name
279
+ # The template ID used for this report definition
280
+ attr_reader :template_id
281
+ # html, db, txt, xml, raw-xml, csv, pdf
282
+ attr_reader :format
283
+ # XXX new
284
+ attr_reader :timezone
285
+ # XXX new
286
+ attr_reader :owner
287
+ # Array of (ReportFilter)* - The Sites, Asset Groups, or Devices to run the report against
288
+ attr_reader :filters
289
+ # Automatically generate a new report at the conclusion of a scan
290
+ # 1 or 0
291
+ attr_reader :generate_after_scan
292
+ # Schedule to generate reports
293
+ # ReportSchedule Object
294
+ attr_reader :schedule
295
+ # Store the reports on the server
296
+ # 1 or 0
297
+ attr_reader :storeOnServer
298
+ # Location to store the report on the server
299
+ attr_reader :store_location
300
+ # Form to send the report via email
301
+ # "file", "zip", "url", or NULL (don’t send email)
302
+ attr_reader :email_As
303
+ # Send the Email to all Authorized Users
304
+ # boolean - Send the Email to all Authorized Users
305
+ attr_reader :email_to_all
306
+ # Array containing the email addresses of the recipients
307
+ attr_reader :email_recipients
308
+ # IP Address or Hostname of SMTP Relay Server
309
+ attr_reader :smtp_relay_server
310
+ # Sets the FROM field of the Email
311
+ attr_reader :sender
312
+ # TODO
313
+ attr_reader :db_export
314
+ # TODO
315
+ attr_reader :csv_export
316
+ # TODO
317
+ attr_reader :xml_export
318
+
319
+
320
+ def initialize(connection, config_id = -1)
321
+
322
+ @error = false
323
+ @connection = connection
324
+ @config_id = config_id
325
+ @xml_tag_stack = Array.new()
326
+ @filters = Array.new()
327
+ @email_recipients = Array.new()
328
+ @name = "New Report " + rand(999999999).to_s
329
+
330
+ r = @connection.execute('<ReportConfigRequest session-id="' + @connection.session_id.to_s + '" reportcfg-id="' + @config_id.to_s + '"/>')
331
+ if (r.success)
332
+ r.res.elements.each('ReportConfigResponse/ReportConfig') do |r|
333
+ @name = r.attributes['name']
334
+ @format = r.attributes['format']
335
+ @timezone = r.attributes['timezone']
336
+ @id = r.attributes['id']
337
+ @template_id = r.attributes['template-id']
338
+ @owner = r.attributes['owner']
339
+ end
340
+ else
341
+ @error = true
342
+ @error_msg = 'Error ReportHistoryReponse'
343
+ end
344
+ end
345
+
346
+ # === Description
347
+ # Generate a new report on this report definition. Returns the new report ID.
348
+ def generateReport(debug = false)
349
+ return generateReport(@connection, @config_id, debug)
350
+ end
351
+
352
+ # === Description
353
+ # Save the report definition to the NSC.
354
+ # Returns the config-id.
355
+ def saveReport()
356
+ r = @connection.execute('<ReportSaveRequest session-id="' + @connection.session_id.to_s + '">' + getXML().to_s + ' </ReportSaveRequest>')
357
+ if (r.success)
358
+ @config_id = r.attributes['reportcfg-id']
359
+ return true
360
+ end
361
+ return false
362
+ end
363
+
364
+ # === Description
365
+ # Adds a new filter to the report config
366
+ def addFilter(filter_type, id)
367
+ filter = ReportFilter.new(filter_type, id)
368
+ @filters.push(filter)
369
+ end
370
+
371
+ # === Description
372
+ # Adds a new email recipient
373
+ def addEmailRecipient(recipient)
374
+ @email_recipients.push(recipient)
375
+ end
376
+
377
+ # === Description
378
+ # Sets the schedule for this report config
379
+ def setSchedule(schedule)
380
+ @schedule = schedule
381
+ end
382
+
383
+ def getXML()
384
+
385
+ xml = '<ReportConfig id="' + @config_id.to_s + '" name="' + @name.to_s + '" template-id="' + @template_id.to_s + '" format="' + @format.to_s + '">'
386
+
387
+ xml += ' <Filters>'
388
+
389
+ @filters.each do |f|
390
+ xml += ' <' + f.type.to_s + ' id="' + f.id.to_s + '"/>'
391
+ end
392
+
393
+ xml += ' </Filters>'
394
+
395
+ xml += ' <Generate after-scan="' + @generate_after_scan.to_s + '">'
396
+
397
+ if (@schedule)
398
+ xml += ' <Schedule type="' + @schedule.type.to_s + '" interval="' + @schedule.interval.to_s + '" start="' + @schedule.start.to_s + '"/>'
399
+ end
400
+
401
+ xml += ' </Generate>'
402
+
403
+ xml += ' <Delivery>'
404
+
405
+ xml += ' <Storage storeOnServer="' + @storeOnServer.to_s + '">'
406
+
407
+ if (@store_location and @store_location.length > 0)
408
+ xml += ' <location>' + @store_location.to_s + '</location>'
409
+ end
410
+
411
+ xml += ' </Storage>'
412
+
413
+
414
+ xml += ' </Delivery>'
415
+
416
+ xml += ' </ReportConfig>'
417
+
418
+ return xml
419
+ end
420
+
421
+ def set_name(name)
422
+ @name = name
423
+ end
424
+
425
+ def set_template_id(template_id)
426
+ @template_id = template_id
427
+ end
428
+
429
+ def set_format(format)
430
+ @format = format
431
+ end
432
+
433
+ def set_email_As(email_As)
434
+ @email_As = email_As
435
+ end
436
+
437
+ def set_storeOnServer(storeOnServer)
438
+ @storeOnServer = storeOnServer
439
+ end
440
+
441
+ def set_smtp_relay_server(smtp_relay_server)
442
+ @smtp_relay_server = smtp_relay_server
443
+ end
444
+
445
+ def set_sender(sender)
446
+ @sender = sender
447
+ end
448
+
449
+ def set_generate_after_scan(generate_after_scan)
450
+ @generate_after_scan = generate_after_scan
451
+ end
452
+ end
453
+
454
+ # === Description
455
+ # Object that represents a report filter which determines which sites, asset
456
+ # groups, and/or devices that a report is run against. gtypes are
457
+ # "SiteFilter", "AssetGroupFilter", "DeviceFilter", or "ScanFilter". gid is
458
+ # the site-id, assetgroup-id, or devce-id. ScanFilter, if used, specifies
459
+ # a specifies a specific scan to use as the data source for the report. The gid
460
+ # can be a specific scan-id or "first" for the first run scan, or “last” for
461
+ # the last run scan.
462
+ #
463
+ class ReportFilter
464
+
465
+ attr_reader :type
466
+ attr_reader :id
467
+
468
+ def initialize(type, id)
469
+
470
+ @type = type
471
+ @id = id
472
+
473
+ end
474
+
475
+ end
476
+
477
+
478
+ # === Description
479
+ # Object that represents the schedule on which to automatically generate new reports.
480
+ #
481
+ class ReportSchedule
482
+
483
+ # The type of schedule
484
+ # (daily, hourly, monthly, weekly)
485
+ attr_reader :type
486
+ # The frequency with which to run the scan
487
+ attr_reader :interval
488
+ # The earliest date to generate the report
489
+ attr_reader :start
490
+
491
+ def initialize(type, interval, start)
492
+
493
+ @type = type
494
+ @interval = interval
495
+ @start = start
496
+
497
+ end
498
+
499
+
500
+ end
501
+
502
+ class ReportTemplateListing
503
+
504
+ attr_reader :error_msg
505
+ attr_reader :error
506
+ attr_reader :request_xml
507
+ attr_reader :response_xml
508
+ attr_reader :connection
509
+ attr_reader :xml_tag_stack
510
+ attr_reader :report_template_summaries #; //Array (ReportTemplateSummary*)
511
+
512
+
513
+ def initialize(connection)
514
+
515
+ @error = nil
516
+ @connection = connection
517
+ @report_template_summaries = Array.new()
518
+
519
+ r = @connection.execute('<ReportTemplateListingRequest session-id="' + connection.session_id.to_s + '"/>')
520
+ if (r.success)
521
+ r.res.elements.each('ReportTemplateListingResponse/ReportTemplateSummary') do |r|
522
+ @report_template_summaries.push(ReportTemplateSumary.new(r.attributes['id'], r.attributes['name']))
523
+ end
524
+ else
525
+ @error = true
526
+ @error_msg = 'ReportTemplateListingRequest Parse Error'
527
+ end
528
+
529
+ end
530
+
531
+ end
532
+
533
+
534
+ class ReportTemplateSummary
535
+
536
+ attr_reader :id
537
+ attr_reader :name
538
+ attr_reader :description
539
+
540
+ def initialize(id, name, description)
541
+
542
+ @id = id
543
+ @name = name
544
+ @description = description
545
+
546
+ end
547
+
548
+ end
549
+
550
+
551
+ class ReportSection
552
+
553
+ attr_reader :name
554
+ attr_reader :properties
555
+
556
+ def initialize(name)
557
+
558
+ @properties = Array.new()
559
+ @name = name
560
+ end
561
+
562
+
563
+ def addProperty(name, value)
564
+
565
+ @properties[name.to_s] = value
566
+ end
567
+
568
+ end
569
+
570
+ end