-
Notifications
You must be signed in to change notification settings - Fork 252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LDAPS vulnerable to MITM - failure to validate hostname against CN or SAN in X509 Cert #258
Comments
Thanks for reporting this. If you have a proposal for documentation or code changes, I'd be happy to review them. I'll take a deeper look when I have some free time. |
@jch I've worked with @JPvRiel a little bit on this today. It seems that OpenSSL offers the opportunity to do this through the I'd say something similar to this would work:
In connection.rb straight after opening the socket. Of course adjusting the context and socket name ( HTH |
@etdsoft, thanks, yep Tried hack in a patch (my first go at ruby monkey patching). But
# Monkey patch to test with
module Net
class LDAP
class Connection
def prepare_socket(server)
socket = server[:socket]
encryption = server[:encryption]
@conn = socket
if encryption
setup_encryption encryption
@conn.post_connection_check(server[:host])
end
end
end
end
end With the above, it sort of works as I get the following if the hostname doesn't match
However, in def open_connection(server)
hosts = server[:hosts]
encryption = server[:encryption]
socket_opts = {
connect_timeout: server[:connect_timeout] || DefaultConnectTimeout,
}
errors = []
hosts.each do |host, port|
begin
prepare_socket(server.merge(socket: @socket_class.new(host, port, socket_opts)))
return
rescue Net::LDAP::Error, SocketError, SystemCallError,
OpenSSL::SSL::SSLError => e
# Ensure the connection is closed in the event a setup failure.
close
errors << [e, host, port]
end
end
raise Net::LDAP::ConnectionError.new(errors)
end |
Tried > multiconn = Net::LDAP.new :hosts => [['<fdqn 1>', 636], ['<fqdn 2>', 636]],
:base => '<base DN>',
:encryption => { :method => :simple_tls, :tls_options => { :verify_mode => OpenSSL::SSL::VERIFY_PEER, :ca_file => 'ca_bundle.pem' } },
:auth => { :username => '<bind user>',
:password => '<bind password>]',
:method => :simple }
> multconn.bind
Net::LDAP::ConnectionError: Unable to connect to any given server:
OpenSSL::SSL::SSLError: hostname "127.0.0.1" does not match the server certificate (<fdqn 1>:636)
OpenSSL::SSL::SSLError: hostname "127.0.0.1" does not match the server certificate (<fdqn 2>:636) Not sure why 127.0.0.1 is used (seems to be falling back to a default). |
That appears to be what's used when class Net::LDAP
DefaultHost = "127.0.0.1"
def initialize(args = {})
@host = args[:host] || DefaultHost |
@meastman, thanks, yeah that confirms my concern that adding |
One option might be to update this line: prepare_socket(server.merge(socket: @socket_class.new(host, port, socket_opts))) to also include the hostname as |
@meastman, thanks for the hint. I simply did the check after It seemed to work for both single host and hosts use cases. But I lack the time to dig into your unit testing add proper negative test cases that double check this. |
Being unfamilair with ruby, and not a regualar programmer, I don't have the time/knowledge to wrap my head around using ruby test suites test_ssl_ber.rb and test_ldap_connection.rb to help add a proper test-suite. Nevertheless, |
Sorry to bump this issue. It's 2 months since it was raised, and there is a pull request to fix it. Anything else from the community needed to get this fixed? |
@JPvRiel sorry about that - I thought that #262 superseded #259 but wasn't ready yet. I missed that #262 got closed in favor of #259. I'm no longer involved with this project, but hopefully @jch can take a look at some point. |
@JPvRiel thanks for the reminder, I'll bump the issue internally as well. |
I spoke too soon about |
This issue has been assigned CVE-2017-17718. |
There are noted TLS/SSL limitations in the documented parts of the code and the info about encryption. Technically, TLS/SSL also provides the ability to authenticate servers by matching the hostname to a CN (common name) or a (SAN) Subject Alternative Name and from what I've seen, while net-ldap notes the certificate and trust chain limitations as insecure default, but it doesn't note the extra step needed to get to proper LDAP server authentication via LDAPS.
The above advice is not sufficient. It only assures that a server has a valid cert which was signed by a trusted CA, but it does not provide proof that it's the correct server E.g. evil.example.net with a cert issued as CN=evil.example.net could still impersonate ldap.example.net to steal credentials.
In addition to the above suggtestion setting a more secure and sane TLS/SSL context that validates certs , the net-ldap lib should also, probably by default, add and make use of verify_certificate_identity. I've browsed connection.rb and don't see anything that checks the hostname (FQDN) is authenticated against the certficate.
Given ruby essentially 'wraps' OpenSSL, this Hostname_validation reference also highlights the issue, with a choice extract
The text was updated successfully, but these errors were encountered: