Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
hubert3 committed Aug 31, 2012
0 parents commit 8efeacf
Show file tree
Hide file tree
Showing 29 changed files with 1,436 additions and 0 deletions.
57 changes: 57 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
iSniff GPS
==========

This tool performs passive WiFi sniffing for SSID probes, ARPs and MDNS (Bonjour) packets broadcast by nearby iPhones, iPads and other wireless devices.
The aim is to collect data which can be used to identify each device and determine previous geographical locations, based solely on information each device discloses about WiFi networks it has previously joined.

iOS devices transmit ARPs which sometimes contain WiFi AP MAC addresses (BSSIDs) of previously joined networks (see [1]). This is believed to be an implementation of RFC 4436.
If such an ARP is detected, iSniff GPS is able to submit this MAC address to Apple's WiFi location service (masquerading as an iOS device) and visualise the location returned through a Google Maps embed.
This is often highly accurate. If only standard SSID probes have been captured for a particular device, iSniff GPS can query each SSID on wigle.net and visualise possible locations.
By geo-locating multiple SSIDs and WiFi router MAC addresses disclosed by a particular device, it is possible to determine where a device (and by implication its owner) is likely to have been.

Components
----------

iSniff GPS contains 2 major components and further python modules:
* A python script (iSniff_import.py) uses scapy to extract data from a live capture or pcap file and inserts it into a database (iSniff_GPS.sqlite3 by default).
* A Django web application provides a browser-based interface to view and analyse the data collected.

wloc.py provides functionality for querying a given BSSID (AP MAC address) on Apple's WiFi location service.
It will return the coordinates of the specific MAC queried for and usually an additional 400 nearby BSSIDs and their coordinates.

wigle.py provides a function for querying a given SSID on the wigle.net database and returns GPS coordinates.
It must be configured with a valid wigle.net auth cookie. Please respect the wigle.net ToS in using this module.

Instructions
------------

Install Django, Scapy and all required Python modules.
Initialise an empty database by running "./manage.py syncdb".
Import data from a pcap by running "./run.sh -r <chan11.pcap>" or start live sniffing with "./run.sh -i mon0".
Start the web interface by running "./manage.py runserver ip:port".

Dependencies
------------

iSniff GPS was developed and tested on a Ubuntu 12.04 (32-bit) VM with Python 2.7.3, Django 1.4 and Scapy 2.2.0-dev.
Additional Python modules are required which can generally be installed by running 'pip install <module>':

* dnslib
* netaddr
* requests
* BeautifulSoup4
* protobuf (Google Protocol Buffers)

Credits
-------

Written by @hubert3 / hubert(at)pentest.com
First presented at Blackhat USA July 2012
Code first published on Github 2012-08-31

The implementation of wloc.py which communicates with Apple's WiFi location service to obtain the GPS coordinates of a given BSSID is based on work by François-Xavier Aguessy and Côme Demoustier [2]
Mark Wuergler of Immunity, Inc. provided helpful information through mailing list posts and Twitter replies.
Bluff JS chart library by James Coglan.

[1] http://arstechnica.com/apple/2012/03/anatomy-of-an-iphone-leak/
[2] http://fxaguessy.fr/rapport-pfe-interception-ssl-analyse-donnees-localisation-smartphones/
36 changes: 36 additions & 0 deletions color.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

style_normal = "\033[0m"
style_great_success = "\033[1;32m"
style_success = "\033[32m"
style_error = "\033[1;31m"
style_warning = "\033[1;33m"
style_info = "\033[1;34m"
style_stealthy = "\033[37m"

def success(s):
return style_success + s + style_normal

def error(s):
return style_error + s + style_normal

def warning(s):
return style_warning + s + style_normal

def great_success(s):
return style_great_success + s + style_normal

def info(s):
return style_info + s + style_normal

def stealthy(s):
return style_stealthy + s + style_normal

def color_status(status):
if status.startswith("2"):
return great_success(status)
elif status.startswith("3"):
return warning(status)
elif status.startswith("4") or status.startswith("5"):
return error(status)
return stealthy(status)

244 changes: 244 additions & 0 deletions iSniff_GPS/BSSIDApple_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file added iSniff_GPS/__init__.py
Empty file.
13 changes: 13 additions & 0 deletions iSniff_GPS/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from models import Client, AP, Location
from django.contrib import admin

class ClientAdmin(admin.ModelAdmin):
list_display = ['manufacturer', 'mac', 'lastseen_date', 'name']

class APAdmin(admin.ModelAdmin):
list_display = ['SSID', 'BSSID', 'manufacturer', 'lastprobed_date', 'name']

admin.site.register(Client, ClientAdmin)
admin.site.register(AP, APAdmin)
admin.site.register(Location)

39 changes: 39 additions & 0 deletions iSniff_GPS/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from django.db import models

class Client(models.Model):
mac = models.CharField(max_length=len('ff:ff:ff:ff:ff:ff'), unique=True)
lastseen_date = models.DateTimeField('date last seen')
name = models.CharField(max_length=200, blank=True)
comment = models.CharField(max_length=200, blank=True)
manufacturer = models.CharField(max_length=200, blank=True)
def __unicode__(self):
return u'%s' % (self.mac)

class AP(models.Model):
client = models.ManyToManyField(Client)
SSID = models.CharField(max_length=200, blank=True)
BSSID = models.CharField(max_length=len('ff:ff:ff:ff:ff:ff'), blank=True)
name = models.CharField(max_length=200, blank=True)
comment = models.CharField(max_length=200, blank=True)
manufacturer = models.CharField(max_length=200, blank=True)
lastprobed_date = models.DateTimeField('date last probed for')
lon = models.FloatField(null=True)
lat = models.FloatField(null=True)
address = models.CharField(max_length=200, blank=True)
def __unicode__(self):
if self.SSID and self.BSSID:
return u'%s [%s]' % (self.SSID,self.BSSID)
if self.SSID:
return u'%s' % self.SSID
if self.BSSID:
return u'<font color="red">ARP:%s</font>' % self.BSSID

class Location(models.Model):
ap = models.ForeignKey(AP)
lon = models.FloatField()
lat = models.FloatField()
name = models.CharField(max_length=200, blank=True)
source = models.CharField(max_length=20) # Apple or Wigle at present
comment = models.CharField(max_length=200, blank=True)
def __unicode__(self):
return u'%s,%s' % (self.lon,self.lat)
Loading

0 comments on commit 8efeacf

Please sign in to comment.