Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers (11 page)

BOOK: Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers
2.57Mb size Format: txt, pdf, ePub
Chapter 3
Forensic Investigations with Python
Information in this chapter:

 
Geo-Location through the Windows Registry

 
Recycle Bin Investigation

 
Examining Metadata in PDFs and Microsoft Documents

 
Extracting GPS Coordinates from Exif Metadata

 
Investigating Skype Artifacts

 
Enumerating Browser Artifacts from Firefox Databases

 
Examining Mobile Device Artifacts

Ultimately, you must forget about technique. The further you progress, the fewer teachings there are. The Great Path is really NO PATH…

—Ueshiba Morihei, Kaiso, Founder, Aikido

Introduction: How Forensics Solved the BTK Murders

In February 2005, Wichita police forensic investigator Mr. Randy Stone unraveled the final clues of a 30-year-old mystery. A couple of days earlier, KSAS Television station had handed the police a 3.5” floppy disk they had received from the infamous BTK (Bind, Torture, Kill) Killer. Responsible for at least 10 murders from 1974 to 1991, the BTK Killer eluded capture while repeatedly taunting the police and his victims. On February 16th, 2005, the BTK Killer sent the television station a 3.5” disk with communication instructions. Among these instructions, the disk contained a file named Test.A.rtf. (
Regan, 2006
). While the file contained instructions from the BTK Killer, it also contained something else: metadata. Embedded in the Microsoft proprietary
Rich Text Format (RTF), the file contained the first name of the BTK Killer and the physical location at which the user had last saved the file.

This narrowed the investigation to a man named Denis at the local Wichita Christ Lutheran Church. Mr. Stone verified that a man named Denis Rader served as a church officer at the Lutheran Church (
Regan, 2006
). With this information, police requested a warrant for a DNA sample from the medical records of Denis Rader’s daughter (
Shapiro, 2007
). The DNA sample confirmed what Mr. Stone already knew—Denis Rader was the BTK Killer. A 31-year investigation that had exhausted 100,000 man hours ended with Mr. Stone’s examination of metadata (
Regan, 2006
).

Computer forensic investigations prove only as good as the investigator and the tools in his or her arsenal. All too often an investigator may have a nagging question but does not have the tool to answer his question. Enter Python. As we have seen in previous chapters, solving complex problems with minimal code proves a strength of the Python programming language. As we will see in the following sections, we can answer questions some pretty complex questions with minimal lines of Python code. Let’s begin by using some unique Windows Registry keys to physically track a user.

Where Have You Been?—Analysis of Wireless Access Points in the Registry

The Windows registry contains a hierarchical database that stores the configuration settings of the operating system. With the advent of wireless networking, the Windows Registry stores information related to the wireless connection. Understanding the location and meaning of these registry keys can provide us with geo-location information about where a laptop has been. From Windows Vista on, the Registry stores each of the networks in subkey under
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\Unmanaged.
From the Windows command prompt, we can list each of the networks, showing the profile Guid, network description, network name, and gateway MAC address.

 C:\Windows\system32>reg query “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\

 CurrentVersion\NetworkList\Signatures\Unmanaged” /s

 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Sign

 atures\Unmanaged\010103000F0000F0080000000F0000F04BCC2360E4B8F7DC8BDAFAB8AE4DAD8

 62E3960B979A7AD52FA5F70188E103148

  ProfileGuid  REG_SZ {3B24CE70-AA79-4C9A-B9CC-83F90C2C9C0D}

  Description  REG_SZ Hooters_San_Pedro

  Source  REG_DWORD 0x8

  DnsSuffix  REG_SZ 

  FirstNetwork  REG_SZ Public_Library

  DefaultGatewayMac  REG_BINARY 00115024687F0000

Using WinReg to Read the Windows Registry

The registry stores the gateway MAC address as a REG_BINARY type. In the previous example, the hex bytes \x00\x11\x50\x24\x68\x7F\x00\x00 refer to the actual address 00:11:50:24:68:7F. We will write a quick function to convert the REG_BINARY value to an actual MAC address. Knowing the MAC address of the wireless network can prove useful, as we will see later.

 def val2addr(val):

  addr = “”

  for ch in val:

   addr += (“%02x “% ord(ch))

  addr = addr.strip(“ “).replace(“ “,”:”)[0:17]

  return addr

Now, let’s write a function to extract the network name and MAC address for every listed network profile from the specific keys in the Windows registry. To do this, we will utilize the
_winreg
library, installed by default with the Windows default Python Installer. After connecting to the registry, we can open the key with the
OpenKey()
function and loop through the network profiles under this key. For each profile, it contains the following sub-keys: ProfileGuid, Description, Source, DnsSuffix, FirstNetwork, DefaultGatewayMac. The registry key indexes the network name and DefaultGatewayMAC as fourth and fifth values in the array. We can now enumerate each of these keys and print them to the screen.

 from _winreg import ∗

 def printNets():

  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

    CloseKey(netKey)

   except:

    break

Putting everything together, we now have a script that will print out the previously connected wireless networks stored in the Windows Registry.

 from _winreg import ∗

 def val2addr(val):

  addr = ’’

  for ch in val:

   addr += ‘%02x ’% ord(ch)

  addr = addr.strip(‘ ’).replace(‘ ’, ‘:’)[0:17]

  return addr

 def printNets():

  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

    CloseKey(netKey)

   except:

    break

 def main():

  printNets()

 if __name__ == “__main__”:

  main()

Running our script against a target laptop, we see the previously connected wireless networks along with their MAC addresses. When testing the script, ensure you are running from inside an Administrator console or you will be unable to read the keys.

 C:\Users\investigator\Desktop\python discoverNetworks.py

 [∗] Networks You have Joined.

 [+] Hooters_San_Pedro, 00:11:50:24:68:7F

 [+] LAX Airport, 00:30:65:03:e8:c6

 [+] Senate_public_wifi, 00:0b:85:23:23:3e

Using Mechanize to Submit the MAC Address to Wigle

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, contain 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/
, provides 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 registering 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/confirmquery/
. 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 latitude and longitude of the access point.

 

 Get Map

 0A:2C:EF:3D:25:1BMcDonald’s FREE Wifi<

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,

      ‘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 -p

     )

  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 connected 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

Other books

Taking Him (Lies We Tell) by Ashenden, Jackie
Remember Me by Irene N. Watts
Totem by Jennifer Maruno
The Food of a Younger Land by Mark Kurlansky
Zooman Sam by Lois Lowry
Fated by Sarah Fine
Satin Island by Tom McCarthy
Climbing the Stairs by Margaret Powell