Windows 注册表是一个分层式的数据库,其中存储了操作系统的配置设置信息。
从 Windows Vista
起,注册表在 HKLM\SOFT_WARE\Microsoft\Windows NT\CurrentVersion\Network-List\Signatures\Unmanaged
子键中就会存储所有的网络信息。在 Windows 命令行提示符中,我们能列出每个网络显示出 profile Guid
对网络的描述、网络名和网关的 MAC 地址。
C:\Windows\system32\reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\Unmanaged" /s HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\NetworkList\Signatures\Unmanaged\010103000F0000F008000000F0000F04BCC2360E4B8F7DC8BDAFAB8AE....
ProfileGuid REG_SZ ...
Description REG_SZ ...
注册表中把网关 MAC 地址存为 REG_BINARY
类型的。形如:00115024687F0000
,其实就是地址 00:11:50:24:68:7F
,下面这个函数可以实现转换:
def val2addr(val):
addr = str()
for ch in val:
addr += "%02x " % ord(ch)
addr = addr.strp(" ").replace(" ", ":")[0:17]
return addr
接下来要从 Windows 注册表指定的键值中提取各个被列出来的网络名称和 MAC 地址。需要使用 _winreg
库,这是 Python 的 Windows 版安装程序默认会安装的一个库。
from _winreg import *
def print_nets():
net = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\Unmanaged"
key = OpenKey(HKEY_LOCAL_MACHINE, net)
print("[*] Networks You have Joined.")
for i in range(100):
try:
guid = EnumKey(key, i)
net_key = OpenKey(key, str(guid))
n, addr, t = EnumValue(net_key, 5)
n, name, t = EnumValue(net_key, 4)
mac_addr = val2addr(addr)
net_name = str(name)
print("[+] {} {}".format(net_name, mac_addr))
CloseKey(net_key)
except:
break
确保在拥有管理员权限的命令行窗口中运行,就可以读取注册表中的键值
知道了无线访问热点的 MAC 地址之后,可以把访问热点的物理位置也打印出来。许多数据库中,都有海量的把无线访问热点与它们所在的物理位置相对应起来的列表。
SkyHook 数据库提供了一个根据 Wi-Fi 的位置获取地理位置信息的软件开发包。Ian McCracken 开发的一个开源项目让我们能访问这个数据库。还有 Google、微软等都有 Wi-Fi 地址位置数据库。
数据库,也是开源项目仍然允许用户根据无线访问热点的 MAC 地址得到它所在的物理位置。通过网页查询某个无线 SSID MAC 地址对应的物理位置,并收集响应页面。其中返回结果 maplat=47.25264359&maplon=-87.25624084
表示的就是无线访问热点的经度和纬度。
需要使用 mechanize
库,它允许 Python 编写带状态的 Web 程序。也就是说在正确地登陆 Wigle 服务器后,它会保存和重用登陆认证 cookie。
import mechanize, urllib, re, urlparse
def wigle_print(username, password, netid):
browser = mechanize.Browser()
browser.open("http://wigle.net")
req_data = urllib.urlencode({"credential_0": username, "credential_1": password})
browser.open("https://wigle.net/gps/gps/main/login", req_data)
params = {}
params["netid"] = netid
req_params = urllib.urlencode(params)
resp_url = "http://wigle.net/gps/gps/main/confirmquery/"
resp = browser.open(resp_url, req_params).read()
map_lat = "N/A"
map_lon = "N/A"
r_lat = re.findall(r"maplat=.*\&", resp)
if r_lat:
map_lat = r_lat[0].split("&")[0].split("=")[1]
r_lon = re.findall(r"maplon=.*\&", resp)
if r_lon:
map_lon = r_lon[0].split()
print("[-] Lat: {}, Lon: {}".format(map_lat, map_lon))
在使用 FAT 文件系统的 Windows 98 及之前的 Windows 系统中,回收站目录是 C:\Recycled\
。在包括 Windows NT/2000 和 Windows XP 在内的支持 NTFS 的操作系统中,回收站是 C:\Recycler\目录
。在 Windows Vista 和 Windows 7 中,回收站目录则是 C:\$Recycle.Bin
依次测试各个文件夹即可,不是判断操作系统再来找对应文件夹
import os
def return_dir():
dirs = ["c:/Recycler/", "c:/Recycled/", "C:/$Recycle.Bin/"]
for recycle_dir in dirs:
if os.path.isdir(recycle_dir):
return recycle_dir
return None
在找到回收站目录之后,就要去检查其中的内容。其中有两个子目录,都含有字符串 S-1-5-21-1275210071-1715567821-725345543-
,并分别以 1005 或 500 结尾。这个字符串表示的是用户的 SID,它对应的是机器里一个唯一的用户帐户
可以用 Windows 注册表把 SID 转换成一个准确的用户名。检查的是注册表键 HKEY_LOCAL_MACHINE\SOFT-WARE\Microsoft\Windows NT\CurrentVersion\ProfileList\<SID>\ProfileImagePath
,看到返回的是 %SystemDrive%\Documents and Settings\<USERID>
值。通过 reg query
命令,可以直接把 SID 转成用户名
C:\RECYCLER>reg query "HKEY_LOCAL...." /v ProfileImagePath
通过 Python 实现,打开注册表检查 ProfileImagePath 键,提取出其中存放的值,并返回位于用户路径中最后一个反斜杠之后的用户名
from _winreg import *
def sid2user(sid):
try:
key = OpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\{}".format(sid))
value, type = QueryValueEx(key, "ProfileImagePath")
user = value.split("\\")[-1]
return user
except:
return sid
作为一种文件里非明显可见的对象,元数据可以存在于文档、电子表格、图片、音频和视频文件中。创建这些文件的应用程序可能会把文档的作者、创建和修改时间、可能的更新版本和注释这类详细信息存储下来。
PyPDF 允许提取文档中的内容,或对文档进行分割、合并、复制、加密和解密操作。若要提取元数据,可以使用 .getDocumentInfo()
方法,该方法会返回一个 tuple 数组,每个 tuple 中都含有对元数据元素的一个描述及它的值。逐一遍历这个数组,就能打印出 PDF 文档的所有元数据。
import pyPdf
from pyPdf import PdfFileReader
def print_meta(file_name):
pdf_file = PdfFileReader(file(file_name, "rb"))
doc_info = pdf_file.getDocumentInfo()
print("[*] PDF MetaData For: {}".format(file_name))
for meta_item in doc_info:
print("[+] {}:{}".format(meta_item, doc_info[meta_item]))
Exif(exchange image file format,交换图像文件格式)标准定义了如何存储图像和音频文件的标准。
Exif 标准中含有多个对取证调查非常有用的标签(tag),工具 exiftool
用它可以解析这些标签。
BeautifulSoup 允许我们快速解析 HTML 和 XML 文档
实现查找所有 img 标签并下载:
import urllib2
from bs4 import BeautifuleSoup
from urlparser import urlsplit
from os.path import basename
def find_images(url):
print("[+] Finding images on {}".format(url))
url_content = urllib2.urlopen(url).read()
soup = BeautifulSoup(url_content)
img_tags = soup.findAll("img")
return img_tags
def download_image(img_tag):
try:
print("[+] Downloading image...")
img_src = img_tag["src"]
img_content = urllib2.urlopen(img_src).read()
img_file_name = basename(urlsplit(img_src)[2])
img_file = open(img_file_name, "wb")
img_file.write(img_content)
img_file.close()
return img_file_name
except:
return ""
利用 PIL 库提取 GPS 元数据:
from PIL import Image
from PIL.ExifTags import TAGS
def test_for_exif(image_file_name):
try:
exif_data = {}
img_file = Image.open(image_file_name)
info = img_file._getexif()
if info:
for tag, value in info.items():
decoded = TAGS.get(tag, tag)
exif_data[decoded] = value
exif_gps = exif_data["GPSINFO"]
if exif_gps:
print("[*] {} contains GPS MetaData".format(img_file_name))
except:
pass
在 Windows 系统中,Skype 在 C:\Documents and Settings\<User>\ApplicationData\Skype\<Skype-account>
目录中存储了一个名为 main.db
的数据库。在 macOS 系统中,这个数据库的存储路径为 /Users/<User>/Library/Application Support/Skype/<Skype-account>
连接 SQLite3 数据库后 SELECT tbl_name FROM sqlite_master WHERE type=='table'
,SQLite 数据库维护一张名为 sqlite_master
的表,这张表中含有一个名为 tbl_name
的列,其中描述了数据库中的各张表。
Accounts 表记录了使用该应用程序的用户账户的相关信息,其中的各列记录了用户名、Skype 的昵称、用户的位置和创建该账户的日期等信息。
数据库是以 UNIX 时间格式存储账户创建时间的,SQL 方法 datetime()
可以把这个值转换成更方便阅读的格式
import sqlite3
def print_profile(skype_db):
conn = sqlite3.connect(skype_db)
c = conn.cursor()
c.execute("SELECT fullname, skypename, city, country, datetime(profile_timestamp, 'unixepoch') FROM Accounts;")
for row in c:
print("[*] -- Found Account --")
print("[+] User: {}".format(row[0]))
print("[+] Skype Username: {}".format(row[1]))
print("[+] Location: {},{}".format(row[2], row[3]))
print("[+] Profile Date: {}".format(row[4]))
多表处理:
def print_call_log(skype_db):
conn = sqlite3.connect(skype_db)
c = conn.cursor()
c.execute("SELECT datetime(begin_timestamp, 'unixepoch'), identity FROM calls, conversations WHERE calls.conv_dbid = conversations.id;")
print("[*] -- Found Calls --")
for row in c:
print("[+] Time: {} | partner: {}".format(row[0], row[1]))
Skype 的数据库会把所有发送和收到的消息都保存在数据库中。数据库中把这些信息存放在一张名为 Messages
的表中。从这张表中用 SELECT 语句选出 timestamp、dialog_partner
、author 和 body_xml
。注意,如果 dialog_partner
和 author 字段是不一样的,那么就是数据库的所有者发送这条消息给 dialog_partner
的。反之,如果 dialog_partner
和 author 字段是一样的,就是 dialog_partner
发送的这条消息,这时需要在消息前加一个 from
def print_messages(skype_db):
conn = sqlite3.connect(skype_db)
c = conn.cursor()
c.execute("SELECT datetime(timestamp, 'unixepoch'), dialog_partner, author, body_xml FROM Messages;")
print("[*] -- Found Messages --")
for row in c:
try:
if "partlist" not in str(row[3]):
if str(row[1]) != str(row[2]):
msg_direction = "To {}: ".format(row[1])
else:
msg_direction = "From {}: ".format(row[2])
print("Time: {} {} {}".format(row[0], msg_direction, row[3]))
except:
pass
只想打印出联系人列表中其生日不为空的联系人:
SELECT fullname, birthday FROM contacts WHERE birthday > 0;
只想输出 conversation 表中只与某个特定的 <SKYPE-PARTNER>
相关的通话记录:
SELECT datetime(timestamp, 'unixepoch'), dialog_partner, author, body_xml, FROM Messages WHERE dialog_partner='<SKYPE-PARTNER>'
要删除 conversation 表中只与某个特定的 <SKYPE-PARTNER>
相关的通话记录
DELETE FROM messages WHERE skypename='<SKYPE-PARTNER>'
在 Windows 操作系统中,火狐把这些数据库存放在 "C:/Documents and Settings/<USER>/Application Data/Mozilla/Firefox/Profiles/<profile folder>/"
目录中,在 macOS 系统中,火狐把这些数据库存放在 "/Users/<USER>/Library/Application Support/Firefox/Profiles/<profile folder>"
目录中
文件 downloads.sqlite
数据库时火狐用户下载文件的相关信息。其中只有一张名为 moz_downloads
的表记录了文件名、源下载地址、下载时间、文件大小、引用(referrer)和本地存放该文件的路径。
import sqlite3
def print_downloads(download_db):
conn = sqlite3.connect(download_db)
c = conn.cursor()
c.execute("SELECT name, source, datetime(endTime/1000000, 'unixepoch') FROM moz_downloads;")
print("[*] --- Files Downloaded ---")
for row in c:
print("[+] File: {} from source: {} at: {}".format(row[0], row[1], row[2]))
数据库 moz_cookies
表中保存的是 cookie 相关的数据。
def print_cookies(cookies_db):
try:
conn = sqlite3.connect(cookie_db)
c = conn.cursor()
c.execute("SELECT host, name, value FROM moz_cookies")
print("[*] --- Found Cookies ---")
for row in c:
host = row[0]
name = row[1]
value = row[2]
print("[+] Host: {}, Cookie: {}, Value: {}".format(host, name, value))
except Exception as e:
if "encrypted" in str(e):
print("[*] Error reading your cookies database.")
print("[*] Upgrade your Python-Sqlite3 Library")
上网历史记录保存在 places.sqlite
的数据库中,其中的 moz_places
表可以给出关于用户在何时(时间)访问了何处(地址)的网站信息。ForensicWiki 网站上建议使用 moz_places
和 moz_historyvisits
表中的数据,以获取一张真正的浏览器上网历史记录。
SELECT url, datetime(visit_date/1000000, 'unixepoch') FROM moz_places, moz_historyvisits WHERE visit_count > 0 AND moz_places.id == moz_historyvisits.place_id;
苹果的 iOS 操作系统实际上会跟踪和记录设备的 GPS 经纬度信息,并把它们存储在 consolidated.db
的数据库中。其中有一张名为 Cell-Location
的表,其中含有手机已经收集到的 GPS 定位点。在备份移动设备时,记录到计算机的移动设备的副本也含有这一信息。尽管 iOS 操作系统设计的功能会删除这些地理位置信息,但调查发现这些数据仍然存在。
当用户对 iPhone/iPad 设备进行备份时,它会把相关文件存放到计算机中一个特定的目录中。在 Windows 操作系统中,iTunes 应用程序会把数据存放在用户目录下的移动设备备份目录中(C:/Documents and Settings/<USERNAME>/Application Data/AppleComputer/MobileSync/Backup
),而在 macOS 中,这个目录则是 /Users/<USERNAME>/Library/Application Support/MobileSync/Backup/
。对移动设备进行备份的 iTunes 程序会把所有的设备备份文件都存放在这个目录中。
为了获取关于文件的信息,用 UNIX 命令 file
来分析各个文件的文件类型。可以看到移动设备备份目录中有一些 SQLite3 数据库文件、JPEG 图片文件、纯二进制文件和 ASCII 文本文件
可以用脚本快速列举出在整个移动设备备份目录中每一个数据库中所有表的表名:
SELECT tbl_name FROM sqlite_master WHERE type=="table"
每个 SQLite 数据库中都会维护一张名为 sqlite_master
的表,其中含有整个数据库结构的信息,记录了整个数据库中各张表的结构。
含有 message
表的库即为文本消息数据库,可以把发送时间、对方手机号码以及消息本身打印出来:
SELECT datetime(date, 'unixepoch'), address, text FROM message WHERE address > 0;