ssl_scan 0.0.1

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