ssl_scan 0.0.1

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,345 @@
1
+ # -*- coding: binary -*-
2
+ require 'ssl_scan/socket'
3
+ ###
4
+ #
5
+ # This class provides methods for interacting with an SSL TCP client
6
+ # connection.
7
+ #
8
+ ###
9
+ module SSLScan::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 SSLScan::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(SSLScan::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
+ SSLScan::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
+ version = :SSLv3
60
+ if(params)
61
+ case params.ssl_version
62
+ when 'SSL2', :SSLv2
63
+ version = :SSLv2
64
+ when 'SSL23', :SSLv23
65
+ version = :SSLv23
66
+ when 'TLS1', :TLSv1
67
+ version = :TLSv1
68
+ end
69
+ end
70
+
71
+ # Build the SSL connection
72
+ self.sslctx = OpenSSL::SSL::SSLContext.new(version)
73
+
74
+ # Configure the SSL context
75
+ # TODO: Allow the user to specify the verify mode callback
76
+ # Valid modes:
77
+ # VERIFY_CLIENT_ONCE
78
+ # VERIFY_FAIL_IF_NO_PEER_CERT
79
+ # VERIFY_NONE
80
+ # VERIFY_PEER
81
+ if params.ssl_verify_mode
82
+ self.sslctx.verify_mode = OpenSSL::SSL.const_get("VERIFY_#{params.ssl_verify_mode}".intern)
83
+ else
84
+ # Could also do this as graceful faildown in case a passed verify_mode is not supported
85
+ self.sslctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
86
+ end
87
+ self.sslctx.options = OpenSSL::SSL::OP_ALL
88
+ if params.ssl_cipher
89
+ self.sslctx.ciphers = params.ssl_cipher
90
+ end
91
+
92
+ # Set the verification callback
93
+ self.sslctx.verify_callback = Proc.new do |valid, store|
94
+ self.peer_verified = valid
95
+ true
96
+ end
97
+
98
+ # Tie the context to a socket
99
+ self.sslsock = OpenSSL::SSL::SSLSocket.new(self, self.sslctx)
100
+
101
+ # XXX - enabling this causes infinite recursion, so disable for now
102
+ # self.sslsock.sync_close = true
103
+
104
+
105
+ # Force a negotiation timeout
106
+ begin
107
+ Timeout.timeout(params.timeout) do
108
+ if not allow_nonblock?
109
+ self.sslsock.connect
110
+ else
111
+ begin
112
+ self.sslsock.connect_nonblock
113
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
114
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
115
+ IO::select(nil, nil, nil, 0.10)
116
+ retry
117
+
118
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
119
+ rescue ::Exception => e
120
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
121
+ IO::select( [ self.sslsock ], nil, nil, 0.10 )
122
+ retry
123
+ end
124
+
125
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
126
+ IO::select( nil, [ self.sslsock ], nil, 0.10 )
127
+ retry
128
+ end
129
+
130
+ raise e
131
+ end
132
+ end
133
+ end
134
+
135
+ rescue ::Timeout::Error
136
+ raise SSLScan::ConnectionTimeout.new(params.peerhost, params.peerport)
137
+ end
138
+ end
139
+
140
+ ##
141
+ #
142
+ # Stream mixin implementations
143
+ #
144
+ ##
145
+
146
+ #
147
+ # Writes data over the SSL socket.
148
+ #
149
+ def write(buf, opts = {})
150
+ return sslsock.write(buf) if not allow_nonblock?
151
+
152
+ total_sent = 0
153
+ total_length = buf.length
154
+ block_size = 16384
155
+ retry_time = 0.5
156
+
157
+ begin
158
+ while( total_sent < total_length )
159
+ s = SSLScan::ThreadSafe.select( nil, [ self.sslsock ], nil, 0.25 )
160
+ if( s == nil || s[0] == nil )
161
+ next
162
+ end
163
+ data = buf[total_sent, block_size]
164
+ sent = sslsock.write_nonblock( data )
165
+ if sent > 0
166
+ total_sent += sent
167
+ end
168
+ end
169
+
170
+ rescue ::IOError, ::Errno::EPIPE
171
+ return nil
172
+
173
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
174
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
175
+ # Sleep for a half a second, or until we can write again
176
+ SSLScan::ThreadSafe.select( nil, [ self.sslsock ], nil, retry_time )
177
+ # Decrement the block size to handle full sendQs better
178
+ block_size = 1024
179
+ # Try to write the data again
180
+ retry
181
+
182
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
183
+ rescue ::Exception => e
184
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
185
+ IO::select( [ self.sslsock ], nil, nil, retry_time )
186
+ retry
187
+ end
188
+
189
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
190
+ IO::select( nil, [ self.sslsock ], nil, retry_time )
191
+ retry
192
+ end
193
+
194
+ # Another form of SSL error, this is always fatal
195
+ if e.kind_of?(::OpenSSL::SSL::SSLError)
196
+ return nil
197
+ end
198
+
199
+ # Bubble the event up to the caller otherwise
200
+ raise e
201
+ end
202
+
203
+ total_sent
204
+ end
205
+
206
+ #
207
+ # Reads data from the SSL socket.
208
+ #
209
+ def read(length = nil, opts = {})
210
+ if not allow_nonblock?
211
+ length = 16384 unless length
212
+ begin
213
+ return sslsock.sysread(length)
214
+ rescue ::IOError, ::Errno::EPIPE, ::OpenSSL::SSL::SSLError
215
+ return nil
216
+ end
217
+ return
218
+ end
219
+
220
+
221
+ begin
222
+ while true
223
+ s = SSLScan::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
224
+ if( s == nil || s[0] == nil )
225
+ next
226
+ end
227
+ return sslsock.read_nonblock( length )
228
+ end
229
+
230
+ rescue ::IOError, ::Errno::EPIPE
231
+ return nil
232
+
233
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
234
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
235
+ # Sleep for a tenth a second, or until we can read again
236
+ SSLScan::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
237
+ # Decrement the block size to handle full sendQs better
238
+ block_size = 1024
239
+ # Try to write the data again
240
+ retry
241
+
242
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
243
+ rescue ::Exception => e
244
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
245
+ IO::select( [ self.sslsock ], nil, nil, 0.5 )
246
+ retry
247
+ end
248
+
249
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
250
+ IO::select( nil, [ self.sslsock ], nil, 0.5 )
251
+ retry
252
+ end
253
+
254
+ # Another form of SSL error, this is always fatal
255
+ if e.kind_of?(::OpenSSL::SSL::SSLError)
256
+ return nil
257
+ end
258
+
259
+ raise e
260
+ end
261
+
262
+ end
263
+
264
+
265
+ #
266
+ # Closes the SSL socket.
267
+ #
268
+ def close
269
+ sslsock.close rescue nil
270
+ super
271
+ end
272
+
273
+ #
274
+ # Ignore shutdown requests
275
+ #
276
+ def shutdown(how=0)
277
+ # Calling shutdown() on an SSL socket can lead to bad things
278
+ # Cause of http://metasploit.com/dev/trac/ticket/102
279
+ end
280
+
281
+ #
282
+ # Access to peer cert
283
+ #
284
+ def peer_cert
285
+ sslsock.peer_cert if sslsock
286
+ end
287
+
288
+ #
289
+ # Access to peer cert chain
290
+ #
291
+ def peer_cert_chain
292
+ sslsock.peer_cert_chain if sslsock
293
+ end
294
+
295
+ #
296
+ # Access to the current cipher
297
+ #
298
+ def cipher
299
+ sslsock.cipher if sslsock
300
+ end
301
+
302
+ #
303
+ # Prevent a sysread from the bare socket
304
+ #
305
+ def sysread(*args)
306
+ raise RuntimeError, "Invalid sysread() call on SSL socket"
307
+ end
308
+
309
+ #
310
+ # Prevent a sysread from the bare socket
311
+ #
312
+ def syswrite(*args)
313
+ raise RuntimeError, "Invalid syswrite() call on SSL socket"
314
+ end
315
+
316
+ #
317
+ # This flag determines whether to use the non-blocking openssl
318
+ # API calls when they are available. This is still buggy on
319
+ # Linux/Mac OS X, but is required on Windows
320
+ #
321
+ def allow_nonblock?
322
+ avail = self.sslsock.respond_to?(:accept_nonblock)
323
+ if avail and SSLScan::Compat.is_windows
324
+ return true
325
+ end
326
+ false
327
+ end
328
+
329
+ attr_reader :peer_verified # :nodoc:
330
+ attr_accessor :sslsock, :sslctx # :nodoc:
331
+
332
+ protected
333
+
334
+ attr_writer :peer_verified # :nodoc:
335
+
336
+
337
+ rescue LoadError
338
+ end
339
+
340
+ def type?
341
+ return 'tcp-ssl'
342
+ end
343
+
344
+ end
345
+
@@ -0,0 +1,188 @@
1
+ # -*- coding: binary -*-
2
+ require 'ssl_scan/socket'
3
+ require 'ssl_scan/socket/tcp_server'
4
+ require 'ssl_scan/io/stream_server'
5
+
6
+ ###
7
+ #
8
+ # This class provides methods for interacting with an SSL wrapped TCP server. It
9
+ # implements the StreamServer IO interface.
10
+ #
11
+ ###
12
+ module SSLScan::Socket::SslTcpServer
13
+
14
+ @@loaded_openssl = false
15
+
16
+ begin
17
+ require 'openssl'
18
+ @@loaded_openssl = true
19
+ require 'openssl/nonblock'
20
+ rescue ::Exception
21
+ end
22
+
23
+ include SSLScan::Socket::TcpServer
24
+
25
+ ##
26
+ #
27
+ # Factory
28
+ #
29
+ ##
30
+
31
+ def self.create(hash = {})
32
+ hash['Proto'] = 'tcp'
33
+ hash['Server'] = true
34
+ hash['SSL'] = true
35
+ self.create_param(SSLScan::Socket::Parameters.from_hash(hash))
36
+ end
37
+
38
+ #
39
+ # Wrapper around the base class' creation method that automatically sets
40
+ # the parameter's protocol to TCP and sets the server flag to true.
41
+ #
42
+ def self.create_param(param)
43
+ param.proto = 'tcp'
44
+ param.server = true
45
+ param.ssl = true
46
+ SSLScan::Socket.create_param(param)
47
+ end
48
+
49
+ def initsock(params = nil)
50
+ raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
51
+ self.sslctx = makessl(params)
52
+ super
53
+ end
54
+
55
+ # (see TcpServer#accept)
56
+ def accept(opts = {})
57
+ sock = super()
58
+ return if not sock
59
+
60
+ begin
61
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, self.sslctx)
62
+
63
+ if not allow_nonblock?(ssl)
64
+ ssl.accept
65
+ else
66
+ begin
67
+ ssl.accept_nonblock
68
+
69
+ # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
70
+ rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
71
+ IO::select(nil, nil, nil, 0.10)
72
+ retry
73
+
74
+ # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
75
+ rescue ::Exception => e
76
+ if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
77
+ IO::select( [ ssl ], nil, nil, 0.10 )
78
+ retry
79
+ end
80
+
81
+ if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
82
+ IO::select( nil, [ ssl ], nil, 0.10 )
83
+ retry
84
+ end
85
+
86
+ raise e
87
+ end
88
+ end
89
+
90
+ sock.extend(SSLScan::Socket::SslTcp)
91
+ sock.sslsock = ssl
92
+ sock.sslctx = self.sslctx
93
+
94
+ return sock
95
+
96
+ rescue ::OpenSSL::SSL::SSLError
97
+ sock.close
98
+ nil
99
+ end
100
+ end
101
+
102
+
103
+ #
104
+ # Create a new ssl context. If +ssl_cert+ is not given, generates a new
105
+ # key and a leaf certificate with random values.
106
+ #
107
+ # @param [SSLScan::Socket::Parameters] params
108
+ # @return [::OpenSSL::SSL::SSLContext]
109
+ def makessl(params)
110
+ ssl_cert = params.ssl_cert
111
+ if ssl_cert
112
+ cert = OpenSSL::X509::Certificate.new(ssl_cert)
113
+ key = OpenSSL::PKey::RSA.new(ssl_cert)
114
+ else
115
+ key = OpenSSL::PKey::RSA.new(1024){ }
116
+ cert = OpenSSL::X509::Certificate.new
117
+ cert.version = 2
118
+ cert.serial = rand(0xFFFFFFFF)
119
+ # name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
120
+ subject = OpenSSL::X509::Name.new([
121
+ ["C","US"],
122
+ ['ST', SSLScan::Text.rand_state()],
123
+ ["L", SSLScan::Text.rand_text_alpha(rand(20) + 10)],
124
+ ["O", SSLScan::Text.rand_text_alpha(rand(20) + 10)],
125
+ ["CN", SSLScan::Text.rand_hostname],
126
+ ])
127
+ issuer = OpenSSL::X509::Name.new([
128
+ ["C","US"],
129
+ ['ST', SSLScan::Text.rand_state()],
130
+ ["L", SSLScan::Text.rand_text_alpha(rand(20) + 10)],
131
+ ["O", SSLScan::Text.rand_text_alpha(rand(20) + 10)],
132
+ ["CN", SSLScan::Text.rand_hostname],
133
+ ])
134
+
135
+ cert.subject = subject
136
+ cert.issuer = issuer
137
+ cert.not_before = Time.now - (3600 * 365)
138
+ cert.not_after = Time.now + (3600 * 365)
139
+ cert.public_key = key.public_key
140
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
141
+ cert.extensions = [
142
+ ef.create_extension("basicConstraints","CA:FALSE"),
143
+ ef.create_extension("subjectKeyIdentifier","hash"),
144
+ ef.create_extension("extendedKeyUsage","serverAuth"),
145
+ ef.create_extension("keyUsage","keyEncipherment,dataEncipherment,digitalSignature")
146
+ ]
147
+ ef.issuer_certificate = cert
148
+ cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
149
+ cert.sign(key, OpenSSL::Digest::SHA1.new)
150
+ end
151
+
152
+ ctx = OpenSSL::SSL::SSLContext.new()
153
+ ctx.key = key
154
+ ctx.cert = cert
155
+ ctx.options = 0
156
+
157
+
158
+ # Older versions of OpenSSL do not export the OP_NO_COMPRESSION symbol
159
+ if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
160
+ # enable/disable the SSL/TLS-level compression
161
+ if params.ssl_compression
162
+ ctx.options &= ~OpenSSL::SSL::OP_NO_COMPRESSION
163
+ else
164
+ ctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION
165
+ end
166
+ end
167
+
168
+ ctx.session_id_context = SSLScan::Text.rand_text(16)
169
+
170
+ return ctx
171
+ end
172
+
173
+ #
174
+ # This flag determines whether to use the non-blocking openssl
175
+ # API calls when they are available. This is still buggy on
176
+ # Linux/Mac OS X, but is required on Windows
177
+ #
178
+ def allow_nonblock?(sock=self.sock)
179
+ avail = sock.respond_to?(:accept_nonblock)
180
+ if avail and SSLScan::Compat.is_windows
181
+ return true
182
+ end
183
+ false
184
+ end
185
+
186
+ attr_accessor :sslctx
187
+ end
188
+
@@ -0,0 +1,76 @@
1
+ # -*- coding: binary -*-
2
+ require 'ssl_scan/socket'
3
+
4
+ module SSLScan
5
+ module Socket
6
+
7
+ ###
8
+ #
9
+ # This class provides an interface to enumerating a subnet with a supplied
10
+ # netmask.
11
+ #
12
+ ###
13
+ class SubnetWalker
14
+
15
+ #
16
+ # Initializes a subnet walker instance using the supplied subnet
17
+ # information.
18
+ #
19
+ def initialize(subnet, netmask)
20
+ self.subnet = Socket.resolv_to_dotted(subnet)
21
+ self.netmask = Socket.resolv_to_dotted(netmask)
22
+
23
+ reset
24
+ end
25
+
26
+ #
27
+ # Resets the subnet walker back to its original state.
28
+ #
29
+ def reset
30
+ self.curr_ip = self.subnet.split('.')
31
+ self.num_ips = (1 << (32 - Socket.net2bitmask(self.netmask).to_i))
32
+ self.curr_ip_idx = 0
33
+ end
34
+
35
+ #
36
+ # Returns the next IP address.
37
+ #
38
+ def next_ip
39
+ if (curr_ip_idx >= num_ips)
40
+ return nil
41
+ end
42
+
43
+ if (curr_ip_idx > 0)
44
+ self.curr_ip[3] = (curr_ip[3].to_i + 1) % 256
45
+ self.curr_ip[2] = (curr_ip[2].to_i + 1) % 256 if (curr_ip[3] == 0)
46
+ self.curr_ip[1] = (curr_ip[1].to_i + 1) % 256 if (curr_ip[2] == 0)
47
+ self.curr_ip[0] = (curr_ip[0].to_i + 1) % 256 if (curr_ip[1] == 0)
48
+ end
49
+
50
+ self.curr_ip_idx += 1
51
+
52
+ self.curr_ip.join('.')
53
+ end
54
+
55
+ #
56
+ # The subnet that is being enumerated.
57
+ #
58
+ attr_reader :subnet
59
+ #
60
+ # The netmask of the subnet.
61
+ #
62
+ attr_reader :netmask
63
+ #
64
+ # The total number of IPs within the subnet.
65
+ #
66
+ attr_reader :num_ips
67
+
68
+ protected
69
+
70
+ attr_writer :subnet, :netmask, :num_ips # :nodoc:
71
+ attr_accessor :curr_ip, :curr_ip_idx # :nodoc:
72
+
73
+ end
74
+
75
+ end
76
+ end