rex-socket 0.1.0

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,46 @@
1
+ module Rex
2
+ module Socket
3
+
4
+ # This class exists to abuse the Proxy capabilities in the Net::SSH library to allow the use of Rex::Sockets
5
+ # for the transport layer in Net::SSH. The SSHFactory object will respond to the #open method and create the
6
+ # {Rex::Socket::Tcp}
7
+ class SSHFactory
8
+
9
+ # @!attribute msfraemwork
10
+ # @return [Object] The framework instance object
11
+ attr_accessor :framework
12
+ # @!attribute msfmodule
13
+ # @return [Object] The metasploit module this socket belongs to
14
+ attr_accessor :msfmodule
15
+ # @!attribute proxies
16
+ # @return [String] Any proxies to use for the connection
17
+ attr_accessor :proxies
18
+
19
+ def initialize(framework, msfmodule, proxies)
20
+ @framework = framework
21
+ @msfmodule = msfmodule
22
+ @proxies = proxies
23
+ end
24
+
25
+ # Responds to the proxy setup routine Net::SSH will call when
26
+ # initialising the Transport Layer. This will instead create our
27
+ # {Rex::Socket::Tcp} and tie the socket back to the calling module
28
+ # @param host [String] The host to open the connection to
29
+ # @param port [Fixnum] the port to open the connection on
30
+ # @param options [Hash] the options hash
31
+ def open(host, port, options={})
32
+ socket = Rex::Socket::Tcp.create(
33
+ 'PeerHost' => host,
34
+ 'PeerPort' => port,
35
+ 'Proxies' => proxies,
36
+ 'Context' => {
37
+ 'Msf' => framework,
38
+ 'MsfExploit' => msfmodule
39
+ }
40
+ )
41
+ msfmodule.add_socket(socket) if msfmodule
42
+ socket
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,374 @@
1
+ # -*- coding: binary -*-
2
+ require 'rex/socket'
3
+ ###
4
+ #
5
+ # This class provides methods for interacting with an SSL TCP client
6
+ # connection.
7
+ #
8
+ ###
9
+ module Rex::Socket::SslTcp
10
+
11
+ begin
12
+ @@loaded_openssl = false
13
+
14
+ begin
15
+ require 'openssl'
16
+ @@loaded_openssl = true
17
+ require 'openssl/nonblock'
18
+ rescue ::Exception
19
+ end
20
+
21
+
22
+ include Rex::Socket::Tcp
23
+
24
+ ##
25
+ #
26
+ # Factory
27
+ #
28
+ ##
29
+
30
+ #
31
+ # Creates an SSL TCP instance.
32
+ #
33
+ def self.create(hash = {})
34
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
35
+ hash['SSL'] = true
36
+ self.create_param(Rex::Socket::Parameters.from_hash(hash))
37
+ end
38
+
39
+ #
40
+ # Set the SSL flag to true and call the base class's create_param routine.
41
+ #
42
+ def self.create_param(param)
43
+ param.ssl = true
44
+ Rex::Socket::Tcp.create_param(param)
45
+ end
46
+
47
+ ##
48
+ #
49
+ # Class initialization
50
+ #
51
+ ##
52
+
53
+ #
54
+ # Initializes the SSL socket.
55
+ #
56
+ def initsock(params = nil)
57
+ super
58
+
59
+ # Default to SSLv23 (automatically negotiate)
60
+ version = :SSLv23
61
+
62
+ # Let the caller specify a particular SSL/TLS version
63
+ if params
64
+ case params.ssl_version
65
+ when 'SSL2', :SSLv2
66
+ version = :SSLv2
67
+ # 'TLS' will be the new name for autonegotation with newer versions of OpenSSL
68
+ when 'SSL23', :SSLv23, 'TLS', 'Auto'
69
+ version = :SSLv23
70
+ when 'SSL3', :SSLv3
71
+ version = :SSLv3
72
+ when 'TLS1','TLS1.0', :TLSv1
73
+ version = :TLSv1
74
+ when 'TLS1.1', :TLSv1_1
75
+ version = :TLSv1_1
76
+ when 'TLS1.2', :TLSv1_2
77
+ version = :TLSv1_2
78
+ end
79
+ end
80
+
81
+ # Raise an error if no selected versions are supported
82
+ if ! OpenSSL::SSL::SSLContext::METHODS.include? version
83
+ raise ArgumentError, 'The system OpenSSL does not support the requested SSL/TLS version'
84
+ end
85
+
86
+ # Try intializing the socket with this SSL/TLS version
87
+ # This will throw an exception if it fails
88
+ initsock_with_ssl_version(params, version)
89
+
90
+ # Track the SSL version
91
+ self.ssl_negotiated_version = version
92
+ end
93
+
94
+ def initsock_with_ssl_version(params, version)
95
+ # Build the SSL connection
96
+ self.sslctx = OpenSSL::SSL::SSLContext.new(version)
97
+
98
+ # Configure the SSL context
99
+ # TODO: Allow the user to specify the verify mode callback
100
+ # Valid modes:
101
+ # VERIFY_CLIENT_ONCE
102
+ # VERIFY_FAIL_IF_NO_PEER_CERT
103
+ # VERIFY_NONE
104
+ # VERIFY_PEER
105
+ if params.ssl_verify_mode
106
+ self.sslctx.verify_mode = OpenSSL::SSL.const_get("VERIFY_#{params.ssl_verify_mode}".intern)
107
+ else
108
+ # Could also do this as graceful faildown in case a passed verify_mode is not supported
109
+ self.sslctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
110
+ end
111
+
112
+ self.sslctx.options = OpenSSL::SSL::OP_ALL
113
+
114
+ if params.ssl_cipher
115
+ self.sslctx.ciphers = params.ssl_cipher
116
+ end
117
+
118
+ # Set the verification callback
119
+ self.sslctx.verify_callback = Proc.new do |valid, store|
120
+ self.peer_verified = valid
121
+ true
122
+ end
123
+
124
+ # Tie the context to a socket
125
+ self.sslsock = OpenSSL::SSL::SSLSocket.new(self, self.sslctx)
126
+
127
+ # If peerhost looks like a hostname, set the undocumented 'hostname'
128
+ # attribute on sslsock, which enables the Server Name Indication (SNI)
129
+ # extension
130
+ self.sslsock.hostname = self.peerhost if !Rex::Socket.dotted_ip?(self.peerhost)
131
+
132
+ # Force a negotiation timeout
133
+ begin
134
+ Timeout.timeout(params.timeout) do
135
+ if not allow_nonblock?
136
+ self.sslsock.connect
137
+ else
138
+ begin
139
+ self.sslsock.connect_nonblock
140
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
141
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
142
+ IO::select(nil, nil, nil, 0.10)
143
+ retry
144
+
145
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
146
+ rescue ::Exception => e
147
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
148
+ IO::select( [ self.sslsock ], nil, nil, 0.10 )
149
+ retry
150
+ end
151
+
152
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
153
+ IO::select( nil, [ self.sslsock ], nil, 0.10 )
154
+ retry
155
+ end
156
+
157
+ raise e
158
+ end
159
+ end
160
+ end
161
+
162
+ rescue ::Timeout::Error
163
+ raise Rex::ConnectionTimeout.new(params.peerhost, params.peerport)
164
+ end
165
+ end
166
+
167
+ ##
168
+ #
169
+ # Stream mixin implementations
170
+ #
171
+ ##
172
+
173
+ #
174
+ # Writes data over the SSL socket.
175
+ #
176
+ def write(buf, opts = {})
177
+ return sslsock.write(buf) if not allow_nonblock?
178
+
179
+ total_sent = 0
180
+ total_length = buf.length
181
+ block_size = 16384
182
+ retry_time = 0.5
183
+
184
+ begin
185
+ while( total_sent < total_length )
186
+ s = Rex::ThreadSafe.select( nil, [ self.sslsock ], nil, 0.25 )
187
+ if( s == nil || s[0] == nil )
188
+ next
189
+ end
190
+ data = buf[total_sent, block_size]
191
+ sent = sslsock.write_nonblock( data )
192
+ if sent > 0
193
+ total_sent += sent
194
+ end
195
+ end
196
+
197
+ rescue ::IOError, ::Errno::EPIPE
198
+ return nil
199
+
200
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
201
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
202
+ # Sleep for a half a second, or until we can write again
203
+ Rex::ThreadSafe.select( nil, [ self.sslsock ], nil, retry_time )
204
+ # Decrement the block size to handle full sendQs better
205
+ block_size = 1024
206
+ # Try to write the data again
207
+ retry
208
+
209
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
210
+ rescue ::Exception => e
211
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
212
+ IO::select( [ self.sslsock ], nil, nil, retry_time )
213
+ retry
214
+ end
215
+
216
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
217
+ IO::select( nil, [ self.sslsock ], nil, retry_time )
218
+ retry
219
+ end
220
+
221
+ # Another form of SSL error, this is always fatal
222
+ if e.kind_of?(::OpenSSL::SSL::SSLError)
223
+ return nil
224
+ end
225
+
226
+ # Bubble the event up to the caller otherwise
227
+ raise e
228
+ end
229
+
230
+ total_sent
231
+ end
232
+
233
+ #
234
+ # Reads data from the SSL socket.
235
+ #
236
+ def read(length = nil, opts = {})
237
+ if not allow_nonblock?
238
+ length = 16384 unless length
239
+ begin
240
+ return sslsock.sysread(length)
241
+ rescue ::IOError, ::Errno::EPIPE, ::OpenSSL::SSL::SSLError
242
+ return nil
243
+ end
244
+ return
245
+ end
246
+
247
+
248
+ begin
249
+ while true
250
+ s = Rex::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
251
+ if( s == nil || s[0] == nil )
252
+ next
253
+ end
254
+ return sslsock.read_nonblock( length )
255
+ end
256
+
257
+ rescue ::IOError, ::Errno::EPIPE
258
+ return nil
259
+
260
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
261
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
262
+ # Sleep for a tenth a second, or until we can read again
263
+ Rex::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
264
+ # Decrement the block size to handle full sendQs better
265
+ block_size = 1024
266
+ # Try to write the data again
267
+ retry
268
+
269
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
270
+ rescue ::Exception => e
271
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
272
+ IO::select( [ self.sslsock ], nil, nil, 0.5 )
273
+ retry
274
+ end
275
+
276
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
277
+ IO::select( nil, [ self.sslsock ], nil, 0.5 )
278
+ retry
279
+ end
280
+
281
+ # Another form of SSL error, this is always fatal
282
+ if e.kind_of?(::OpenSSL::SSL::SSLError)
283
+ return nil
284
+ end
285
+
286
+ raise e
287
+ end
288
+
289
+ end
290
+
291
+
292
+ #
293
+ # Closes the SSL socket.
294
+ #
295
+ def close
296
+ sslsock.close rescue nil
297
+ super
298
+ end
299
+
300
+ #
301
+ # Ignore shutdown requests
302
+ #
303
+ def shutdown(how=0)
304
+ # Calling shutdown() on an SSL socket can lead to bad things
305
+ # Cause of http://metasploit.com/dev/trac/ticket/102
306
+ end
307
+
308
+ #
309
+ # Access to peer cert
310
+ #
311
+ def peer_cert
312
+ sslsock.peer_cert if sslsock
313
+ end
314
+
315
+ #
316
+ # Access to peer cert chain
317
+ #
318
+ def peer_cert_chain
319
+ sslsock.peer_cert_chain if sslsock
320
+ end
321
+
322
+ #
323
+ # Access to the current cipher
324
+ #
325
+ def cipher
326
+ sslsock.cipher if sslsock
327
+ end
328
+
329
+ #
330
+ # Prevent a sysread from the bare socket
331
+ #
332
+ def sysread(*args)
333
+ raise RuntimeError, "Invalid sysread() call on SSL socket"
334
+ end
335
+
336
+ #
337
+ # Prevent a sysread from the bare socket
338
+ #
339
+ def syswrite(*args)
340
+ raise RuntimeError, "Invalid syswrite() call on SSL socket"
341
+ end
342
+
343
+ #
344
+ # This flag determines whether to use the non-blocking openssl
345
+ # API calls when they are available. This is still buggy on
346
+ # Linux/Mac OS X, but is required on Windows
347
+ #
348
+ def allow_nonblock?
349
+ avail = self.sslsock.respond_to?(:accept_nonblock)
350
+ if avail and Rex::Compat.is_windows
351
+ return true
352
+ end
353
+ false
354
+ end
355
+
356
+ attr_reader :peer_verified # :nodoc:
357
+ attr_reader :ssl_negotiated_version # :nodoc:
358
+ attr_accessor :sslsock, :sslctx, :sslhash # :nodoc:
359
+
360
+ def type?
361
+ return 'tcp-ssl'
362
+ end
363
+
364
+ protected
365
+
366
+ attr_writer :peer_verified # :nodoc:
367
+ attr_writer :ssl_negotiated_version # :nodoc:
368
+
369
+
370
+ rescue LoadError
371
+ end
372
+
373
+ end
374
+
@@ -0,0 +1,220 @@
1
+ # -*- coding: binary -*-
2
+ require 'rex/socket'
3
+ require 'rex/socket/tcp_server'
4
+ require 'rex/io/stream_server'
5
+ require 'rex/socket/x509_certificate'
6
+
7
+ ###
8
+ #
9
+ # This class provides methods for interacting with an SSL wrapped TCP server. It
10
+ # implements the StreamServer IO interface.
11
+ #
12
+ ###
13
+ module Rex::Socket::SslTcpServer
14
+
15
+ @@loaded_openssl = false
16
+
17
+ begin
18
+ require 'openssl'
19
+ @@loaded_openssl = true
20
+ require 'openssl/nonblock'
21
+ rescue ::Exception
22
+ end
23
+
24
+ include Rex::Socket::TcpServer
25
+
26
+ ##
27
+ #
28
+ # Factory
29
+ #
30
+ ##
31
+
32
+ def self.create(hash = {})
33
+ hash['Proto'] = 'tcp'
34
+ hash['Server'] = true
35
+ hash['SSL'] = true
36
+ self.create_param(Rex::Socket::Parameters.from_hash(hash))
37
+ end
38
+
39
+ #
40
+ # Wrapper around the base class' creation method that automatically sets
41
+ # the parameter's protocol to TCP and sets the server flag to true.
42
+ #
43
+ def self.create_param(param)
44
+ param.proto = 'tcp'
45
+ param.server = true
46
+ param.ssl = true
47
+ Rex::Socket.create_param(param)
48
+ end
49
+
50
+ def initsock(params = nil)
51
+ raise RuntimeError, 'No OpenSSL support' unless @@loaded_openssl
52
+
53
+ if params && params.sslctx && params.sslctx.kind_of?(OpenSSL::SSL::SSLContext)
54
+ self.sslctx = params.sslctx
55
+ else
56
+ self.sslctx = makessl(params)
57
+ end
58
+
59
+ super
60
+ end
61
+
62
+ # (see TcpServer#accept)
63
+ def accept(opts = {})
64
+ sock = super()
65
+ return if not sock
66
+
67
+ begin
68
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, self.sslctx)
69
+
70
+ if not allow_nonblock?(ssl)
71
+ ssl.accept
72
+ else
73
+ begin
74
+ ssl.accept_nonblock
75
+
76
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
77
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
78
+ IO::select(nil, nil, nil, 0.10)
79
+ retry
80
+
81
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
82
+ rescue ::Exception => e
83
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
84
+ IO::select( [ ssl ], nil, nil, 0.10 )
85
+ retry
86
+ end
87
+
88
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
89
+ IO::select( nil, [ ssl ], nil, 0.10 )
90
+ retry
91
+ end
92
+
93
+ raise e
94
+ end
95
+ end
96
+
97
+ sock.extend(Rex::Socket::SslTcp)
98
+ sock.sslsock = ssl
99
+ sock.sslctx = self.sslctx
100
+
101
+ return sock
102
+
103
+ rescue ::OpenSSL::SSL::SSLError
104
+ sock.close
105
+ nil
106
+ end
107
+ end
108
+
109
+ #
110
+ # Parse a certificate in unified PEM format that contains a private key and
111
+ # one or more certificates. The first certificate is the primary, while any
112
+ # additional certificates are treated as intermediary certificates. This emulates
113
+ # the behavior of web servers like nginx.
114
+ #
115
+ # @param [String] ssl_cert
116
+ # @return [String, String, Array]
117
+ def self.ssl_parse_pem(ssl_cert)
118
+ Rex::Socket::X509Certificate.parse_pem(ssl_cert)
119
+ end
120
+
121
+ #
122
+ # Shim for the ssl_parse_pem module method
123
+ #
124
+ def ssl_parse_pem(ssl_cert)
125
+ Rex::Socket::SslTcpServer.ssl_parse_pem(ssl_cert)
126
+ end
127
+
128
+ #
129
+ # Generate a realistic-looking but obstensibly fake SSL
130
+ # certificate. This matches a typical "snakeoil" cert.
131
+ #
132
+ # @return [String, String, Array]
133
+ def self.ssl_generate_certificate
134
+ yr = 24*3600*365
135
+ vf = Time.at(Time.now.to_i - rand(yr * 3) - yr)
136
+ vt = Time.at(vf.to_i + (10 * yr))
137
+ cn = Rex::Text.rand_text_alpha_lower(rand(8)+2)
138
+ key = OpenSSL::PKey::RSA.new(2048){ }
139
+ cert = OpenSSL::X509::Certificate.new
140
+ cert.version = 2
141
+ cert.serial = (rand(0xFFFFFFFF) << 32) + rand(0xFFFFFFFF)
142
+ cert.subject = OpenSSL::X509::Name.new([["CN", cn]])
143
+ cert.issuer = OpenSSL::X509::Name.new([["CN", cn]])
144
+ cert.not_before = vf
145
+ cert.not_after = vt
146
+ cert.public_key = key.public_key
147
+
148
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
149
+ cert.extensions = [
150
+ ef.create_extension("basicConstraints","CA:FALSE")
151
+ ]
152
+ ef.issuer_certificate = cert
153
+
154
+ cert.sign(key, OpenSSL::Digest::SHA256.new)
155
+
156
+ [key, cert, nil]
157
+ end
158
+
159
+ #
160
+ # Shim for the ssl_generate_certificate module method
161
+ #
162
+ def ssl_generate_certificate
163
+ Rex::Socket::SslTcpServer.ssl_generate_certificate
164
+ end
165
+
166
+ #
167
+ # Create a new ssl context. If +ssl_cert+ is not given, generates a new
168
+ # key and a leaf certificate with random values.
169
+ #
170
+ # @param [Rex::Socket::Parameters] params
171
+ # @return [::OpenSSL::SSL::SSLContext]
172
+ def makessl(params)
173
+
174
+ if params.ssl_cert
175
+ key, cert, chain = ssl_parse_pem(params.ssl_cert)
176
+ else
177
+ key, cert, chain = ssl_generate_certificate
178
+ end
179
+
180
+ ctx = OpenSSL::SSL::SSLContext.new()
181
+ ctx.key = key
182
+ ctx.cert = cert
183
+ ctx.extra_chain_cert = chain
184
+ ctx.options = 0
185
+
186
+ if params.ssl_cipher
187
+ ctx.ciphers = params.ssl_cipher
188
+ end
189
+
190
+ # Older versions of OpenSSL do not export the OP_NO_COMPRESSION symbol
191
+ if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
192
+ # enable/disable the SSL/TLS-level compression
193
+ if params.ssl_compression
194
+ ctx.options &= ~OpenSSL::SSL::OP_NO_COMPRESSION
195
+ else
196
+ ctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION
197
+ end
198
+ end
199
+
200
+ ctx.session_id_context = Rex::Text.rand_text(16)
201
+
202
+ return ctx
203
+ end
204
+
205
+ #
206
+ # This flag determines whether to use the non-blocking openssl
207
+ # API calls when they are available. This is still buggy on
208
+ # Linux/Mac OS X, but is required on Windows
209
+ #
210
+ def allow_nonblock?(sock=self.sock)
211
+ avail = sock.respond_to?(:accept_nonblock)
212
+ if avail and Rex::Compat.is_windows
213
+ return true
214
+ end
215
+ false
216
+ end
217
+
218
+ attr_accessor :sslctx
219
+ end
220
+