@@ -71,20 +71,32 @@ def connect(global = true)
71
71
# This method currently only knows about PLAIN authentication.
72
72
#
73
73
def connect_login ( global = true )
74
- vprint_status ( "Connecting to SMTP server #{ rhost } :#{ rport } ..." )
75
- nsock = connect ( global )
76
-
77
- if datastore [ 'DOMAIN' ] and not datastore [ 'DOMAIN' ] == ''
74
+ if datastore [ 'DOMAIN' ] && datastore [ 'DOMAIN' ] != ''
78
75
domain = datastore [ 'DOMAIN' ]
79
76
else
80
77
domain = Rex ::Text . rand_text_alpha ( rand ( 32 ) +1 )
81
78
end
82
79
83
- res = raw_send_recv ( "EHLO #{ domain } \r \n " , nsock )
80
+ nsock , res = connect_ehlo ( global , domain )
81
+
84
82
if res =~ /STARTTLS/
85
83
print_status ( "Starting tls" )
86
84
raw_send_recv ( "STARTTLS\r \n " , nsock )
87
- swap_sock_plain_to_ssl ( nsock )
85
+
86
+ [ :high , :medium , :default ] . each do |level |
87
+ begin
88
+ swap_sock_plain_to_ssl ( nsock , level )
89
+ break
90
+ rescue OpenSSL ::SSL ::SSLError
91
+ # Perform manual fallback for servers that can't
92
+ print_status 'Could not negotiate SSL, falling back to older ciphers'
93
+ nsock . close
94
+ nsock , res = connect_ehlo ( global )
95
+ raw_send_recv ( "STARTTLS\r \n " , nsock )
96
+ raise if level == :default
97
+ end
98
+ end
99
+
88
100
res = raw_send_recv ( "EHLO #{ domain } \r \n " , nsock )
89
101
end
90
102
@@ -122,6 +134,12 @@ def connect_login(global = true)
122
134
return nsock
123
135
end
124
136
137
+ def connect_ehlo ( global = true , domain )
138
+ vprint_status ( "Connecting to SMTP server #{ rhost } :#{ rport } ..." )
139
+ nsock = connect ( global )
140
+
141
+ [ nsock , raw_send_recv ( "EHLO #{ domain } \r \n " , nsock ) ]
142
+ end
125
143
126
144
#
127
145
# Sends an email message, connecting to the server first if a connection is
@@ -216,8 +234,8 @@ def raw_send_recv(cmd, nsock=self.sock)
216
234
# Create a new SSL session on the existing socket. Used for STARTTLS
217
235
# support.
218
236
#
219
- def swap_sock_plain_to_ssl ( nsock = self . sock )
220
- ctx = generate_ssl_context ( )
237
+ def swap_sock_plain_to_ssl ( nsock = self . sock , security = :high )
238
+ ctx = generate_ssl_context ( security )
221
239
ssl = OpenSSL ::SSL ::SSLSocket . new ( nsock , ctx )
222
240
223
241
ssl . connect
@@ -227,10 +245,17 @@ def swap_sock_plain_to_ssl(nsock=self.sock)
227
245
nsock . sslctx = ctx
228
246
end
229
247
230
- def generate_ssl_context
231
- ctx = OpenSSL ::SSL ::SSLContext . new ( :SSLv23 )
232
- ctx . ciphers = "ALL:!ADH:!EXPORT:!SSLv2:!SSLv3:+HIGH:+MEDIUM"
233
- ctx
248
+ def generate_ssl_context ( security = :high )
249
+ case security
250
+ when :high
251
+ ctx = OpenSSL ::SSL ::SSLContext . new ( :SSLv23 )
252
+ ctx . ciphers = "ALL:!ADH:!EXPORT:!SSLv2:!SSLv3:+HIGH:+MEDIUM"
253
+ ctx
254
+ when :medium
255
+ OpenSSL ::SSL ::SSLContext . new ( :TLSv1 )
256
+ when :default
257
+ OpenSSL ::SSL ::SSLContext . new
258
+ end
234
259
end
235
260
236
261
end
0 commit comments