diff --git a/nselib/sslcert.lua b/nselib/sslcert.lua index 9353ce288..66b2896eb 100644 --- a/nselib/sslcert.lua +++ b/nselib/sslcert.lua @@ -10,12 +10,16 @@ -- -- * FTP -- * IMAP +-- * LDAP -- * POP3 -- * SMTP -- * XMPP -- -- @author "Patrik Karlsson " +local asn1 = require "asn1" +local bin = require "bin" +local ldap = require "ldap" local nmap = require "nmap" local stdnse = require "stdnse" local string = require "string" @@ -24,7 +28,7 @@ _ENV = stdnse.module("sslcert", stdnse.seeall) StartTLS = { - -- TODO: Implement STARTTLS for LDAP, NNTP + -- TODO: Implement STARTTLS for NNTP ftp_prepare_tls_without_reconnect = function(host, port) local s = nmap.new_socket() @@ -145,6 +149,85 @@ StartTLS = { return false, "Failed to connect to IMAP server" end, + ldap_prepare_tls_without_reconnect = function(host, port) + local s = nmap.new_socket() + -- Attempt to negotiate TLS over LDAP for services that support it + -- Works for LDAP (389) + + -- Open a standard TCP socket + local status, error = s:connect(host, port, "tcp") + if not status then + return false, "Failed to connect to LDAP server" + end + + -- Create an ExtendedRequest and specify the OID for the + -- Start TTLS operation (see http://www.ietf.org/rfc/rfc2830.txt) + local ExtendedRequest = 23 + local ExtendedResponse = 24 + local oid, ldapRequest, ldapRequestId + oid = ldap.encode("1.3.6.1.4.1.1466.20037") + ldapRequest = ldap.encodeLDAPOp(ExtendedRequest, true, oid) + ldapRequestId = ldap.encode(1) + + -- Send the STARTTLS request + local encoder = asn1.ASN1Encoder:new() + local data = encoder:encodeSeq(ldapRequestId .. ldapRequest) + status = s:send(data) + if not status then + return false, "STARTTLS failed" + end + + -- Decode the response + local response + status, response = s:receive() + if not status then + return false, "STARTTLS failed" + end + + local decoder = asn1.ASN1Decoder:new() + local len, pos, messageId, ldapOp, tmp = "" + pos, len = decoder.decodeLength(response, 2) + pos, messageId = ldap.decode(response, pos) + pos, tmp = bin.unpack("C", response, pos) + ldapOp = asn1.intToBER(tmp) + + if ldapOp.number ~= ExtendedResponse then + stdnse.print_debug(1, string.format( + "STARTTLS failed (got wrong op number: %d)", ldapOp.number)) + return false, "STARTTLS failed" + end + + local resultCode + pos, len = decoder.decodeLength(response, pos) + pos, resultCode = ldap.decode(response, pos) + + if resultCode ~= 0 then + stdnse.print_debug(1, string.format( + "STARTTLS failed (LDAP error code is: %d)", resultCode)) + return false, "STARTTLS failed" + end + + -- Should have a solid TLS over LDAP session now... + return true,s + end, + + ldap_prepare_tls = function(host, port) + local err + local status, s = StartTLS.ldap_prepare_tls_without_reconnect(host, port) + if status then + status,err = s:reconnect_ssl() + if not status then + stdnse.print_debug( + 1,"Could not establish SSL session after STARTTLS command.") + s:close() + return false, "Failed to connect to LDAP server" + else + return true,s + end + end + return false, "Failed to connect to LDAP server" + end, + pop3_prepare_tls_without_reconnect = function(host, port) local s = nmap.new_socket() -- Attempt to negotiate TLS over POP3 for services that support it @@ -345,6 +428,8 @@ local SPECIALIZED_PREPARE_TLS = { [21] = StartTLS.ftp_prepare_tls, imap = StartTLS.imap_prepare_tls, [143] = StartTLS.imap_prepare_tls, + [ldap] = StartTLS.ldap_prepare_tls, + [389] = StartTLS.ldap_prepare_tls, pop3 = StartTLS.pop3_prepare_tls, [110] = StartTLS.pop3_prepare_tls, smtp = StartTLS.smtp_prepare_tls, @@ -360,6 +445,8 @@ local SPECIALIZED_PREPARE_TLS_WITHOUT_RECONNECT = { [21] = StartTLS.ftp_prepare_tls_without_reconnect, imap = StartTLS.imap_prepare_tls_without_reconnect, [143] = StartTLS.imap_prepare_tls_without_reconnect, + ldap = StartTLS.ldap_prepare_tls_without_reconnect, + [389] = StartTLS.ldap_prepare_tls_without_reconnect, pop3 = StartTLS.pop3_prepare_tls_without_reconnect, [110] = StartTLS.pop3_prepare_tls_without_reconnect, smtp = StartTLS.smtp_prepare_tls_without_reconnect,