#!/usr/env/python # Version 0.1 # http://pykismetearth.google.pages.com # Send email to pykismetearth@gmail.com # Usage: python pykismetearth.py Kismet-Sep-07-2006 # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import sys import random import urllib from xml.sax import make_parser, handler class KismetFileHandler(handler.ContentHandler): """This class parses kismet .gps and .xml files. The idea is to produce a folder for each ssid with a signal strength map, metadata about the AP, and a best guess location (currently placed at location of strongest power). """ def __init__(self): self.signal_strength={} self.color={} self.max_signal_strength={} self.max_signal_strength_coords={} self.net={} self.path="" self.output="" self.tag="none" self.interested=False def startElement(self, name, attrs): if name=="gps-run": #This is the first thing in our gps file. self.output=""" """+sys.argv[1]+""" """+attrs["start-time"]+""" 1 1""" elif name=="wireless-network": if attrs["type"]=="infrastructure": #We only care about infrastructure networks. self.interested=True self.net["cloaked"]=attrs["cloaked"] self.net["first-seen"]=attrs["first-time"] self.net["last-seen"]=attrs["last-time"] elif name=="SSID" and self.interested: self.tag="ssid" elif name=="BSSID" and self.interested: self.tag="bssid" elif name=="channel" and self.interested: self.tag=name elif name=="maxrate" and self.interested: self.tag=name elif name=="maxseenrate" and self.interested: self.tag=name elif name=="carrier" and self.interested: self.tag=name elif name=="encryption" and self.interested: self.tag=name elif name=="LLC" and self.interested: self.tag="llc" elif name=="data" and self.interested: self.tag=name elif name=="crypt" and self.interested: self.tag=name elif name=="weak" and self.interested: self.tag=name elif name=="dupeiv" and self.interested: self.tag=name elif name=="total" and self.interested: self.tag=name elif name=="datasize" and self.interested: self.tag=name elif name=="min-lat" and self.interested: self.tag=name elif name=="min-lon" and self.interested: self.tag=name elif name=="min-alt" and self.interested: self.tag=name elif name=="min-spd" and self.interested: self.tag=name elif name=="max-lat" and self.interested: self.tag=name elif name=="max-lon" and self.interested: self.tag=name elif name=="max-alt" and self.interested: self.tag=name elif name=="max-spd" and self.interested: self.tag=name elif name=="gps-point": #Storlat/long/altwarpath track self.path = self.path + attrs["lon"] + "," + attrs["lat"] + ",0 " if attrs["bssid"] != "GP:SD:TR:AC:KL:OG": try: #Create a point for each gps measurement. Build an array #of measurements per bssid. self.signal_strength[attrs["bssid"]]+=""" 0 0 1 1 relativeToGround """ + attrs["lon"]+","+attrs["lat"]+","+attrs["signal"]+""" """ try: if int(attrs["signal"]) > int(self.max_signal_strength[attrs["bssid"]]): self.max_signal_strength[attrs["bssid"]]=attrs["signal"] self.max_signal_strength_coords[attrs["bssid"]]=[attrs["lon"],attrs["lat"]] except KeyError: self.max_signal_strength[attrs["bssid"]]=attrs["signal"] self.max_signal_strength_coords[attrs["bssid"]]=[attrs["lon"],attrs["lat"]] except KeyError: #This is a new BSSID, assign it a color and add in the first point self.color[attrs["bssid"]]=hex(random.randrange(0xFF000000,0xFFFFFFFF))[2:-1] self.signal_strength[attrs["bssid"]]=""" 0 0 1 1 relativeToGround """ + attrs["lon"]+","+attrs["lat"]+","+attrs["signal"]+""" """ else: self.tag="none" def endElement(self, name): if name=="gps-run": temp=self.path.split(" ",1)[0] startlat=temp.split(",")[1] startlong=temp.split(",")[0] #Write out the warpath route self.output+=""" Warpath Route Taken Route """+startlong+""" """+startlat+""" 1000 54 -35 1 0 0 1 clampedToGround """ + self.path + """ """ if name=="wireless-network" and self.interested: try: #People have ssid's with lots of funky chars that google earth doesn't like. ssid=urllib.quote(self.net["ssid"]) except KeyError: #Must have been no ssid ssid="no-ssid" try: sig_str=self.signal_strength[self.net["bssid"]] max_sig_lon=self.max_signal_strength_coords[self.net["bssid"]][0] max_sig_lat=self.max_signal_strength_coords[self.net["bssid"]][1] lookat=""" %s %s 100 54 -35 """ % (max_sig_lon,max_sig_lat) except KeyError: #We don't have gps data for this MAC for whatever reason sig_str="No GPS Data Available!!" lookat="" max_sig_lon=0 max_sig_lat=0 try: if (self.net["encryption"].index("WPA")>=0) or self.net["encryption"].contains("TKIP"): encryption="%s" % self.net["encryption"] icon="node_closed.png" except ValueError: if self.net["encryption"]=="WEP": encryption="%s" % self.net["encryption"] icon="node_open.png" elif self.net["encryption"]=="None": encryption="%s" % self.net["encryption"] icon="node_open.png" self.output+=""" %s %s Last-seen:%s

BSSID:%s
channel:%s
encryption:%s
cloaked:%s
max rate:%s

GPS Coordinates
Min lat/long/alt:%s lat, %s lon, %s alt
Max lat/long/alt:%s lat, %s lon, %s alt

Captured Packets
llc:%s
data:%s
crypt:%s
weak:%s
dupeiv:%s
total:%s
total datasize captured:%s
]]>
%s Location of max AP signal strength 0 0 %s clampedToGround 0 0 %s,%s,0 Signal Strength Map %s %s
""" % (ssid,lookat,self.net["first-seen"],self.net["last-seen"],self.net["bssid"],self.net["channel"],encryption,self.net["cloaked"],self.net["maxrate"],self.net["min-lat"],self.net["min-lon"],self.net["min-alt"],self.net["max-lat"],self.net["max-lon"],self.net["max-alt"],self.net["llc"],self.net["data"],self.net["crypt"],self.net["weak"],self.net["dupeiv"],self.net["total"],self.net["datasize"],ssid,lookat,icon,max_sig_lon,max_sig_lat,lookat,sig_str) self.tag="none" self.net={} self.interested=False def characters(self,chars): #The characters output is a bit messy - throw away whitespace only stuff if self.interested and self.tag !="none" and len(chars.strip())!=0: try: if self.net[self.tag]: #We already have a value for this key so append self.net[self.tag]+=" "+str(chars) except KeyError: self.net[self.tag]=str(chars) except: print "Couldn't process string: %s" % chars def endDocument(self): handle = open(sys.argv[1]+".kml","w+") handle.write(self.output) handle.write("
\n
") kismetparser = make_parser() kismetparser.setContentHandler(KismetFileHandler()) kismetparser.parse(sys.argv[1]+".gps") kismetparser.parse(sys.argv[1]+".xml")