mirror of
https://github.com/nmap/nmap.git
synced 2025-12-07 13:11:28 +00:00
New scripts for geo mapping. Closes #606
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE][GH#606] Three new scripts render IP geolocation data as maps.
|
||||||
|
ip-geolocation-map-bing uses Bing Maps, ip-geolocation-map-google uses Google
|
||||||
|
Maps, and ip-geolocation-map-kml outputs KML map data for import into other
|
||||||
|
mapping software. [Mak Kolybabi]
|
||||||
|
|
||||||
|
o [NSE][GH#606] New NSE library, geoip.lua, provides a common framework for
|
||||||
|
storing and retrieving IP geolocation results. [Mak Kolybabi]
|
||||||
|
|
||||||
o [NSE][GH#518] Brute scripts are faster and more accurate. New feedback and
|
o [NSE][GH#518] Brute scripts are faster and more accurate. New feedback and
|
||||||
adaptivity mechanisms in brute.lua help brute scripts use resources more
|
adaptivity mechanisms in brute.lua help brute scripts use resources more
|
||||||
efficiently, dynamically changing number of threads based on protocol
|
efficiently, dynamically changing number of threads based on protocol
|
||||||
|
|||||||
81
nselib/geoip.lua
Normal file
81
nselib/geoip.lua
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
local nmap = require "nmap"
|
||||||
|
local stdnse = require "stdnse"
|
||||||
|
local table = require "table"
|
||||||
|
|
||||||
|
_ENV = stdnse.module("geoip", stdnse.seeall)
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Consolidation of GeoIP functions.
|
||||||
|
--
|
||||||
|
-- @author "Mak Kolybabi <mak@kolybabi.com>"
|
||||||
|
-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html
|
||||||
|
|
||||||
|
--- Add a geolocation to the registry
|
||||||
|
-- @param ip The IP that was geolocated
|
||||||
|
-- @param lat The latitude in degrees
|
||||||
|
-- @param lon The longitude in degrees
|
||||||
|
add = function(ip, lat, lon)
|
||||||
|
if not nmap.registry.geoip then
|
||||||
|
nmap.registry.geoip = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
if not nmap.registry.geoip[ip] then
|
||||||
|
nmap.registry.geoip[ip] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local lat_n = tonumber(lat)
|
||||||
|
if lat_n < -90 or lat_n > 90 then
|
||||||
|
stdnse.debug1("Invalid latitude for %s: %s.", ip, lat)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local lon_n = tonumber(lon)
|
||||||
|
if lon_n < -180 or lon_n > 180 then
|
||||||
|
stdnse.debug1("Invalid longitude for %s: %s.", ip, lon)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
nmap.registry.geoip[ip]["latitude"] = lat
|
||||||
|
nmap.registry.geoip[ip]["longitude"] = lon
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if any coordinates have been stored in the registry
|
||||||
|
--@return True if any coordinates have been returned, false otherwise
|
||||||
|
empty = function()
|
||||||
|
return not nmap.registry.geoip
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Retrieve the table of coordinates by IP
|
||||||
|
--@return A table of coordinates keyed by IP.
|
||||||
|
get_all_by_ip = function()
|
||||||
|
if empty() then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return nmap.registry.geoip
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Retrieve a table of IPs by coordinate
|
||||||
|
--@return A table of IPs keyed by coordinate in <code>lat,lon</code> format
|
||||||
|
get_all_by_gps = function(limit)
|
||||||
|
if empty() then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = {}
|
||||||
|
for ip, coords in pairs(get_all_by_ip()) do
|
||||||
|
if limit and limit < #t then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local key = coords["latitude"] .. "," .. coords["longitude"]
|
||||||
|
if not t[key] then
|
||||||
|
t[key] = {}
|
||||||
|
end
|
||||||
|
table.insert(t[key], ip)
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
return _ENV;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
local geoip = require "geoip"
|
||||||
local http = require "http"
|
local http = require "http"
|
||||||
local ipOps = require "ipOps"
|
local ipOps = require "ipOps"
|
||||||
local json = require "json"
|
local json = require "json"
|
||||||
@@ -39,24 +40,35 @@ end
|
|||||||
local geoplugin = function(ip)
|
local geoplugin = function(ip)
|
||||||
local response = http.get("www.geoplugin.net", 80, "/json.gp?ip="..ip, {any_af=true})
|
local response = http.get("www.geoplugin.net", 80, "/json.gp?ip="..ip, {any_af=true})
|
||||||
local stat, loc = json.parse(response.body)
|
local stat, loc = json.parse(response.body)
|
||||||
if not stat then return nil end
|
if not stat then
|
||||||
|
return false, loc
|
||||||
|
end
|
||||||
|
|
||||||
local output = {}
|
local output = {}
|
||||||
table.insert(output, "coordinates (lat,lon): "..loc.geoplugin_latitude..","..loc.geoplugin_longitude)
|
table.insert(output, "coordinates (lat,lon): "..loc.geoplugin_latitude..","..loc.geoplugin_longitude)
|
||||||
local regionName = (loc.geoplugin_regionName == json.NULL) and "Unknown" or loc.geoplugin_regionName
|
local regionName = (loc.geoplugin_regionName == json.NULL) and "Unknown" or loc.geoplugin_regionName
|
||||||
table.insert(output,"state: ".. regionName ..", ".. loc.geoplugin_countryName)
|
table.insert(output,"state: ".. regionName ..", ".. loc.geoplugin_countryName)
|
||||||
|
|
||||||
return output
|
geoip.add(ip, loc.geoplugin_latitude, loc.geoplugin_longitude)
|
||||||
|
|
||||||
|
return true, output
|
||||||
end
|
end
|
||||||
|
|
||||||
action = function(host,port)
|
action = function(host,port)
|
||||||
local output = geoplugin(host.ip)
|
local output = stdnse.output_table()
|
||||||
|
|
||||||
if(#output~=0) then
|
local status, result = geoplugin(host.ip)
|
||||||
output.name = host.ip
|
if not status then
|
||||||
if host.targetname then
|
if result == "syntax error" then
|
||||||
output.name = output.name.." ("..host.targetname..")"
|
result = "The geoPlugin service has likely blocked you due to excessive usage, but the response received was 'syntax error'."
|
||||||
end
|
end
|
||||||
|
output.ERROR = result
|
||||||
|
return output, output.ERROR
|
||||||
|
end
|
||||||
|
|
||||||
|
output.name = host.ip
|
||||||
|
if host.targetname then
|
||||||
|
output.name = output.name.." ("..host.targetname..")"
|
||||||
end
|
end
|
||||||
|
|
||||||
return stdnse.format_output(true,output)
|
return stdnse.format_output(true,output)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
local geoip = require "geoip"
|
||||||
local http = require "http"
|
local http = require "http"
|
||||||
local ipOps = require "ipOps"
|
local ipOps = require "ipOps"
|
||||||
local json = require "json"
|
local json = require "json"
|
||||||
@@ -70,6 +71,8 @@ local ipinfodb = function(ip)
|
|||||||
table.insert(output, "coordinates (lat,lon): "..loc.latitude..","..loc.longitude)
|
table.insert(output, "coordinates (lat,lon): "..loc.latitude..","..loc.longitude)
|
||||||
table.insert(output,"city: ".. loc.cityName..", ".. loc.regionName..", ".. loc.countryName)
|
table.insert(output,"city: ".. loc.cityName..", ".. loc.regionName..", ".. loc.countryName)
|
||||||
|
|
||||||
|
geoip.add(ip, loc.latitude, loc.longitude)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
177
scripts/ip-geolocation-map-bing.nse
Normal file
177
scripts/ip-geolocation-map-bing.nse
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
local http = require "http"
|
||||||
|
local geoip = require "geoip"
|
||||||
|
local io = require "io"
|
||||||
|
local stdnse = require "stdnse"
|
||||||
|
local string = require "string"
|
||||||
|
local table = require "table"
|
||||||
|
local url = require "url"
|
||||||
|
|
||||||
|
description = [[
|
||||||
|
This script queries the Nmap registry for the GPS coordinates of targets stored
|
||||||
|
by previous geolocation scripts and renders a Bing Map of markers representing
|
||||||
|
the targets.
|
||||||
|
|
||||||
|
Additional information for the Bing Maps REST Services API can be found at:
|
||||||
|
- https://msdn.microsoft.com/en-us/library/ff701724.aspx
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @usage
|
||||||
|
-- nmap -sn -Pn --script ip-geolocation-geoplugin,ip-geolocation-map-bing --script-args ip-geolocation-map-bing.api_key=[redacted],ip-geolocation-map-bing.map_path=map.png <target>
|
||||||
|
--
|
||||||
|
-- @output
|
||||||
|
-- | ip-geolocation-map-bing:
|
||||||
|
-- |_ The map has been saved at 'map.png'.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-bing.api_key The required Bing Maps API key for your
|
||||||
|
-- account. An API key can be generated at https://www.bingmapsportal.com/
|
||||||
|
--
|
||||||
|
-- ip-geolocation-map-bing.center GPS coordinates defining the center of the
|
||||||
|
-- image. If omitted, Bing Maps will choose a center that shows all the
|
||||||
|
-- markers.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-bing.format The default value is 'jpeg', 'png', and
|
||||||
|
-- 'gif' are also allowed.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-bing.language The default value is 'en', but other
|
||||||
|
-- two-letter language codes are accepted.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-bing.layer The default value is 'Road',
|
||||||
|
-- 'Aerial', and 'AerialWithLabels' are also allowed.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-bing.map_path The path at which the rendered
|
||||||
|
-- Bing Map will be saved to the local filesystem.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-bing.marker_style This argument can apply styling
|
||||||
|
-- to the markers.
|
||||||
|
-- https://msdn.microsoft.com/en-us/library/ff701719.aspx
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-bing.size The default value is '640x640' pixels, but
|
||||||
|
-- can be changed so long as the width is between 80 and 2000 pixels and the
|
||||||
|
-- height is between 80 and 1500 pixels.
|
||||||
|
|
||||||
|
author = "Mak Kolybabi <mak@kolybabi.com>"
|
||||||
|
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"external", "safe"}
|
||||||
|
|
||||||
|
local render = function(params, options)
|
||||||
|
-- Format marker style for inclusion in parameters.
|
||||||
|
local style = ""
|
||||||
|
if options["marker_style"] then
|
||||||
|
style = ";" .. options["marker_style"]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add in a marker for each host.
|
||||||
|
local markers = {}
|
||||||
|
for coords, ip in pairs(geoip.get_all_by_gps(100)) do
|
||||||
|
table.insert(markers, "pp=" .. coords .. style)
|
||||||
|
end
|
||||||
|
local body = table.concat(markers, "&")
|
||||||
|
|
||||||
|
-- Format the parameters into a properly encoded URL.
|
||||||
|
local query = "/REST/v1/Imagery/Map/" .. options["layer"] .. "?" .. url.build_query(params)
|
||||||
|
stdnse.debug1("The query URL is: %s", query)
|
||||||
|
stdnse.debug1("The query body is: %s", body)
|
||||||
|
|
||||||
|
local headers = {
|
||||||
|
["header"] = {
|
||||||
|
["Content-Type"] = "text/plain; charset=utf-8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local res = http.post("dev.virtualearth.net", 80, query, headers, nil, body)
|
||||||
|
if not res or res.status ~= 200 then
|
||||||
|
stdnse.debug1("Error %d from API: %s", res.status, res.body)
|
||||||
|
return false, ("Failed to recieve map using query '%s'."):format(query)
|
||||||
|
end
|
||||||
|
|
||||||
|
local f = io.open(options["map_path"], "w")
|
||||||
|
if not f then
|
||||||
|
return false, ("Failed to open file '%s'."):format(options["map_path"])
|
||||||
|
end
|
||||||
|
|
||||||
|
if not f:write(res.body) then
|
||||||
|
return false, ("Failed to write file '%s'."):format(options["map_path"])
|
||||||
|
end
|
||||||
|
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
local msg
|
||||||
|
|
||||||
|
return true, ("The map has been saved at '%s'."):format(options["map_path"])
|
||||||
|
end
|
||||||
|
|
||||||
|
local parse_args = function()
|
||||||
|
local options = {}
|
||||||
|
local params = {}
|
||||||
|
|
||||||
|
local api_key = stdnse.get_script_args(SCRIPT_NAME .. '.api_key')
|
||||||
|
if not api_key then
|
||||||
|
return false, "Need to specify an API key, get one at https://www.bingmapsportal.com/."
|
||||||
|
end
|
||||||
|
params["key"] = api_key
|
||||||
|
|
||||||
|
local center = stdnse.get_script_args(SCRIPT_NAME .. ".center")
|
||||||
|
if center then
|
||||||
|
params["centerPoint"] = center
|
||||||
|
end
|
||||||
|
|
||||||
|
local format = stdnse.get_script_args(SCRIPT_NAME .. ".format")
|
||||||
|
if format then
|
||||||
|
params["format"] = format
|
||||||
|
end
|
||||||
|
|
||||||
|
local language = stdnse.get_script_args(SCRIPT_NAME .. ".language")
|
||||||
|
if language then
|
||||||
|
params["language"] = language
|
||||||
|
end
|
||||||
|
|
||||||
|
local layer = stdnse.get_script_args(SCRIPT_NAME .. ".layer")
|
||||||
|
if not layer then
|
||||||
|
layer = "Road"
|
||||||
|
end
|
||||||
|
options["layer"] = layer
|
||||||
|
|
||||||
|
local map_path = stdnse.get_script_args(SCRIPT_NAME .. '.map_path')
|
||||||
|
if map_path then
|
||||||
|
options["map_path"] = map_path
|
||||||
|
else
|
||||||
|
return false, "Need to specify a path for the map."
|
||||||
|
end
|
||||||
|
|
||||||
|
local size = stdnse.get_script_args(SCRIPT_NAME .. ".size")
|
||||||
|
if not size then
|
||||||
|
-- This size is arbitrary, and is chosen to match the default that Google
|
||||||
|
-- Maps will produce.
|
||||||
|
size = "640x640"
|
||||||
|
end
|
||||||
|
size = string.gsub(size, "x", ",")
|
||||||
|
params["mapSize"] = size
|
||||||
|
|
||||||
|
return true, params, options
|
||||||
|
end
|
||||||
|
|
||||||
|
postrule = function()
|
||||||
|
-- Only run if a previous script has registered geolocation data.
|
||||||
|
return not geoip.empty()
|
||||||
|
end
|
||||||
|
|
||||||
|
action = function()
|
||||||
|
local output = stdnse.output_table()
|
||||||
|
|
||||||
|
-- Parse and sanity check the command line arguments.
|
||||||
|
local status, params, options = parse_args()
|
||||||
|
if not status then
|
||||||
|
output.ERROR = params
|
||||||
|
return output, output.ERROR
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Render the map.
|
||||||
|
local status, msg = render(params, options)
|
||||||
|
if not status then
|
||||||
|
output.ERROR = msg
|
||||||
|
return output, output.ERROR
|
||||||
|
end
|
||||||
|
|
||||||
|
return output, stdnse.format_output(true, msg)
|
||||||
|
end
|
||||||
182
scripts/ip-geolocation-map-google.nse
Normal file
182
scripts/ip-geolocation-map-google.nse
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
local http = require "http"
|
||||||
|
local geoip = require "geoip"
|
||||||
|
local io = require "io"
|
||||||
|
local stdnse = require "stdnse"
|
||||||
|
local table = require "table"
|
||||||
|
local url = require "url"
|
||||||
|
|
||||||
|
description = [[
|
||||||
|
This script queries the Nmap registry for the GPS coordinates of targets stored
|
||||||
|
by previous geolocation scripts and renders a Google Map of markers representing
|
||||||
|
the targets.
|
||||||
|
|
||||||
|
Additional information for the Google Static Maps API can be found at:
|
||||||
|
- https://developers.google.com/maps/documentation/static-maps/intro
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @usage
|
||||||
|
-- nmap -sn -Pn --script ip-geolocation-geoplugin,ip-geolocation-map-google --script-args ip-geolocation-map-google.api_key=[redacted],ip-geolocation-map-google.map_path=map.png <target>
|
||||||
|
--
|
||||||
|
-- @output
|
||||||
|
-- | ip-geolocation-map-google:
|
||||||
|
-- |_ The map has been saved at 'map.png'.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-google.api_key The required Google Maps API key for
|
||||||
|
-- your account. An API key can be generated at
|
||||||
|
-- https://developers.google.com/maps/documentation/static-maps/." @args
|
||||||
|
--
|
||||||
|
-- ip-geolocation-map-google.center GPS coordinates defining the center of the
|
||||||
|
-- image. If omitted, Google Maps will choose a center that shows all the
|
||||||
|
-- markers.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-google.format The default value is 'png' (alias for
|
||||||
|
-- 'png8'), 'png32', 'gif', 'jpg', and 'jpg-baseline' are also allowed.
|
||||||
|
-- https://developers.google.com/maps/documentation/static-maps/intro#ImageFormats
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-google.language The default value is 'en', but other
|
||||||
|
-- two-letter language codes are accepted.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-google.layer The default value is 'roadmap',
|
||||||
|
-- 'satellite', 'hybrid', and 'terrain' are also allowed.
|
||||||
|
-- https://developers.google.com/maps/documentation/static-maps/intro#MapTypes
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-google.map_path The path at which the rendered
|
||||||
|
-- Google Map will be saved to the local filesystem.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-google.marker_style This argument can apply styling
|
||||||
|
-- to the markers.
|
||||||
|
-- https://developers.google.com/maps/documentation/static-maps/intro#MarkerStyles
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-google.scale The default value is 1, but values 2
|
||||||
|
-- and 4 are permitted. Scale level 4 is only available to Google Maps Premium
|
||||||
|
-- customers.
|
||||||
|
-- https://developers.google.com/maps/documentation/static-maps/intro#scale_values
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-google.size The default value is '640x640' pixels,
|
||||||
|
-- but can be increased by Google Maps Premium customers.
|
||||||
|
-- https://developers.google.com/maps/documentation/static-maps/intro#Imagesizes
|
||||||
|
|
||||||
|
author = "Mak Kolybabi <mak@kolybabi.com>"
|
||||||
|
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"external", "safe"}
|
||||||
|
|
||||||
|
local render = function(params, options)
|
||||||
|
-- Add in a marker for each GPS coordinate.
|
||||||
|
local markers = {}
|
||||||
|
for coords, ips in pairs(geoip.get_all_by_gps()) do
|
||||||
|
table.insert(markers, coords)
|
||||||
|
end
|
||||||
|
params["markers"] = options["marker_style"] .. "|" .. table.concat(markers, "|")
|
||||||
|
|
||||||
|
-- Format the parameters into a properly encoded URL.
|
||||||
|
local query = "/maps/api/staticmap?" .. url.build_query(params)
|
||||||
|
stdnse.debug1("The query URL is: %s", query)
|
||||||
|
|
||||||
|
-- Check that the query string is below the 8192 character limit after
|
||||||
|
-- URL-encoding.
|
||||||
|
if #query > 8192 then
|
||||||
|
return false, ("Refused to send query since URL path is %d chararacters, but Google Maps limits to 8192."):format(#query)
|
||||||
|
end
|
||||||
|
|
||||||
|
local res = http.get("maps.googleapis.com", 80, query)
|
||||||
|
if not res or res.status ~= 200 then
|
||||||
|
return false, ("Failed to recieve map using query '%s'."):format(query)
|
||||||
|
end
|
||||||
|
|
||||||
|
local f = io.open(options["map_path"], "w")
|
||||||
|
if not f then
|
||||||
|
return false, ("Failed to open file '%s'."):format(options["map_path"])
|
||||||
|
end
|
||||||
|
|
||||||
|
if not f:write(res.body) then
|
||||||
|
return false, ("Failed to write file '%s'."):format(options["map_path"])
|
||||||
|
end
|
||||||
|
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
return true, ("The map has been saved at '%s'."):format(options["map_path"])
|
||||||
|
end
|
||||||
|
|
||||||
|
local parse_args = function()
|
||||||
|
local options = {}
|
||||||
|
local params = {}
|
||||||
|
|
||||||
|
local api_key = stdnse.get_script_args(SCRIPT_NAME .. '.api_key')
|
||||||
|
if not api_key then
|
||||||
|
return false, "Need to specify an API key, get one at https://developers.google.com/maps/documentation/static-maps/."
|
||||||
|
end
|
||||||
|
params["key"] = api_key
|
||||||
|
|
||||||
|
local center = stdnse.get_script_args(SCRIPT_NAME .. ".center")
|
||||||
|
if center then
|
||||||
|
params["center"] = center
|
||||||
|
end
|
||||||
|
|
||||||
|
local format = stdnse.get_script_args(SCRIPT_NAME .. ".format")
|
||||||
|
if format then
|
||||||
|
params["format"] = format
|
||||||
|
end
|
||||||
|
|
||||||
|
local language = stdnse.get_script_args(SCRIPT_NAME .. ".language")
|
||||||
|
if language then
|
||||||
|
params["language"] = language
|
||||||
|
end
|
||||||
|
|
||||||
|
local layer = stdnse.get_script_args(SCRIPT_NAME .. ".layer")
|
||||||
|
if layer then
|
||||||
|
params["layer"] = layer
|
||||||
|
end
|
||||||
|
|
||||||
|
local map_path = stdnse.get_script_args(SCRIPT_NAME .. '.map_path')
|
||||||
|
if map_path then
|
||||||
|
options["map_path"] = map_path
|
||||||
|
else
|
||||||
|
return false, "Need to specify a path for the map."
|
||||||
|
end
|
||||||
|
|
||||||
|
local marker_style = stdnse.get_script_args(SCRIPT_NAME .. ".marker_style")
|
||||||
|
stdnse.debug1('--> [%s]', marker_style)
|
||||||
|
if not marker_style then
|
||||||
|
marker_style = ""
|
||||||
|
end
|
||||||
|
options["marker_style"] = marker_style
|
||||||
|
|
||||||
|
local scale = stdnse.get_script_args(SCRIPT_NAME .. ".scale")
|
||||||
|
if scale then
|
||||||
|
params["scale"] = scale
|
||||||
|
end
|
||||||
|
|
||||||
|
local size = stdnse.get_script_args(SCRIPT_NAME .. ".size")
|
||||||
|
if not size then
|
||||||
|
size = "640x640"
|
||||||
|
end
|
||||||
|
params["size"] = size
|
||||||
|
|
||||||
|
return true, params, options
|
||||||
|
end
|
||||||
|
|
||||||
|
postrule = function()
|
||||||
|
-- Only run if a previous script has registered geolocation data.
|
||||||
|
return not geoip.empty()
|
||||||
|
end
|
||||||
|
|
||||||
|
action = function()
|
||||||
|
local output = stdnse.output_table()
|
||||||
|
|
||||||
|
-- Parse and sanity check the command line arguments.
|
||||||
|
local status, params, options = parse_args()
|
||||||
|
if not status then
|
||||||
|
output.ERROR = params
|
||||||
|
return output, output.ERROR
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Render the map.
|
||||||
|
local status, msg = render(params, options)
|
||||||
|
if not status then
|
||||||
|
output.ERROR = msg
|
||||||
|
return output, output.ERROR
|
||||||
|
end
|
||||||
|
|
||||||
|
return output, stdnse.format_output(true, msg)
|
||||||
|
end
|
||||||
91
scripts/ip-geolocation-map-kml.nse
Normal file
91
scripts/ip-geolocation-map-kml.nse
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
local http = require "http"
|
||||||
|
local geoip = require "geoip"
|
||||||
|
local io = require "io"
|
||||||
|
local stdnse = require "stdnse"
|
||||||
|
local table = require "table"
|
||||||
|
|
||||||
|
description = [[
|
||||||
|
This script queries the Nmap registry for the GPS coordinates of targets stored
|
||||||
|
by previous geolocation scripts and produces a KML file of points representing
|
||||||
|
the targets.
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @usage
|
||||||
|
-- nmap -sn -Pn --script ip-geolocation-geoplugin,ip-geolocation-map-kml --script-args ip-geolocation-map-kml.map_path=map.kml <target>
|
||||||
|
--
|
||||||
|
-- @output
|
||||||
|
-- | ip-geolocation-map-kml:
|
||||||
|
-- |_ The map has been saved at 'map.kml'.
|
||||||
|
--
|
||||||
|
-- @args ip-geolocation-map-kml.map_path (REQUIRED)
|
||||||
|
|
||||||
|
author = "Mak Kolybabi <mak@kolybabi.com>"
|
||||||
|
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"safe"}
|
||||||
|
|
||||||
|
local render = function(path)
|
||||||
|
local kml = {'<?xml version="1.0" encoding="UTF-8"?>\n<kml xmlns="http://www.opengis.net/kml/2.2">\n <Document>'}
|
||||||
|
|
||||||
|
for ip, coords in pairs(geoip.get_all_by_ip()) do
|
||||||
|
table.insert(kml, ([[
|
||||||
|
<Placemark>
|
||||||
|
<name>%s</name>
|
||||||
|
<Point>
|
||||||
|
<coordinates>%s,%s</coordinates>
|
||||||
|
</Point>
|
||||||
|
</Placemark>]]):format(ip, coords["longitude"], coords["latitude"])
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(kml, ' </Document>\n</kml>\n')
|
||||||
|
|
||||||
|
kml = table.concat(kml, "\n")
|
||||||
|
|
||||||
|
local f = io.open(path, "w")
|
||||||
|
if not f then
|
||||||
|
return false, ("Failed to open file '%s'."):format(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not f:write(kml) then
|
||||||
|
return false, ("Failed to write file '%s'."):format(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
return true, ("The map has been saved at '%s'."):format(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
local parse_args = function()
|
||||||
|
local map_path = stdnse.get_script_args(SCRIPT_NAME .. '.map_path')
|
||||||
|
if not map_path then
|
||||||
|
return false, "Need to specify a path for the map."
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, map_path
|
||||||
|
end
|
||||||
|
|
||||||
|
postrule = function()
|
||||||
|
-- Only run if a previous script has registered geolocation data.
|
||||||
|
return not geoip.empty()
|
||||||
|
end
|
||||||
|
|
||||||
|
action = function()
|
||||||
|
local output = stdnse.output_table()
|
||||||
|
|
||||||
|
-- Parse and sanity check the command line arguments.
|
||||||
|
local status, path = parse_args()
|
||||||
|
if not status then
|
||||||
|
output.ERROR = path
|
||||||
|
return output, output.ERROR
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Render the map.
|
||||||
|
local status, msg = render(path)
|
||||||
|
if not status then
|
||||||
|
output.ERROR = msg
|
||||||
|
return output, output.ERROR
|
||||||
|
end
|
||||||
|
|
||||||
|
return msg
|
||||||
|
end
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
local bit = require "bit"
|
local bit = require "bit"
|
||||||
|
local geoip = require "geoip"
|
||||||
local io = require "io"
|
local io = require "io"
|
||||||
local ipOps = require "ipOps"
|
local ipOps = require "ipOps"
|
||||||
local math = require "math"
|
local math = require "math"
|
||||||
@@ -492,6 +493,7 @@ local GeoIP = {
|
|||||||
output_record_by_addr = function(self,addr)
|
output_record_by_addr = function(self,addr)
|
||||||
local loc = self:record_by_addr(addr)
|
local loc = self:record_by_addr(addr)
|
||||||
if not loc then return nil end
|
if not loc then return nil end
|
||||||
|
geoip.add(addr, loc.latitude, loc.longitude)
|
||||||
setmetatable(loc, record_metatable)
|
setmetatable(loc, record_metatable)
|
||||||
return loc
|
return loc
|
||||||
end,
|
end,
|
||||||
|
|||||||
@@ -279,6 +279,9 @@ Entry { filename = "informix-tables.nse", categories = { "auth", "intrusive", }
|
|||||||
Entry { filename = "ip-forwarding.nse", categories = { "discovery", "safe", } }
|
Entry { filename = "ip-forwarding.nse", categories = { "discovery", "safe", } }
|
||||||
Entry { filename = "ip-geolocation-geoplugin.nse", categories = { "discovery", "external", "safe", } }
|
Entry { filename = "ip-geolocation-geoplugin.nse", categories = { "discovery", "external", "safe", } }
|
||||||
Entry { filename = "ip-geolocation-ipinfodb.nse", categories = { "discovery", "external", "safe", } }
|
Entry { filename = "ip-geolocation-ipinfodb.nse", categories = { "discovery", "external", "safe", } }
|
||||||
|
Entry { filename = "ip-geolocation-map-bing.nse", categories = { "external", "safe", } }
|
||||||
|
Entry { filename = "ip-geolocation-map-google.nse", categories = { "external", "safe", } }
|
||||||
|
Entry { filename = "ip-geolocation-map-kml.nse", categories = { "safe", } }
|
||||||
Entry { filename = "ip-geolocation-maxmind.nse", categories = { "discovery", "external", "safe", } }
|
Entry { filename = "ip-geolocation-maxmind.nse", categories = { "discovery", "external", "safe", } }
|
||||||
Entry { filename = "ip-https-discover.nse", categories = { "default", "discovery", "safe", } }
|
Entry { filename = "ip-https-discover.nse", categories = { "default", "discovery", "safe", } }
|
||||||
Entry { filename = "ipidseq.nse", categories = { "discovery", "safe", } }
|
Entry { filename = "ipidseq.nse", categories = { "discovery", "safe", } }
|
||||||
|
|||||||
Reference in New Issue
Block a user