Pretty simple, it takes a file with a list of ips, one/line and generates a kml file. Very handy if you’re working on a large pentest and want to track down (and visualize) where a particular host is located. It uses the Yahoo GeoIP API to grab location data.
#!/usr/bin/ruby require 'net/http' require 'rexml/document' include REXML def getAddress(ip) #takes an ip and returns an xml blob with city/state # example: http://ipinfodb.com/ip_query.php?ip=65.23.23.33 url = "http://ipinfodb.com/ip_query.php?ip=" + ip #puts "DEBUG: URL: #{url.to_s}" resp = Net::HTTP.get(URI.parse(url)) #print "DEBUG: got " + resp return resp end def getCoordinates(address) #takes a hash with city, state address and returns a hash w/ coords url = "http://local.yahooapis.com/MapsService/V1/geocode" params = { "appid" => "GwLDY.bV34HH7gkBDs97p_5U5P_tBfXBnfDyYFwpTRLwZDEvgj8BOQqws1JOCFPyhTQR", "street" => "", "city" => address["city"], "state" => address["state"] } #puts "DEBUG: URL: #{url.to_s}" resp = Net::HTTP.post_form(URI.parse(url), params) resp_text = resp.body #print "DEBUG: got " + resp_text return resp_text end def parseAddress(xml) #takes an xml blob with city / state & returns a hash with address,city,state doc = Document.new xml root = doc.root city = root.elements["City"].get_text.to_s state = root.elements["RegionName"].get_text.to_s country = root.elements["CountryCode"].get_text.to_s #puts "DEBUG: city: " + city #puts "DEBUG: state: " + state #puts "DEBUG: country: " + country toReturn = Hash["city" => city, "state" => state, "country" => country] return toReturn end def parseCoordinates(xml) #takes an xml blob with coordinates & returns a hash with long/lat doc = REXML::Document.new xml root = doc.root long = REXML::XPath.first( doc, "//Longitude" ).get_text.to_s lat = REXML::XPath.first( doc, "//Latitude" ).get_text.to_s toReturn = Hash["long" => long, "lat" => lat] #puts "DEBUG: long: " + long #puts "DEBUG: lat: " + lat return toReturn end def genKML(ips) kml = "" kml = kml + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" kml = kml + "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" kml = kml + "<Document>\n" ips.each do |ip| ip = ip.to_s.chomp kmlplacemark = mip(ip,"error.log") if kmlplacemark.to_s != "" then # puts "DEBUG: adding non-blank placemark" + kmlplacemark kml = kml + kmlplacemark else # puts "DEBUG: unable to map ip: " + ip + "\n" end end kml = kml + "</Document>\n" kml = kml + "</kml>\n" end def genPlacemark(ip,address,coordinates) xml = "" xml = xml + " <Placemark>\n" xml = xml + " <name>" + ip + "</name>\n" xml = xml + " <description>" xml = xml + address["city"] + ", " xml = xml + address["state"] + ", " xml = xml + address["country"] xml = xml + "</description>\n" xml = xml + " <Point>\n" xml = xml + " <coordinates>" + coordinates["long"] + "," + coordinates["lat"] + ",0</coordinates>\n" xml = xml + " </Point>\n" xml = xml + " </Placemark>\n" end def mip(ip,errorfile) begin if (ip != "") then xmlAddress = getAddress(ip) objAddress = parseAddress(xmlAddress) if (objAddress["state"] != "") then xmlCoordinates = getCoordinates(objAddress) objCoordinates = parseCoordinates(xmlCoordinates) kmlplacemark = genPlacemark(ip,objAddress,objCoordinates) else File.open(errorfile, 'w') {|f| f.write(ip) } end end rescue kmlplacemark = "" end return kmlplacemark end def mips(file) counter = 0 ips = Array.new File.open(file, "r") do |infile| while (line = infile.gets) #puts "mapping #{counter}: #{line}" ips[counter] = line counter = counter + 1 end end kml = genKML(ips) return kml end kml = mips(ARGV[0]) out = File.new(ARGV[0]+".kml", "w") out.puts kml
Awesome!