nexpose 0.2.8 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8303bf73cfbd73693c68670f4dd448eccc8c2a0
4
- data.tar.gz: b28294ca9658ae322e759a851ad13fa35d2bf06e
3
+ metadata.gz: 096649e7275b4dd061fab3b7331e93f66fdec709
4
+ data.tar.gz: 483e8f15738e9b4297a702ee07c78b9f75381f6a
5
5
  SHA512:
6
- metadata.gz: b58c671197ce229fb7518f2cfd7ee02940931bee4c9e5a832ae54737600331f2e831ea085b4ec2b9c5d90380e9f0ca37b3534dc0c9c6ee0802b3397c96ef549a
7
- data.tar.gz: 7423eb92c736ef27cd5273bdc079dbf9806845663c98d7bd79197d79660ebab8187d80110b145ac70c385644caa33b88bbff5211e0f8ab4deda787d02e372c41
6
+ metadata.gz: 368763434ec2b93e957cbf596b36eeeddad7728170234dee6eaa72155e30f11d3826bc7503e22952005f2f10b6bc9cce0ad39769355cd1aeff59082d107db335
7
+ data.tar.gz: a02679981f17023624c99887fd2c9677678c6e1148a302c0aa7e0b1ce17c292bad83810c6a56da2e4614853fd009702a740f5d87fb41eb935a18359592a233ad
data/lib/nexpose.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  #
4
4
  =begin
5
5
 
6
- Copyright (C) 2009-2012, Rapid7 LLC
6
+ Copyright (C) 2009-2013, Rapid7 LLC
7
7
  All rights reserved.
8
8
 
9
9
  Redistribution and use in source and binary forms, with or without modification,
@@ -54,25 +54,34 @@ require 'net/http'
54
54
  require 'uri'
55
55
  require 'rex/mime'
56
56
  require 'ipaddr'
57
+ require 'json'
57
58
  require 'nexpose/error'
58
59
  require 'nexpose/util'
59
- require 'nexpose/user'
60
+ require 'nexpose/alert'
61
+ require 'nexpose/ajax'
60
62
  require 'nexpose/api_request'
63
+ require 'nexpose/common'
64
+ require 'nexpose/creds'
65
+ require 'nexpose/data_table'
66
+ require 'nexpose/device'
67
+ require 'nexpose/engine'
68
+ require 'nexpose/filter'
69
+ require 'nexpose/group'
70
+ require 'nexpose/dag'
61
71
  require 'nexpose/manage'
62
- require 'nexpose/misc'
72
+ require 'nexpose/pool'
63
73
  require 'nexpose/report'
74
+ require 'nexpose/report_template'
75
+ require 'nexpose/role'
64
76
  require 'nexpose/scan'
65
- require 'nexpose/scan_engine'
77
+ require 'nexpose/scan_template'
66
78
  require 'nexpose/silo'
67
79
  require 'nexpose/site'
68
80
  require 'nexpose/ticket'
81
+ require 'nexpose/user'
69
82
  require 'nexpose/vuln'
70
- require 'nexpose/creds'
83
+ require 'nexpose/vuln_exception'
71
84
  require 'nexpose/connection'
72
- require 'nexpose/role'
73
- require 'nexpose/common'
74
- require 'nexpose/group'
75
- require 'nexpose/alert'
76
85
 
77
86
  module Nexpose
78
87
 
@@ -0,0 +1,127 @@
1
+ # encoding: utf-8
2
+
3
+ module Nexpose
4
+
5
+ # Accessor to the Nexpose AJAX API.
6
+ # These core methods should allow direct access to underlying controllers
7
+ # in order to test functionality that is not currently exposed
8
+ # through the XML API.
9
+ #
10
+ module AJAX
11
+ module_function
12
+
13
+ # GET call to a Nexpose controller.
14
+ #
15
+ # @param [Connection] nsc API connection to a Nexpose console.
16
+ # @param [String] uri Controller address relative to https://host:port
17
+ # @param [String] content_type Content type to use when issuing the GET.
18
+ # @return [String|REXML::Document|Hash] The response from the call.
19
+ #
20
+ def get(nsc, uri, content_type = 'text/xml; charset=UTF-8')
21
+ get = Net::HTTP::Get.new(uri)
22
+ get.set_content_type(content_type)
23
+ _request(nsc, get)
24
+ end
25
+
26
+ # PUT call to a Nexpose controller.
27
+ #
28
+ # @param [Connection] nsc API connection to a Nexpose console.
29
+ # @param [String] uri Controller address relative to https://host:port
30
+ # @param [String|REXML::Document] payload XML document required by the call.
31
+ # @param [String] content_type Content type to use when issuing the PUT.
32
+ # @return [String] The response from the call.
33
+ #
34
+ def put(nsc, uri, payload = nil, content_type = 'text/xml; charset=UTF-8')
35
+ put = Net::HTTP::Put.new(uri)
36
+ put.set_content_type(content_type)
37
+ put.body = payload.to_s if payload
38
+ _request(nsc, put)
39
+ end
40
+
41
+ # POST call to a Nexpose controller.
42
+ #
43
+ # @param [Connection] nsc API connection to a Nexpose console.
44
+ # @param [String] uri Controller address relative to https://host:port
45
+ # @param [String|REXML::Document] payload XML document required by the call.
46
+ # @param [String] content_type Content type to use when issuing the POST.
47
+ # @return [String|REXML::Document|Hash] The response from the call.
48
+ #
49
+ def post(nsc, uri, payload = nil, content_type = 'text/xml')
50
+ post = Net::HTTP::Post.new(uri)
51
+ post.set_content_type(content_type)
52
+ post.body = payload.to_s if payload
53
+ _request(nsc, post)
54
+ end
55
+
56
+ # POST call to a Nexpose controller that uses a form-post model.
57
+ # This is here to support legacy use of POST in old controllers.
58
+ #
59
+ # @param [Connection] nsc API connection to a Nexpose console.
60
+ # @param [String] uri Controller address relative to https://host:port
61
+ # @param [Hash] parameters Hash of attributes that need to be sent
62
+ # to the controller.
63
+ # @param [String] content_type Content type to use when issuing the POST.
64
+ # @return [Hash] The parsed JSON response from the call.
65
+ #
66
+ def form_post(nsc, uri, parameters, content_type = 'application/x-www-form-urlencoded; charset=UTF-8')
67
+ post = Net::HTTP::Post.new(uri)
68
+ post.set_content_type(content_type)
69
+ post.set_form_data(parameters)
70
+ _request(nsc, post)
71
+ end
72
+
73
+ # DELETE call to a Nexpose controller.
74
+ #
75
+ # @param [Connection] nsc API connection to a Nexpose console.
76
+ # @param [String] uri Controller address relative to https://host:port
77
+ # @param [String] content_type Content type to use when issuing the DELETE.
78
+ def delete(nsc, uri, content_type = 'text/xml')
79
+ delete = Net::HTTP::Delete.new(uri)
80
+ delete.set_content_type(content_type)
81
+ _request(nsc, delete)
82
+ end
83
+
84
+ # Append the query parameters to given URI.
85
+ #
86
+ # @param [String] uri Controller address relative to https://host:port
87
+ # @param [Hash] parameters Hash of attributes that need to be sent
88
+ # to the controller.
89
+ # @return [Hash] The parametrized URI.
90
+
91
+ def parametrize_uri(uri, parameters)
92
+ uri = uri.concat(('?').concat(parameters.map { |k, v| "#{k}=#{CGI.escape(v[0].to_s)}" }.join('&'))) if parameters
93
+ end
94
+
95
+ ###
96
+ # Internal helper methods
97
+
98
+ # Use the Nexpose::Connection to establish a correct HTTPS object.
99
+ def _https(nsc)
100
+ http = Net::HTTP.new(nsc.host, nsc.port)
101
+ http.use_ssl = true
102
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
103
+ http
104
+ end
105
+
106
+ # Attach necessary header fields.
107
+ def _headers(nsc, request)
108
+ request.add_field('nexposeCCSessionID', nsc.session_id)
109
+ request.add_field('Cookie', "nexposeCCSessionID=#{nsc.session_id}")
110
+ end
111
+
112
+ def _request(nsc, request)
113
+ http = _https(nsc)
114
+ _headers(nsc, request)
115
+
116
+ # Return response body if request is successful. Brittle.
117
+ response = http.request(request)
118
+ case response
119
+ when Net::HTTPOK
120
+ response.body
121
+ else
122
+ req_type = request.class.name.split('::').last
123
+ raise Nexpose::APIError.new(response, "#{req_type} request to #{request.path} failed. #{request.body}")
124
+ end
125
+ end
126
+ end
127
+ end
data/lib/nexpose/alert.rb CHANGED
@@ -7,21 +7,16 @@ module Nexpose
7
7
 
8
8
  # Name for this alert.
9
9
  attr_accessor :name
10
-
11
10
  # Whether or not this alert is currently active.
12
11
  attr_accessor :enabled
13
-
14
12
  # Send at most this many alerts per scan.
15
13
  attr_accessor :max_alerts
16
-
17
14
  # Send alerts based upon scan status.
18
15
  attr_accessor :scan_filter
19
-
20
16
  # Send alerts based upon vulnerability finding status.
21
17
  attr_accessor :vuln_filter
22
-
23
18
  # Alert type and its configuration. One of SMTPAlert, SyslogAlert, SNMPAlert
24
- attr_accessor :alert
19
+ attr_accessor :type
25
20
 
26
21
  def initialize(name, enabled = 1, max_alerts = -1)
27
22
  @name, @enabled, @max_alerts = name, enabled, max_alerts
@@ -29,13 +24,13 @@ module Nexpose
29
24
 
30
25
  def to_xml
31
26
  xml = '<Alert'
32
- xml << %Q( name="#{@name}")
33
- xml << %Q( enabled="#{@enabled}")
34
- xml << %Q( maxAlerts="#{@max_alerts}")
27
+ xml << %( name="#{@name}")
28
+ xml << %( enabled="#{@enabled}")
29
+ xml << %( maxAlerts="#{@max_alerts}")
35
30
  xml << '>'
36
31
  xml << scan_filter.to_xml
37
32
  xml << vuln_filter.to_xml
38
- xml << alert.to_xml
33
+ xml << type.to_xml
39
34
  xml << '</Alert>'
40
35
  end
41
36
 
@@ -43,7 +38,7 @@ module Nexpose
43
38
  #
44
39
  # @param [REXML::Document] rexml XML document to parse.
45
40
  # @return [Alert] Alert object represented by the XML.
46
- #
41
+ #
47
42
  def self.parse(rexml)
48
43
  name = rexml.attributes['name']
49
44
  rexml.elements.each("//Alert[@name='#{name}']") do |xml|
@@ -53,11 +48,11 @@ module Nexpose
53
48
  alert.scan_filter = ScanFilter.parse(REXML::XPath.first(xml, "//Alert[@name='#{name}']/scanFilter"))
54
49
  alert.vuln_filter = VulnFilter.parse(REXML::XPath.first(xml, "//Alert[@name='#{name}']/vulnFilter"))
55
50
  if (type = REXML::XPath.first(xml, "//Alert[@name='#{name}']/smtpAlert"))
56
- alert.alert = SMTPAlert.parse(type)
51
+ alert.type = SMTPAlert.parse(type)
57
52
  elsif (type = REXML::XPath.first(xml, "//Alert[@name='#{name}']/syslogAlert"))
58
- alert.alert = SyslogAlert.parse(type)
53
+ alert.type = SyslogAlert.parse(type)
59
54
  elsif (type = REXML::XPath.first(xml, "//Alert[@name='#{name}']/snmpAlert"))
60
- alert.alert = SNMPAlert.parse(type)
55
+ alert.type = SNMPAlert.parse(type)
61
56
  end
62
57
  return alert
63
58
  end
@@ -78,11 +73,11 @@ module Nexpose
78
73
 
79
74
  def to_xml
80
75
  xml = '<scanFilter'
81
- xml << %Q( scanStart="#{@start}")
82
- xml << %Q( scanStop="#{@stop}")
83
- xml << %Q( scanFailed="#{@fail}")
84
- xml << %Q( scanResumed="#{@resume}")
85
- xml << %Q( scanPaused="#{@pause}")
76
+ xml << %( scanStart="#{@start}")
77
+ xml << %( scanStop="#{@stop}")
78
+ xml << %( scanFailed="#{@fail}")
79
+ xml << %( scanResumed="#{@resume}")
80
+ xml << %( scanPaused="#{@pause}")
86
81
  xml << '/>'
87
82
  end
88
83
 
@@ -99,6 +94,7 @@ module Nexpose
99
94
  # Set values to 1 to enable and 0 to disable.
100
95
  #
101
96
  class VulnFilter
97
+
102
98
  # Only alert on vulnerability findings with a severity level greater than this level.
103
99
  # Range is 0 to 10.
104
100
  # Values in the UI correspond as follows:
@@ -116,10 +112,10 @@ module Nexpose
116
112
 
117
113
  def to_xml
118
114
  xml = '<vulnFilter'
119
- xml << %Q( severityThreshold="#{@severity}")
120
- xml << %Q( confirmed="#{@confirmed}")
121
- xml << %Q( unconfirmed="#{@unconfirmed}")
122
- xml << %Q( potential="#{@potential}")
115
+ xml << %( severityThreshold="#{@severity}")
116
+ xml << %( confirmed="#{@confirmed}")
117
+ xml << %( unconfirmed="#{@unconfirmed}")
118
+ xml << %( potential="#{@potential}")
123
119
  xml << '/>'
124
120
  end
125
121
 
@@ -151,7 +147,7 @@ module Nexpose
151
147
 
152
148
  def to_xml
153
149
  xml = '<syslogAlert'
154
- xml << %Q( server="#{replace_entities(server)}">)
150
+ xml << %( server="#{replace_entities(server)}">)
155
151
  xml << '</syslogAlert>'
156
152
  end
157
153
  end
@@ -180,8 +176,8 @@ module Nexpose
180
176
 
181
177
  def to_xml
182
178
  xml = '<snmpAlert'
183
- xml << %Q( community="#{replace_entities(community)}")
184
- xml << %Q( server="#{replace_entities(server)}">)
179
+ xml << %( community="#{replace_entities(community)}")
180
+ xml << %( server="#{replace_entities(server)}">)
185
181
  xml << '</snmpAlert>'
186
182
  end
187
183
  end
@@ -191,15 +187,12 @@ module Nexpose
191
187
  #
192
188
  class SMTPAlert
193
189
 
194
- # The email address of the sender
190
+ # The e-mail address of the sender.
195
191
  attr_accessor :sender
196
-
197
- # The server to sent this alert
192
+ # The server to sent this alert.
198
193
  attr_accessor :server
199
-
200
- # Limit the text for mobile devices
194
+ # Limit the text for mobile devices.
201
195
  attr_accessor :limit_text
202
-
203
196
  # Array of strings with the e-mail addresses of the intended recipients.
204
197
  attr_accessor :recipients
205
198
 
@@ -210,7 +203,7 @@ module Nexpose
210
203
  @recipients = []
211
204
  end
212
205
 
213
- # Adds a new Recipient to the recipients array
206
+ # Adds a new recipient to the alert.
214
207
  def add_recipient(recipient)
215
208
  @recipients << recipient
216
209
  end
@@ -219,9 +212,9 @@ module Nexpose
219
212
 
220
213
  def to_xml
221
214
  xml = '<smtpAlert'
222
- xml << %Q( sender="#{replace_entities(sender)}")
223
- xml << %Q( server="#{replace_entities(server)}")
224
- xml << %Q( limitText="#{limit_text}">)
215
+ xml << %( sender="#{replace_entities(sender)}")
216
+ xml << %( server="#{replace_entities(server)}")
217
+ xml << %( limitText="#{limit_text}">)
225
218
  recipients.each do |recpt|
226
219
  xml << "<recipient>#{replace_entities(recpt)}</recipient>"
227
220
  end
@@ -27,6 +27,7 @@ module Nexpose
27
27
  # the application will send reports via e-mail to access-list members and
28
28
  # non-members.
29
29
  class Email
30
+
30
31
  # Send as file attachment or zipped file to individuals who are not members
31
32
  # of the report access list. One of: file|zip
32
33
  attr_accessor :send_as
@@ -55,17 +56,17 @@ module Nexpose
55
56
 
56
57
  def to_xml
57
58
  xml = '<Email'
58
- xml << %Q{ toAllAuthorized='#{@toAllAuthorized ? 1 : 0}'}
59
- xml << %Q{ sendToOwnerAs='#{@send_to_owner_as}'} if @send_to_owner_as
60
- xml << %Q{ sendToAclAs='#{@send_to_acl_as}'} if @send_to_acl_as
61
- xml << %Q{ sendAs='#{@send_as}'} if @send_as
59
+ xml << %( toAllAuthorized='#{@toAllAuthorized ? 1 : 0}')
60
+ xml << %( sendToOwnerAs='#{@send_to_owner_as}') if @send_to_owner_as
61
+ xml << %( sendToAclAs='#{@send_to_acl_as}') if @send_to_acl_as
62
+ xml << %( sendAs='#{@send_as}') if @send_as
62
63
  xml << '>'
63
- xml << %Q{<Sender>#{@sender}</Sender>} if @sender
64
- xml << %Q{<SmtpRelayServer>#{@smtp_relay_server}</SmtpRelayServer>} if @smtp_relay_server
64
+ xml << %(<Sender>#{@sender}</Sender>) if @sender
65
+ xml << %(<SmtpRelayServer>#{@smtp_relay_server}</SmtpRelayServer>) if @smtp_relay_server
65
66
  if @recipients
66
67
  xml << '<Recipients>'
67
68
  @recipients.each do |recipient|
68
- xml << %Q{<Recipient>#{recipient}</Recipient>}
69
+ xml << %(<Recipient>#{recipient}</Recipient>)
69
70
  end
70
71
  xml << '</Recipients>'
71
72
  end
@@ -121,11 +122,11 @@ module Nexpose
121
122
  end
122
123
 
123
124
  def to_xml
124
- xml = %Q{<Schedule enabled='#{@enabled ? 1 : 0}' type='#{@type}' interval='#{@interval}' start='#{@start}'}
125
- xml << %Q{ maxDuration='#@max_duration'} if @max_duration
126
- xml << %Q{ notValidAfter='#@not_valid_after'} if @not_valid_after
127
- xml << %Q{ incremental='#{@incremental ? 1 : 0}'} if @incremental
128
- xml << %Q{ repeaterType='#@repeater_type'} if @repeater_type
125
+ xml = %(<Schedule enabled='#{@enabled ? 1 : 0}' type='#{@type}' interval='#{@interval}' start='#{@start}')
126
+ xml << %( maxDuration='#{@max_duration}') if @max_duration
127
+ xml << %( notValidAfter='#{@not_valid_after}') if @not_valid_after
128
+ xml << %( incremental='#{@incremental ? 1 : 0}') if @incremental
129
+ xml << %( repeaterType='#{@repeater_type}') if @repeater_type
129
130
  xml << '/>'
130
131
  end
131
132
 
@@ -4,9 +4,12 @@ module Nexpose
4
4
  # Object that represents a connection to a Nexpose Security Console.
5
5
  #
6
6
  # === Examples
7
- # # Create a new Nexpose Connection on the default port
7
+ # # Create a new Nexpose::Connection on the default port
8
8
  # nsc = Connection.new('10.1.40.10', 'nxadmin', 'password')
9
9
  #
10
+ # # Create a new Nexpose::Connection from a URI or "URI" String
11
+ # nsc = Connection.from_uri('https://10.1.40.10:3780', 'nxadmin', 'password')
12
+ #
10
13
  # # Login to NSC and Establish a Session ID
11
14
  # nsc.login
12
15
  #
@@ -17,7 +20,7 @@ module Nexpose
17
20
  # puts 'Login Failure'
18
21
  # end
19
22
  #
20
- # # //Logout
23
+ # # Logout
21
24
  # logout_success = nsc.logout
22
25
  #
23
26
  class Connection
@@ -42,7 +45,13 @@ module Nexpose
42
45
  # The last XML response received by this object, useful for debugging.
43
46
  attr_reader :response_xml
44
47
 
45
- # Constructor for Connection
48
+ # A constructor to load a Connection object from a URI
49
+ def self.from_uri(uri, user, pass, silo_id = nil)
50
+ uri = URI.parse(uri)
51
+ new(uri.host, user, pass, uri.port, silo_id)
52
+ end
53
+
54
+ # A constructor for Connection
46
55
  def initialize(ip, user, pass, port = 3780, silo_id = nil)
47
56
  @host = ip
48
57
  @port = port
@@ -57,25 +66,21 @@ module Nexpose
57
66
  def login
58
67
  begin
59
68
  login_hash = {'sync-id' => 0, 'password' => @password, 'user-id' => @username}
60
- unless @silo_id.nil?
61
- login_hash['silo-id'] = @silo_id
62
- end
69
+ login_hash['silo-id'] = @silo_id if @silo_id
63
70
  r = execute(make_xml('LoginRequest', login_hash))
71
+ if r.success
72
+ @session_id = r.sid
73
+ true
74
+ end
64
75
  rescue APIError
65
76
  raise AuthenticationFailed.new(r)
66
77
  end
67
- if (r.success)
68
- @session_id = r.sid
69
- true
70
- end
71
78
  end
72
79
 
73
80
  # Logout of the current connection
74
81
  def logout
75
82
  r = execute(make_xml('LogoutRequest', {'sync-id' => 0}))
76
- if (r.success)
77
- return true
78
- end
83
+ return true if r.success
79
84
  raise APIError.new(r, 'Logout failed')
80
85
  end
81
86