nexpose 0.0.9 → 0.0.91

Sign up to get free protection for your applications and to get access to all the features.
@@ -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