diff --git a/CHANGELOG b/CHANGELOG index 12ac1a21a..b4c26a44d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE][GH#540] Add tls.servername script-arg for forcing a name to be used for + TLS Server Name Indication extension. The argument overrides the default use + of the host's targetname. [Bertrand Bonnefoy-Claudet] + o [NSE] Script fingerprint-strings will print the ASCII strings it finds in the service fingerprints that Nmap shows for unidentified services. [Daniel Miller] diff --git a/nselib/tls.lua b/nselib/tls.lua index 7ffcabbda..30782ce3f 100644 --- a/nselib/tls.lua +++ b/nselib/tls.lua @@ -1502,4 +1502,20 @@ function record_buffer(sock, buffer, i) return true, buffer end +-- Get a server_name for use with the TLS Server Name Indication extension. +-- +-- This returns the value of the script argument "tls.servername" if given. Otherwise, it +-- returns the target name of the host parameter. +-- +-- @param host Host table as received by the action function +-- @return String of the selected host name +function servername(host) + local script_arg = stdnse.get_script_args("tls.servername") + if script_arg then + return script_arg + elseif type(host) == "table" then + return host.targetname + end +end + return _ENV; diff --git a/scripts/ssl-cert.nse b/scripts/ssl-cert.nse index d67efc9b5..725787714 100644 --- a/scripts/ssl-cert.nse +++ b/scripts/ssl-cert.nse @@ -3,6 +3,7 @@ local shortport = require "shortport" local sslcert = require "sslcert" local stdnse = require "stdnse" local string = require "string" +local tls = require "tls" local unicode = require "unicode" description = [[ @@ -264,6 +265,7 @@ local function output_str(cert) end action = function(host, port) + host.targetname = tls.servername(host) local status, cert = sslcert.getCertificate(host, port) if ( not(status) ) then stdnse.debug1("getCertificate error: %s", cert or "unknown") diff --git a/scripts/ssl-dh-params.nse b/scripts/ssl-dh-params.nse index 62137e838..58cf829b8 100644 --- a/scripts/ssl-dh-params.nse +++ b/scripts/ssl-dh-params.nse @@ -633,11 +633,10 @@ local function get_dhe_params(host, port, protocol, ciphers) local t = {} local pos = 1 t.protocol = protocol - t.extensions = {} - - if host.targetname then - t.extensions.server_name = tls.EXTENSION_HELPERS.server_name(host.targetname) - end + local tlsname = tls.servername(host) + t.extensions = { + server_name = tlsname and tls.EXTENSION_HELPERS["server_name"](tlsname), + } -- Keep ClientHello record size below 255 bytes and the number of ciphersuites -- to 64 or less in order to avoid implementation issues with some TLS servers diff --git a/scripts/ssl-enum-ciphers.nse b/scripts/ssl-enum-ciphers.nse index f21354192..7cecaa4aa 100644 --- a/scripts/ssl-enum-ciphers.nse +++ b/scripts/ssl-enum-ciphers.nse @@ -499,26 +499,17 @@ local function remove_high_byte_ciphers(t) return output end --- Claim to support every elliptic curve and EC point format -local base_extensions = { - -- Claim to support every elliptic curve - ["elliptic_curves"] = tls.EXTENSION_HELPERS["elliptic_curves"](sorted_keys(tls.ELLIPTIC_CURVES)), - -- Claim to support every EC point format - ["ec_point_formats"] = tls.EXTENSION_HELPERS["ec_point_formats"](sorted_keys(tls.EC_POINT_FORMATS)), -} - --- Recursively copy a table. --- Only recurs when a value is a table, other values are copied by assignment. -local function tcopy (t) - local tc = {}; - for k,v in pairs(t) do - if type(v) == "table" then - tc[k] = tcopy(v); - else - tc[k] = v; - end - end - return tc; +-- Get TLS extensions +local function base_extensions(host) + local tlsname = tls.servername(host) + return { + -- Claim to support every elliptic curve + ["elliptic_curves"] = tls.EXTENSION_HELPERS["elliptic_curves"](sorted_keys(tls.ELLIPTIC_CURVES)), + -- Claim to support every EC point format + ["ec_point_formats"] = tls.EXTENSION_HELPERS["ec_point_formats"](sorted_keys(tls.EC_POINT_FORMATS)), + -- Enable SNI if a server name is available + ["server_name"] = tlsname and tls.EXTENSION_HELPERS["server_name"](tlsname), + } end -- Get a message body from a record which has the specified property set to value @@ -587,11 +578,8 @@ local function find_ciphers_group(host, port, protocol, group, scores) local results = {} local t = { ["protocol"] = protocol, - ["extensions"] = tcopy(base_extensions), + ["extensions"] = base_extensions(host), } - if host.targetname then - t["extensions"]["server_name"] = tls.EXTENSION_HELPERS["server_name"](host.targetname) - end -- This is a hacky sort of tristate variable. There are three conditions: -- 1. false = either ciphers or protocol is bad. Keep trying with new ciphers @@ -775,11 +763,8 @@ local function get_chunk_size(host, protocol) local len_t = { protocol = protocol, ciphers = {}, - extensions = tcopy(base_extensions), + extensions = base_extensions(host), } - if host.targetname then - len_t.extensions.server_name = tls.EXTENSION_HELPERS.server_name(host.targetname) - end local cipher_len_remaining = 255 - #tls.client_hello(len_t) -- if we're over 255 anyway, just go for it. -- Each cipher adds 2 bytes @@ -815,11 +800,8 @@ local function find_compressors(host, port, protocol, good_ciphers) local t = { ["protocol"] = protocol, ["ciphers"] = good_ciphers, - ["extensions"] = tcopy(base_extensions), + ["extensions"] = base_extensions(host), } - if host.targetname then - t["extensions"]["server_name"] = tls.EXTENSION_HELPERS["server_name"](host.targetname) - end local results = {} @@ -896,11 +878,8 @@ local function compare_ciphers(host, port, protocol, cipher_a, cipher_b) local t = { ["protocol"] = protocol, ["ciphers"] = {cipher_a, cipher_b}, - ["extensions"] = tcopy(base_extensions), + ["extensions"] = base_extensions(host), } - if host.targetname then - t["extensions"]["server_name"] = tls.EXTENSION_HELPERS["server_name"](host.targetname) - end local records = try_params(host, port, t) local server_hello = records.handshake and get_body(records.handshake, "type", "server_hello") if server_hello then diff --git a/scripts/ssl-google-cert-catalog.nse b/scripts/ssl-google-cert-catalog.nse index 7d70f7da4..88c27f178 100644 --- a/scripts/ssl-google-cert-catalog.nse +++ b/scripts/ssl-google-cert-catalog.nse @@ -6,6 +6,7 @@ local sslcert = require "sslcert" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tls = require "tls" description = [[ Queries Google's Certificate Catalog for the SSL certificates retrieved from @@ -41,6 +42,7 @@ end portrule = shortport.ssl action = function(host, port) + host.targetname = tls.servername(host) local lines, sha1, query local status, cert = sslcert.getCertificate(host, port) diff --git a/scripts/ssl-known-key.nse b/scripts/ssl-known-key.nse index a630e40f1..9575c6e09 100644 --- a/scripts/ssl-known-key.nse +++ b/scripts/ssl-known-key.nse @@ -3,6 +3,7 @@ local nmap = require "nmap" local shortport = require "shortport" local stdnse = require "stdnse" local sslcert = require "sslcert" +local tls = require "tls" local bin = require "bin" -- -*- mode: lua -*- @@ -108,6 +109,7 @@ portrule = shortport.ssl action = function(host, port) -- Get script arguments. + host.targetname = tls.servername(host) local path = stdnse.get_script_args("ssl-known-key.fingerprintfile") or FINGERPRINT_FILE local status, result = get_fingerprints(path) if not status then diff --git a/scripts/ssl-poodle.nse b/scripts/ssl-poodle.nse index 29ef39c3c..297c3eeb9 100644 --- a/scripts/ssl-poodle.nse +++ b/scripts/ssl-poodle.nse @@ -174,13 +174,17 @@ local function remove_high_byte_ciphers(t) return output end --- Claim to support every elliptic curve and EC point format -local base_extensions = { - -- Claim to support every elliptic curve - ["elliptic_curves"] = tls.EXTENSION_HELPERS["elliptic_curves"](sorted_keys(tls.ELLIPTIC_CURVES)), - -- Claim to support every EC point format - ["ec_point_formats"] = tls.EXTENSION_HELPERS["ec_point_formats"](sorted_keys(tls.EC_POINT_FORMATS)), -} +local function base_extensions(host) + local tlsname = tls.servername(host) + return { + -- Claim to support every elliptic curve + ["elliptic_curves"] = tls.EXTENSION_HELPERS["elliptic_curves"](sorted_keys(tls.ELLIPTIC_CURVES)), + -- Claim to support every EC point format + ["ec_point_formats"] = tls.EXTENSION_HELPERS["ec_point_formats"](sorted_keys(tls.EC_POINT_FORMATS)), + -- Enable SNI if a server name is available + ["server_name"] = tlsname and tls.EXTENSION_HELPERS["server_name"](tlsname), + } +end -- Recursively copy a table. -- Only recurs when a value is a table, other values are copied by assignment. @@ -202,11 +206,8 @@ local function find_ciphers_group(host, port, protocol, group) results = {} local t = { ["protocol"] = protocol, - ["extensions"] = tcopy(base_extensions), + ["extensions"] = base_extensions(host), } - if host.targetname then - t["extensions"]["server_name"] = tls.EXTENSION_HELPERS["server_name"](host.targetname) - end -- This is a hacky sort of tristate variable. There are three conditions: -- 1. false = either ciphers or protocol is bad. Keep trying with new ciphers @@ -303,11 +304,8 @@ local function check_fallback_scsv(host, port, protocol, ciphers) local results = {} local t = { ["protocol"] = protocol, - ["extensions"] = tcopy(base_extensions), + ["extensions"] = base_extensions(host), } - if host.targetname then - t["extensions"]["server_name"] = tls.EXTENSION_HELPERS["server_name"](host.targetname) - end t["ciphers"] = tcopy(ciphers) t.ciphers[#t.ciphers+1] = "TLS_FALLBACK_SCSV"