Module: Rex::Socket::SslTcpServer

Includes:
TcpServer
Defined in:
lib/rex/socket/ssl_tcp_server.rb

Overview

This class provides methods for interacting with an SSL wrapped TCP server. It implements the StreamServer IO interface.

Constant Summary collapse

@@loaded_openssl =
false

Constants included from Rex::Socket

MATCH_IPV4, MATCH_IPV4_PRIVATE, MATCH_IPV6, MATCH_MAC_ADDR, VERSION

Instance Attribute Summary collapse

Attributes included from Rex::Socket

#context, #ipv, #localhost, #localport, #peerhost, #peerport

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Rex::Socket

addr_atoc, addr_atoi, addr_atoi_list, addr_aton, addr_ctoa, addr_itoa, addr_iton, addr_ntoa, addr_ntoi, bit2netmask, cidr_crack, compress_address, create_ip, create_tcp, create_tcp_server, create_udp, dotted_ip?, eth_aton, eth_ntoa, #fd, from_sockaddr, getaddress, getaddresses, gethostbyname, #getlocalname, #getpeername_as_array, #getsockname, ipv6_link_address, ipv6_mac, is_internal?, is_ip_addr?, is_ipv4?, is_ipv6?, is_mac_addr?, #localinfo, net2bitmask, #peerinfo, portlist_to_portspec, portspec_crack, portspec_to_portlist, resolv_nbo, resolv_nbo_i, resolv_nbo_i_list, resolv_nbo_list, resolv_to_dotted, source_address, support_ipv6?, tcp_socket_pair, to_sockaddr, #type?, udp_socket_pair

Instance Attribute Details

#sslctxObject

Returns the value of attribute sslctx.



241
242
243
# File 'lib/rex/socket/ssl_tcp_server.rb', line 241

def sslctx
  @sslctx
end

Class Method Details

.create(hash = {}) ⇒ Object

Factory



33
34
35
36
37
38
# File 'lib/rex/socket/ssl_tcp_server.rb', line 33

def self.create(hash = {})
  hash['Proto']  = 'tcp'
  hash['Server'] = true
  hash['SSL']    = true
  self.create_param(Rex::Socket::Parameters.from_hash(hash))
end

.create_param(param) ⇒ Object

Wrapper around the base class’ creation method that automatically sets the parameter’s protocol to TCP and sets the server flag to true.



44
45
46
47
48
49
# File 'lib/rex/socket/ssl_tcp_server.rb', line 44

def self.create_param(param)
  param.proto  = 'tcp'
  param.server = true
  param.ssl    = true
  Rex::Socket.create_param(param)
end

.ssl_generate_certificateString, Array

Generate a realistic-looking but obstensibly fake SSL certificate. This matches a typical “snakeoil” cert.

Returns:

  • (String, String, Array)


155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/rex/socket/ssl_tcp_server.rb', line 155

def self.ssl_generate_certificate
  yr      = 24*3600*365
  vf      = Time.at(Time.now.to_i - rand(yr * 3) - yr)
  vt      = Time.at(vf.to_i + (rand(9)+1) * yr)
  subject = ssl_generate_subject
  issuer  = ssl_generate_issuer
  key     = OpenSSL::PKey::RSA.new(2048){ }
  cert    = OpenSSL::X509::Certificate.new
  cert.version    = 2
  cert.serial     = (rand(0xFFFFFFFF) << 32) + rand(0xFFFFFFFF)
  cert.subject    = OpenSSL::X509::Name.new([["C", subject]])
  cert.issuer     = OpenSSL::X509::Name.new([["C", issuer]])
  cert.not_before = vf
  cert.not_after  = vt
  cert.public_key = key.public_key

  ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
  cert.extensions = [
    ef.create_extension("basicConstraints","CA:FALSE")
  ]
  ef.issuer_certificate = cert

  cert.sign(key, OpenSSL::Digest::SHA256.new)

  [key, cert, nil]
end

.ssl_generate_issuerObject



144
145
146
147
148
# File 'lib/rex/socket/ssl_tcp_server.rb', line 144

def self.ssl_generate_issuer
  org = Rex::Text.rand_name.capitalize
  cn  = Rex::Text.rand_name.capitalize + " " + Rex::Text.rand_name.capitalize
  "US/O=#{org}/CN=#{cn}"
end

.ssl_generate_subjectObject



136
137
138
139
140
141
142
# File 'lib/rex/socket/ssl_tcp_server.rb', line 136

def self.ssl_generate_subject
  st  = Rex::Text.rand_state
  loc = Rex::Text.rand_name.capitalize
  org = Rex::Text.rand_name.capitalize
  cn  = Rex::Text.rand_hostname
  "US/ST=#{st}/L=#{loc}/O=#{org}/CN=#{cn}"
end

.ssl_parse_pem(ssl_cert) ⇒ String, Array

Parse a certificate in unified PEM format that contains a private key and one or more certificates. The first certificate is the primary, while any additional certificates are treated as intermediary certificates. This emulates the behavior of web servers like nginx.

Parameters:

  • ssl_cert (String)

Returns:

  • (String, String, Array)


125
126
127
# File 'lib/rex/socket/ssl_tcp_server.rb', line 125

def self.ssl_parse_pem(ssl_cert)
  Rex::Socket::X509Certificate.parse_pem(ssl_cert)
end

Instance Method Details

#accept(opts = {}) ⇒ Object

Accepts a child connection.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rex/socket/ssl_tcp_server.rb', line 64

def accept(opts = {})
  sock = super()
  return if not sock

  begin
    ssl = OpenSSL::SSL::SSLSocket.new(sock, self.sslctx)

    if not allow_nonblock?(ssl)
      begin
        Timeout::timeout(3.5) {
          ssl.accept
        }
      rescue ::Timeout::Error => e
        sock.close
        raise ::OpenSSL::SSL::SSLError
      end
    else
      begin
        ssl.accept_nonblock

      # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
      rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
          IO::select(nil, nil, nil, 0.10)
          retry

      # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
      rescue ::Exception => e
        if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
          IO::select( [ ssl ], nil, nil, 0.10 )
          retry
        end

        if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
          IO::select( nil, [ ssl ], nil, 0.10 )
          retry
        end

        raise e
      end
    end

    sock.extend(Rex::Socket::SslTcp)
    sock.sslsock = ssl
    sock.sslctx  = self.sslctx

    return sock

  rescue ::OpenSSL::SSL::SSLError
    sock.close
    nil
  end
end

#allow_nonblock?(sock = self.sock) ⇒ Boolean

This flag determines whether to use the non-blocking openssl API calls when they are available. This is still buggy on Linux/Mac OS X, but is required on Windows

Returns:

  • (Boolean)


233
234
235
236
237
238
239
# File 'lib/rex/socket/ssl_tcp_server.rb', line 233

def allow_nonblock?(sock=self.sock)
  avail = sock.respond_to?(:accept_nonblock)
  if avail and Rex::Compat.is_windows
    return true
  end
  false
end

#initsock(params = nil) ⇒ Object

Raises:

  • (RuntimeError)


51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rex/socket/ssl_tcp_server.rb', line 51

def initsock(params = nil)
  raise RuntimeError, 'No OpenSSL support' unless @@loaded_openssl

  if params && params.sslctx && params.sslctx.kind_of?(OpenSSL::SSL::SSLContext)
    self.sslctx = params.sslctx
  else
    self.sslctx  = makessl(params)
  end

  super
end

#makessl(params) ⇒ ::OpenSSL::SSL::SSLContext

Create a new ssl context. If ssl_cert is not given, generates a new key and a leaf certificate with random values.

Parameters:

Returns:

  • (::OpenSSL::SSL::SSLContext)


195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/rex/socket/ssl_tcp_server.rb', line 195

def makessl(params)

  if params.ssl_cert
    key, cert, chain = ssl_parse_pem(params.ssl_cert)
  else
    key, cert, chain = ssl_generate_certificate
  end

  ctx = OpenSSL::SSL::SSLContext.new()
  ctx.key = key
  ctx.cert = cert
  ctx.extra_chain_cert = chain
  ctx.options = 0

  if params.ssl_cipher
    ctx.ciphers = params.ssl_cipher
  end

  # Older versions of OpenSSL do not export the OP_NO_COMPRESSION symbol
  if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
    # enable/disable the SSL/TLS-level compression
    if params.ssl_compression
      ctx.options &= ~OpenSSL::SSL::OP_NO_COMPRESSION
    else
      ctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION
    end
  end

  ctx.session_id_context = Rex::Text.rand_text(16)

  return ctx
end

#ssl_generate_certificateObject

Shim for the ssl_generate_certificate module method



185
186
187
# File 'lib/rex/socket/ssl_tcp_server.rb', line 185

def ssl_generate_certificate
  Rex::Socket::SslTcpServer.ssl_generate_certificate
end

#ssl_parse_pem(ssl_cert) ⇒ Object

Shim for the ssl_parse_pem module method



132
133
134
# File 'lib/rex/socket/ssl_tcp_server.rb', line 132

def ssl_parse_pem(ssl_cert)
  Rex::Socket::SslTcpServer.ssl_parse_pem(ssl_cert)
end