However, the script does not end here. With the MAC address of a wireless access point, we can now also print out the physical location of the access point as well. Quite a few databases, both open-source and proprietary, con-tain enormous listings of wireless access points correlated to their physical locations. Proprietary products such as cell phones use these databases to geo-locate without the use of GPS.
The SkyHook database, available at http://www.skyhookwireless.com/, pro-vides a software developer kit to geo-locate based off of Wi-Fi positioning.
An open-source project developed by Ian McCracken provided access to this database for several years at http://code.google.com/p/maclocate/. However, just recently SkyHook changed the SDK to use an API key to interact with the database. Google also maintained a similarly large database for the purpose of correlating access-point MAC addresses to physical locations. However, shortly after Gorjan Petrovski developed an NMAP NSE script to interact with it, Google deprecated open source interaction with the database (Google, 2012;
Petrovski, 2011). Microsoft locked down a similar Wi-Fi geo-location database shortly afterwards, citing privacy concerns (Bright, 2011).
A remaining database and open-source project, wigle.net, continues to allow users to search for physical locations from an access point address. After reg-istering for an account, a user can interact with wigle.net with a little creative Python scripting. Let us quickly examine how to build a script to interact with wigle.net.
Using wigle.net, a user will quickly realize that he or she must interact with three separate pages in order to return a Wigle result. First, he must open the wigle.net initial page at http://wigle.net; next the user must log in to Wigle at http://wigle.net//gps/gps/main/login. Finally, the user can query a specific wireless SSID MAC address at the page http://wigle.net/gps/gps/main/confir-mquery/. Capturing the MAC address query, we see that the netid parameter
contains the MAC address in the HTTP Post that requests the GPS location of the wireless access point.
POST /gps/gps/main/confirmquery/ HTTP/1.1 Accept-Encoding: identity
Content-Length: 33 Host: wigle.net
User-Agent: AppleWebKit/531.21.10 Connection: close
Content-Type: application/x-www-form-urlencoded netid=0A%3A2C%3AEF%3A3D%3A25%3A1B
<..SNIPPED..>
Furthermore, we see the response from the page includes the GPS coordinates.
The string maplat=47.25264359&maplon=-87.25624084 contains the lati-tude and longilati-tude of the access point.
<tr class="search"><td>
<a
href="/gps/gps/Map/onlinemap2/?maplat=47.25264359&maplon=-87.25624084&mapzoom=17&ssid=McDonald's FREE Wifi&netid=0A:2C:EF:3D:
25:1B">Get Map</a></td>
<td>0A:2C:EF:3D:25:1B</td><td>McDonald's FREE Wifi</td><
With this information, we now have enough to build a simple function that will return the latitude and longitude of a wireless access point as recorded in the Wigle database. Notice the use of the mechanize library. Available from http://wwwsearch.sourceforge.net/mechanize/, mechanize allows stateful web programming in Python. This means that once we correctly log on to the Wigle service, it will store and reuse the authentication cookie for us.
The script may appear complex, but let’s quickly walk through it together.
First, we create an instance of a mechanize browser. Next, we open the initial wigle.net page. We then encode our username and password as parameters and request a login at the Wigle login page. Once we have successfully logged in, we create an HTTP post using the parameter netid as the MAC address to search the database. We then search the result of our HTTP post for the terms maplat= and maplon= for our latitude and longitude coordinates. Once found, we return these coordinates as a tuple.
import mechanize, urllib, re, urlparse def wiglePrint(username, password, netid):
browser = mechanize.Browser() browser.open('http://wigle.net')
reqData = urllib.urlencode({'credential_0': username,
Where Have You Been?—Analysis of Wireless Access Points in the Registry 87
'credential_1': password})
browser.open('https://wigle.net/gps/gps/main/login', reqData) params = {}
params['netid'] = netid
reqParams = urllib.urlencode(params)
respURL = 'http://wigle.net/gps/gps/main/confirmquery/' resp = browser.open(respURL, reqParams).read()
mapLat = 'N/A' mapLon = 'N/A'
rLat = re.findall(r'maplat=.*\&', resp) if rLat:
mapLat = rLat[0].split('&')[0].split('=')[1]
rLon = re.findall(r'maplon=.*\&', resp) if rLon:
mapLon = rLon[0].split
print '[-] Lat: ' + mapLat + ', Lon: ' + mapLon
Adding the Wigle MAC address functionality to our original script, we now have the ability to examine a registry for previously connected wireless access points and then look up their physical locations.
import os import optparse import mechanize import urllib import re import urlparse from _winreg import * def val2addr(val):
addr = '' for ch in val:
addr += '%02x '% ord(ch)
addr = addr.strip(' ').replace(' ', ':')[0:17]
return addr
def wiglePrint(username, password, netid):
browser = mechanize.Browser() browser.open('http://wigle.net')
reqData = urllib.urlencode({'credential_0': username, 'credential_1': password})
browser.open('https://wigle.net//gps/gps/main/login', reqData) params = {}
params['netid'] = netid
reqParams = urllib.urlencode(params)
respURL = 'http://wigle.net/gps/gps/main/confirmquery/' resp = browser.open(respURL, reqParams).read()
mapLat = 'N/A' mapLon = 'N/A'
rLat = re.findall(r'maplat=.*\&', resp) if rLat:
mapLat = rLat[0].split('&')[0].split('=')[1]
rLon = re.findall(r'maplon=.*\&', resp) if rLon:
mapLon = rLon[0].split
print '[-] Lat: ' + mapLat + ', Lon: ' + mapLon def printNets(username, password):
net = \
"SOFTWARE\Microsoft\Windows
NT\CurrentVersion\NetworkList\Signatures\Unmanaged"
key = OpenKey(HKEY_LOCAL_MACHINE, net) print '\n[*] Networks You have Joined.' for i in range(100):
try:
guid = EnumKey(key, i)
netKey = OpenKey(key, str(guid)) (n, addr, t) = EnumValue(netKey, 5) (n, name, t) = EnumValue(netKey, 4) macAddr = val2addr(addr)
netName = str(name)
print '[+] ' + netName + ' ' + macAddr wiglePrint(username, password, macAddr) CloseKey(netKey)
except:
break def main():
parser = \
optparse.OptionParser("usage%prog "+
"-u <wigle username> -p <wigle password>"
)
Using Python to Recover Deleted Items in the Recycle Bin 89
parser.add_option('-u', dest='username', type='string', help='specify wigle password')
parser.add_option('-p', dest='password', type='string', help='specify wigle username')
(options, args) = parser.parse_args() username = options.username
password = options.password
if username == None or password == None:
print parser.usage exit(0)
else:
printNets(username, password) if __name__ == '__main__':
main()
Running our script with the new functionality, we now see the previously con-nected wireless networks and their physical locations. With the knowledge of where a computer has been, let’s now use the next section to examine the trash.
C:\Users\investigator\Desktop\python discoverNetworks.py [*] Networks You have Joined.
[+] Hooters_San_Pedro, 00:11:50:24:68:7F [-] Lat: 29.55995369, Lon: -98.48358154 [+] LAX Airport, 00:30:65:03:e8:c6 [-] Lat: 28.04605293, Lon: -82.60256195 [+] Senate_public_wifi, 00:0b:85:23:23:3e [-] Lat: 44.95574570, Lon: -93.10277557