summaryrefslogtreecommitdiffstats
path: root/scripts/ip-geolocation-map-google.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/ip-geolocation-map-google.nse')
-rw-r--r--scripts/ip-geolocation-map-google.nse181
1 files changed, 181 insertions, 0 deletions
diff --git a/scripts/ip-geolocation-map-google.nse b/scripts/ip-geolocation-map-google.nse
new file mode 100644
index 0000000..807c8ea
--- /dev/null
+++ b/scripts/ip-geolocation-map-google.nse
@@ -0,0 +1,181 @@
+local http = require "http"
+local geoip = require "geoip"
+local io = require "io"
+local oops = require "oops"
+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
+--
+-- @see ip-geolocation-geoplugin.nse
+-- @see ip-geolocation-ipinfodb.nse
+-- @see ip-geolocation-map-bing.nse
+-- @see ip-geolocation-map-kml.nse
+-- @see ip-geolocation-maxmind.nse
+
+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 receive 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")
+ 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()
+ -- Parse and sanity check the command line arguments.
+ local status, params, options = oops.raise(
+ "Script argument problem",
+ parse_args())
+ if not status then
+ return params
+ end
+
+ -- Render the map.
+ return oops.output(render(params, options))
+end