o [NSE] Added gps library and the gpsd-info script that collects GPS data

from the gpsd daemon. [Patrik Karlsson]
This commit is contained in:
patrik 2012-04-17 19:32:37 +00:00
parent 63072d89d7
commit 59294eff19
4 changed files with 219 additions and 0 deletions

View file

@ -1,5 +1,8 @@
# Nmap Changelog ($Id$); -*-text-*-
o [NSE] Added gps library and the gpsd-info script that collects GPS data
from the gpsd daemon. [Patrik Karlsson]
o [NSE] Ported the pop3-brute script to use the brute library.
[Piotr Olma]

116
nselib/gps.lua Normal file
View file

@ -0,0 +1,116 @@
---
-- A smallish gps parsing module.
-- Currently does GPRMC NMEA decoding
--
-- @author "Patrik Karlsson <patrik@cqure.net>"
--
--
module(... or "gps", package.seeall)
local bit = require('bit')
NMEA = {
-- Parser for the RMC sentence
RMC = {
parse = function(str)
local time, status, latitude, ns_indicator, longitude,
ew_indicator, speed, course, date, variation,
ew_variation, checksum = str:match("^%$GPRMC,([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^%*]*)(.*)$")
if ( not(latitude) or not(longitude) ) then
return
end
local deg, min = latitude:match("^(..)(.*)$")
if ( not(deg) or not(min) ) then
return
end
latitude = tonumber(deg) + (tonumber(min)/60)
deg, min = longitude:match("^(..)(.*)$")
if ( not(deg) or not(min) ) then
return
end
longitude = tonumber(deg) + (tonumber(min)/60)
if ( ew_indicator == 'W' ) then
longitude = -longitude
end
if ( ns_indicator == 'S' ) then
latitude = -latitude
end
return { time = time, status = status, latitude = latitude,
longitude = longitude, speed = speed, course = course,
date = date, variation = variation,
ew_variation = ew_variation }
end,
},
-- Calculates an verifies the message checksum
--
-- @param str containing the GPS sentence
-- @return status true on success, false if the checksum does not match
-- @return err string if status is false
checksum = function(str)
local val = 0
for c in str:sub(2,-4):gmatch(".") do
val = bit.bxor(val, string.byte(c))
end
if ( str:sub(-2):upper() ~= stdnse.tohex(string.char(val)):upper() ) then
return false, ("Failed to verify checksum (got: %s; expected: %s)"):format(stdnse.tohex(string.char(val)), str:sub(-2))
end
return true
end,
-- Parses a GPS sentence using the apropriate parser
--
-- @param str containing the GPS sentence
-- @return entry table containing the parsed response or
-- err string if status is false
-- @return status true on success, false on failure
parse = function(str)
local status, err = NMEA.checksum(str)
if ( not(status) ) then
return false, err
end
local prefix = str:match("^%$GP([^,]*)")
if ( not(prefix) ) then
return false, "Not a NMEA sentence"
end
if ( NMEA[prefix] and NMEA[prefix].parse ) then
local e = NMEA[prefix].parse(str)
if (not(e)) then
return false, ("Failed to parse entry: %s"):format(str)
end
return true, e
else
local err = ("No parser for prefix: %s"):format(prefix)
stdnse.print_debug(2, err)
return false, err
end
end
}
Util = {
convertTime = function(date, time)
local d = {}
d.hour, d.min, d.sec = time:match("(..)(..)(..)")
d.day, d.month, d.year = date:match("(..)(..)(..)")
d.year = d.year + 2000
return os.time(d)
end
}

99
scripts/gpsd-info.nse Normal file
View file

@ -0,0 +1,99 @@
description = [[
Retrieves GPS time, coordinates and speed from the GPSD network daemon.
]]
---
-- @usage
-- nmap -p 2947 <ip> --script gpsd-info
--
-- @output
-- PORT STATE SERVICE REASON
-- 2947/tcp open gpsd-ng syn-ack
-- | gpsd-info:
-- | Time of fix: Sat Apr 14 15:54:23 2012
-- | Coordinates: 59.321685,17.886493
-- |_ Speed: - knots
--
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
local shortport = require 'shortport'
local gps = require 'gps'
local json = require 'json'
local match = require 'match'
portrule = shortport.port_or_service(2947, "gpsd-ng", "tcp")
local arg_timeout = tonumber(stdnse.get_script_args(SCRIPT_NAME .. ".timeout")) or 10
local function updateData(gpsinfo, entry)
for k, v in pairs(gpsinfo) do
if ( entry[k] and 0 < #tostring(entry[k]) ) then
gpsinfo[k] = entry[k]
end
end
end
local function hasAllData(gpsinfo)
for k, v in pairs(gpsinfo) do
if ( k ~= "speed" and v == '-' ) then
return false
end
end
return true
end
local function fail(err) return ("\n ERROR: %s"):format(err or "") end
action = function(host, port)
local gpsinfo = {
longitude = "-",
latitude = "-",
speed = "-",
time = "-",
date = "-",
}
local socket = nmap.new_socket()
socket:set_timeout(1000)
local status = socket:connect(host, port)
if ( not(status) ) then
return fail("Failed to connect to server")
end
-- get the banner
local status, line = socket:receive_lines(1)
socket:send('?WATCH={"enable":true,"nmea":true}\r\n')
local start_time = os.time()
repeat
local entry
status, line = socket:receive_buf("\r\n")
if ( status ) then
status, entry = gps.NMEA.parse(line)
if ( status ) then
updateData(gpsinfo, entry)
end
end
until( os.time() - start_time > arg_timeout or hasAllData(gpsinfo) )
socket:send('?WATCH={"enable":false}\r\n')
if ( not(hasAllData(gpsinfo)) ) then
return
end
local output = {
("Time of fix: %s UTC"):format(os.date("%c", gps.Util.convertTime(gpsinfo.date, gpsinfo.time))),
("Coordinates: %.4f,%.4f"):format(tonumber(gpsinfo.latitude), tonumber(gpsinfo.longitude)),
("Speed: %s knots"):format(gpsinfo.speed)
}
return stdnse.format_output(true, output)
end

View file

@ -94,6 +94,7 @@ Entry { filename = "ftp-vuln-cve2010-4221.nse", categories = { "intrusive", "vul
Entry { filename = "ganglia-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "giop-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "gopher-ls.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "gpsd-info.nse", categories = { "discovery", "safe", } }
Entry { filename = "hadoop-datanode-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "hadoop-jobtracker-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "hadoop-namenode-info.nse", categories = { "default", "discovery", "safe", } }