Nmap Development mailing list archives

Re: [NSE] False timestamp in ssl-date


From: nnposter () users sourceforge net
Date: Thu, 7 Aug 2014 22:22:25 +0000

David Fifield wrote:
This is great. I think I would just always make two probes, and not base
the decision on a comparison to local time. If the server is generating
the field randomly, then the chances that two measurements differ by 10
or less is about 10/2^32 = 2.3e-09 = 2^-28.6, or 1 in 400 million. You
could always do three probes and make the probability negligible.

Maybe there are servers that don't use the time and don't generate
randomly, but do something else? Like a fixed value?

I guess you can also reject if the second sample is less than the first.

I have tried to incorporate David's suggestions. The resulting script
first takes two TLS time samples. If they are identical then it waits
1.1s and retakes the second sample. The script fails unless the second
sample is greater than the first and the difference between the two
samples is consistent with the actual time elapsed.

Compared to the previous version of the script, this change attempts
to detect and eliminate fixed values. The penalty for doing so is the
one-second forced sleep that occurs against most targets (where the TLS
value indeed represents time) because the first two samples are
overwhelmingly taken within the same second (so there is no distinction
from fixed values).

Personally I would have preferred to keep the original quick-success
clause and call the first sample good enough if it does not differ
substantially from the scanner clock. Its main advantage is that it
eliminates the forced sleep (and two additional connections/handshakes)
in most cases. (It would be easy to add it back. If the concern is
a false-positive match then we could be less tolerant than the original
+/- 15 minutes.)


Cheers,
nnposter



Patch against revision 33449 follows:


--- scripts/ssl-date.nse.orig   2014-08-07 15:49:02.990490400 -0600
+++ scripts/ssl-date.nse        2014-08-07 15:53:20.340222800 -0600
@@ -134,39 +134,56 @@
   -- extract time from response
   local tstatus, ttm = extract_time(response)
   if not tstatus then return nil end
-  return ttm, stm
+  stdnse.debug(2, "TLS time sample: %s", stdnse.format_timestamp(ttm, 0))
+  return {target=ttm, scanner=stm, delta=os.difftime(ttm, stm)}
+end
+
+local result = { STAGNANT = "stagnant",
+                 ACCEPTED = "accepted",
+                 REJECTED = "rejected" }
+
+local test_time_sample = function (host, port, reftm)
+  local tm = get_time_sample(host, port)
+  if not tm then return nil end
+  local tchange = os.difftime(tm.target, reftm.target)
+  local schange = os.difftime(tm.scanner, reftm.scanner)
+  local status =
+           -- clock cannot run backwards or drift substantially
+           (tchange < 0 or math.abs(tchange - schange) > 3)
+             and result.REJECTED
+           -- the clock did not advance
+           or tchange == 0
+             and result.STAGNANT
+           -- plausible enough
+           or result.ACCEPTED
+  stdnse.debug(2, "TLS time test result: %s", status)
+  return status, tm
 end
 
 
 action = function(host, port)
-  local ttm, stm = get_time_sample(host, port)
-  if not ttm then
+  local reftm = get_time_sample(host, port)
+  if not reftm 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
+  local status, tm = test_time_sample(host, port, reftm)
+  if status and status == result.STAGNANT then
+    stdnse.sleep(1.1)
+    status, tm = test_time_sample(host, port, reftm)
+  end
+  if not status then
+    return stdnse.format_output(false, "Unable to obtain data from the target")
+  end
+  if status ~= result.ACCEPTED then
+    return stdnse.format_output(false, "TLS randomness does not represent time")
   end
 
   local output = {
-                 date = stdnse.format_timestamp(ttm, 0),
-                 delta = delta,
+                 date = stdnse.format_timestamp(tm.target, 0),
+                 delta = tm.delta,
                  }
   return output,
          string.format("%s; %s from scanner time.", output.date,
-                 stdnse.format_difftime(os.date("!*t",ttm),os.date("!*t", stm)))
+                 stdnse.format_difftime(os.date("!*t", tm.target),
+                                        os.date("!*t", tm.scanner)))
 end
_______________________________________________
Sent through the dev mailing list
http://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/


Current thread: