1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"
local nmap = require "nmap"
local os = require "os"
local string = require "string"
local sslcert = require "sslcert"
local tls = require "tls"
description = [[
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.
Original idea by Jacob Appelbaum and his TeaTime and tlsdate tools:
* https://github.com/ioerror/TeaTime
* https://github.com/ioerror/tlsdate
]]
author = "Aleksandar Nikolic"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe", "default"}
portrule = function(host, port)
return shortport.ssl(host, port) or sslcert.isPortSupported(port)
end
---
-- @usage
-- nmap <target> --script=ssl-date
--
-- @output
-- PORT STATE SERVICE REASON
-- 5222/tcp open xmpp-client syn-ack
-- |_ssl-date: 2012-08-02T18:29:31Z; +4s from local time.
--
-- @xmloutput
-- <elem key="date">2012-08-02T18:29:31+00:00</elem>
-- <elem key="delta">4</elem>
--
-- most of the code snatched from tls-nextprotoneg until we decide if we want a separate library
--
--- Function that sends a client hello packet
-- target host and returns the response
--@args host The target host table.
--@args port The target port table.
--@return status true if response, false else.
--@return response if status is true.
local client_hello = function(host, port)
local sock, status, response, err, cli_h
-- Craft Client Hello
cli_h = tls.client_hello({
["protocol"] = "TLSv1.0",
["ciphers"] = {
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_RC4_128_MD5",
},
["compressors"] = {"NULL"},
})
-- Connect to the target server
local specialized_function = sslcert.getPrepareTLSWithoutReconnect(port)
if not specialized_function then
sock = nmap.new_socket()
sock:set_timeout(5000)
status, err = sock:connect(host, port)
if not status then
sock:close()
stdnse.print_debug("Can't send: %s", err)
return false
end
else
status,sock = specialized_function(host,port)
if not status then
return false
end
end
-- 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)
sock:close()
return false
end
-- Read response
status, response, err = tls.record_buffer(sock)
if not status then
stdnse.print_debug("Couldn't receive: %s", err)
sock:close()
return false
end
return true, response
end
-- extract time from ServerHello response
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)
return nil
end
if record.type == "handshake" then
for _, body in ipairs(record.body) do
if body.type == "server_hello" then
return true, body.time
end
end
end
stdnse.print_debug("%s: Server response was not server_hello", SCRIPT_NAME)
return nil
end
action = function(host, port)
local status, response
-- 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)))
end
end
end
|