Nmap Development mailing list archives
Re: [NSE] False timestamp in ssl-date
From: Daniel Miller <bonsaiviking () gmail com>
Date: Fri, 1 Aug 2014 16:58:58 -0500
nnposter, Thanks for another reality-based patch! I appreciate your feedback on how Nmap's scripts are handled by a variety of implementations that we haven't tested against. I applied this change in r33403, but had to follow it up with a change in r33404 to remove SCRIPT_NAME from some of the stdnse.debug calls, since stdnse.debug already includes that info. Dan On Fri, Aug 1, 2014 at 4:13 PM, <nnposter () users sourceforge net> wrote:
The current version of ssl-date.nse does not try to validate whether the TLS server randomness in fact represents time. Recent versions of OpenSSL are prominent examples where this is not true. It would be desirable to differentiate between target clocks that are simply off and cases where TLS does not give back the timestamp at all. The patch below changes the script behavior as follows: 1: Take a TLS time sample 2: (original version of the script simply reports the result and exits) 3: Compare it with the scanner clock 4: If the difference is less than 15 minutes then report the time and exit 5: Otherwise take a second TLS time sample 6: Compare it with the scanner clock 7: If the two differences from steps #3 and #6 are consistent (differ in less than 5 seconds) then report the time and exit 8: Otherwise fail the script It could be debated whether step #4 should be implemented but for me it was a compromise between accuracy and having to take the second sample every single time. I have also implemented two unrelated changes: * Calls to stdnse.print_debug have been replaced with stdnse.debug * Changed term "local time" to "scanner time" to avoid any confusion with respect to local time reflecting a time zone. Results from a "positive" target: PORT STATE SERVICE REASON 443/tcp open https syn-ack |_ssl-date-orig: 2014-08-01T20:50:33+00:00; +1m48s from local time. |_ssl-date: 2014-08-01T20:50:33+00:00; +1m48s from scanner time. Results from a "negative" target: PORT STATE SERVICE REASON 443/tcp open https syn-ack |_ssl-date-orig: 2000-10-20T18:00:16+00:00; -13y285d1h21m39s from local time. Results from a "negative" target with -d: PORT STATE SERVICE REASON 443/tcp open https syn-ack |_ssl-date-orig: 1901-12-13T20:45:52+00:00; -112y230d23h12m39s from local time. | ssl-date: |_ ERROR: TLS randomness does not represent time Results from a "negative" target with -dd: NSE: [ssl-date X.X.X.X:443] Sample #1 time difference is 1960996270 seconds NSE: [ssl-date X.X.X.X:443] Sample #2 time difference is -84839085 seconds PORT STATE SERVICE REASON 443/tcp open https syn-ack |_ssl-date-orig: 2091-09-04T19:19:15+00:00; +77y33d22h42m41s from local time. | ssl-date: |_ ERROR: TLS randomness does not represent time Cheers, nnposter Patch against revision 33394 follows: --- scripts/ssl-date.nse.orig 2014-08-01 13:17:36.902341200 -0600 +++ scripts/ssl-date.nse 2014-08-01 14:36:16.370138900 -0600 @@ -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 @@ 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 @@ -- <elem key="date">2012-08-02T18:29:31+00:00</elem> -- <elem key="delta">4</elem> -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 @@ 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 @@ -- 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 @@ -- 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 @@ local extract_time = function(response) local i, record = tls.record_read(response, 0) if record == nil then - stdnse.print_debug("%s: Unknown response from server", SCRIPT_NAME) + stdnse.debug("%s: Unknown response from server", SCRIPT_NAME) return nil end @@ -120,27 +122,51 @@ end end end - stdnse.print_debug("%s: Server response was not server_hello", SCRIPT_NAME) + 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 _______________________________________________ Sent through the dev mailing list http://nmap.org/mailman/listinfo/dev Archived at http://seclists.org/nmap-dev/
_______________________________________________ Sent through the dev mailing list http://nmap.org/mailman/listinfo/dev Archived at http://seclists.org/nmap-dev/
Current thread:
- [NSE] False timestamp in ssl-date nnposter (Aug 01)
- Re: [NSE] False timestamp in ssl-date Daniel Miller (Aug 01)
- Re: [NSE] False timestamp in ssl-date David Fifield (Aug 01)
- Re: [NSE] False timestamp in ssl-date nnposter (Aug 07)
- Re: [NSE] False timestamp in ssl-date nnposter (Aug 07)
- Re: [NSE] False timestamp in ssl-date Fyodor (Aug 16)
- Re: [NSE] False timestamp in ssl-date nnposter (Aug 18)
- Re: [NSE] False timestamp in ssl-date Daniel Miller (Aug 20)
- Re: [NSE] False timestamp in ssl-date nnposter (Aug 22)
- Re: [NSE] False timestamp in ssl-date nnposter (Aug 07)