Artefacts importants dans Windows-II

Ce chapitre décrit certains artefacts plus importants dans Windows et leur méthode d'extraction à l'aide de Python.

Activités des utilisateurs

Windows ayant NTUSER.DATfichier pour stocker diverses activités de l'utilisateur. Chaque profil utilisateur a une ruche commeNTUSER.DAT, qui stocke spécifiquement les informations et les configurations liées à cet utilisateur. Par conséquent, il est très utile aux fins d'enquête par les analystes légistes.

Le script Python suivant analysera certaines des clés de NTUSER.DATpour explorer les actions d'un utilisateur sur le système. Avant de continuer, pour le script Python, nous devons installer des modules tiers à savoirRegistry, pytsk3, pyewf et Jinja2. Nous pouvons utiliser pip pour les installer.

Nous pouvons suivre les étapes suivantes pour extraire des informations de NTUSER.DAT fichier -

  • Tout d'abord, recherchez tout NTUSER.DAT fichiers dans le système.

  • Puis analysez le WordWheelQuery, TypePath and RunMRU clé pour chacun NTUSER.DAT fichier.

  • Enfin, nous écrirons ces artefacts, déjà traités, dans un rapport HTML en utilisant Jinja2 fmodule.

Code Python

Voyons comment utiliser le code Python à cette fin -

Tout d'abord, nous devons importer les modules Python suivants -

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

Maintenant, fournissez un argument pour le gestionnaire de ligne de commande. Ici, il acceptera trois arguments - le premier est le chemin d'accès au fichier de preuves, le second est le type de fichier de preuves et le troisième est le chemin de sortie souhaité vers le rapport HTML, comme indiqué ci-dessous -

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)

Maintenant, définissons main() fonction de recherche de tout NTUSER.DAT fichiers, comme indiqué -

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'}
   }

Maintenant, nous allons essayer de trouver la clé dans NTUSER.DAT et une fois que vous l'avez trouvé, définissez les fonctions de traitement de l'utilisateur comme indiqué ci-dessous -

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()

Maintenant, passez l'objet dictionnaire et son chemin à write_html() méthode comme suit -

write_html(report, nt_rec)

Maintenant, définissez une méthode qui prend pytsk descripteur de fichier et lisez-le dans la classe Registry via le StringIO classe.

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)

Maintenant, nous allons définir la fonction qui analysera et gère WordWheelQuery clé de NTUSER.DAT fichier comme suit -

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

Maintenant, nous allons définir la fonction qui analysera et gère TypedPaths clé de NTUSER.DAT fichier comme suit -

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

Maintenant, nous allons définir la fonction qui analysera et gère RunMRU clé de NTUSER.DAT fichier comme suit -

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

Désormais, la fonction suivante gérera la création du rapport HTML -

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)

Enfin, nous pouvons écrire un document HTML pour le rapport. Après avoir exécuté le script ci-dessus, nous obtiendrons les informations du fichier NTUSER.DAT au format de document HTML.

Fichiers LINK

Les fichiers de raccourcis sont créés lorsqu'un utilisateur ou le système d'exploitation crée des fichiers de raccourcis pour les fichiers qui sont fréquemment utilisés, double-cliqués ou accessibles à partir de lecteurs système tels que le stockage attaché. Ces types de fichiers de raccourcis sont appelés fichiers de liens. En accédant à ces fichiers de lien, un enquêteur peut trouver l'activité de la fenêtre telle que l'heure et l'emplacement à partir desquels ces fichiers ont été consultés.

Laissez-nous discuter du script Python que nous pouvons utiliser pour obtenir les informations de ces fichiers Windows LINK.

Pour le script Python, installez des modules tiers à savoir pylnk, pytsk3, pyewf. Nous pouvons suivre les étapes suivantes pour extraire des informations delnk des dossiers

  • Tout d'abord, recherchez lnk fichiers dans le système.

  • Ensuite, extrayez les informations de ce fichier en les parcourant.

  • Maintenant, nous avons enfin besoin de ces informations dans un rapport CSV.

Code Python

Voyons comment utiliser le code Python à cette fin -

Tout d'abord, importez les bibliothèques Python suivantes -

from __future__ import print_function
from argparse import ArgumentParser

import csv
import StringIO

from utility.pytskutil import TSKUtil
import pylnk

Maintenant, fournissez l'argument du gestionnaire de ligne de commande. Ici, il acceptera trois arguments - le premier est le chemin d'accès au fichier de preuves, le second est le type de fichier de preuves et le troisième est le chemin de sortie souhaité vers le rapport CSV, comme indiqué ci-dessous -

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)

Maintenant, interprétez le fichier de preuves en créant un objet de TSKUtil et parcourez le système de fichiers pour trouver les fichiers se terminant par lnk. Cela peut être fait en définissantmain() fonction comme suit -

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'
   ]

Maintenant, avec l'aide du code suivant, nous allons parcourir lnk fichiers en créant une fonction comme suit -

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)

Nous devons maintenant définir deux fonctions, l'une ouvrira le pytsk objet de fichier et autre seront utilisés pour écrire le rapport CSV comme indiqué ci-dessous -

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)

Après avoir exécuté le script ci-dessus, nous obtiendrons les informations de la découverte lnk fichiers dans un rapport CSV -

Pré-extraire les fichiers

Chaque fois qu'une application s'exécute pour la première fois à partir d'un emplacement spécifique, Windows crée prefetch files. Ceux-ci sont utilisés pour accélérer le processus de démarrage de l'application. L'extension de ces fichiers est.PF et ceux-ci sont stockés dans le ”\Root\Windows\Prefetch” dossier.

Les experts en criminalistique numérique peuvent révéler la preuve de l'exécution du programme à partir d'un emplacement spécifié ainsi que les détails de l'utilisateur. Les fichiers de prélecture sont des artefacts utiles pour l'examinateur, car leur entrée est conservée même après la suppression ou la désinstallation du programme.

Laissez-nous discuter du script Python qui récupérera les informations des fichiers de prélecture Windows comme indiqué ci-dessous -

Pour le script Python, installez des modules tiers à savoir pylnk, pytsk3 et unicodecsv. Rappelons que nous avons déjà travaillé avec ces bibliothèques dans les scripts Python dont nous avons parlé dans les chapitres précédents.

Nous devons suivre les étapes ci-dessous pour extraire des informations de prefetch fichiers -

  • Tout d'abord, recherchez .pf fichiers d'extension ou les fichiers de prélecture.

  • Maintenant, effectuez la vérification de la signature pour éliminer les faux positifs.

  • Ensuite, analysez le format de fichier de prélecture Windows. Cela diffère avec la version Windows. Par exemple, pour Windows XP, il est de 17, pour Windows Vista et Windows 7, il est de 23, 26 pour Windows 8.1 et 30 pour Windows 10.

  • Enfin, nous écrirons le résultat analysé dans un fichier CSV.

Code Python

Voyons comment utiliser le code Python à cette fin -

Tout d'abord, importez les bibliothèques Python suivantes -

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

Maintenant, fournissez un argument pour le gestionnaire de ligne de commande. Ici, il acceptera deux arguments, le premier serait le chemin d'accès au fichier de preuve et le second serait le type de fichier de preuve. Il accepte également un argument facultatif pour spécifier le chemin pour rechercher les fichiers de prélecture -

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)

Maintenant, interprétez le fichier de preuves en créant un objet de TSKUtil et parcourez le système de fichiers pour trouver les fichiers se terminant par .pf. Cela peut être fait en définissantmain() fonction comme suit -

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)

Maintenant, définissez une méthode qui fera la validation des signatures comme indiqué ci-dessous -

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)

Maintenant, commencez à traiter les fichiers de prélecture Windows. Ici, nous prenons l'exemple des fichiers de prélecture de Windows XP -

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)

Maintenant, extrayez les données incorporées dans les fichiers pré-extraits en utilisant struct comme suit -

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 ]

Comme nous avons fourni la version de prélecture pour Windows XP, que se passe-t-il si elle rencontre des versions de prélecture pour d'autres Windows. Ensuite, il doit afficher un message d'erreur comme suit -

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)

Maintenant, définissez la méthode d'écriture du résultat dans le rapport CSV comme suit -

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)

Après avoir exécuté le script ci-dessus, nous obtiendrons les informations des fichiers de prélecture de la version Windows XP dans une feuille de calcul.