'wrong version number (OpenSSL::SSL::SSLError)' in simple Ruby SSL client - ruby

I am writing a simple SSL client for pentester lab bootcamp module 4. I enabled SSL for the virtualhost and enabled the module. The SSL client is written in Ruby and when running the script I get the following error:
Traceback (most recent call last):
6: from 4-http_ssl.rb:8:in <main>
5: from /usr/lib/ruby/2.5.0/net/http.rb:1458:in request
4: from /usr/lib/ruby/2.5.0/net/http.rb:909:in start
3: from /usr/lib/ruby/2.5.0/net/http.rb:920:in do_start
2: from /usr/lib/ruby/2.5.0/net/http.rb:985:in connect
1: from /usr/lib/ruby/2.5.0/net/protocol.rb:44:in ssl_socket_connect
/usr/lib/ruby/2.5.0/net/protocol.rb:44:in connect_nonblock: SSL_connect returned=1 errno=0
state=error: wrong version number (OpenSSL::SSL::SSLError)
Here is my script
require "net/https"
require "uri"
http = Net::HTTP.new("vulnerable", 443)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.request(Net::HTTP::Get.new("/"))
response.code
response.body
response.status
Can someone throw me a line here? I've checked the example and the server files but can't find the error. This seems like shouldn't be much trouble. Am I missing some configuration steps?
As pointed out by Steffen Ullrich, I tried to run
openssl> s_client
and got the following output:
Openssl> s_client -connect vulnerable:443
CONNECTED(00000003)
140093579711616:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../ssl/record/ssl3_record.c:332:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 5 bytes and written 293 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
error in s_client
What steps should I follow? I understand the server is not accepting SSL connections because of missing CA certificates, how can I fix this I know I can create a custom CA certificate for my ssl client any leads on this? Thanks in advance

Related

"sslv3 alert handshake failure" on ruby 2

I am trying to use a webservice with ruby, but it seems to be an issue with it's SSL configuration and ruby 2:
>> require "open-uri"
=> true
>> open("https://w390w.gipuzkoa.net/WAS/HACI/HFAServiciosProveedoresWEB/services/FacturaSSPPWebServiceProxyPort") {|f| p f.content_type }
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: sslv3 alert handshake failure
I've tried with curl and openssl and it works:
curl https://w390w.gipuzkoa.net/WAS/HACI/HFAServiciosProveedoresWEB/services/FacturaSSPPWebServiceProxyPort
openssl s_client -connect w390w.gipuzkoa.net:443
it also works with ruby 1.9:
irb(main):001:0> require "open-uri"
=> true
irb(main):003:0> open("https://w390w.gipuzkoa.net/WAS/HACI/HFAServiciosProveedoresWEB/services/FacturaSSPPWebServiceProxyPort") {|f| p f.content_type }
"text/html"
with ruby 2, I've tried using TLS, without success
>> OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ssl_version] = :TLSv1
=> :TLSv1
>> open("https://w390w.gipuzkoa.net/WAS/HACI/HFAServiciosProveedoresWEB/services/FacturaSSPPWebServiceProxyPort") {|f| p f.content_type }
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=unknown state: sslv3 alert handshake failure
>> OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ssl_version] = :TLSv1_2
=> :TLSv1_2
>> open("https://w390w.gipuzkoa.net/WAS/HACI/HFAServiciosProveedoresWEB/services/FacturaSSPPWebServiceProxyPort") {|f| p f.content_type }
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=unknown state: wrong version number
checking server SSL configuration on https://www.ssllabs.com/ssltest/analyze.html?d=w390w.gipuzkoa.net it returns this error: "Assessment failed: Unexpected failure", since I can access several similar webservices with ruby 2, I guess they have something miss-configured.
any ideas how can I access this webservice with ruby 2?
That is quite a poor configuration for a server. Comodo's SSL Analyzer appears to be more lenient and shows the four supported cipher suites.
Also, the server supports TLSv1.0.
Now, I cannot find a resource online that indicates if these cipher suites were disabled by default in Ruby 2, but here's something you can try:
Enable the best of the ciphers using OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ciphers] = "DES-CBC3-SHA"
Cipher name obtained from OpenSSL ciphers.
Attempting to connect now should display this error as the site's CA isn't trusted:
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3
read server certificate B: certificate verify failed
You can add this CA using ssl_ca_cert or bypass verification (not recommended) using ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE. E.g.,
open("https://w390w.gipuzkoa.net/WAS/HACI/HFAServiciosProveedoresWEB/services/FacturaSSPPWebServiceProxyPort", {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}) {|f| p f.content_type }
You can also give Net::HTTP a shot.
The server supports only very few ciphers, most of the completely insecure (export ciphers, DES-CBC-SHA) and the only at least a bit secure cipher (DES-CBC3-SHA) is considered insecure since Sweet32. Chances are high that because of this insecurity modern TLS stacks in the client will fail with the handshake.

Net:HTTP SSL negotiation timeout on Ubuntu 14.04

After a long day I managed to get to the bottom of what I believe is a SSL/TLS cipher negotiation issue with a server that doesn't support the latest and greatest versions.
Stack:
Ubuntu 14.04 fully patched
OpenSSL 1.0.1f 6 Jan 2014
irb 0.9.6(09/06/30)
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux] (using rbenv)
After 60 seconds the snippet below gives me an error:
require 'net/http'
require 'openssl'
uri = URI.parse('https://some_old_server/my/path')
http = Net::HTTP.new('some_old_server', 443)
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
response = http.request(Net::HTTP::Get.new(uri.request_uri))
Errno::ECONNRESET: Connection reset by peer - SSL_connect
If I add this to the code, it works:
(...)
http.ciphers = ['AES128-SHA']
(...)
=> #<Net::HTTPOK 200 OK readbody=true>
This isn't a ruby-specific issue but ideally there's a ruby solution. I can't lock the ciphers to 'AES128-SHA' because the same code handles a number of sites that may or may not support this cipher.
Has anyone ever come across this and found a generic solution?
EDIT: this seems to be caused by the "TLS hang bug" and was fixed in openssl 1.0.1g.
New question: is there a work-around that can be implemented on the ruby side?
More information.
A Gentoo server running OpenSSL 1.0.1j 15 Oct 2014 doesn't have this issue. I tried installing 1.0.1j on the Ubuntu 14.04 server, recompiling ruby (rbenv install 2.2.2) and the error was still present.
I've tried to monkey patch ext/openssl but that didn't work.
Using the whole cipher list from the link above doesn't work. However, using a small subset does work:
require 'net/http'
require 'openssl'
uri = URI.parse('https://some_old_server/my/path')
http = Net::HTTP.new('some_old_server', 443)
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
http.ciphers = %w{
AES128-GCM-SHA256
AES256-GCM-SHA384
AES128-SHA256
AES256-SHA256
AES128-SHA
AES256-SHA
ECDHE-ECDSA-RC4-SHA
ECDHE-RSA-RC4-SHA
RC4-SHA
}.join(":")
response = http.request(Net::HTTP::Get.new(uri.request_uri))
Openssl agrees with ruby (as it should). Running these, on the same system, replicates the issue as I see them in ruby:
openssl s_client -connect some_old_server:443
CONNECTED(00000003)
(...)
write:errno=104
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 295 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---
Passing the cipher:
openssl s_client -cipher AES128-SHA -connect some_old_server:443
CONNECTED(00000003)
(...)
---
No client certificate CA names sent
---
SSL handshake has read 2721 bytes and written 425 bytes
---
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : AES128-SHA
Session-ID: removed
Session-ID-ctx:
Master-Key: removed
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1454394952
Timeout : 300 (sec)
Verify return code: 20 (unable to get local issuer certificate)
---
I read somewhere to use
http.ssl_options = OpenSSL::SSL::OP_ALL
but ssl_options isn't available in Net::HTTP on ruby 2.2.2.
After spending more time on this than I'd care to admit, my solution was to upgrade from Ubuntu 14.04 to 15.10 which comes with OpenSSL 1.0.2d 9 Jul 2015.
While the TLS negotiation still hangs using the openssl CLI, in Ruby it does not:
require 'net/http'
require 'openssl'
require 'pp'
uri = URI.parse('https://broken_server/my/path')
http = Net::HTTP.new('broken_server', 443)
http.instance_eval {
#ssl_context = OpenSSL::SSL::SSLContext.new
#ssl_context.set_params({:options=>OpenSSL::SSL::OP_ALL})
}
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
pp response = http.request(Net::HTTP::Get.new(uri.request_uri))
SSL context code above courtesy of #vinhboy.
The CLI equivalent of the above is turned-on with the -bugs option:
openssl s_client -bugs -connect broken_server:443

How do I get the peer_cert for a https request using Ruby?

How can I get access to the peer_cert when making a SSL request?
I've updated my ruby ssl certs with rvm osx-ssl-certs update all
What I'm trying is
require 'httpclient'
c = HTTPClient.new
r = c.get( "https://gmail.com" )
puts r.peer_cert
But I keep getting either
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server hello A: sslv3 alert handshake failure
or
OpenSSL::SSL::SSLError: hostname "gmail.com" does not match the server certificate
What does the first error mean? Is there a way to get it to set the property version automatically?
I'm able to load up the data on the URL using HTTParty and Farday, but in that case I don't know here to access the actual SSL cert that was used.
You can't get the peer cert until you succesfully make the connection, and you're getting an error in succesfully making the connection. Have you upgraded to the latest httpclient? Many servers changed their SSL handshake configurations in response to recent vulnerabilties, and a new httpclient was released in response to same, which perhaps is neccesary to be compatible with new server configurations.

Net::HTTP SSL_CTX_set_cipher_list: no cipher match

I'm using ActiveResource to proxy a CRUD endpoint, but getting no cipher match errors when trying to connect. I have tried everything from explicitly setting the SSL version, to upgrading my local openssl client to setting the cipher list directly.
I wish I could provide more information, but I know the exception is raised here and that it throws a SSL_CTX_set_cipher_list: no cipher match error.
Do you know why I'm getting this error and how to fix?
Here is the connection information from Chrome:
Your connection to domain.com is encrypted with 128-bit encryption.
The connection uses TLS 1.0.
The connection is encrypted using AES_128_CBC, with SHA1 for message authentication and RSA as the key exchange mechanism.
The server does not support the TLS renegotiation extension.
Update
I ran the following command in terminal with openSSL to check the connection:
openssl s_client -showcerts -connect stage.example.com:13902
Here was the output:
CONNECTED(00000003)
140735228511072:error:140773F2:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert unexpected message:s23_clnt.c:762:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 308 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---
Not exactly sure what that means. Chrome can parse the certificate just fine. Is this a bug with OpenSSL?

Connecting using https to a server with a certificate signed by a CA I created

I have a test environment that uses Ruby to drive a server over an https connection. Since the latest versions of Ruby refuse to connect to an https server with an invalid certificate (see this earlier question of mine) and I would like to start using a newer version of Ruby, I am trying to set up a valid certificate.
I have created a CA certificate to use (there are multiple servers being tested so this seems the easier way), and have successfully used it to sign a new certificate which has been installed on a server and is being used. I have added the CA certificate to the browser store and it (the browser) will now connect to the server without complaint. So I am confident my certificates are valid and set up correctly.
I know that Ruby does not use the same store as the browser. I have used the CA file available here to test connecting to other (public) servers (set using the Net::HTTP#ca_file= method) and this also works.
What I cannot get to work is Ruby connecting to my server using my certificate. I have tried various ways of pointing it at my certificate (including adding my certificate to the file linked above) and it always gives the same error:
SSL_connect SYSCALL returned=5 errno=0 state=SSLv2/v3 read server hello A (OpenSSL::SSL::SSLError)
What do I have to do to convince Ruby to accept my certificate and connect to my server?
The code I am using is:
require 'net/https'
uri = URI.parse("https://hostname/index.html")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.ca_file = "My CA cert file"
request = Net::HTTP::Get.new(uri.path)
response = http.request(request)
I'm assuming this is wrong somehow. What I want to know is, what should I do to use my CA certificate?
I assume that your Tomcat doesn't like the protocol version that Ruby tries to negotiate. Ruby uses SSLv23 by default, but I've heard other cases where this was a problem for Java-based web servers. The error message you are getting indicates that the handshake fails while setting up the connection and trying to read the server's response. Try adding either
http.ssl_version = :TLSv1
or
http.ssl_version = :SSLv3
and see if that already helps.
If this does not fix the problem yet, it would be very interesting to see why your server rejects the connection attempt. Try running your Tomcat with -Djavax.net.debug=ssl and please post the relevant parts (connection information, exception stacktrace) as to why the attempt fails.
I am using ruby 1.9.3 and faced the same error while using nokogiri to parse some secure urls.
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: (null)
The above answer provided by emboss is correct but make sure the ssl error generated is this one that is mentioned above. I have followed the same and found a solution like this mentioned below.
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.ssl_version = :SSLv3
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
response = http.get(url)
now the response is having the correct html parsed for the secured url that is passed to the codes in the url .
Make sure that the your certificate file is in PEM format, not CRT (so the documentation for Net::HTTP in Ruby 1.9.3 says).
Update it looks like the documentation is not up to date, Ruby 1.9.3 will accept any kind of certificate.

Resources