Wichtige Artefakte in Windows-II

In diesem Kapitel werden einige wichtigere Artefakte in Windows und ihre Extraktionsmethode mit Python beschrieben.

Benutzeraktivitäten

Windows mit NTUSER.DATDatei zum Speichern verschiedener Benutzeraktivitäten. Jedes Benutzerprofil hat einen Bienenstock wieNTUSER.DATHier werden die Informationen und Konfigurationen gespeichert, die sich speziell auf diesen Benutzer beziehen. Daher ist es sehr nützlich für die Untersuchung durch forensische Analysten.

Das folgende Python-Skript analysiert einige der Schlüssel von NTUSER.DATzum Erkunden der Aktionen eines Benutzers im System. Bevor wir fortfahren, müssen wir für Python-Skripte nämlich Module von Drittanbietern installierenRegistry, pytsk3, pyewf und Jinja2. Wir können pip verwenden, um sie zu installieren.

Wir können die folgenden Schritte ausführen, um Informationen daraus zu extrahieren NTUSER.DAT Datei -

  • Suchen Sie zuerst nach allen NTUSER.DAT Dateien im System.

  • Dann analysieren Sie die WordWheelQuery, TypePath and RunMRU Schlüssel für jeden NTUSER.DAT Datei.

  • Zuletzt werden wir diese bereits verarbeiteten Artefakte mithilfe von in einen HTML-Bericht schreiben Jinja2 Modul.

Python-Code

Lassen Sie uns sehen, wie Python-Code für diesen Zweck verwendet wird -

Zunächst müssen wir die folgenden Python-Module importieren:

from __future__ import print_function
from argparse import ArgumentParser

import os
import StringIO
import struct

from utility.pytskutil import TSKUtil
from Registry import Registry
import jinja2

Geben Sie nun ein Argument für den Befehlszeilenhandler an. Hier werden drei Argumente akzeptiert - erstens der Pfad zur Beweisdatei, zweitens der Typ der Beweisdatei und drittens der gewünschte Ausgabepfad zum HTML-Bericht, wie unten gezeigt -

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Information from user activities')
   parser.add_argument('EVIDENCE_FILE',help = "Path to evidence file")
   parser.add_argument('IMAGE_TYPE',help = "Evidence file format",choices = ('ewf', 'raw'))
   parser.add_argument('REPORT',help = "Path to report file")
   args = parser.parse_args()
   main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT)

Lassen Sie uns nun definieren main() Funktion zum Durchsuchen aller NTUSER.DAT Dateien, wie gezeigt -

def main(evidence, image_type, report):
   tsk_util = TSKUtil(evidence, image_type)
   tsk_ntuser_hives = tsk_util.recurse_files('ntuser.dat','/Users', 'equals')
   
   nt_rec = {
      'wordwheel': {'data': [], 'title': 'WordWheel Query'},
      'typed_path': {'data': [], 'title': 'Typed Paths'},
      'run_mru': {'data': [], 'title': 'Run MRU'}
   }

Jetzt werden wir versuchen, den Schlüssel zu finden NTUSER.DAT Datei und sobald Sie es gefunden haben, definieren Sie die Benutzerverarbeitungsfunktionen wie unten gezeigt -

for ntuser in tsk_ntuser_hives:
   uname = ntuser[1].split("/")

open_ntuser = open_file_as_reg(ntuser[2])
try:
   explorer_key = open_ntuser.root().find_key("Software").find_key("Microsoft")
      .find_key("Windows").find_key("CurrentVersion").find_key("Explorer")
   except Registry.RegistryKeyNotFoundException:
      continue
   nt_rec['wordwheel']['data'] += parse_wordwheel(explorer_key, uname)
   nt_rec['typed_path']['data'] += parse_typed_paths(explorer_key, uname)
   nt_rec['run_mru']['data'] += parse_run_mru(explorer_key, uname)
   nt_rec['wordwheel']['headers'] = \ nt_rec['wordwheel']['data'][0].keys()
   nt_rec['typed_path']['headers'] = \ nt_rec['typed_path']['data'][0].keys()
   nt_rec['run_mru']['headers'] = \ nt_rec['run_mru']['data'][0].keys()

Übergeben Sie nun das Wörterbuchobjekt und seinen Pfad an write_html() Methode wie folgt -

write_html(report, nt_rec)

Definieren Sie nun eine Methode, die benötigt wird pytsk Dateihandle und lesen Sie es in die Registry-Klasse über die StringIO Klasse.

def open_file_as_reg(reg_file):
   file_size = reg_file.info.meta.size
   file_content = reg_file.read_random(0, file_size)
   file_like_obj = StringIO.StringIO(file_content)
   return Registry.Registry(file_like_obj)

Jetzt definieren wir die Funktion, die analysiert und verarbeitet wird WordWheelQuery Schlüssel von NTUSER.DAT Datei wie folgt -

def parse_wordwheel(explorer_key, username):
   try:
      wwq = explorer_key.find_key("WordWheelQuery")
   except Registry.RegistryKeyNotFoundException:
      return []
   mru_list = wwq.value("MRUListEx").value()
   mru_order = []
   
   for i in xrange(0, len(mru_list), 2):
      order_val = struct.unpack('h', mru_list[i:i + 2])[0]
   if order_val in mru_order and order_val in (0, -1):
      break
   else:
      mru_order.append(order_val)
   search_list = []
   
   for count, val in enumerate(mru_order):
      ts = "N/A"
      if count == 0:
         ts = wwq.timestamp()
      search_list.append({
         'timestamp': ts,
         'username': username,
         'order': count,
         'value_name': str(val),
         'search': wwq.value(str(val)).value().decode("UTF-16").strip("\x00")
})
   return search_list

Jetzt definieren wir die Funktion, die analysiert und verarbeitet wird TypedPaths Schlüssel von NTUSER.DAT Datei wie folgt -

def parse_typed_paths(explorer_key, username):
   try:
      typed_paths = explorer_key.find_key("TypedPaths")
   except Registry.RegistryKeyNotFoundException:
      return []
   typed_path_details = []
   
   for val in typed_paths.values():
      typed_path_details.append({
         "username": username,
         "value_name": val.name(),
         "path": val.value()
      })
   return typed_path_details

Jetzt definieren wir die Funktion, die analysiert und verarbeitet wird RunMRU Schlüssel von NTUSER.DAT Datei wie folgt -

def parse_run_mru(explorer_key, username):
   try:
      run_mru = explorer_key.find_key("RunMRU")
   except Registry.RegistryKeyNotFoundException:
      return []
   
   if len(run_mru.values()) == 0:
      return []
   mru_list = run_mru.value("MRUList").value()
   mru_order = []
   
   for i in mru_list:
      mru_order.append(i)
   mru_details = []
   
   for count, val in enumerate(mru_order):
      ts = "N/A"
      if count == 0:
         ts = run_mru.timestamp()
      mru_details.append({
         "username": username,
         "timestamp": ts,
         "order": count,
         "value_name": val,
         "run_statement": run_mru.value(val).value()
      })
   return mru_details

Die folgende Funktion übernimmt nun die Erstellung eines HTML-Berichts:

def write_html(outfile, data_dict):
   cwd = os.path.dirname(os.path.abspath(__file__))
   env = jinja2.Environment(loader=jinja2.FileSystemLoader(cwd))
   template = env.get_template("user_activity.html")
   rendering = template.render(nt_data=data_dict)
   
   with open(outfile, 'w') as open_outfile:
      open_outfile.write(rendering)

Endlich können wir ein HTML-Dokument für den Bericht schreiben. Nach dem Ausführen des obigen Skripts erhalten wir die Informationen aus der Datei NTUSER.DAT im HTML-Dokumentformat.

LINK-Dateien

Verknüpfungsdateien werden erstellt, wenn ein Benutzer oder das Betriebssystem Verknüpfungsdateien für die Dateien erstellt, die häufig verwendet, doppelt angeklickt oder von Systemlaufwerken wie angeschlossenem Speicher aus aufgerufen werden. Solche Arten von Verknüpfungsdateien werden als Linkdateien bezeichnet. Durch den Zugriff auf diese Linkdateien kann ein Ermittler die Aktivität des Fensters ermitteln, z. B. die Zeit und den Ort, von dem aus auf diese Dateien zugegriffen wurde.

Lassen Sie uns das Python-Skript diskutieren, mit dem wir die Informationen aus diesen Windows LINK-Dateien abrufen können.

Installieren Sie für Python-Skripte nämlich Module von Drittanbietern pylnk, pytsk3, pyewf. Wir können die folgenden Schritte ausführen, um Informationen daraus zu extrahierenlnk Dateien

  • Suchen Sie zunächst nach lnk Dateien innerhalb des Systems.

  • Extrahieren Sie dann die Informationen aus dieser Datei, indem Sie sie durchlaufen.

  • Jetzt brauchen wir endlich diese Informationen zu einem CSV-Bericht.

Python-Code

Lassen Sie uns sehen, wie Python-Code für diesen Zweck verwendet wird -

Importieren Sie zunächst die folgenden Python-Bibliotheken:

from __future__ import print_function
from argparse import ArgumentParser

import csv
import StringIO

from utility.pytskutil import TSKUtil
import pylnk

Geben Sie nun das Argument für den Befehlszeilenhandler an. Hier werden drei Argumente akzeptiert - erstens der Pfad zur Beweisdatei, zweitens der Typ der Beweisdatei und drittens der gewünschte Ausgabepfad zum CSV-Bericht, wie unten gezeigt -

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Parsing LNK files')
   parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
   parser.add_argument('IMAGE_TYPE', help = "Evidence file format",choices = ('ewf', 'raw'))
   parser.add_argument('CSV_REPORT', help = "Path to CSV report")
   args = parser.parse_args()
   main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.CSV_REPORT)

Interpretieren Sie nun die Beweisdatei, indem Sie ein Objekt von erstellen TSKUtil und iterieren Sie durch das Dateisystem, um Dateien zu finden, die mit enden lnk. Dies kann durch Definieren erfolgenmain() Funktion wie folgt -

def main(evidence, image_type, report):
   tsk_util = TSKUtil(evidence, image_type)
   lnk_files = tsk_util.recurse_files("lnk", path="/", logic="endswith")
   
   if lnk_files is None:
      print("No lnk files found")
      exit(0)
   columns = [
      'command_line_arguments', 'description', 'drive_serial_number',
      'drive_type', 'file_access_time', 'file_attribute_flags',
      'file_creation_time', 'file_modification_time', 'file_size',
      'environmental_variables_location', 'volume_label',
      'machine_identifier', 'local_path', 'network_path',
      'relative_path', 'working_directory'
   ]

Mit Hilfe des folgenden Codes werden wir nun durchlaufen lnk Dateien durch Erstellen einer Funktion wie folgt -

parsed_lnks = []

for entry in lnk_files:
   lnk = open_file_as_lnk(entry[2])
   lnk_data = {'lnk_path': entry[1], 'lnk_name': entry[0]}
   
   for col in columns:
      lnk_data[col] = getattr(lnk, col, "N/A")
   lnk.close()
   parsed_lnks.append(lnk_data)
write_csv(report, columns + ['lnk_path', 'lnk_name'], parsed_lnks)

Jetzt müssen wir zwei Funktionen definieren, eine öffnet die pytsk Dateiobjekt und andere werden zum Schreiben des CSV-Berichts verwendet, wie unten gezeigt -

def open_file_as_lnk(lnk_file):
   file_size = lnk_file.info.meta.size
   file_content = lnk_file.read_random(0, file_size)
   file_like_obj = StringIO.StringIO(file_content)
   lnk = pylnk.file()
   lnk.open_file_object(file_like_obj)
   return lnk
def write_csv(outfile, fieldnames, data):
   with open(outfile, 'wb') as open_outfile:
      csvfile = csv.DictWriter(open_outfile, fieldnames)
      csvfile.writeheader()
      csvfile.writerows(data)

Nach dem Ausführen des obigen Skripts erhalten wir die Informationen von den entdeckten lnk Dateien in einem CSV-Bericht -

Dateien vorab abrufen

Immer wenn eine Anwendung zum ersten Mal von einem bestimmten Speicherort ausgeführt wird, erstellt Windows prefetch files. Diese werden verwendet, um den Startvorgang der Anwendung zu beschleunigen. Die Erweiterung für diese Dateien lautet.PF und diese sind in der gespeichert ”\Root\Windows\Prefetch” Mappe.

Experten für digitale Forensik können den Nachweis der Programmausführung von einem bestimmten Ort aus zusammen mit den Details des Benutzers erbringen. Prefetch-Dateien sind nützliche Artefakte für den Prüfer, da ihr Eintrag auch nach dem Löschen oder Deinstallieren des Programms erhalten bleibt.

Lassen Sie uns das Python-Skript diskutieren, das Informationen aus Windows-Prefetch-Dateien abruft, wie unten angegeben -

Installieren Sie für Python-Skripte nämlich Module von Drittanbietern pylnk, pytsk3 und unicodecsv. Denken Sie daran, dass wir bereits mit diesen Bibliotheken in den Python-Skripten gearbeitet haben, die wir in den vorherigen Kapiteln besprochen haben.

Wir müssen die unten angegebenen Schritte ausführen, um Informationen daraus zu extrahieren prefetch Dateien -

  • Scannen Sie zuerst nach .pf Erweiterungsdateien oder die Prefetch-Dateien.

  • Führen Sie nun die Signaturüberprüfung durch, um Fehlalarme zu beseitigen.

  • Analysieren Sie als Nächstes das Windows-Prefetch-Dateiformat. Dies unterscheidet sich von der Windows-Version. Für Windows XP sind es beispielsweise 17, für Windows Vista und Windows 7 23, 26 für Windows 8.1 und 30 für Windows 10.

  • Zuletzt schreiben wir das analysierte Ergebnis in eine CSV-Datei.

Python-Code

Lassen Sie uns sehen, wie Python-Code für diesen Zweck verwendet wird -

Importieren Sie zunächst die folgenden Python-Bibliotheken:

from __future__ import print_function
import argparse
from datetime import datetime, timedelta

import os
import pytsk3
import pyewf
import struct
import sys
import unicodecsv as csv
from utility.pytskutil import TSKUtil

Geben Sie nun ein Argument für den Befehlszeilenhandler an. Hier werden zwei Argumente akzeptiert, erstens der Pfad zur Beweisdatei und zweitens der Typ der Beweisdatei. Es wird auch ein optionales Argument zum Angeben des Pfads akzeptiert, der nach Prefetch-Dateien durchsucht werden soll.

if __name__ == "__main__":
   parser = argparse.ArgumentParser('Parsing Prefetch files')
   parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
   parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
   parser.add_argument("OUTPUT_CSV", help = "Path to write output csv")
   parser.add_argument("-d", help = "Prefetch directory to scan",default = "/WINDOWS/PREFETCH")
   args = parser.parse_args()
   
   if os.path.exists(args.EVIDENCE_FILE) and \
      os.path.isfile(args.EVIDENCE_FILE):
   main(args.EVIDENCE_FILE, args.TYPE, args.OUTPUT_CSV, args.d)
else:
   print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
   sys.exit(1)

Interpretieren Sie nun die Beweisdatei, indem Sie ein Objekt von erstellen TSKUtil und iterieren Sie durch das Dateisystem, um Dateien zu finden, die mit enden .pf. Dies kann durch Definieren erfolgenmain() Funktion wie folgt -

def main(evidence, image_type, output_csv, path):
   tsk_util = TSKUtil(evidence, image_type)
   prefetch_dir = tsk_util.query_directory(path)
   prefetch_files = None
   
   if prefetch_dir is not None:
      prefetch_files = tsk_util.recurse_files(".pf", path=path, logic="endswith")
   
   if prefetch_files is None:
      print("[-] No .pf files found")
      sys.exit(2)
   print("[+] Identified {} potential prefetch files".format(len(prefetch_files)))
   prefetch_data = []
   
   for hit in prefetch_files:
      prefetch_file = hit[2]
      pf_version = check_signature(prefetch_file)

Definieren Sie nun eine Methode, mit der Signaturen wie unten gezeigt validiert werden.

def check_signature(prefetch_file):
   version, signature = struct.unpack("^<2i", prefetch_file.read_random(0, 8))
   
   if signature == 1094927187:
      return version
   else:
      return None
   
   if pf_version is None:
      continue
   pf_name = hit[0]
   
   if pf_version == 17:
      parsed_data = parse_pf_17(prefetch_file, pf_name)
      parsed_data.append(os.path.join(path, hit[1].lstrip("//")))
      prefetch_data.append(parsed_data)

Starten Sie jetzt die Verarbeitung von Windows-Prefetch-Dateien. Hier nehmen wir das Beispiel von Windows XP-Prefetch-Dateien -

def parse_pf_17(prefetch_file, pf_name):
   create = convert_unix(prefetch_file.info.meta.crtime)
   modify = convert_unix(prefetch_file.info.meta.mtime)
def convert_unix(ts):
   if int(ts) == 0:
      return ""
   return datetime.utcfromtimestamp(ts)
def convert_filetime(ts):
   if int(ts) == 0:
      return ""
   return datetime(1601, 1, 1) + timedelta(microseconds=ts / 10)

Extrahieren Sie nun die in die vorabgerufenen Dateien eingebetteten Daten mit struct wie folgt:

pf_size, name, vol_info, vol_entries, vol_size, filetime, \
   count = struct.unpack("<i60s32x3iq16xi",prefetch_file.read_random(12, 136))
name = name.decode("utf-16", "ignore").strip("/x00").split("/x00")[0]

vol_name_offset, vol_name_length, vol_create, \
   vol_serial = struct.unpack("<2iqi",prefetch_file.read_random(vol_info, 20))
   vol_serial = hex(vol_serial).lstrip("0x")
   vol_serial = vol_serial[:4] + "-" + vol_serial[4:]
   vol_name = struct.unpack(
      "<{}s".format(2 * vol_name_length),
      prefetch_file.read_random(vol_info + vol_name_offset,vol_name_length * 2))[0]

vol_name = vol_name.decode("utf-16", "ignore").strip("/x00").split("/x00")[0]
return [
   pf_name, name, pf_size, create,
   modify, convert_filetime(filetime), count, vol_name,
   convert_filetime(vol_create), vol_serial ]

Wie wir die Prefetch-Version für Windows XP bereitgestellt haben, aber was ist, wenn Prefetch-Versionen für andere Windows auftreten. Dann muss eine Fehlermeldung wie folgt angezeigt werden:

elif pf_version == 23:
   print("[-] Windows Vista / 7 PF file {} -- unsupported".format(pf_name))
   continue
elif pf_version == 26:
   print("[-] Windows 8 PF file {} -- unsupported".format(pf_name))
   continue
elif pf_version == 30:
   print("[-] Windows 10 PF file {} -- unsupported".format(pf_name))
continue

else:
   print("[-] Signature mismatch - Name: {}\nPath: {}".format(hit[0], hit[1]))
continue
write_output(prefetch_data, output_csv)

Definieren Sie nun die Methode zum Schreiben des Ergebnisses in den CSV-Bericht wie folgt:

def write_output(data, output_csv):
   print("[+] Writing csv report")
   with open(output_csv, "wb") as outfile:
      writer = csv.writer(outfile)
      writer.writerow([
         "File Name", "Prefetch Name", "File Size (bytes)",
         "File Create Date (UTC)", "File Modify Date (UTC)",
         "Prefetch Last Execution Date (UTC)",
         "Prefetch Execution Count", "Volume", "Volume Create Date",
         "Volume Serial", "File Path" ])
      writer.writerows(data)

Nach dem Ausführen des obigen Skripts erhalten wir die Informationen aus Prefetch-Dateien der Windows XP-Version in eine Tabelle.