Kismet Wireless

Kismet Forums

 

Posted by:greg912
Subject:python sax parser to convert kismet logs to google earth kml
Date:12:42:59 14/09/2006

Hi all,

Here is a script I wrote to convert kismet logs to google earth. I realise there is a php one here:

http://www.niquille.com/kismet-earth/

But I wrote my own because:

- I got php out of memory errors for large gps files
- The signal strength data wasn't mapped onto google earth
- The APs were not placed at points of max signal strength, and so didn't really make sense.

I have addressed all these issues. I have included the text below, but as this is python the indenting is important so I have emailled dragorn@kismetwireless.net with the file. Hopefully kismetwireless will host it for everyone. Certainly many improvement can still be made to the script.

greg


#!/bin/python

#greg912noharvesting@gmail.com
#please remove "noharvesting" to send me email.

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="""<?xml version='1.0' encoding='UTF-8'?>
<kml xmlns='http://earth.google.com/kml/2.0'>
<Folder>
<name>"""+sys.argv[1]+"""</name>
<description>"""+attrs["start-time"]+"""</description>
<visibility>1</visibility>
<open>1</open>"""

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"]]+="""
<Placemark>
<visibility>0</visibility>
<open>0</open>
<Style>
<LineStyle>
<color>""" + self.color[attrs["bssid"]] + """</color>
<width>4</width>
</LineStyle>
</Style>
<LineString>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>relativeToGround</altitudeMode>
<coordinates>""" + attrs["lon"]+","+attrs["lat"]+","+attrs["signal"]+"""
</coordinates>
</LineString>
</Placemark>"""

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"]]="""
<Placemark>
<visibility>0</visibility>
<open>0</open>
<Style>
<LineStyle>
<color>""" + self.color[attrs["bssid"]] + """</color>
<width>4</width>
</LineStyle>
</Style>
<LineString>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>relativeToGround</altitudeMode>
<coordinates>""" + attrs["lon"]+","+attrs["lat"]+","+attrs["signal"]+"""
</coordinates>
</LineString>
</Placemark>"""

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+="""

<Placemark>
<description>Warpath Route Taken</description>
<name>Route</name>
<LookAt>
<longitude>"""+startlong+"""</longitude>
<latitude>"""+startlat+"""</latitude>
<range>1000</range>
<tilt>54</tilt>
<heading>-35</heading>
</LookAt>
<visibility>1</visibility>
<open>0</open>
<Style>
<LineStyle>
<color>BB0000FF</color>
<width>4</width>
</LineStyle>
</Style>
<LineString>
<extrude>0</extrude>
<tessellate>1</tessellate>
<altitudeMode>clampedToGround</altitudeMode>
<coordinates>""" + self.path + """
</coordinates>
</LineString>
</Placemark>"""

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="""
<LookAt>
<longitude>%s</longitude>
<latitude>%s</latitude>
<range>100</range>
<tilt>54</tilt>
<heading>-35</heading>
</LookAt>
""" % (max_sig_lon,max_sig_lat)

except KeyError:
#We don't have gps data for this MAC for whatever reason
sig_str="<description>No GPS Data Available!!</description>"
lookat=""
max_sig_lon=0
max_sig_lat=0


try:
if (self.net["encryption"].index("WPA")>=0) or self.net["encryption"].contains("TKIP"):
encryption="<font color=\"green\">%s</font>" % self.net["encryption"]
icon="node_closed.png"
except ValueError:
if self.net["encryption"]=="WEP":
encryption="<font color=\"blue\">%s</font>" % self.net["encryption"]
icon="node_open.png"
elif self.net["encryption"]=="None":
encryption="<font color=\"red\">%s</font>" % self.net["encryption"]
icon="node_open.png"


self.output+="""
<Folder>
<name>%s</name>
%s
<description><![CDATA[First-seen:%s<br>
Last-seen:%s<br><hr>
BSSID:%s<br>
channel:%s<br>
encryption:%s<br>
cloaked:%s<br>
max rate:%s<br><hr>
GPS Coordinates<br>
Min lat/long/alt:%s lat, %s lon, %s alt<br>
Max lat/long/alt:%s lat, %s lon, %s alt<br><hr>
Captured Packets<br>
llc:%s<br>
data:%s<br>
crypt:%s<br>
weak:%s<br>
dupeiv:%s<br>
total:%s<br>
total datasize captured:%s<br>
]]></description>
<Placemark>
<name>%s</name>
<description>Location of max AP signal strength</description>
<visibility>0</visibility>
<open>0</open>
%s
<Style>
<icon>%s</icon>
</Style>
<Point>
<altitudeMode>clampedToGround</altitudeMode>
<extrude>0</extrude>
<tessellate>0</tessellate>
<coordinates>%s,%s,0</coordinates>
</Point>
</Placemark>
<Folder>
<name>Signal Strength Map</name>
%s
%s
</Folder></Folder>""" % (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("</Folder>\n</kml>")


kismetparser = make_parser()
kismetparser.setContentHandler(KismetFileHandler())
kismetparser.parse(sys.argv[1]+".gps")
kismetparser.parse(sys.argv[1]+".xml")


Reply to this message