coderrr

September 10, 2008

Get the physical location of wireless router from its MAC address (BSSID)

Filed under: network, ruby, security, slashdotted — Tags: , , , — coderrr @ 1:20 am

Update: Here’s a coverage map showing what areas they have data on.

A nice company called SkyHook Wireless has been war driving the country for years. Basically they’ve been paying people to ride around in cars and record the unique IDs (BSSID, aka MAC address) that your wireless routers broadcast. Doesn’t matter if your router has encryption on or not, its BSSID is still public and in their database (if they’ve driven past your house). They’ve then taken all this information and put it in a huge database. They’ve even made a nice little javascript API which given a BSSID will tell you its longitude and latitude. But it will only let you do this for yourself, only sending BSSIDs which you are in range of.

For their API to work it requires you to install a browser extension. Which contains, along with the extension source code (which is fully viewable, for Firefox at least), some compiled c++ code (loki.dll for windows). So what does the proprietary stuff do? It does the actual query to their API. And what does it send? It asks your wireless card to list all of the BSSIDs that you are in range of and sends those along with the signal strength of each.

So why can’t you just send any BSSID you want? Simple, because they don’t tell you how. The actual query is done inside of their compiled code, so it’s a secret and no one will ever figure it out. Well, only the people that try at least. After reverse engineering their code I did a google search on one of the unique-ish terms in the XML that is used as part of the API call and it seems there are others who know how to use this secret API of theirs.

So to keep things short. Here’s how to query their service to find the physical location of any wireless router whose BSSID you know.

Send an HTTPS POST request to api.skyhookwireless.com/wps2/location with XML in the following format:

<?xml version='1.0'?>
<LocationRQ xmlns='http://skyhookwireless.com/wps/2005' version='2.6' street-address-lookup='full'>
  <authentication version='2.0'>
    <simple>
      <username>beta</username>
      <realm>js.loki.com</realm>
    </simple>
  </authentication>
  <access-point>
    <mac>00AA11BB22CC</mac>
    <signal-strength>-50</signal-strength>
  </access-point>
</LocationRQ>

You’ll receive back either this (success!):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LocationRS version="2.6" xmlns="http://skyhookwireless.com/wps/2005"><location nap="1"><latitude>49.2422507</latitude><longitude>11.4624963</longitude><hpe>150</hpe></location></LocationRS>

or this (failure!):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LocationRS version="2.6" xmlns="http://skyhookwireless.com/wps/2005"><error>Unable to locate location</error></LocationRS>

Here’s a dirty little ruby script which does the query based on a BSSID you pass in from the command line:

require 'net/https'

mac = ARGV.first.delete(':').upcase

req_body = %{
<?xml version='1.0'?>
<LocationRQ xmlns='http://skyhookwireless.com/wps/2005' version='2.6' street-address-lookup='full'>
  <authentication version='2.0'>
    <simple>
      <username>beta</username>
      <realm>js.loki.com</realm>
    </simple>
  </authentication>
  <access-point>
    <mac>#{mac}</mac>
    <signal-strength>-50</signal-strength>
  </access-point>
</LocationRQ>
}.gsub(/^\s+|[\r\n]/, '')

http = Net::HTTP.new('api.skyhookwireless.com', 443)
http.use_ssl = true

http.start do |h|
  resp = h.post '/wps2/location', req_body, 'Content-Type' => 'text/xml'

  if resp.body =~ /<latitude>([^<]+).+<longitude>([^<]+)/
    puts "#$1, #$2"
  else
    puts "not found"
  end
end

Usage:
getloc.rb aa:bb:cc:dd:ee:ff

Or here’s a one liner for UNIX thanks to George:

MYMAC=AABBCCDDEEFF && curl --header "Content-Type: text/xml" --data "<?xml version='1.0'?><LocationRQ xmlns='http://skyhookwireless.com/wps/2005' version='2.6' street-address-lookup='full'><authentication version='2.0'><simple><username>beta</username><realm>js.loki.com</realm></simple></authentication><access-point><mac>$MYMAC</mac><signal-strength>-50</signal-strength></access-point></LocationRQ>" https://api.skyhookwireless.com/wps2/location

* note: This API is how the iPhone’s “Locate me” feature works

34 Comments »

  1. Anyone have a vaild BSSID to “track” for testing?

    I’m out in BFE not near skyhook…

    Comment by George — September 10, 2008 @ 3:29 am

  2. FF:FF:FF:FF:FF:FF and AA:BB:CC:DD:EE:FF and 00:02:2D:04:26:67

    Comment by coderrr — September 10, 2008 @ 3:36 am

  3. If you have terminal access: (Curl is your friend)!

    curl –header “Content-Type: text/xml” –data “betajs.loki.com00022D042667-50″ https://api.skyhookwireless.com/wps2/location

    Comment by George — September 10, 2008 @ 3:54 am

  4. oops well that didn’t post the code…

    Sorry…

    Comment by George — September 10, 2008 @ 3:55 am

  5. I wrote a quick app in C#. They must have taken URI down.

    “The server at api.skyhookwireless.com is taking too long to respond.”

    Comment by Scott — September 12, 2008 @ 2:57 pm

  6. Still works for me.

    It would be nice if you could give it your location and have it spit out a list of access points near you.

    Comment by Chris — September 12, 2008 @ 3:29 pm

  7. [...] can get more documentation on the API from here and [...]

    Pingback by Worried About Skyhook Mapping Your Wifi Router To a GeoLocation? | Creeva's World 2.0 — September 12, 2008 @ 3:32 pm

  8. [...] Get the physical location of wireless router from its MAC address (BSSID) [...]

    Pingback by robert.schuppenies.de - weblog » Get the physical location of wireless router from its MAC address (BSSID) — September 12, 2008 @ 3:38 pm

  9. I’ve written up a quick Python interface. You can get it from the cheese shop:

    easy_install maclocate

    or from http://maclocate.googlecode.com.

    The egg installs a shell script you can use like:

    $ maclocate 00:50:56:c0:00:08

    Comment by Ian — September 12, 2008 @ 6:31 pm

  10. Why not implement the HTTP API this way?
    Just support HTTP GET of
    https://api.skyhookwireless.com/api/location/access-point00AA11BB22CC?signal-strength=-50

    Then use Basic authentication to pass in username and realm as password?

    There’s no reason a POST is necessary.

    Comment by REST — September 12, 2008 @ 6:38 pm

  11. [...] saw a slashdot post earlier today about a not-so-secret API from SkyHook Wireless to Locate Any WiFi Router By Its MAC Address. I thought this was pretty cool and useful, so I wrote up a quick python hack/script that would use [...]

    Pingback by Midnight Research Labs - Locate Any WiFi Router By Its MAC Address — September 13, 2008 @ 6:37 am

  12. I also posted a quick python version of this script that prints out all of the information (not just the lat/long). It can also output a google earth KML file.

    http://midnightresearch.com/pages/locate-any-wifi-router-by-its-mac-address/

    I’m curious how much longer the service is going to stay up, :)

    Comment by aaronp — September 13, 2008 @ 6:44 am

  13. [...] database mapping wireless routers’ MAC addresses to their physical locations. They provide an minimally documented API (doc here) which allows anyone to query the database directly for any MAC address. This could [...]

    Pingback by Data Cube Systems » Blog Archive » Locate Any WiFi Router By Its MAC Address — September 13, 2008 @ 10:42 pm

  14. At http://www.singeo.com.sg/?p=206

    I’ve posted an amended version of the ruby script above which combines it with the “airport -s” command in OSX. This means Mac users can automatically locate all the wifi routers around them.

    Also it writes the results to a kml file.

    Comment by Singeo — September 15, 2008 @ 10:56 am

  15. [...] here’s a one liner for UNIX thanks to George: [...]

    Pingback by .:: Hackology Blog ::. - Get physical location of wireless router from its MAC address(BSSID) — September 15, 2008 @ 6:04 pm

  16. Still up? This was a great find (while it lasted if its still going).

    Comment by George — September 18, 2008 @ 4:05 am

  17. Yea it still works. Since the iPhone uses this same (or a similar) API for its “Locate Me” feature I don’t think it would be easy for them to turn off.

    If they did try to block it, you would probably be able to still access it with whatever username or authentication the iPhone uses.

    And if they were to block the API I have described here their loki.com browser extension would cease to work.

    Comment by coderrr — September 18, 2008 @ 6:43 am

  18. [...] Get the physical location of wireless router from its MAC address (BSSID) – How to query SkyHook Wireless location API using a POST request [...]

    Pingback by Links for 2008-09-10 through 2008-09-19 | /dev/random — September 19, 2008 @ 6:00 pm

  19. I am trying to implement this via php and I am getting an error:

    http://www.tampascanner.info/wifi_mac_loki.php

    HTTP Status 400 – javax.xml.bind.UnmarshalException: Content is not allowed in trailing section. – with linked exception: [org.xml.sax.SAXParseException: Content is not allowed in trailing section.]

    You can view the code and comments at:

    http://www.dslreports.com/forum/r21107466-php-XML-and-https-post

    Comment by rec9140 — September 20, 2008 @ 4:28 pm

  20. [...] be in their DB. I tested it with my AP and it was only off by about 200ft. Try it. It’s fun. Get the physical location of wireless router from its MAC address (BSSID) __________________ Now here’s a fellow attempting to ride a bicycle but he’s having some trouble [...]

    Pingback by Kinda scary, Kinda useful. Locate physical address from WiFi AP MAC - Super Off Topic Syndicate — September 21, 2008 @ 3:52 am

  21. Here is the Perl version:

    http://spl0it.org/files/bssid-location.pl

    Comment by Jabra — September 21, 2008 @ 9:52 pm

  22. But how does one find out their BSSID?

    Google turns up tons of hits on how to find the MAC address for your network card, but I can’t seem to find anything that tells out to get the MAC address of the external Wireless interface.

    Comment by Mark — September 24, 2008 @ 5:43 am

  23. anyone can share the code in C#??

    Comment by poper — October 17, 2008 @ 7:12 pm

  24. Has someone found how to query the hidden Google Maps MyLocation SSID API ?

    Comment by kael — October 27, 2008 @ 7:02 pm

  25. [...] clever people have also found out how to use the skyhook API without their software, with some code here. This entry was posted on Tuesday, November 4th, 2008 at 4:21 pm and is filed under Industry [...]

    Pingback by Mobile to Internet of Things » Blog Archive » Where am I - positioning for mobile applications — November 4, 2008 @ 4:24 pm

  26. A very Nice Website Ive seen Uptill. Excellent post. Keep it up! Good day!

    Comment by Shams.(S60) — January 4, 2009 @ 11:01 am

  27. [...] For your reading pleasure, take a look @ this article. [...]

    Pingback by Geo-Tracking the iPod Touch… | Egeste.NET — February 7, 2009 @ 3:13 am

  28. What sort of scale is signal strength based on?

    Comment by Brandon — February 27, 2009 @ 3:13 am

  29. should be dBm (http://en.wikipedia.org/wiki/DBm)

    Comment by coderrr — February 27, 2009 @ 8:00 pm

  30. It seems beta/js.loki.com pair is not working now.

    Comment by unxed — April 3, 2009 @ 9:00 pm

  31. I have seen another code that does the same, but it’s different from this one that you just give here.

    Comment by wireless — April 21, 2009 @ 8:19 pm

  32. [...] The little button at the bottom should tell you your physical location. Its meant to be used for Geo Targetting by Online Advertisers. Its pretty neat and you can try a demo yourself. Anyway, so the way it works is that there is a company called Skyhook that maintains a database of BSSIDs an their physical locations. So if i was at home, my wireless router would be sending out this BSSID/Mac address. Someone outside my apartment could note the BSSID and its physical location as in “BSSID:12345 = 1000 Random st, SF, CA”. When i use this utility, it finds the BSSID with the best Signal Strength and does a reverse lookup for the physical address. (More info here). [...]

    Pingback by United We BandStand » My location eeez — August 11, 2009 @ 2:36 am

  33. [...] address constitutes invasion of privacy (an enterprising “enthusiast” found a way to query Skyhook’s database to get Lat/Lon coordinates associated with MAC addresses). There’s an argument to be made [...]

    Pingback by Have a Wi-Fi Device in Your Pocket? You Can Be Tracked! | Lawyerling — September 29, 2009 @ 12:37 am


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.