diff --git a/scripts/ssl-date.nse b/scripts/ssl-date.nse index c6d32c950..61d050cb5 100644 --- a/scripts/ssl-date.nse +++ b/scripts/ssl-date.nse @@ -1,6 +1,7 @@ local shortport = require "shortport" local stdnse = require "stdnse" local table = require "table" +local math = require "math" local nmap = require "nmap" local os = require "os" local string = require "string" @@ -12,7 +13,8 @@ Retrieves a target host's time and date from its TLS ServerHello response. In many TLS implementations, the first four bytes of server randomness -are a Unix timestamp. +are a Unix timestamp. The script will test whether this is indeed true +and report the time only if it passes this test. Original idea by Jacob Appelbaum and his TeaTime and tlsdate tools: * https://github.com/ioerror/TeaTime @@ -32,7 +34,7 @@ Original idea by Jacob Appelbaum and his TeaTime and tlsdate tools: -- 2012-08-02T18:29:31+00:00 -- 4 -author = "Aleksandar Nikolic" +author = "Aleksandar Nikolic, nnposter" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"discovery", "safe", "default"} @@ -75,7 +77,7 @@ local client_hello = function(host, port) status, err = sock:connect(host, port) if not status then sock:close() - stdnse.print_debug("Can't send: %s", err) + stdnse.debug("Can't send: %s", err) return false end else @@ -89,7 +91,7 @@ local client_hello = function(host, port) -- Send Client Hello to the target server status, err = sock:send(cli_h) if not status then - stdnse.print_debug("Couldn't send: %s", err) + stdnse.debug("Couldn't send: %s", err) sock:close() return false end @@ -97,7 +99,7 @@ local client_hello = function(host, port) -- Read response status, response, err = tls.record_buffer(sock) if not status then - stdnse.print_debug("Couldn't receive: %s", err) + stdnse.debug("Couldn't receive: %s", err) sock:close() return false end @@ -109,7 +111,7 @@ end local extract_time = function(response) local i, record = tls.record_read(response, 0) if record == nil then - stdnse.debug1("Unknown response from server") + stdnse.debug("%s: Unknown response from server", SCRIPT_NAME) return nil end @@ -120,27 +122,51 @@ local extract_time = function(response) end end end - stdnse.debug1("Server response was not server_hello") + stdnse.debug("%s: Server response was not server_hello", SCRIPT_NAME) return nil end -action = function(host, port) - local status, response - +local get_time_sample = function (host, port) -- Send crafted client hello - status, response = client_hello(host, port) - local now = os.time() - if status and response then - -- extract time from response - local result - status, result = extract_time(response) - if status then - local output = { - date = stdnse.format_timestamp(result, 0), - delta = os.difftime(result, now), - } - return output, string.format("%s; %s from local time.", output.date, - stdnse.format_difftime(os.date("!*t",result),os.date("!*t", now))) + local rstatus, response = client_hello(host, port) + local stm = os.time() + if not (rstatus and response) then return nil end + -- extract time from response + local tstatus, ttm = extract_time(response) + if not tstatus then return nil end + return ttm, stm +end + + +action = function(host, port) + local ttm, stm = get_time_sample(host, port) + if not ttm then + return stdnse.format_output(false, "Unable to obtain data from the target") + end + local delta = os.difftime(ttm, stm) + stdnse.debug(2, "Sample #1 time difference is %d seconds", delta) + + if math.abs(delta) > 15*60 then + -- time difference is suspect + -- get a second sample to determine if the clock is simply off + -- or if the TLS randomness does not represent the time at all + ttm, stm = get_time_sample(host, port) + if not ttm then + return stdnse.format_output(false, "Unable to obtain data from the target") + end + local origdelta = delta + delta = os.difftime(ttm, stm) + stdnse.debug(2, "Sample #2 time difference is %d seconds", delta) + if math.abs(origdelta - delta) > 5 then + return stdnse.format_output(false, "TLS randomness does not represent time") end end + + local output = { + date = stdnse.format_timestamp(ttm, 0), + delta = delta, + } + return output, + string.format("%s; %s from scanner time.", output.date, + stdnse.format_difftime(os.date("!*t",ttm),os.date("!*t", stm))) end