Apple lagrar GPS-data samt BSSID (accesspunkter) på ipad/iphone med GPS-mottagare

Lets face it. Data är idag en handelsvara och i vårt mobila samhälle innebär geolokaliseringsdata guld inte bara för marknadsförare utan även för allehanda marknadsintressen eftersom man ur geolokaliseringsdata kan dra slutsatser om beteenden etc.

De flesta webbläsare stöder exempelvis Googles API för att geolokalisera dig med hjälp av omgärdande BSSID (hårdvaruadresser för trådlösa accesspunkter). Googlebilen som åkte runt och fotade byggnader, gator osv samlade även in BSSID och korresponderande GPS-data (longitud och latitud).

Webbläsartillverkarna vill ofta få det till att man nu "implementerat skydd" mot att ofrivilligt bli geolokaliserad när man inför denna funktionalitet i webbläsarna. I själva verket har man infört stöd för geolokaliseringsmetoden som behöver access till bl a ditt trådlösa nätverkskort.

Jag själv har inget emot att bli tillfrågad om jag vill dela med mig av min geografiska position för att t ex få riktade annonser, men det är viktigt att konsumenten känner till vad för slags data som faktiskt samlas in.

 

I forensikerkretsar (även podcasts med inriktningen forensics) har pratat om dessa databaser ett tag (drygt ett år) och det är egentligen inga konstiga data det handlar om. När GPS-mottagaren är påslagen, har mottagning och tar emot data så loggas detta i en SQLitedatabas (consolidated.db) innehållande flertalet tabeller vilka innehåller GPS-data. De GPS-data som lagras i databasen lagras med en tidsstämpel i float-format (antal sekunder sedan 1 januari 2001) som inte riktigt överensstämmer med när dessa lästes från GPS-mottagaren. Verkar vara någon form av cache som efter en tid "flushas" till consolidated.db.

 

 

sqlite> .TABLES
Cell                           CellLocationLocalBoxes_rowid 
CellLocation                   CellLocationLocalCounts      
CellLocationBoxes              CompassCalibration           
CellLocationBoxes_node         Fences                       
CellLocationBoxes_parent       Location                     
CellLocationBoxes_rowid        LocationHarvest              
CellLocationCounts             LocationHarvestCounts        
CellLocationHarvest            TableInfo                    
CellLocationHarvestCounts      Wifi                         
CellLocationLocal              WifiLocation                 
CellLocationLocalBoxes         WifiLocationCounts           
CellLocationLocalBoxes_node    WifiLocationHarvest          
CellLocationLocalBoxes_parent  WifiLocationHarvestCounts

 

 

 

De tabellnamn som är intressanta i sammanhanget är CellLocation, WifiLocation men också de *Harvest och *HarvestCounts tabeller som finns i databasen.

*Harvest-tabellerna skulle kunna vara en indikation på att viss data skickas till Apple. Det skulle kunna förklara varför CellLocationHarvest* tabellerna är tomma och innehåller räknevärdet 0. Denna information snor i dagsläget inte Apple från databasen (detta kan dock komma att ändras, man har väl inte skapat

dessa tabeller utan ett syfte?).

 

 

1
2
3
4
5
6
sqlite> SELECT * FROM CellLocationHarvest;
sqlite> SELECT * FROM CellLocationHarvestCounts;
0
sqlite> SELECT * FROM WifiLocationHarvest;
sqlite> SELECT * FROM WifiLocationHarvestCounts;
0

 

 

 

Lite grävande i SQLitetabellernas uppbyggnad:

 

 

1
2
3
4
5
sqlite> .schema CellLocation
CREATE TABLE CellLocation (MCC INTEGER, MNC INTEGER, LAC INTEGER, CI INTEGER, Timestamp FLOAT, Latitude FLOAT, Longitude FLOAT, HorizontalAccuracy FLOAT, Altitude FLOAT, VerticalAccuracy FLOAT, Speed FLOAT, Course FLOAT, Confidence INTEGER, PRIMARY KEY (MCC, MNC, LAC, CI));
CREATE TRIGGER CellLocationDecrementRowCount AFTER DELETE ON CellLocation FOR EACH ROW BEGIN UPDATE CellLocationCounts SET Count=Count-1 WHERE rowid=1; END;
CREATE TRIGGER CellLocationIncrementRowCount AFTER INSERT ON CellLocation FOR EACH ROW BEGIN UPDATE CellLocationCounts SET Count=Count+1 WHERE rowid=1; END;
 

 

 

 

 

1
2
3
4
sqlite> .schema WifiLocation
CREATE TABLE WifiLocation (MAC TEXT, Timestamp FLOAT, Latitude FLOAT, Longitude FLOAT, HorizontalAccuracy FLOAT, Altitude FLOAT, VerticalAccuracy FLOAT, Speed FLOAT, Course FLOAT, Confidence INTEGER, PRIMARY KEY (MAC));
CREATE TRIGGER WifiLocationDecrementRowCount AFTER DELETE ON WifiLocation FOR EACH ROW BEGIN UPDATE WifiLocationCounts SET Count=Count-1 WHERE rowid=1; END;
CREATE TRIGGER WifiLocationIncrementRowCount AFTER INSERT ON WifiLocation FOR EACH ROW BEGIN UPDATE WifiLocationCounts SET Count=Count+1 WHERE rowid=1; END;

 

Slutligen en pythonmodul för att skriva ut data. Kan användas direkt på devicen om den är jailbreakad och har python installerad eller på extraherad databasfil som t ex kommer från en iphone-backup.

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# get_location.py - Part of Jonathan James's forensic toolkit for iPhone. http://jonathanj.com - 
 This e-mail address is being protected from spambots. You need JavaScript enabled to view it
 
# Standalone usage: get_location.py [file] [limit] or get_location.py to set the standard values.
 
import time
import sys
from sqlite3 import dbapi2 as sql
 
class location_info:
        location_db = ""
        def __init__(self,dbfile):
                self.location_db = dbfile
        def list_gps(self,limit):
                rows = 0
                self.dbconnect()
                self.c.execute("select Timestamp, Latitude, Longitude from CellLocation limit %s;" % (limit))
                print "Row:\tTimestamp:\t\t\tLatitude:\tLongitude:"
                for row in self.c:
                        if len(row)==3:
                                rows += 1
                                floattime = float(row[0])
                                ctime = time.ctime(floattime + 978328800)
                                print "%s\t%s\t%s\t%s" % (rows,ctime,row[1],row[2])
        def list_gpswlan(self,limit):
                rows = 0
                self.dbconnect()
                self.c.execute("select MAC, Timestamp, Latitude, Longitude from WifiLocation limit %s;" % (limit))
                print "Row:\tBSSID:\t\tTimestamp:\t\t\tLatitude:\tLongitude:"
                for row in self.c:
                        if len(row)==4:
                                rows += 1
                                floattime = float(row[1])
                                ctime = time.ctime(floattime + 978328800)
                                print "%s\t%s\t%s\t%s\t%s" % (rows, row[0], ctime, row[2], row[3])
        def dbconnect(self):
                self.db = sql.connect(self.location_db)
                self.c = self.db.cursor()
 
if __name__ == '__main__':
 
        # Build our location_info object        
        if (len(sys.argv) > 1):
                f=location_info(sys.argv[1])
        else:
                f=location_info('/var/root/Library/Caches/locationd/consolidated.db')
        if (len(sys.argv) > 2):
                limit = int(sys.argv[2])
        else:
                limit = 100
 
        #List data from CellLocation table
        f.list_gps(limit)
 
        #List data from WifiLocation table
        f.list_gpswlan(limit)
 
Prenumerera på Jonathans bytes