1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-10 17:59:04 +00:00

Add the http-date.nse script. Also the function http.parse_date that

parses an HTTP date in any of three possible formats.

http-date.nse gets the Date: header field value from and HTTP server,
then displays it with how much it differs from local time.
This commit is contained in:
david
2009-07-13 22:03:02 +00:00
parent c455e12b7d
commit 426ed74a8b
2 changed files with 137 additions and 0 deletions

View File

@@ -428,6 +428,63 @@ request = function( host, port, data, options )
end end
local MONTH_MAP = {
Jan = 1, Feb = 2, Mar = 3, Apr = 4, May = 5, Jun = 6,
Jul = 7, Aug = 8, Sep = 9, Oct = 10, Nov = 11, Dec = 12
}
--- Parses an HTTP date string, in any of the following formats from section
-- 3.3.1 of RFC 2616:
-- * Sun, 06 Nov 1994 08:49:37 GMT (RFC 822, updated by RFC 1123)
-- * Sunday, 06-Nov-94 08:49:37 GMT (RFC 850, obsoleted by RFC 1036)
-- * Sun Nov 6 08:49:37 1994 (ANSI C's <code>asctime()</code> format)
-- @arg s the date string.
-- @return a table with keys <code>year</code>, <code>month</code>,
-- <code>day</code>, <code>hour</code>, <code>min</code>, <code>sec</code>, and
-- <code>isdst</code>, relative to GMT, suitable for input to
-- <code>os.time</code>.
function parse_date(s)
local day, month, year, hour, min, sec, tz, month_name
-- RFC 2616, section 3.3.1:
-- Handle RFC 1123 and 1036 at once.
day, month_name, year, hour, min, sec, tz = s:match("^%w+, (%d+)[- ](%w+)[- ](%d+) (%d+):(%d+):(%d+) (%w+)$")
if not day then
month_name, day, hour, min, sec, year = s:match("%w+ (%w+) ?(%d+) (%d+):(%d+):(%d+) (%d+)")
tz = "GMT"
end
if not day then
stdnse.print_debug(1, "http.parse_date: can't parse date \"%s\": unknown format.", s)
return nil
end
-- Look up the numeric code for month.
month = MONTH_MAP[month_name]
if not month then
stdnse.print_debug(1, "http.parse_date: unknown month name \"%s\".", month_name)
return nil
end
if tz ~= "GMT" then
stdnse.print_debug(1, "http.parse_date: don't know time zone \"%s\", only \"GMT\".", tz)
return nil
end
day = tonumber(day)
year = tonumber(year)
hour = tonumber(hour)
min = tonumber(min)
sec = tonumber(sec)
if year < 100 then
-- Two-digit year. Make a guess.
if year < 70 then
year = year + 2000
else
year = year + 1900
end
end
return { year = year, month = month, day = day, hour = hour, min = min, sec = sec, isdst = false }
end
get_default_timeout = function( nmap_timing ) get_default_timeout = function( nmap_timing )
local timeout = {} local timeout = {}
if nmap_timing >= 0 and nmap_timing <= 3 then if nmap_timing >= 0 and nmap_timing <= 3 then

80
scripts/http-date.nse Normal file
View File

@@ -0,0 +1,80 @@
description = [[
Gets the date from HTTP-like services. Also prints how much the date
differs from local time. Local time is the time the HTTP request was
sent, so the difference includes at least the duration of one RTT.
]]
---
-- @output
-- 80/tcp open http
-- |_ http-date: Mon, 13 Jul 2009 20:53:46 GMT; -5s from local time.
author = "David Fifield <david@bamsoftware.com>"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
require("http")
require("shortport")
portrule = shortport.port_or_service({80, 443, 631, 8080},
{"http", "https", "ipp", "http-alt"})
-- Turn a positive or negative number of seconds into a string in one of the
-- forms:
-- 0s
-- +2s
-- -4s
-- +02m38s
-- -9h12m34s
-- 5d17h05m06s
local function format_difftime(t)
local s, sign, sec
if t > 0 then
sign = "+"
elseif t < 0 then
sign = "-"
else
sign = ""
end
t = math.abs(t)
-- Seconds.
sec = t % 60
s = string.format("%gs", sec)
t = math.floor(t / 60)
if t == 0 then return sign .. s end
-- Minutes.
s = string.format("%02dm%02ds", t % 60, sec)
t = math.floor(t / 60)
if t == 0 then return sign .. s end
-- Hours.
s = string.format("%dh", t % 24) .. s
t = math.floor(t / 24)
if t == 0 then return sign .. s end
-- Days.
s = string.format("%dd", t) .. s
return sign .. s
end
action = function(host, port)
-- Get local time in UTC.
local request_time = os.time(os.date("!*t"))
local response = http.get(host, port, "/")
if not response.status or not response.header["date"] then
return
end
local date = http.parse_date(response.header["date"])
if not date then
return
end
-- Should account for estimated RTT too.
local diff = os.difftime(os.time(date), request_time)
return string.format("%s; %s from local time.",
response.header["date"], format_difftime(diff))
end