forked from hubert3/iSniff-GPS
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8efeacf
Showing
29 changed files
with
1,436 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Oops, something went wrong.