Python Digital Forensics - Kurzanleitung

In diesem Kapitel erhalten Sie eine Einführung in die digitale Forensik und ihre historische Übersicht. Sie werden auch verstehen, wo Sie die digitale Forensik im wirklichen Leben und ihre Grenzen anwenden können.

Was ist digitale Forensik?

Digitale Forensik kann als Zweig der forensischen Wissenschaft definiert werden, der die digitalen Beweise auf elektronischen Geräten analysiert, untersucht, identifiziert und wiederherstellt. Es wird häufig für das Strafrecht und private Ermittlungen verwendet.

Sie können sich beispielsweise auf Beweise für digitale Forensik-Extrakte verlassen, falls jemand Daten auf einem elektronischen Gerät stiehlt.

Kurzer historischer Rückblick auf die digitale Forensik

Die Geschichte der Computerkriminalität und die historische Überprüfung der digitalen Forensik werden in diesem Abschnitt wie folgt erläutert:

1970er bis 1980er Jahre: Erste Computerkriminalität

Vor diesem Jahrzehnt wurde keine Computerkriminalität erkannt. Wenn es jedoch passieren soll, haben sich die damals geltenden Gesetze mit ihnen befasst. Später, 1978, wurde die erste Computerkriminalität im Florida Computer Crime Act anerkannt, die Gesetze gegen unbefugte Änderung oder Löschung von Daten auf einem Computersystem enthielt. Im Laufe der Zeit nahm jedoch aufgrund des technologischen Fortschritts auch die Zahl der begangenen Computerkriminalität zu. Um Verbrechen im Zusammenhang mit Urheberrecht, Datenschutz und Kinderpornografie zu bekämpfen, wurden verschiedene andere Gesetze verabschiedet.

1980er-1990er Jahre: Entwicklungsdekade

Dieses Jahrzehnt war das Entwicklungsjahrzehnt für die digitale Forensik, alles aufgrund der ersten Untersuchung (1986), in der Cliff Stoll den Hacker namens Markus Hess verfolgte. In dieser Zeit entwickelten sich zwei Arten von Disziplinen der digitalen Forensik - die erste wurde mithilfe von Ad-hoc-Tools und -Techniken entwickelt, die von Praktikern entwickelt wurden, die sie als Hobby betrachteten, während die zweite von der wissenschaftlichen Gemeinschaft entwickelt wurde. Im Jahr 1992 wurde der Begriff“Computer Forensics”wurde in der akademischen Literatur verwendet.

2000er-2010er Jahre: Jahrzehnt der Standardisierung

Nach der Entwicklung der digitalen Forensik bis zu einem gewissen Grad mussten einige spezifische Standards festgelegt werden, die bei der Durchführung von Untersuchungen eingehalten werden können. Dementsprechend haben verschiedene wissenschaftliche Stellen und Gremien Richtlinien für die digitale Forensik veröffentlicht. Im Jahr 2002 veröffentlichte die Wissenschaftliche Arbeitsgruppe für digitale Evidenz (SWGDE) ein Papier mit dem Titel „Best Practices for Computer Forensics“. Eine weitere Feder in der Kappe war nämlich ein von Europa geführter internationaler Vertrag“The Convention on Cybercrime”wurde von 43 Nationen unterzeichnet und von 16 Nationen ratifiziert. Selbst nach solchen Standards müssen noch einige Probleme gelöst werden, die von Forschern festgestellt wurden.

Prozess der digitalen Forensik

Seit der ersten Computerkriminalität im Jahr 1978 haben die digitalen kriminellen Aktivitäten stark zugenommen. Aufgrund dieses Zuwachses besteht ein Bedarf an strukturiertem Umgang mit ihnen. 1984 wurde ein formalisiertes Verfahren eingeführt, und danach wurde eine große Anzahl neuer und verbesserter Verfahren zur Untersuchung der Computerforensik entwickelt.

Ein Computerforensik-Untersuchungsprozess umfasst drei Hauptphasen, wie nachstehend erläutert:

Phase 1: Erwerb oder Bildgebung von Exponaten

In der ersten Phase der digitalen Forensik wird der Status des digitalen Systems gespeichert, damit es später analysiert werden kann. Es ist dem Fotografieren, Blutproben usw. von einem Tatort sehr ähnlich. Beispielsweise wird ein Image von zugewiesenen und nicht zugewiesenen Bereichen einer Festplatte oder eines RAM erfasst.

Phase 2: Analyse

Die Eingabe dieser Phase sind die Daten, die in der Erfassungsphase erfasst wurden. Hier wurden diese Daten untersucht, um Beweise zu identifizieren. Diese Phase liefert drei Arten von Beweisen:

  • Inculpatory evidences - Diese Beweise stützen eine bestimmte Geschichte.

  • Exculpatory evidences - Diese Beweise widersprechen einer bestimmten Geschichte.

  • Evidence of tampering- Diese Beweise zeigen, dass das System temperiert wurde, um eine Identifizierung zu vermeiden. Dazu gehört das Überprüfen der Dateien und des Verzeichnisinhalts auf die Wiederherstellung der gelöschten Dateien.

Phase 3: Präsentation oder Berichterstattung

Wie der Name schon sagt, präsentiert diese Phase die Schlussfolgerung und die entsprechenden Beweise aus der Untersuchung.

Anwendungen der digitalen Forensik

Die digitale Forensik befasst sich mit dem Sammeln, Analysieren und Bewahren der Beweise, die in jedem digitalen Gerät enthalten sind. Die Verwendung der digitalen Forensik hängt von der Anwendung ab. Wie bereits erwähnt, wird es hauptsächlich in den folgenden beiden Anwendungen verwendet:

Strafrecht

Im Strafrecht werden die Beweise gesammelt, um eine Hypothese vor Gericht zu stützen oder abzulehnen. Forensische Verfahren sind denen bei strafrechtlichen Ermittlungen sehr ähnlich, unterliegen jedoch unterschiedlichen gesetzlichen Anforderungen und Einschränkungen.

Privatermittlung

Hauptsächlich nutzt die Unternehmenswelt die digitale Forensik für private Ermittlungen. Es wird verwendet, wenn Unternehmen den Verdacht haben, dass Mitarbeiter auf ihren Computern illegale Aktivitäten ausführen, die gegen die Unternehmensrichtlinien verstoßen. Die digitale Forensik bietet einen der besten Wege für Unternehmen oder Personen, um jemanden auf digitales Fehlverhalten zu untersuchen.

Zweige der digitalen Forensik

Das digitale Verbrechen ist nicht nur auf Computer beschränkt, sondern Hacker und Kriminelle verwenden auch kleine digitale Geräte wie Tablets, Smartphones usw. in sehr großem Umfang. Einige der Geräte verfügen über einen flüchtigen Speicher, während andere über einen nichtflüchtigen Speicher verfügen. Daher hat die digitale Forensik je nach Gerätetyp die folgenden Zweige:

Computer-Forensik

Dieser Zweig der digitalen Forensik befasst sich mit Computern, eingebetteten Systemen und statischen Speichern wie USB-Laufwerken. In der Computerforensik kann eine breite Palette von Informationen untersucht werden, von Protokollen bis hin zu tatsächlichen Dateien auf dem Laufwerk.

Mobile Forensik

Hier geht es um die Untersuchung von Daten von Mobilgeräten. Dieser Zweig unterscheidet sich von der Computerforensik in dem Sinne, dass mobile Geräte über ein eingebautes Kommunikationssystem verfügen, das nützlich ist, um nützliche Informationen in Bezug auf den Standort bereitzustellen.

Netzwerkforensik

Dies befasst sich mit der Überwachung und Analyse des Computernetzwerkverkehrs, sowohl lokal als auch WAN (Wide Area Network), zum Zwecke der Informationserfassung, Beweiserhebung oder Erkennung von Eindringlingen.

Datenbankforensik

Dieser Zweig der digitalen Forensik befasst sich mit der forensischen Untersuchung von Datenbanken und ihren Metadaten.

Erforderliche Fähigkeiten für die Untersuchung der digitalen Forensik

Prüfer für digitale Forensik helfen dabei, Hacker aufzuspüren, gestohlene Daten wiederherzustellen, Computerangriffe bis zu ihrer Quelle zurückzuverfolgen und andere Arten von Untersuchungen mit Computern durchzuführen. Einige der Schlüsselkompetenzen, die erforderlich sind, um Prüfer für digitale Forensik zu werden, wie unten erläutert -

Hervorragende Denkfähigkeiten

Ein Ermittler für digitale Forensik muss ein hervorragender Denker sein und in der Lage sein, verschiedene Werkzeuge und Methoden auf eine bestimmte Aufgabe anzuwenden, um die Ausgabe zu erhalten. Er / sie muss in der Lage sein, verschiedene Muster zu finden und Korrelationen zwischen ihnen herzustellen.

Technische Fähigkeiten

Ein Prüfer für digitale Forensik muss über gute technologische Fähigkeiten verfügen, da dieses Gebiet die Kenntnis des Netzwerks und der Interaktion des digitalen Systems erfordert.

Leidenschaft für Cybersicherheit

Da es auf dem Gebiet der digitalen Forensik nur um die Aufklärung von Cyber-Verbrechen geht und dies eine mühsame Aufgabe ist, braucht es viel Leidenschaft, damit jemand ein Ass der digitalen Forensik wird.

Kommunikationsfähigkeit

Gute Kommunikationsfähigkeiten sind ein Muss, um sich mit verschiedenen Teams abzustimmen und fehlende Daten oder Informationen zu extrahieren.

Geschickt in der Berichterstellung

Nach erfolgreicher Implementierung der Erfassung und Analyse muss ein digitaler forensischer Prüfer alle Ergebnisse im Abschlussbericht und in der Präsentation angeben. Daher muss er / sie über gute Fähigkeiten zur Berichterstellung und Liebe zum Detail verfügen.

Einschränkungen

Die digitale forensische Untersuchung bietet bestimmte Einschränkungen, wie hier erläutert -

Es müssen überzeugende Beweise vorgelegt werden

Einer der größten Rückschläge bei der Untersuchung der digitalen Forensik besteht darin, dass der Prüfer die Standards einhalten muss, die für die Beweisaufnahme vor Gericht erforderlich sind, da die Daten leicht manipuliert werden können. Auf der anderen Seite muss der computerforensische Ermittler über umfassende Kenntnisse der gesetzlichen Anforderungen, der Beweisverarbeitung und der Dokumentationsverfahren verfügen, um überzeugende Beweise vor Gericht vorlegen zu können.

Werkzeuge untersuchen

Die Wirksamkeit der digitalen Untersuchung beruht ausschließlich auf dem Fachwissen des Prüfers für digitale Forensik und der Auswahl des geeigneten Untersuchungsinstruments. Wenn das verwendete Werkzeug nicht den festgelegten Standards entspricht, können die Beweise vor Gericht vom Richter abgelehnt werden.

Mangel an technischem Wissen beim Publikum

Eine weitere Einschränkung besteht darin, dass einige Personen mit der Computerforensik nicht vollständig vertraut sind. Daher verstehen viele Menschen dieses Gebiet nicht. Die Ermittler müssen sicherstellen, dass sie ihre Ergebnisse den Gerichten so mitteilen, dass jeder die Ergebnisse besser verstehen kann.

Kosten

Die Erstellung und Aufbewahrung digitaler Beweise ist sehr kostspielig. Daher wird dieser Prozess möglicherweise nicht von vielen Menschen gewählt, die sich die Kosten nicht leisten können.

Im vorherigen Kapitel haben wir die Grundlagen der digitalen Forensik sowie ihre Vor- und Nachteile kennengelernt. In diesem Kapitel werden Sie mit Python vertraut gemacht, dem wesentlichen Werkzeug, das wir in dieser Untersuchung der digitalen Forensik verwenden.

Warum Python für digitale Forensik?

Python ist eine beliebte Programmiersprache und wird als Werkzeug für Cybersicherheit, Penetrationstests sowie digitale forensische Untersuchungen verwendet. Wenn Sie Python als Tool für die digitale Forensik auswählen, benötigen Sie keine andere Software von Drittanbietern, um die Aufgabe auszuführen.

Einige der einzigartigen Funktionen der Programmiersprache Python, die sie für digitale Forensikprojekte gut geeignet machen, sind nachstehend aufgeführt:

  • Simplicity of Syntax - Die Syntax von Python ist im Vergleich zu anderen Sprachen einfach, was das Lernen und die Verwendung für die digitale Forensik erleichtert.

  • Comprehensive inbuilt modules - Die umfassenden integrierten Module von Python sind eine hervorragende Hilfe für die Durchführung einer vollständigen digitalen forensischen Untersuchung.

  • Help and Support - Als Open-Source-Programmiersprache wird Python von der Entwickler- und Benutzergemeinschaft hervorragend unterstützt.

Funktionen von Python

Python ist eine übergeordnete, interpretierte, interaktive und objektorientierte Skriptsprache und bietet die folgenden Funktionen:

  • Easy to Learn - Python ist eine entwicklerfreundliche und leicht zu erlernende Sprache, da sie weniger Schlüsselwörter und eine einfachste Struktur aufweist.

  • Expressive and Easy to read- Python-Sprache ist ausdrucksstark; Daher ist sein Code verständlicher und lesbarer.

  • Cross-platform Compatible - Python ist eine plattformübergreifende kompatible Sprache, die auf verschiedenen Plattformen wie UNIX, Windows und Macintosh effizient ausgeführt werden kann.

  • Interactive Mode Programming - Wir können Code interaktiv testen und debuggen, da Python einen interaktiven Programmiermodus unterstützt.

  • Provides Various Modules and Functions - Python verfügt über eine große Standardbibliothek, mit der wir zahlreiche Module und Funktionen für unser Skript verwenden können.

  • Supports Dynamic Type Checking - Python unterstützt die dynamische Typprüfung und bietet dynamische Datentypen auf sehr hoher Ebene.

  • GUI Programming - Python unterstützt die GUI-Programmierung zur Entwicklung grafischer Benutzeroberflächen.

  • Integration with other programming languages - Python kann problemlos in andere Programmiersprachen wie C, C ++, JAVA usw. integriert werden.

Python installieren

Die Python-Distribution ist für verschiedene Plattformen wie Windows, UNIX, Linux und Mac verfügbar. Wir müssen nur den Binärcode gemäß unserer Plattform herunterladen. Falls der Binärcode für eine Plattform nicht verfügbar ist, benötigen wir einen C-Compiler, damit der Quellcode manuell kompiliert werden kann.

In diesem Abschnitt werden Sie mit der Installation von Python auf verschiedenen Plattformen vertraut gemacht

Python-Installation unter Unix und Linux

Sie können die folgenden Schritte ausführen, um Python auf einem Unix / Linux-Computer zu installieren.

Step 1- Öffnen Sie einen Webbrowser. Geben Sie www.python.org/downloads/ ein und geben Sie es ein.

Step 2 - Laden Sie den für Unix / Linux verfügbaren komprimierten Quellcode herunter.

Step 3 - Extrahieren Sie die heruntergeladenen komprimierten Dateien.

Step 4 - Wenn Sie einige Optionen anpassen möchten, können Sie die bearbeiten Modules/Setup file.

Step 5 - Verwenden Sie die folgenden Befehle, um die Installation abzuschließen. -

run ./configure script
make
make install

Sobald Sie die oben angegebenen Schritte erfolgreich ausgeführt haben, wird Python an seinem Standardspeicherort installiert /usr/local/bin und seine Bibliotheken bei /usr/local/lib/pythonXX Dabei ist XX die Version von Python.

Python-Installation unter Windows

Wir können die folgenden einfachen Schritte ausführen, um Python auf einem Windows-Computer zu installieren.

Step 1- Öffnen Sie einen Webbrowser. Geben Sie www.python.org/downloads/ ein und geben Sie es ein.

Step 2 - Laden Sie das Windows-Installationsprogramm herunter python-XYZ.msi Datei, wobei XYZ die Version ist, die wir installieren müssen.

Step 3 - Führen Sie nun diese MSI-Datei aus, nachdem Sie die Installationsdatei auf Ihrem lokalen Computer gespeichert haben.

Step 4 - Führen Sie die heruntergeladene Datei aus, um den Python-Installationsassistenten aufzurufen.

Python-Installation auf Macintosh

Für die Installation von Python 3 unter Mac OS X müssen Sie ein Paketinstallationsprogramm mit dem Namen verwenden Homebrew.

Sie können den folgenden Befehl verwenden, um Homebrew zu installieren, falls Sie es nicht auf Ihrem System haben -

$ ruby -e "$(curl -fsSL
https://raw.githubusercontent.com/Homebrew/install/master/install)"

Wenn Sie den Paketmanager aktualisieren müssen, können Sie dies mithilfe des folgenden Befehls tun:

$ brew update

Verwenden Sie nun den folgenden Befehl, um Python3 auf Ihrem System zu installieren:

$ brew install python3

PATH einstellen

Wir müssen den Pfad für die Python-Installation festlegen. Dies unterscheidet sich von Plattformen wie UNIX, WINDOWS oder MAC.

Pfadeinstellung unter Unix / Linux

Mit den folgenden Optionen können Sie den Pfad unter Unix / Linux festlegen:

  • If using csh shell - Art setenv PATH "$PATH:/usr/local/bin/python" und drücken Sie dann die Eingabetaste.

  • If using bash shell (Linux) - Typ export ATH="$PATH:/usr/local/bin/python" und drücken Sie dann die Eingabetaste.

  • If using sh or ksh shell - Art PATH="$PATH:/usr/local/bin/python" und drücken Sie dann die Eingabetaste.

Pfadeinstellung unter Windows

Art path %path%;C:\Python an der Eingabeaufforderung und drücken Sie die Eingabetaste.

Python ausführen

Sie können eine der folgenden drei Methoden auswählen, um den Python-Interpreter zu starten:

Methode 1: Interaktiven Interpreter verwenden

Ein System, das einen Befehlszeileninterpreter oder eine Shell bereitstellt, kann problemlos zum Starten von Python verwendet werden. Zum Beispiel Unix, DOS usw. Sie können die folgenden Schritte ausführen, um die Codierung in einem interaktiven Interpreter zu starten.

Step 1 - Geben Sie ein python an der Kommandozeile.

Step 2 - Beginnen Sie sofort mit der Codierung im interaktiven Interpreter mit den unten gezeigten Befehlen. -

$python # Unix/Linux
or
python% # Unix/Linux
or
C:> python # Windows/DOS

Methode 2: Verwenden von Script über die Befehlszeile

Wir können ein Python-Skript auch über die Befehlszeile ausführen, indem wir den Interpreter in unserer Anwendung aufrufen. Sie können die unten gezeigten Befehle verwenden -

$python script.py # Unix/Linux
or
python% script.py # Unix/Linux
or
C: >python script.py # Windows/DOS

Methode 3: Integrierte Entwicklungsumgebung

Wenn ein System über eine GUI-Anwendung verfügt, die Python unterstützt, kann Python in dieser GUI-Umgebung ausgeführt werden. Einige der IDE für verschiedene Plattformen sind unten angegeben -

  • Unix IDE - UNIX hat IDLE IDE für Python.

  • Windows IDE - Windows hat PythonWin, die erste Windows-Oberfläche für Python zusammen mit der GUI.

  • Macintosh IDE - Macintosh verfügt über IDLE IDE, die auf der Hauptwebsite verfügbar ist und entweder als MacBinary- oder BinHex-Datei heruntergeladen werden kann.

Nachdem Sie mit der Installation und Ausführung von Python-Befehlen auf Ihrem lokalen System vertraut sind, möchten wir uns ausführlich mit den Konzepten der Forensik befassen. In diesem Kapitel werden verschiedene Konzepte zum Umgang mit Artefakten in der digitalen Forensik von Python erläutert.

Notwendigkeit der Berichterstellung

Der Prozess der digitalen Forensik umfasst die Berichterstattung als dritte Phase. Dies ist einer der wichtigsten Teile des digitalen forensischen Prozesses. Die Berichterstellung ist aus folgenden Gründen erforderlich:

  • Es ist das Dokument, in dem der digitale forensische Prüfer den Untersuchungsprozess und seine Ergebnisse umreißt.

  • Ein guter Prüfer kann auf einen guten digitalen forensischen Bericht verweisen, um mit denselben Repositories das gleiche Ergebnis zu erzielen.

  • Es ist ein technisches und wissenschaftliches Dokument, das Fakten enthält, die innerhalb der Einsen und Nullen digitaler Beweise gefunden wurden.

Allgemeine Richtlinien für die Berichterstellung

Die Berichte dienen der Information des Lesers und müssen auf einer soliden Grundlage beginnen. Ermittler können Schwierigkeiten haben, ihre Ergebnisse effizient zu präsentieren, wenn der Bericht ohne einige allgemeine Richtlinien oder Standards erstellt wird. Einige allgemeine Richtlinien, die beim Erstellen digitaler forensischer Berichte befolgt werden müssen, sind nachstehend aufgeführt:

  • Summary - Der Bericht muss eine kurze Zusammenfassung der Informationen enthalten, damit der Leser den Zweck des Berichts feststellen kann.

  • Tools used - Wir müssen die Werkzeuge erwähnen, die zur Durchführung des Prozesses der digitalen Forensik verwendet wurden, einschließlich ihres Zwecks.

  • Repository - Angenommen, wir haben den Computer einer Person untersucht, dann die Zusammenfassung der Beweise und die Analyse des relevanten Materials wie E-Mail, interne Suchhistorie usw., dann müssen sie in den Bericht aufgenommen werden, damit der Fall klar dargestellt werden kann.

  • Recommendations for counsel - Der Bericht muss die Empfehlungen enthalten, damit der Anwalt die Untersuchung auf der Grundlage der im Bericht enthaltenen Ergebnisse fortsetzen oder einstellen kann.

Erstellen verschiedener Arten von Berichten

Im obigen Abschnitt haben wir die Bedeutung von Berichten in der digitalen Forensik sowie die Richtlinien für deren Erstellung kennengelernt. Einige der Formate in Python zum Erstellen verschiedener Arten von Berichten werden nachfolgend erläutert.

CSV-Berichte

Eines der häufigsten Ausgabeformate von Berichten ist ein CSV-Tabellenbericht. Sie können eine CSV erstellen, um mithilfe des Python-Codes einen Bericht über verarbeitete Daten zu erstellen.

Importieren Sie zunächst nützliche Bibliotheken zum Schreiben der Tabelle -

from __future__ import print_function
import csv
import os
import sys

Rufen Sie nun die folgende Methode auf:

Write_csv(TEST_DATA_LIST, ["Name", "Age", "City", "Job description"], os.getcwd())

Wir verwenden die folgende globale Variable, um Beispieldatentypen darzustellen:

TEST_DATA_LIST = [["Ram", 32, Bhopal, Manager], 
   ["Raman", 42, Indore, Engg.],
   ["Mohan", 25, Chandigarh, HR], 
   ["Parkash", 45, Delhi, IT]]

Als nächstes definieren wir die Methode, um mit weiteren Operationen fortzufahren. Wir öffnen die Datei im Modus „w“ und setzen das Schlüsselwortargument newline auf eine leere Zeichenfolge.

def Write_csv(data, header, output_directory, name = None):
   if name is None:
      name = "report1.csv"
   print("[+] Writing {} to {}".format(name, output_directory))
   
   with open(os.path.join(output_directory, name), "w", newline = "") as \ csvfile:
      writer = csv.writer(csvfile)
      writer.writerow(header)
      writer.writerow(data)

Wenn Sie das obige Skript ausführen, werden die folgenden Details in der Datei report1.csv gespeichert.

Name Alter Stadt Bezeichnung
RAM 32 Bhopal Managerh
Raman 42 Indore Engg
Mohan 25 Chandigarh HR
Parkash 45 Delhi ES

Excel-Berichte

Ein weiteres gängiges Ausgabeformat von Berichten ist der Excel-Tabellenbericht (.xlsx). Wir können eine Tabelle erstellen und das Diagramm auch mit Excel zeichnen. Wir können einen Bericht über verarbeitete Daten im Excel-Format mit Python-Code erstellen, wie unten gezeigt

Importieren Sie zunächst das XlsxWriter-Modul zum Erstellen einer Tabelle.

import xlsxwriter

Erstellen Sie nun ein Arbeitsmappenobjekt. Dazu müssen wir den Workbook () -Konstruktor verwenden.

workbook = xlsxwriter.Workbook('report2.xlsx')

Erstellen Sie jetzt ein neues Arbeitsblatt mit dem Modul add_worksheet ().

worksheet = workbook.add_worksheet()

Schreiben Sie als Nächstes die folgenden Daten in das Arbeitsblatt:

report2 = (['Ram', 32, ‘Bhopal’],['Mohan',25, ‘Chandigarh’] ,['Parkash',45, ‘Delhi’])

row = 0
col = 0

Sie können diese Daten durchlaufen und wie folgt schreiben:

for item, cost in (a):
   worksheet.write(row, col, item)
   worksheet.write(row, col+1, cost)
   row + = 1

Lassen Sie uns nun diese Excel-Datei mit der Methode close () schließen.

workbook.close()

Das obige Skript erstellt eine Excel-Datei mit dem Namen report2.xlsx mit den folgenden Daten:

RAM 32 Bhopal
Mohan 25 Chandigarh
Parkash 45 Delhi

Investigation Acquisition Media

Für einen Ermittler ist es wichtig, über detaillierte Untersuchungsnotizen zu verfügen, um die Ergebnisse genau wiederzugeben oder alle Untersuchungsgegenstände zusammenzustellen. Ein Screenshot ist sehr nützlich, um die Schritte zu verfolgen, die für eine bestimmte Untersuchung unternommen wurden. Mit Hilfe des folgenden Python-Codes können wir den Screenshot aufnehmen und zur späteren Verwendung auf der Festplatte speichern.

Installieren Sie zunächst das Python-Modul pyscreenshot mit dem folgenden Befehl:

Pip install pyscreenshot

Importieren Sie nun die erforderlichen Module wie gezeigt -

import pyscreenshot as ImageGrab

Verwenden Sie die folgende Codezeile, um den Screenshot zu erhalten -

image = ImageGrab.grab()

Verwenden Sie die folgende Codezeile, um den Screenshot an dem angegebenen Speicherort zu speichern:

image.save('d:/image123.png')

Wenn Sie den Screenshot als Diagramm anzeigen möchten, können Sie den folgenden Python-Code verwenden:

import numpy as np
import matplotlib.pyplot as plt
import pyscreenshot as ImageGrab
imageg = ImageGrab.grab()
plt.imshow(image, cmap='gray', interpolation='bilinear')
plt.show()

In diesem Kapitel werden die digitale Forensik von Python auf Mobilgeräten und die damit verbundenen Konzepte erläutert.

Einführung

Die Forensik mobiler Geräte ist der Zweig der digitalen Forensik, der sich mit der Erfassung und Analyse mobiler Geräte befasst, um digitale Beweise von Untersuchungsinteresse wiederherzustellen. Dieser Zweig unterscheidet sich von der Computerforensik, da mobile Geräte über ein eingebautes Kommunikationssystem verfügen, das nützlich ist, um nützliche Informationen zum Standort bereitzustellen.

Obwohl die Verwendung von Smartphones in der digitalen Forensik von Tag zu Tag zunimmt, wird sie aufgrund ihrer Heterogenität immer noch als nicht standardisiert angesehen. Auf der anderen Seite wird Computerhardware wie Festplatten als Standard angesehen und auch als stabile Disziplin entwickelt. In der digitalen forensischen Industrie wird viel über die Techniken diskutiert, die für Geräte verwendet werden, die nicht dem Standard entsprechen und vorübergehende Beweise aufweisen, wie z. B. Smartphones.

Aus mobilen Geräten extrahierbare Artefakte

Moderne mobile Geräte verfügen im Vergleich zu älteren Telefonen mit nur einem Anrufprotokoll oder SMS-Nachrichten über viele digitale Informationen. Auf diese Weise können mobile Geräte den Ermittlern viele Einblicke in ihre Benutzer liefern. Einige Artefakte, die von Mobilgeräten extrahiert werden können, sind wie folgt:

  • Messages - Dies sind die nützlichen Artefakte, die den Geisteszustand des Besitzers offenbaren und dem Ermittler sogar einige bisher unbekannte Informationen geben können.

  • Location History- Die Standortverlaufsdaten sind ein nützliches Artefakt, mit dem die Ermittler den jeweiligen Standort einer Person überprüfen können.

  • Applications Installed - Durch den Zugriff auf die Art der installierten Anwendungen erhält der Ermittler einen Einblick in die Gewohnheiten und das Denken des mobilen Benutzers.

Beweisquellen und Verarbeitung in Python

Smartphones haben SQLite-Datenbanken und PLIST-Dateien als Hauptbeweisquellen. In diesem Abschnitt werden wir die Beweisquellen in Python verarbeiten.

PLIST-Dateien analysieren

Eine PLIST (Property List) ist ein flexibles und praktisches Format zum Speichern von Anwendungsdaten, insbesondere auf iPhone-Geräten. Es verwendet die Erweiterung.plist. Solche Dateien werden zum Speichern von Informationen über Bundles und Anwendungen verwendet. Es kann in zwei Formaten vorliegen:XML und binary. Der folgende Python-Code öffnet und liest die PLIST-Datei. Beachten Sie, dass wir, bevor wir fortfahren, unsere eigenen erstellen müssenInfo.plist Datei.

Installieren Sie zunächst eine Drittanbieter-Bibliothek mit dem Namen biplist mit dem folgenden Befehl -

Pip install biplist

Importieren Sie nun einige nützliche Bibliotheken, um Plist-Dateien zu verarbeiten.

import biplist
import os
import sys

Verwenden Sie jetzt den folgenden Befehl unter main method, um die plist-Datei in eine Variable einzulesen.

def main(plist):
   try:
      data = biplist.readPlist(plist)
   except (biplist.InvalidPlistException,biplist.NotBinaryPlistException) as e:
print("[-] Invalid PLIST file - unable to be opened by biplist")
sys.exit(1)

Jetzt können wir die Daten entweder auf der Konsole lesen oder direkt aus dieser Variablen drucken.

SQLite-Datenbanken

SQLite dient als primäres Datenrepository auf Mobilgeräten. SQLite ist eine In-Process-Bibliothek, die ein in sich geschlossenes, serverloses, konfigurationsfreies SQL-Transaktionsdatenbankmodul implementiert. Es handelt sich um eine Datenbank, die auf Null konfiguriert ist. Sie müssen sie im Gegensatz zu anderen Datenbanken nicht in Ihrem System konfigurieren.

Wenn Sie ein Anfänger sind oder mit SQLite-Datenbanken nicht vertraut sind, können Sie dem Link www.tutorialspoint.com/sqlite/index.htm folgen. Außerdem können Sie dem Link www.tutorialspoint.com/sqlite/sqlite_python.htm folgen, falls Sie möchten Machen Sie sich mit Python mit SQLite vertraut.

Während der mobilen Forensik können wir mit dem interagieren sms.db Datei eines mobilen Geräts und kann wertvolle Informationen aus extrahieren messageTabelle. Python hat eine eingebaute Bibliothek namenssqlite3zum Verbinden mit der SQLite-Datenbank. Sie können dasselbe mit dem folgenden Befehl importieren:

import sqlite3

Jetzt können wir mit Hilfe des folgenden Befehls beispielsweise eine Verbindung mit der Datenbank herstellen sms.db bei mobilen Geräten -

Conn = sqlite3.connect(‘sms.db’)
C = conn.cursor()

Hier ist C das Cursorobjekt, mit dessen Hilfe wir mit der Datenbank interagieren können.

Angenommen, wir möchten einen bestimmten Befehl ausführen, z. B. um die Details aus dem zu erhalten abc tablekann dies mit Hilfe des folgenden Befehls erfolgen -

c.execute(“Select * from abc”)
c.close()

Das Ergebnis des obigen Befehls würde in der gespeichert cursorObjekt. Ebenso können wir verwendenfetchall() Methode, um das Ergebnis in eine Variable zu kopieren, die wir manipulieren können.

Wir können den folgenden Befehl verwenden, um Spaltennamendaten der Nachrichtentabelle in abzurufen sms.db - -

c.execute(“pragma table_info(message)”)
table_data = c.fetchall()
columns = [x[1] for x in table_data

Beachten Sie, dass wir hier den SQLite PRAGMA-Befehl verwenden, einen speziellen Befehl zur Steuerung verschiedener Umgebungsvariablen und Statusflags in der SQLite-Umgebung. Im obigen Befehl wird diefetchall()Methode gibt ein Tupel von Ergebnissen zurück. Der Name jeder Spalte wird im ersten Index jedes Tupels gespeichert.

Mit Hilfe des folgenden Befehls können wir nun die Tabelle nach allen Daten abfragen und in der genannten Variablen speichern data_msg - -

c.execute(“Select * from message”)
data_msg = c.fetchall()

Der obige Befehl speichert die Daten in der Variablen und außerdem können wir die obigen Daten mithilfe von in eine CSV-Datei schreiben csv.writer() Methode.

iTunes Backups

Die mobile Forensik für das iPhone kann mit den von iTunes erstellten Backups durchgeführt werden. Forensische Prüfer verlassen sich auf die Analyse der über iTunes erworbenen logischen iPhone-Backups. Das AFC-Protokoll (Apple File Connection) wird von iTunes verwendet, um das Backup zu erstellen. Außerdem ändert der Sicherungsprozess nichts auf dem iPhone außer den Treuhandschlüsseleinträgen.

Nun stellt sich die Frage, warum es für einen Experten für digitale Forensik wichtig ist, die Techniken in iTunes-Backups zu verstehen. Es ist wichtig, dass wir anstelle des iPhone direkt auf den Computer des Verdächtigen zugreifen können, da bei der Synchronisierung eines Computers mit dem iPhone die meisten Informationen auf dem iPhone wahrscheinlich auf dem Computer gesichert werden.

Sicherungsprozess und sein Speicherort

Wenn ein Apple-Produkt auf dem Computer gesichert wird, ist es mit iTunes synchronisiert und es gibt einen bestimmten Ordner mit der eindeutigen ID des Geräts. Im neuesten Sicherungsformat werden die Dateien in Unterordnern gespeichert, die die ersten beiden Hexadezimalzeichen des Dateinamens enthalten. Aus diesen Sicherungsdateien stammen einige Dateien wie info.plist, die zusammen mit der Datenbank Manifest.db nützlich sind. In der folgenden Tabelle sind die Sicherungsspeicherorte aufgeführt, die je nach Betriebssystem der iTunes-Sicherungen variieren.

Betriebssystem Sicherungsort
Win7 C: \ Benutzer \ [Benutzername] \ AppData \ Roaming \ AppleComputer \ MobileSync \ Backup \
MAC OS X ~ / Library / Application Suport / MobileSync / Backup /

Um das iTunes-Backup mit Python zu verarbeiten, müssen wir zuerst alle Backups am Backup-Speicherort gemäß unserem Betriebssystem identifizieren. Dann werden wir jede Sicherung durchlaufen und die Datenbank Manifest.db lesen.

Mit Hilfe des folgenden Python-Codes können wir jetzt dasselbe tun -

Importieren Sie zunächst die erforderlichen Bibliotheken wie folgt:

from __future__ import print_function
import argparse
import logging
import os

from shutil import copyfile
import sqlite3
import sys
logger = logging.getLogger(__name__)

Geben Sie nun zwei Positionsargumente an, nämlich INPUT_DIR und OUTPUT_DIR, die das iTunes-Backup und den gewünschten Ausgabeordner darstellen.

if __name__ == "__main__":
   parser.add_argument("INPUT_DIR",help = "Location of folder containing iOS backups, ""e.g. ~\Library\Application Support\MobileSync\Backup folder")
   parser.add_argument("OUTPUT_DIR", help = "Output Directory")
   parser.add_argument("-l", help = "Log file path",default = __file__[:-2] + "log")
   parser.add_argument("-v", help = "Increase verbosity",action = "store_true") args = parser.parse_args()

Richten Sie das Protokoll nun wie folgt ein:

if args.v:
   logger.setLevel(logging.DEBUG)
else:
   logger.setLevel(logging.INFO)

Richten Sie nun das Nachrichtenformat für dieses Protokoll wie folgt ein:

msg_fmt = logging.Formatter("%(asctime)-15s %(funcName)-13s""%(levelname)-8s %(message)s")
strhndl = logging.StreamHandler(sys.stderr)
strhndl.setFormatter(fmt = msg_fmt)

fhndl = logging.FileHandler(args.l, mode = 'a')
fhndl.setFormatter(fmt = msg_fmt)

logger.addHandler(strhndl)
logger.addHandler(fhndl)
logger.info("Starting iBackup Visualizer")
logger.debug("Supplied arguments: {}".format(" ".join(sys.argv[1:])))
logger.debug("System: " + sys.platform)
logger.debug("Python Version: " + sys.version)

Die folgende Codezeile erstellt mithilfe von die erforderlichen Ordner für das gewünschte Ausgabeverzeichnis os.makedirs() Funktion -

if not os.path.exists(args.OUTPUT_DIR):
   os.makedirs(args.OUTPUT_DIR)

Übergeben Sie nun die bereitgestellten Eingabe- und Ausgabeverzeichnisse wie folgt an die Funktion main ():

if os.path.exists(args.INPUT_DIR) and os.path.isdir(args.INPUT_DIR):
   main(args.INPUT_DIR, args.OUTPUT_DIR)
else:
   logger.error("Supplied input directory does not exist or is not ""a directory")
   sys.exit(1)

Schreibe jetzt main() Funktion, die weiter aufruft backup_summary() Funktion zum Identifizieren aller im Eingabeordner vorhandenen Sicherungen -

def main(in_dir, out_dir):
   backups = backup_summary(in_dir)
def backup_summary(in_dir):
   logger.info("Identifying all iOS backups in {}".format(in_dir))
   root = os.listdir(in_dir)
   backups = {}
   
   for x in root:
      temp_dir = os.path.join(in_dir, x)
      if os.path.isdir(temp_dir) and len(x) == 40:
         num_files = 0
         size = 0
         
         for root, subdir, files in os.walk(temp_dir):
            num_files += len(files)
            size += sum(os.path.getsize(os.path.join(root, name))
               for name in files)
         backups[x] = [temp_dir, num_files, size]
   return backups

Drucken Sie nun die Zusammenfassung jeder Sicherung wie folgt auf die Konsole:

print("Backup Summary")
print("=" * 20)

if len(backups) > 0:
   for i, b in enumerate(backups):
      print("Backup No.: {} \n""Backup Dev. Name: {} \n""# Files: {} \n""Backup Size (Bytes): {}\n".format(i, b, backups[b][1], backups[b][2]))

Speichern Sie nun den Inhalt der Datei Manifest.db in der Variablen db_items.

try:
   db_items = process_manifest(backups[b][0])
   except IOError:
      logger.warn("Non-iOS 10 backup encountered or " "invalid backup. Continuing to next backup.")
continue

Definieren wir nun eine Funktion, die den Verzeichnispfad der Sicherung übernimmt -

def process_manifest(backup):
   manifest = os.path.join(backup, "Manifest.db")
   
   if not os.path.exists(manifest):
      logger.error("Manifest DB not found in {}".format(manifest))
      raise IOError

Mit SQLite3 stellen wir nun über den Cursor c - eine Verbindung zur Datenbank her.

c = conn.cursor()
items = {}

for row in c.execute("SELECT * from Files;"):
   items[row[0]] = [row[2], row[1], row[3]]
return items

create_files(in_dir, out_dir, b, db_items)
   print("=" * 20)
else:
   logger.warning("No valid backups found. The input directory should be
      " "the parent-directory immediately above the SHA-1 hash " "iOS device backups")
      sys.exit(2)

Definieren Sie nun die create_files() Methode wie folgt -

def create_files(in_dir, out_dir, b, db_items):
   msg = "Copying Files for backup {} to {}".format(b, os.path.join(out_dir, b))
   logger.info(msg)

Durchlaufen Sie nun jeden Schlüssel in der db_items Wörterbuch -

for x, key in enumerate(db_items):
   if db_items[key][0] is None or db_items[key][0] == "":
      continue
   else:
      dirpath = os.path.join(out_dir, b,
os.path.dirname(db_items[key][0]))
   filepath = os.path.join(out_dir, b, db_items[key][0])
   
   if not os.path.exists(dirpath):
      os.makedirs(dirpath)
      original_dir = b + "/" + key[0:2] + "/" + key
   path = os.path.join(in_dir, original_dir)
   
   if os.path.exists(filepath):
      filepath = filepath + "_{}".format(x)

Jetzt benutzen shutil.copyfile() Methode zum Kopieren der gesicherten Datei wie folgt:

try:
   copyfile(path, filepath)
   except IOError:
      logger.debug("File not found in backup: {}".format(path))
         files_not_found += 1
   if files_not_found > 0:
      logger.warning("{} files listed in the Manifest.db not" "found in
backup".format(files_not_found))
   copyfile(os.path.join(in_dir, b, "Info.plist"), os.path.join(out_dir, b,
"Info.plist"))
   copyfile(os.path.join(in_dir, b, "Manifest.db"), os.path.join(out_dir, b,
"Manifest.db"))
   copyfile(os.path.join(in_dir, b, "Manifest.plist"), os.path.join(out_dir, b,
"Manifest.plist"))
   copyfile(os.path.join(in_dir, b, "Status.plist"),os.path.join(out_dir, b,
"Status.plist"))

Mit dem obigen Python-Skript können wir die aktualisierte Struktur der Sicherungsdatei in unserem Ausgabeordner abrufen. Wir können benutzenpycrypto Python-Bibliothek zum Entschlüsseln der Backups.

W-lan

Mobile Geräte können verwendet werden, um eine Verbindung zur Außenwelt herzustellen, indem eine Verbindung über Wi-Fi-Netzwerke hergestellt wird, die überall verfügbar sind. Manchmal wird das Gerät automatisch mit diesen offenen Netzwerken verbunden.

Beim iPhone wird die Liste der offenen Wi-Fi-Verbindungen, mit denen das Gerät verbunden wurde, in einer PLIST-Datei mit dem Namen gespeichert com.apple.wifi.plist. Diese Datei enthält die Wi-Fi-SSID, die BSSID und die Verbindungszeit.

Wir müssen Wi-Fi-Details mit Python aus dem Standard-Cellebrite-XML-Bericht extrahieren. Dazu benötigen wir die API der Wireless Geographic Logging Engine (WIGLE), einer beliebten Plattform, mit der der Standort eines Geräts anhand der Namen von Wi-Fi-Netzwerken ermittelt werden kann.

Wir können die Python-Bibliothek namens verwenden requestsum von WIGLE auf die API zuzugreifen. Es kann wie folgt installiert werden:

pip install requests

API von WIGLE

Wir müssen uns auf der Website von WIGLE registrieren https://wigle.net/accountum eine kostenlose API von WIGLE zu erhalten. Das Python-Skript zum Abrufen der Informationen zum Benutzergerät und seiner Verbindung über die WIGEL-API wird nachfolgend erläutert.

Importieren Sie zunächst die folgenden Bibliotheken, um verschiedene Aufgaben zu erledigen:

from __future__ import print_function

import argparse
import csv
import os
import sys
import xml.etree.ElementTree as ET
import requests

Geben Sie nun nämlich zwei Positionsargumente an INPUT_FILE und OUTPUT_CSV die die Eingabedatei mit der Wi-Fi-MAC-Adresse bzw. die gewünschte Ausgabe-CSV-Datei darstellt -

if __name__ == "__main__":
   parser.add_argument("INPUT_FILE", help = "INPUT FILE with MAC Addresses")
   parser.add_argument("OUTPUT_CSV", help = "Output CSV File")
   parser.add_argument("-t", help = "Input type: Cellebrite XML report or TXT
file",choices = ('xml', 'txt'), default = "xml")
   parser.add_argument('--api', help = "Path to API key
   file",default = os.path.expanduser("~/.wigle_api"),
   type = argparse.FileType('r'))
   args = parser.parse_args()

Die folgenden Codezeilen prüfen nun, ob die Eingabedatei vorhanden und eine Datei ist. Wenn nicht, wird das Skript beendet -

if not os.path.exists(args.INPUT_FILE) or \ not os.path.isfile(args.INPUT_FILE):
   print("[-] {} does not exist or is not a
file".format(args.INPUT_FILE))
   sys.exit(1)
directory = os.path.dirname(args.OUTPUT_CSV)
if directory != '' and not os.path.exists(directory):
   os.makedirs(directory)
api_key = args.api.readline().strip().split(":")

Übergeben Sie das Argument nun wie folgt an main:

main(args.INPUT_FILE, args.OUTPUT_CSV, args.t, api_key)
def main(in_file, out_csv, type, api_key):
   if type == 'xml':
      wifi = parse_xml(in_file)
   else:
      wifi = parse_txt(in_file)
query_wigle(wifi, out_csv, api_key)

Jetzt analysieren wir die XML-Datei wie folgt:

def parse_xml(xml_file):
   wifi = {}
   xmlns = "{http://pa.cellebrite.com/report/2.0}"
   print("[+] Opening {} report".format(xml_file))
   
   xml_tree = ET.parse(xml_file)
   print("[+] Parsing report for all connected WiFi addresses")
   
   root = xml_tree.getroot()

Durchlaufen Sie nun das untergeordnete Element der Wurzel wie folgt:

for child in root.iter():
   if child.tag == xmlns + "model":
      if child.get("type") == "Location":
         for field in child.findall(xmlns + "field"):
            if field.get("name") == "TimeStamp":
               ts_value = field.find(xmlns + "value")
               try:
               ts = ts_value.text
               except AttributeError:
continue

Jetzt werden wir überprüfen, ob die Zeichenfolge 'ssid' im Text des Werts vorhanden ist oder nicht -

if "SSID" in value.text:
   bssid, ssid = value.text.split("\t")
   bssid = bssid[7:]
   ssid = ssid[6:]

Jetzt müssen wir BSSID, SSID und Zeitstempel wie folgt zum WLAN-Wörterbuch hinzufügen:

if bssid in wifi.keys():

wifi[bssid]["Timestamps"].append(ts)
   wifi[bssid]["SSID"].append(ssid)
else:
   wifi[bssid] = {"Timestamps": [ts], "SSID":
[ssid],"Wigle": {}}
return wifi

Der Textparser, der viel einfacher als der XML-Parser ist, wird unten gezeigt -

def parse_txt(txt_file):
   wifi = {}
   print("[+] Extracting MAC addresses from {}".format(txt_file))
   
   with open(txt_file) as mac_file:
      for line in mac_file:
         wifi[line.strip()] = {"Timestamps": ["N/A"], "SSID":
["N/A"],"Wigle": {}}
return wifi

Lassen Sie uns nun das Anforderungsmodul verwenden, um zu machen WIGLE APIruft an und muss weiter zum query_wigle() Methode -

def query_wigle(wifi_dictionary, out_csv, api_key):
   print("[+] Querying Wigle.net through Python API for {} "
"APs".format(len(wifi_dictionary)))
   for mac in wifi_dictionary:

   wigle_results = query_mac_addr(mac, api_key)
def query_mac_addr(mac_addr, api_key):

   query_url = "https://api.wigle.net/api/v2/network/search?" \
"onlymine = false&freenet = false&paynet = false" \ "&netid = {}".format(mac_addr)
   req = requests.get(query_url, auth = (api_key[0], api_key[1]))
   return req.json()

Tatsächlich gibt es ein Limit pro Tag für WIGLE-API-Aufrufe. Wenn dieses Limit überschritten wird, muss ein Fehler wie folgt angezeigt werden:

try:
   if wigle_results["resultCount"] == 0:
      wifi_dictionary[mac]["Wigle"]["results"] = []
         continue
   else:
      wifi_dictionary[mac]["Wigle"] = wigle_results
except KeyError:
   if wigle_results["error"] == "too many queries today":
      print("[-] Wigle daily query limit exceeded")
      wifi_dictionary[mac]["Wigle"]["results"] = []
      continue
   else:
      print("[-] Other error encountered for " "address {}: {}".format(mac,
wigle_results['error']))
   wifi_dictionary[mac]["Wigle"]["results"] = []
   continue
prep_output(out_csv, wifi_dictionary)

Jetzt werden wir verwenden prep_output() Methode, um das Wörterbuch in leicht beschreibbare Teile zu glätten -

def prep_output(output, data):
   csv_data = {}
   google_map = https://www.google.com/maps/search/

Greifen Sie jetzt wie folgt auf alle Daten zu, die wir gesammelt haben:

for x, mac in enumerate(data):
   for y, ts in enumerate(data[mac]["Timestamps"]):
      for z, result in enumerate(data[mac]["Wigle"]["results"]):
         shortres = data[mac]["Wigle"]["results"][z]
         g_map_url = "{}{},{}".format(google_map, shortres["trilat"],shortres["trilong"])

Jetzt können wir die Ausgabe in eine CSV-Datei schreiben, wie wir es in früheren Skripten in diesem Kapitel getan haben write_csv() Funktion.

In diesem Kapitel erfahren Sie ausführlich, wie Sie eingebettete Metadaten mithilfe der digitalen Python-Forensik untersuchen.

Einführung

Eingebettete Metadaten sind Informationen zu Daten, die in derselben Datei gespeichert sind, in der sich das von diesen Daten beschriebene Objekt befindet. Mit anderen Worten, es handelt sich um Informationen über ein digitales Asset, die in der digitalen Datei selbst gespeichert sind. Es ist immer mit der Datei verknüpft und kann niemals getrennt werden.

Bei der digitalen Forensik können wir nicht alle Informationen zu einer bestimmten Datei extrahieren. Auf der anderen Seite können eingebettete Metadaten uns wichtige Informationen für die Untersuchung liefern. Beispielsweise können die Metadaten einer Textdatei Informationen über den Autor, seine Länge, das geschriebene Datum und sogar eine kurze Zusammenfassung dieses Dokuments enthalten. Ein digitales Bild kann Metadaten wie die Länge des Bildes, die Verschlusszeit usw. enthalten.

Artefakte mit Metadatenattributen und deren Extraktion

In diesem Abschnitt lernen wir verschiedene Artefakte mit Metadatenattributen und deren Extraktionsprozess mit Python kennen.

Audio und Video

Dies sind die beiden sehr häufigen Artefakte, in die die Metadaten eingebettet sind. Diese Metadaten können zu Untersuchungszwecken extrahiert werden.

Mit dem folgenden Python-Skript können Sie allgemeine Attribute oder Metadaten aus Audio- oder MP3-Dateien und Video- oder MP4-Dateien extrahieren.

Beachten Sie, dass wir für dieses Skript eine Python-Bibliothek eines Drittanbieters mit dem Namen mutagen installieren müssen, mit der wir Metadaten aus Audio- und Videodateien extrahieren können. Es kann mit Hilfe des folgenden Befehls installiert werden -

pip install mutagen

Einige der nützlichen Bibliotheken, die wir für dieses Python-Skript importieren müssen, sind folgende:

from __future__ import print_function

import argparse
import json
import mutagen

Der Befehlszeilenhandler verwendet ein Argument, das den Pfad zu den MP3- oder MP4-Dateien darstellt. Dann werden wir verwendenmutagen.file() Methode zum Öffnen eines Handles für die Datei wie folgt:

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Python Metadata Extractor')
   parser.add_argument("AV_FILE", help="File to extract metadata from")
   args = parser.parse_args()
   av_file = mutagen.File(args.AV_FILE)
   file_ext = args.AV_FILE.rsplit('.', 1)[-1]
   
   if file_ext.lower() == 'mp3':
      handle_id3(av_file)
   elif file_ext.lower() == 'mp4':
      handle_mp4(av_file)

Jetzt müssen wir zwei Handles verwenden, eines zum Extrahieren der Daten aus MP3 und eines zum Extrahieren von Daten aus MP4-Dateien. Wir können diese Handles wie folgt definieren:

def handle_id3(id3_file):
   id3_frames = {'TIT2': 'Title', 'TPE1': 'Artist', 'TALB': 'Album','TXXX':
      'Custom', 'TCON': 'Content Type', 'TDRL': 'Date released','COMM': 'Comments',
         'TDRC': 'Recording Date'}
   print("{:15} | {:15} | {:38} | {}".format("Frame", "Description","Text","Value"))
   print("-" * 85)
   
   for frames in id3_file.tags.values():
      frame_name = id3_frames.get(frames.FrameID, frames.FrameID)
      desc = getattr(frames, 'desc', "N/A")
      text = getattr(frames, 'text', ["N/A"])[0]
      value = getattr(frames, 'value', "N/A")
      
      if "date" in frame_name.lower():
         text = str(text)
      print("{:15} | {:15} | {:38} | {}".format(
         frame_name, desc, text, value))
def handle_mp4(mp4_file):
   cp_sym = u"\u00A9"
   qt_tag = {
      cp_sym + 'nam': 'Title', cp_sym + 'art': 'Artist',
      cp_sym + 'alb': 'Album', cp_sym + 'gen': 'Genre',
      'cpil': 'Compilation', cp_sym + 'day': 'Creation Date',
      'cnID': 'Apple Store Content ID', 'atID': 'Album Title ID',
      'plID': 'Playlist ID', 'geID': 'Genre ID', 'pcst': 'Podcast',
      'purl': 'Podcast URL', 'egid': 'Episode Global ID',
      'cmID': 'Camera ID', 'sfID': 'Apple Store Country',
      'desc': 'Description', 'ldes': 'Long Description'}
genre_ids = json.load(open('apple_genres.json'))

Jetzt müssen wir diese MP4-Datei wie folgt durchlaufen:

print("{:22} | {}".format('Name', 'Value'))
print("-" * 40)

for name, value in mp4_file.tags.items():
   tag_name = qt_tag.get(name, name)
   
   if isinstance(value, list):
      value = "; ".join([str(x) for x in value])
   if name == 'geID':
      value = "{}: {}".format(
      value, genre_ids[str(value)].replace("|", " - "))
   print("{:22} | {}".format(tag_name, value))

Das obige Skript gibt uns zusätzliche Informationen zu MP3- und MP4-Dateien.

Bilder

Bilder können je nach Dateiformat unterschiedliche Arten von Metadaten enthalten. Die meisten Bilder enthalten jedoch GPS-Informationen. Wir können diese GPS-Informationen mithilfe von Python-Bibliotheken von Drittanbietern extrahieren. Sie können das folgende Python-Skript verwenden, um dasselbe zu tun:

Laden Sie zunächst die Python-Bibliothek eines Drittanbieters mit dem Namen herunter Python Imaging Library (PIL) wie folgt -

pip install pillow

Dies hilft uns, Metadaten aus Bildern zu extrahieren.

Wir können auch die in Bilder eingebetteten GPS-Details in die KML-Datei schreiben, dafür müssen wir jedoch die Python-Bibliothek eines Drittanbieters mit dem Namen herunterladen simplekml wie folgt -

pip install simplekml

In diesem Skript müssen wir zuerst die folgenden Bibliotheken importieren:

from __future__ import print_function
import argparse

from PIL import Image
from PIL.ExifTags import TAGS

import simplekml
import sys

Jetzt akzeptiert der Befehlszeilenhandler ein Positionsargument, das im Wesentlichen den Dateipfad der Fotos darstellt.

parser = argparse.ArgumentParser('Metadata from images')
parser.add_argument('PICTURE_FILE', help = "Path to picture")
args = parser.parse_args()

Jetzt müssen wir die URLs angeben, die die Koordinateninformationen füllen. Die URLs sindgmaps und open_maps. Wir benötigen auch eine Funktion, um die von der PIL-Bibliothek bereitgestellte DMS-Tupelkoordinate (Grad Minute Sekunden) in Dezimalzahlen umzuwandeln. Dies kann wie folgt erfolgen:

gmaps = "https://www.google.com/maps?q={},{}"
open_maps = "http://www.openstreetmap.org/?mlat={}&mlon={}"

def process_coords(coord):
   coord_deg = 0
   
   for count, values in enumerate(coord):
      coord_deg += (float(values[0]) / values[1]) / 60**count
   return coord_deg

Jetzt werden wir verwenden image.open() Funktion zum Öffnen der Datei als PIL-Objekt.

img_file = Image.open(args.PICTURE_FILE)
exif_data = img_file._getexif()

if exif_data is None:
   print("No EXIF data found")
   sys.exit()
for name, value in exif_data.items():
   gps_tag = TAGS.get(name, name)
   if gps_tag is not 'GPSInfo':
      continue

Nach dem Finden der GPSInfo Tag speichern wir die GPS-Referenz und verarbeiten die Koordinaten mit dem process_coords() Methode.

lat_ref = value[1] == u'N'
lat = process_coords(value[2])

if not lat_ref:
   lat = lat * -1
lon_ref = value[3] == u'E'
lon = process_coords(value[4])

if not lon_ref:
   lon = lon * -1

Nun initiieren kml Objekt aus simplekml Bibliothek wie folgt -

kml = simplekml.Kml()
kml.newpoint(name = args.PICTURE_FILE, coords = [(lon, lat)])
kml.save(args.PICTURE_FILE + ".kml")

Wir können jetzt die Koordinaten aus verarbeiteten Informationen wie folgt drucken:

print("GPS Coordinates: {}, {}".format(lat, lon))
print("Google Maps URL: {}".format(gmaps.format(lat, lon)))
print("OpenStreetMap URL: {}".format(open_maps.format(lat, lon)))
print("KML File {} created".format(args.PICTURE_FILE + ".kml"))

PDF-Dokumente

PDF-Dokumente verfügen über eine Vielzahl von Medien, einschließlich Bilder, Text, Formulare usw. Wenn wir eingebettete Metadaten in PDF-Dokumente extrahieren, erhalten wir die resultierenden Daten möglicherweise im Format Extensible Metadata Platform (XMP). Wir können Metadaten mit Hilfe des folgenden Python-Codes extrahieren -

Installieren Sie zunächst eine Python-Bibliothek eines Drittanbieters mit dem Namen PyPDF2zum Lesen von Metadaten, die im XMP-Format gespeichert sind. Es kann wie folgt installiert werden:

pip install PyPDF2

Importieren Sie nun die folgenden Bibliotheken, um die Metadaten aus PDF-Dateien zu extrahieren:

from __future__ import print_function
from argparse import ArgumentParser, FileType

import datetime
from PyPDF2 import PdfFileReader
import sys

Jetzt akzeptiert der Befehlszeilenhandler ein Positionsargument, das im Wesentlichen den Dateipfad der PDF-Datei darstellt.

parser = argparse.ArgumentParser('Metadata from PDF')
parser.add_argument('PDF_FILE', help='Path to PDF file',type=FileType('rb'))
args = parser.parse_args()

Jetzt können wir verwenden getXmpMetadata() Methode zum Bereitstellen eines Objekts mit den verfügbaren Metadaten wie folgt:

pdf_file = PdfFileReader(args.PDF_FILE)
xmpm = pdf_file.getXmpMetadata()

if xmpm is None:
   print("No XMP metadata found in document.")
   sys.exit()

Wir können benutzen custom_print() Methode zum Extrahieren und Drucken der relevanten Werte wie Titel, Ersteller, Mitwirkender usw. wie folgt:

custom_print("Title: {}", xmpm.dc_title)
custom_print("Creator(s): {}", xmpm.dc_creator)
custom_print("Contributors: {}", xmpm.dc_contributor)
custom_print("Subject: {}", xmpm.dc_subject)
custom_print("Description: {}", xmpm.dc_description)
custom_print("Created: {}", xmpm.xmp_createDate)
custom_print("Modified: {}", xmpm.xmp_modifyDate)
custom_print("Event Dates: {}", xmpm.dc_date)

Wir können auch definieren custom_print() Methode für den Fall, dass PDF mit mehreren Software wie folgt erstellt wird -

def custom_print(fmt_str, value):
   if isinstance(value, list):
      print(fmt_str.format(", ".join(value)))
   elif isinstance(value, dict):
      fmt_value = [":".join((k, v)) for k, v in value.items()]
      print(fmt_str.format(", ".join(value)))
   elif isinstance(value, str) or isinstance(value, bool):
      print(fmt_str.format(value))
   elif isinstance(value, bytes):
      print(fmt_str.format(value.decode()))
   elif isinstance(value, datetime.datetime):
      print(fmt_str.format(value.isoformat()))
   elif value is None:
      print(fmt_str.format("N/A"))
   else:
      print("warn: unhandled type {} found".format(type(value)))

Wir können auch jede andere von der Software gespeicherte benutzerdefinierte Eigenschaft wie folgt extrahieren:

if xmpm.custom_properties:
   print("Custom Properties:")
   
   for k, v in xmpm.custom_properties.items():
      print("\t{}: {}".format(k, v))

Das obige Skript liest das PDF-Dokument und druckt die im XMP-Format gespeicherten Metadaten einschließlich einiger benutzerdefinierter Eigenschaften, die von der Software gespeichert wurden, mit deren Hilfe das PDF erstellt wurde.

Windows Executables-Dateien

Manchmal können wir auf eine verdächtige oder nicht autorisierte ausführbare Datei stoßen. Für Untersuchungszwecke kann es jedoch aufgrund der eingebetteten Metadaten nützlich sein. Wir können Informationen wie den Speicherort, den Zweck und andere Attribute wie Hersteller, Kompilierungsdatum usw. abrufen. Mithilfe des folgenden Python-Skripts können wir das Kompilierungsdatum, nützliche Daten aus Kopfzeilen und importierte sowie exportierte Symbole abrufen.

Installieren Sie zu diesem Zweck zuerst die Python-Bibliothek eines Drittanbieters pefile. Dies kann wie folgt erfolgen:

pip install pefile

Importieren Sie nach erfolgreicher Installation die folgenden Bibliotheken wie folgt:

from __future__ import print_function

import argparse
from datetime import datetime
from pefile import PE

Jetzt akzeptiert der Befehlszeilenhandler ein Positionsargument, das im Wesentlichen den Dateipfad der ausführbaren Datei darstellt. Sie können auch den Ausgabestil auswählen, unabhängig davon, ob Sie ihn detailliert und ausführlich oder vereinfacht benötigen. Dazu müssen Sie ein optionales Argument angeben, wie unten gezeigt -

parser = argparse.ArgumentParser('Metadata from executable file')
parser.add_argument("EXE_FILE", help = "Path to exe file")
parser.add_argument("-v", "--verbose", help = "Increase verbosity of output",
action = 'store_true', default = False)
args = parser.parse_args()

Jetzt laden wir die ausführbare Eingabedatei mithilfe der PE-Klasse. Wir werden auch die ausführbaren Daten mithilfe von in ein Wörterbuchobjekt sicherndump_dict() Methode.

pe = PE(args.EXE_FILE)
ped = pe.dump_dict()

Mit dem unten gezeigten Code können wir grundlegende Dateimetadaten wie eingebettete Autorenschaft, Version und Kompilierungszeit extrahieren.

file_info = {}
for structure in pe.FileInfo:
   if structure.Key == b'StringFileInfo':
      for s_table in structure.StringTable:
         for key, value in s_table.entries.items():
            if value is None or len(value) == 0:
               value = "Unknown"
            file_info[key] = value
print("File Information: ")
print("==================")

for k, v in file_info.items():
   if isinstance(k, bytes):
      k = k.decode()
   if isinstance(v, bytes):
      v = v.decode()
   print("{}: {}".format(k, v))
comp_time = ped['FILE_HEADER']['TimeDateStamp']['Value']
comp_time = comp_time.split("[")[-1].strip("]")
time_stamp, timezone = comp_time.rsplit(" ", 1)
comp_time = datetime.strptime(time_stamp, "%a %b %d %H:%M:%S %Y")
print("Compiled on {} {}".format(comp_time, timezone.strip()))

Wir können die nützlichen Daten wie folgt aus den Headern extrahieren:

for section in ped['PE Sections']:
   print("Section '{}' at {}: {}/{} {}".format(
      section['Name']['Value'], hex(section['VirtualAddress']['Value']),
      section['Misc_VirtualSize']['Value'],
      section['SizeOfRawData']['Value'], section['MD5'])
   )

Extrahieren Sie nun die Liste der Importe und Exporte aus ausführbaren Dateien wie unten gezeigt -

if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
   print("\nImports: ")
   print("=========")
   
   for dir_entry in pe.DIRECTORY_ENTRY_IMPORT:
      dll = dir_entry.dll
      
      if not args.verbose:
         print(dll.decode(), end=", ")
         continue
      name_list = []
      
      for impts in dir_entry.imports:
         if getattr(impts, "name", b"Unknown") is None:
            name = b"Unknown"
         else:
            name = getattr(impts, "name", b"Unknown")
			name_list.append([name.decode(), hex(impts.address)])
      name_fmt = ["{} ({})".format(x[0], x[1]) for x in name_list]
      print('- {}: {}'.format(dll.decode(), ", ".join(name_fmt)))
   if not args.verbose:
      print()

Jetzt drucken exports, names und addresses Verwenden Sie den Code wie unten gezeigt -

if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
   print("\nExports: ")
   print("=========")
   
   for sym in pe.DIRECTORY_ENTRY_EXPORT.symbols:
      print('- {}: {}'.format(sym.name.decode(), hex(sym.address)))

Das obige Skript extrahiert die grundlegenden Metadaten, Informationen aus Headern aus ausführbaren Windows-Dateien.

Office-Dokument-Metadaten

Die meiste Arbeit am Computer wird in drei Anwendungen von MS Office ausgeführt - Word, PowerPoint und Excel. Diese Dateien verfügen über riesige Metadaten, die interessante Informationen über ihre Urheberschaft und Geschichte enthalten können.

Beachten Sie, dass Metadaten aus dem 2007er Format von Word (.docx), Excel (.xlsx) und Powerpoint (.pptx) in einer XML-Datei gespeichert sind. Wir können diese XML-Dateien in Python mithilfe des folgenden Python-Skripts verarbeiten:

Importieren Sie zunächst die erforderlichen Bibliotheken wie unten gezeigt -

from __future__ import print_function
from argparse import ArgumentParser
from datetime import datetime as dt
from xml.etree import ElementTree as etree

import zipfile
parser = argparse.ArgumentParser('Office Document Metadata’)
parser.add_argument("Office_File", help="Path to office file to read")
args = parser.parse_args()

Überprüfen Sie nun, ob es sich bei der Datei um eine ZIP-Datei handelt. Andernfalls wird ein Fehler ausgelöst. Öffnen Sie nun die Datei und extrahieren Sie die Schlüsselelemente für die Verarbeitung mit dem folgenden Code:

zipfile.is_zipfile(args.Office_File)
zfile = zipfile.ZipFile(args.Office_File)
core_xml = etree.fromstring(zfile.read('docProps/core.xml'))
app_xml = etree.fromstring(zfile.read('docProps/app.xml'))

Erstellen Sie nun ein Wörterbuch, um die Extraktion der Metadaten zu starten -

core_mapping = {
   'title': 'Title',
   'subject': 'Subject',
   'creator': 'Author(s)',
   'keywords': 'Keywords',
   'description': 'Description',
   'lastModifiedBy': 'Last Modified By',
   'modified': 'Modified Date',
   'created': 'Created Date',
   'category': 'Category',
   'contentStatus': 'Status',
   'revision': 'Revision'
}

Verwenden iterchildren() Methode, um auf jedes der Tags in der XML-Datei zuzugreifen -

for element in core_xml.getchildren():
   for key, title in core_mapping.items():
      if key in element.tag:
         if 'date' in title.lower():
            text = dt.strptime(element.text, "%Y-%m-%dT%H:%M:%SZ")
         else:
            text = element.text
         print("{}: {}".format(title, text))

Führen Sie dies in ähnlicher Weise für die Datei app.xml aus, die statistische Informationen zum Inhalt des Dokuments enthält.

app_mapping = {
   'TotalTime': 'Edit Time (minutes)',
   'Pages': 'Page Count',
   'Words': 'Word Count',
   'Characters': 'Character Count',
   'Lines': 'Line Count',
   'Paragraphs': 'Paragraph Count',
   'Company': 'Company',
   'HyperlinkBase': 'Hyperlink Base',
   'Slides': 'Slide count',
   'Notes': 'Note Count',
   'HiddenSlides': 'Hidden Slide Count',
}
for element in app_xml.getchildren():
   for key, title in app_mapping.items():
      if key in element.tag:
         if 'date' in title.lower():
            text = dt.strptime(element.text, "%Y-%m-%dT%H:%M:%SZ")
         else:
            text = element.text
         print("{}: {}".format(title, text))

Nachdem wir das obige Skript ausgeführt haben, können wir nun die verschiedenen Details zu dem bestimmten Dokument abrufen. Beachten Sie, dass wir dieses Skript nur auf Office 2007-Dokumente oder höher anwenden können.

In diesem Kapitel werden die Grundlagen für die Durchführung der Netzwerkforensik mit Python erläutert.

Grundlegendes zur Netzwerkforensik

Die Netzwerkforensik ist ein Zweig der digitalen Forensik, der sich mit der Überwachung und Analyse des lokalen und des WAN-Netzwerks (Wide Area Network) zum Zwecke der Informationserfassung, Beweiserfassung oder Erkennung von Eindringlingen befasst. Netzwerkforensik spielt eine entscheidende Rolle bei der Untersuchung digitaler Verbrechen wie Diebstahl von geistigem Eigentum oder Informationsverlust. Ein Bild der Netzwerkkommunikation hilft einem Ermittler, einige wichtige Fragen wie folgt zu lösen:

  • Auf welche Websites wurde zugegriffen?

  • Welche Art von Inhalten wurde in unser Netzwerk hochgeladen?

  • Welche Art von Inhalten wurde von unserem Netzwerk heruntergeladen?

  • Auf welche Server wird zugegriffen?

  • Sendet jemand vertrauliche Informationen außerhalb der Firewalls des Unternehmens?

Internet Evidence Finder (IEF)

IEF ist ein digitales forensisches Tool zum Auffinden, Analysieren und Präsentieren digitaler Beweise, die auf verschiedenen digitalen Medien wie Computern, Smartphones, Tablets usw. gefunden wurden. Es ist sehr beliebt und wird von Tausenden von Forensikern verwendet.

Verwendung von IEF

Aufgrund seiner Beliebtheit wird IEF in großem Umfang von Forensikern eingesetzt. Einige der Verwendungen von IEF sind wie folgt:

  • Aufgrund seiner leistungsstarken Suchfunktionen werden mehrere Dateien oder Datenmedien gleichzeitig durchsucht.

  • Es wird auch verwendet, um gelöschte Daten aus dem nicht zugewiesenen RAM-Speicher durch neue Carving-Techniken wiederherzustellen.

  • Wenn Ermittler Webseiten zum Zeitpunkt ihrer Eröffnung in ihrem ursprünglichen Format neu erstellen möchten, können sie IEF verwenden.

  • Es wird auch zum Durchsuchen logischer oder physischer Datenträger verwendet.

Dumping von Berichten von IEF zu CSV mit Python

IEF speichert Daten in einer SQLite-Datenbank. Das folgende Python-Skript identifiziert die Ergebnistabellen in der IEF-Datenbank dynamisch und speichert sie in den entsprechenden CSV-Dateien.

Dieser Vorgang wird in den unten gezeigten Schritten ausgeführt

  • Generieren Sie zunächst eine IEF-Ergebnisdatenbank, bei der es sich um eine SQLite-Datenbankdatei handelt, die mit der Erweiterung .db endet.

  • Fragen Sie dann diese Datenbank ab, um alle Tabellen zu identifizieren.

  • Zuletzt schreiben Sie diese Ergebnistabellen in eine einzelne CSV-Datei.

Python-Code

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

Importieren Sie für Python-Skripte die erforderlichen Bibliotheken wie folgt:

from __future__ import print_function

import argparse
import csv
import os
import sqlite3
import sys

Jetzt müssen wir den Pfad zur IEF-Datenbankdatei angeben -

if __name__ == '__main__':
   parser = argparse.ArgumentParser('IEF to CSV')
   parser.add_argument("IEF_DATABASE", help="Input IEF database")
   parser.add_argument("OUTPUT_DIR", help="Output DIR")
   args = parser.parse_args()

Nun werden wir die Existenz der IEF-Datenbank wie folgt bestätigen:

if not os.path.exists(args.OUTPUT_DIR):
   os.makedirs(args.OUTPUT_DIR)
if os.path.exists(args.IEF_DATABASE) and \ os.path.isfile(args.IEF_DATABASE):
   main(args.IEF_DATABASE, args.OUTPUT_DIR)
else:
   print("[-] Supplied input file {} does not exist or is not a " "file".format(args.IEF_DATABASE))
   sys.exit(1)

Stellen Sie nun wie in früheren Skripten die Verbindung zur SQLite-Datenbank wie folgt her, um die Abfragen über den Cursor auszuführen:

def main(database, out_directory):
   print("[+] Connecting to SQLite database")
   conn = sqlite3.connect(database)
   c = conn.cursor()

Die folgenden Codezeilen rufen die Namen der Tabellen aus der Datenbank ab -

print("List of all tables to extract")
c.execute("select * from sqlite_master where type = 'table'")
tables = [x[2] for x in c.fetchall() if not x[2].startswith('_') and not x[2].endswith('_DATA')]

Jetzt werden wir alle Daten aus der Tabelle auswählen und verwenden fetchall() Methode auf dem Cursor-Objekt speichern wir die Liste der Tupel, die die Daten der Tabelle in ihrer Gesamtheit enthalten, in einer Variablen -

print("Dumping {} tables to CSV files in {}".format(len(tables), out_directory))

for table in tables:
c.execute("pragma table_info('{}')".format(table))
table_columns = [x[1] for x in c.fetchall()]

c.execute("select * from '{}'".format(table))
table_data = c.fetchall()

Jetzt mit CSV_Writer() Methode werden wir den Inhalt in CSV-Datei schreiben -

csv_name = table + '.csv'
csv_path = os.path.join(out_directory, csv_name)
print('[+] Writing {} table to {} CSV file'.format(table,csv_name))

with open(csv_path, "w", newline = "") as csvfile:
   csv_writer = csv.writer(csvfile)
   csv_writer.writerow(table_columns)
   csv_writer.writerows(table_data)

Das obige Skript ruft alle Daten aus Tabellen der IEF-Datenbank ab und schreibt den Inhalt in die CSV-Datei unserer Wahl.

Arbeiten mit zwischengespeicherten Daten

Aus der IEF-Ergebnisdatenbank können wir weitere Informationen abrufen, die nicht unbedingt von IEF selbst unterstützt werden. Mithilfe der IEF-Ergebnisdatenbank können wir die zwischengespeicherten Daten, ein Bi-Produkt zur Information, von E-Mail-Dienstanbietern wie Yahoo, Google usw. abrufen.

Das folgende Python-Skript ermöglicht den Zugriff auf die zwischengespeicherten Dateninformationen aus Yahoo Mail, auf die über Google Chrome zugegriffen wird, mithilfe der IEF-Datenbank. Beachten Sie, dass die Schritte mehr oder weniger den im letzten Python-Skript beschriebenen entsprechen.

Importieren Sie zunächst die erforderlichen Bibliotheken für Python wie folgt:

from __future__ import print_function
import argparse
import csv
import os
import sqlite3
import sys
import json

Geben Sie nun den Pfad zur IEF-Datenbankdatei zusammen mit zwei Positionsargumenten an, die vom Befehlszeilenhandler akzeptiert werden, wie im letzten Skript ausgeführt.

if __name__ == '__main__':
   parser = argparse.ArgumentParser('IEF to CSV')
   parser.add_argument("IEF_DATABASE", help="Input IEF database")
   parser.add_argument("OUTPUT_DIR", help="Output DIR")
   args = parser.parse_args()

Bestätigen Sie nun die Existenz der IEF-Datenbank wie folgt:

directory = os.path.dirname(args.OUTPUT_CSV)

if not os.path.exists(directory):os.makedirs(directory)
if os.path.exists(args.IEF_DATABASE) and \ os.path.isfile(args.IEF_DATABASE):
   main(args.IEF_DATABASE, args.OUTPUT_CSV)
   else: print("Supplied input file {} does not exist or is not a " "file".format(args.IEF_DATABASE))
sys.exit(1)

Stellen Sie nun die Verbindung mit der SQLite-Datenbank wie folgt her, um die Abfragen über den Cursor auszuführen:

def main(database, out_csv):
   print("[+] Connecting to SQLite database")
   conn = sqlite3.connect(database)
   c = conn.cursor()

Sie können die folgenden Codezeilen verwenden, um die Instanzen des Yahoo Mail-Kontaktcache-Datensatzes abzurufen:

print("Querying IEF database for Yahoo Contact Fragments from " "the Chrome Cache Records Table")
   try:
      c.execute("select * from 'Chrome Cache Records' where URL like " "'https://data.mail.yahoo.com" "/classicab/v2/contacts/?format=json%'")
   except sqlite3.OperationalError:
      print("Received an error querying the database --    database may be" "corrupt or not have a Chrome Cache Records table")
      sys.exit(2)

Nun wird die Liste der von der obigen Abfrage zurückgegebenen Tupel wie folgt in einer Variablen gespeichert:

contact_cache = c.fetchall()
contact_data = process_contacts(contact_cache)
write_csv(contact_data, out_csv)

Beachten Sie, dass wir hier nämlich zwei Methoden verwenden werden process_contacts() zum Einrichten der Ergebnisliste sowie zum Durchlaufen jedes Kontakt-Cache-Datensatzes und json.loads() um die aus der Tabelle extrahierten JSON-Daten zur weiteren Bearbeitung in einer Variablen zu speichern -

def process_contacts(contact_cache):
   print("[+] Processing {} cache files matching Yahoo contact cache " " data".format(len(contact_cache)))
   results = []
   
   for contact in contact_cache:
      url = contact[0]
      first_visit = contact[1]
      last_visit = contact[2]
      last_sync = contact[3]
      loc = contact[8]
	   contact_json = json.loads(contact[7].decode())
      total_contacts = contact_json["total"]
      total_count = contact_json["count"]
      
      if "contacts" not in contact_json:
         continue
      for c in contact_json["contacts"]:
         name, anni, bday, emails, phones, links = ("", "", "", "", "", "")
            if "name" in c:
            name = c["name"]["givenName"] + " " + \ c["name"]["middleName"] + " " + c["name"]["familyName"]
            
            if "anniversary" in c:
            anni = c["anniversary"]["month"] + \"/" + c["anniversary"]["day"] + "/" + \c["anniversary"]["year"]
            
            if "birthday" in c:
            bday = c["birthday"]["month"] + "/" + \c["birthday"]["day"] + "/" + c["birthday"]["year"]
            
            if "emails" in c:
               emails = ', '.join([x["ep"] for x in c["emails"]])
            
            if "phones" in c:
               phones = ', '.join([x["ep"] for x in c["phones"]])
            
            if "links" in c:
              links = ', '.join([x["ep"] for x in c["links"]])

Für Firma, Titel und Notizen wird nun die get-Methode wie unten gezeigt verwendet -

company = c.get("company", "")
title = c.get("jobTitle", "")
notes = c.get("notes", "")

Lassen Sie uns nun die Liste der Metadaten und extrahierten Datenelemente wie folgt an die Ergebnisliste anhängen:

results.append([url, first_visit, last_visit, last_sync, loc, name, bday,anni, emails, phones, links, company, title, notes,total_contacts, total_count])
return results

Jetzt mit CSV_Writer() Methode werden wir den Inhalt in CSV-Datei schreiben -

def write_csv(data, output):
   print("[+] Writing {} contacts to {}".format(len(data), output))
   with open(output, "w", newline="") as csvfile:
      csv_writer = csv.writer(csvfile)
      csv_writer.writerow([
         "URL", "First Visit (UTC)", "Last Visit (UTC)",
         "Last Sync (UTC)", "Location", "Contact Name", "Bday",
         "Anniversary", "Emails", "Phones", "Links", "Company", "Title",
         "Notes", "Total Contacts", "Count of Contacts in Cache"])
      csv_writer.writerows(data)

Mit Hilfe des obigen Skripts können wir die zwischengespeicherten Daten aus Yahoo Mail mithilfe der IEF-Datenbank verarbeiten.

Das vorherige Kapitel befasste sich mit einigen Konzepten der Netzwerkforensik unter Verwendung von Python. Lassen Sie uns in diesem Kapitel die Netzwerkforensik mit Python auf einer tieferen Ebene verstehen.

Webseitenerhaltung mit schöner Suppe

Das World Wide Web (WWW) ist eine einzigartige Informationsquelle. Das Erbe ist jedoch aufgrund des alarmierenden Inhaltsverlusts einem hohen Risiko ausgesetzt. Eine Reihe von Kulturerbe- und akademischen Institutionen, gemeinnützigen Organisationen und privaten Unternehmen haben die damit verbundenen Probleme untersucht und zur Entwicklung technischer Lösungen für die Webarchivierung beigetragen.

Bei der Aufbewahrung von Webseiten oder der Webarchivierung werden die Daten aus dem World Wide Web gesammelt, um sicherzustellen, dass die Daten in einem Archiv aufbewahrt werden, und um sie zukünftigen Forschern, Historikern und der Öffentlichkeit zur Verfügung zu stellen. Bevor wir mit der Aufbewahrung von Webseiten fortfahren, wollen wir einige wichtige Fragen im Zusammenhang mit der Aufbewahrung von Webseiten erörtern, wie unten angegeben:

  • Change in Web Resources - Webressourcen ändern sich täglich, was eine Herausforderung für die Erhaltung von Webseiten darstellt.

  • Large Quantity of Resources - Ein weiteres Problem im Zusammenhang mit der Aufbewahrung von Webseiten ist die große Menge an Ressourcen, die erhalten bleiben sollen.

  • Integrity - Webseiten müssen vor unbefugten Änderungen, Löschungen oder Entfernungen geschützt werden, um ihre Integrität zu schützen.

  • Dealing with multimedia data - Während wir Webseiten beibehalten, müssen wir uns auch mit Multimediadaten befassen, und dies kann dabei zu Problemen führen.

  • Providing access - Neben dem Erhalt muss auch das Problem der Bereitstellung des Zugriffs auf Webressourcen und der Behandlung von Eigentumsfragen gelöst werden.

In diesem Kapitel verwenden wir die Python-Bibliothek mit dem Namen Beautiful Soup zur Aufbewahrung von Webseiten.

Was ist schöne Suppe?

Beautiful Soup ist eine Python-Bibliothek zum Abrufen von Daten aus HTML- und XML-Dateien. Es kann mit verwendet werdenurlibweil es eine Eingabe (Dokument oder URL) benötigt, um ein Suppenobjekt zu erstellen, da es die Webseite selbst nicht abrufen kann. Weitere Informationen hierzu finden Sie unter www.crummy.com/software/BeautifulSoup/bs4/doc/.

Beachten Sie, dass wir vor der Verwendung eine Bibliothek eines Drittanbieters mit dem folgenden Befehl installieren müssen:

pip install bs4

Als nächstes können wir mit dem Anaconda-Paketmanager Beautiful Soup wie folgt installieren:

conda install -c anaconda beautifulsoup4

Python-Skript zum Speichern von Webseiten

Das Python-Skript zum Speichern von Webseiten mithilfe der Drittanbieter-Bibliothek Beautiful Soup wird hier erläutert.

Importieren Sie zunächst die erforderlichen Bibliotheken wie folgt:

from __future__ import print_function
import argparse

from bs4 import BeautifulSoup, SoupStrainer
from datetime import datetime

import hashlib
import logging
import os
import ssl
import sys
from urllib.request import urlopen

import urllib.error
logger = logging.getLogger(__name__)

Beachten Sie, dass dieses Skript zwei Positionsargumente akzeptiert, eines ist die URL, die beibehalten werden soll, und das andere ist das gewünschte Ausgabeverzeichnis, wie unten gezeigt -

if __name__ == "__main__":
   parser = argparse.ArgumentParser('Web Page preservation')
   parser.add_argument("DOMAIN", help="Website Domain")
   parser.add_argument("OUTPUT_DIR", help="Preservation Output Directory")
   parser.add_argument("-l", help="Log file path",
   default=__file__[:-3] + ".log")
   args = parser.parse_args()

Richten Sie nun die Protokollierung für das Skript ein, indem Sie einen Datei- und Stream-Handler für die Schleife angeben und den Erfassungsprozess wie gezeigt dokumentieren.

logger.setLevel(logging.DEBUG)
msg_fmt = logging.Formatter("%(asctime)-15s %(funcName)-10s""%(levelname)-8s %(message)s")
strhndl = logging.StreamHandler(sys.stderr)
strhndl.setFormatter(fmt=msg_fmt)
fhndl = logging.FileHandler(args.l, mode='a')
fhndl.setFormatter(fmt=msg_fmt)

logger.addHandler(strhndl)
logger.addHandler(fhndl)
logger.info("Starting BS Preservation")
logger.debug("Supplied arguments: {}".format(sys.argv[1:]))
logger.debug("System " + sys.platform)
logger.debug("Version " + sys.version)

Lassen Sie uns nun die Eingabevalidierung für das gewünschte Ausgabeverzeichnis wie folgt durchführen:

if not os.path.exists(args.OUTPUT_DIR):
   os.makedirs(args.OUTPUT_DIR)
main(args.DOMAIN, args.OUTPUT_DIR)

Nun werden wir die definieren main() Funktion, die den Basisnamen der Website extrahiert, indem die unnötigen Elemente vor dem tatsächlichen Namen entfernt und die Eingabe-URL wie folgt zusätzlich überprüft werden:

def main(website, output_dir):
   base_name = website.replace("https://", "").replace("http://", "").replace("www.", "")
   link_queue = set()
   
   if "http://" not in website and "https://" not in website:
      logger.error("Exiting preservation - invalid user input: {}".format(website))
      sys.exit(1)
   logger.info("Accessing {} webpage".format(website))
   context = ssl._create_unverified_context()

Jetzt müssen wir eine Verbindung mit der URL mithilfe der urlopen () -Methode herstellen. Verwenden wir den Try-Except-Block wie folgt:

try:
   index = urlopen(website, context=context).read().decode("utf-8")
except urllib.error.HTTPError as e:
   logger.error("Exiting preservation - unable to access page: {}".format(website))
   sys.exit(2)
logger.debug("Successfully accessed {}".format(website))

Die nächsten Codezeilen enthalten drei Funktionen, wie unten erläutert -

  • write_output() um die erste Webseite in das Ausgabeverzeichnis zu schreiben

  • find_links() Funktion zum Identifizieren der Links auf dieser Webseite

  • recurse_pages() Funktion zum Durchlaufen und Erkennen aller Links auf der Webseite.

write_output(website, index, output_dir)
link_queue = find_links(base_name, index, link_queue)
logger.info("Found {} initial links on webpage".format(len(link_queue)))
recurse_pages(website, link_queue, context, output_dir)
logger.info("Completed preservation of {}".format(website))

Lassen Sie uns nun definieren write_output() Methode wie folgt -

def write_output(name, data, output_dir, counter=0):
   name = name.replace("http://", "").replace("https://", "").rstrip("//")
   directory = os.path.join(output_dir, os.path.dirname(name))
   
   if not os.path.exists(directory) and os.path.dirname(name) != "":
      os.makedirs(directory)

Wir müssen einige Details über die Webseite protokollieren und dann den Hash der Daten mithilfe von protokollieren hash_data() Methode wie folgt -

logger.debug("Writing {} to {}".format(name, output_dir)) logger.debug("Data Hash: {}".format(hash_data(data)))
path = os.path.join(output_dir, name)
path = path + "_" + str(counter)
with open(path, "w") as outfile:
   outfile.write(data)
logger.debug("Output File Hash: {}".format(hash_file(path)))

Definieren Sie nun hash_data() Methode, mit deren Hilfe wir die lesen UTF-8 verschlüsselte Daten und generieren dann die SHA-256 Hash davon wie folgt -

def hash_data(data):
   sha256 = hashlib.sha256()
   sha256.update(data.encode("utf-8"))
   return sha256.hexdigest()
def hash_file(file):
   sha256 = hashlib.sha256()
   with open(file, "rb") as in_file:
      sha256.update(in_file.read())
return sha256.hexdigest()

Lassen Sie uns nun eine erstellen Beautifulsoup Objekt aus den Webseitendaten unter find_links() Methode wie folgt -

def find_links(website, page, queue):
   for link in BeautifulSoup(page, "html.parser",parse_only = SoupStrainer("a", href = True)):
      if website in link.get("href"):
         if not os.path.basename(link.get("href")).startswith("#"):
            queue.add(link.get("href"))
   return queue

Jetzt müssen wir definieren recurse_pages() Methode durch Bereitstellung der Eingaben der Website-URL, der aktuellen Link-Warteschlange, des nicht verifizierten SSL-Kontexts und des Ausgabeverzeichnisses wie folgt:

def recurse_pages(website, queue, context, output_dir):
   processed = []
   counter = 0
   
   while True:
      counter += 1
      if len(processed) == len(queue):
         break
      for link in queue.copy(): if link in processed:
         continue
	   processed.append(link)
      try:
      page = urlopen(link,      context=context).read().decode("utf-8")
      except urllib.error.HTTPError as e:
         msg = "Error accessing webpage: {}".format(link)
         logger.error(msg)
         continue

Schreiben Sie nun die Ausgabe jeder Webseite, auf die in einer Datei zugegriffen wird, indem Sie den Linknamen, die Seitendaten, das Ausgabeverzeichnis und den Zähler wie folgt übergeben:

write_output(link, page, output_dir, counter)
queue = find_links(website, page, queue)
logger.info("Identified {} links throughout website".format(
   len(queue)))

Wenn wir dieses Skript ausführen, indem wir die URL der Website, das Ausgabeverzeichnis und einen Pfad zur Protokolldatei angeben, erhalten wir die Details zu dieser Webseite, die für die zukünftige Verwendung verwendet werden können.

Virusjagd

Haben Sie sich jemals gefragt, wie forensische Analysten, Sicherheitsforscher und Befragte den Unterschied zwischen nützlicher Software und Malware verstehen können? Die Antwort liegt in der Frage selbst, denn ohne das Studium der Malware, die von Hackern schnell generiert wird, ist es für Forscher und Spezialisten unmöglich, den Unterschied zwischen nützlicher Software und Malware zu erkennen. Lassen Sie uns in diesem Abschnitt darüber diskutierenVirusShare, ein Werkzeug, um diese Aufgabe zu erfüllen.

Grundlegendes zu VirusShare

VirusShare ist die größte Sammlung von Malware-Beispielen in Privatbesitz, mit der Sicherheitsforscher, Incident-Responder und forensische Analysten Beispiele für Live-Schadcode erhalten. Es enthält über 30 Millionen Proben.

Der Vorteil von VirusShare ist die Liste der frei verfügbaren Malware-Hashes. Jeder kann diese Hashes verwenden, um ein sehr umfassendes Hash-Set zu erstellen und damit potenziell schädliche Dateien zu identifizieren. Bevor Sie VirusShare verwenden, empfehlen wir Ihnen einen Besuchhttps://virusshare.com für mehr Details.

Erstellen einer durch Zeilenumbrüche getrennten Hash-Liste aus VirusShare mit Python

Eine Hash-Liste von VirusShare kann von verschiedenen forensischen Tools wie X-Way und EnCase verwendet werden. In dem unten beschriebenen Skript werden wir das Herunterladen von Hash-Listen von VirusShare automatisieren, um eine durch Zeilenumbrüche getrennte Hash-Liste zu erstellen.

Für dieses Skript benötigen wir eine Python-Bibliothek eines Drittanbieters tqdm die wie folgt heruntergeladen werden kann -

pip install tqdm

Beachten Sie, dass wir in diesem Skript zuerst die VirusShare-Hasheseite lesen und die neueste Hash-Liste dynamisch identifizieren. Dann initialisieren wir den Fortschrittsbalken und laden die Hash-Liste im gewünschten Bereich herunter.

Importieren Sie zunächst die folgenden Bibliotheken:

from __future__ import print_function

import argparse
import os
import ssl
import sys
import tqdm

from urllib.request import urlopen
import urllib.error

Dieses Skript verwendet ein Positionsargument, das der gewünschte Pfad für die Hash-Menge wäre -

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Hash set from VirusShare')
   parser.add_argument("OUTPUT_HASH", help = "Output Hashset")
   parser.add_argument("--start", type = int, help = "Optional starting location")
   args = parser.parse_args()

Jetzt führen wir die Standardeingabevalidierung wie folgt durch:

directory = os.path.dirname(args.OUTPUT_HASH)
if not os.path.exists(directory):
   os.makedirs(directory)
if args.start:
   main(args.OUTPUT_HASH, start=args.start)
else:
   main(args.OUTPUT_HASH)

Jetzt müssen wir definieren main() Funktion mit **kwargs Als Argument, da dadurch ein Wörterbuch erstellt wird, können wir auf die unterstützten Schlüsselargumente verweisen, wie unten gezeigt -

def main(hashset, **kwargs):
   url = "https://virusshare.com/hashes.4n6"
   print("[+] Identifying hash set range from {}".format(url))
   context = ssl._create_unverified_context()

Jetzt müssen wir die VirusShare-Hasheseite mithilfe von öffnen urlib.request.urlopen()Methode. Wir werden den Try-Except-Block wie folgt verwenden:

try:
   index = urlopen(url, context = context).read().decode("utf-8")
except urllib.error.HTTPError as e:
   print("[-] Error accessing webpage - exiting..")
   sys.exit(1)

Identifizieren Sie jetzt die neueste Hash-Liste von den heruntergeladenen Seiten. Sie können dies tun, indem Sie die letzte Instanz des HTML suchenhrefTag zur VirusShare-Hash-Liste. Dies kann mit den folgenden Codezeilen erfolgen:

tag = index.rfind(r'a href = "hashes/VirusShare_')
stop = int(index[tag + 27: tag + 27 + 5].lstrip("0"))

if "start" not in kwa<rgs:
   start = 0
else:
   start = kwargs["start"]

if start < 0 or start > stop:
   print("[-] Supplied start argument must be greater than or equal ""to zero but less than the latest hash list, ""currently: {}".format(stop))
sys.exit(2)
print("[+] Creating a hashset from hash lists {} to {}".format(start, stop))
hashes_downloaded = 0

Jetzt werden wir verwenden tqdm.trange() Methode zum Erstellen einer Schleife und eines Fortschrittsbalkens wie folgt:

for x in tqdm.trange(start, stop + 1, unit_scale=True,desc="Progress"):
   url_hash = "https://virusshare.com/hashes/VirusShare_"\"{}.md5".format(str(x).zfill(5))
   try:
      hashes = urlopen(url_hash, context=context).read().decode("utf-8")
      hashes_list = hashes.split("\n")
   except urllib.error.HTTPError as e:
      print("[-] Error accessing webpage for hash list {}"" - continuing..".format(x))
   continue

Nachdem Sie die obigen Schritte erfolgreich ausgeführt haben, öffnen wir die Hash-Set-Textdatei in einem + -Modus, um sie an den unteren Rand der Textdatei anzuhängen.

with open(hashset, "a+") as hashfile:
   for line in hashes_list:
   if not line.startswith("#") and line != "":
      hashes_downloaded += 1
      hashfile.write(line + '\n')
   print("[+] Finished downloading {} hashes into {}".format(
      hashes_downloaded, hashset))

Nach dem Ausführen des obigen Skripts erhalten Sie die neueste Hash-Liste mit MD5-Hash-Werten im Textformat.

In den vorherigen Kapiteln wurden die Bedeutung und der Prozess der Netzwerkforensik sowie die damit verbundenen Konzepte erörtert. In diesem Kapitel lernen wir die Rolle von E-Mails in der digitalen Forensik und ihre Untersuchung mit Python kennen.

Rolle der E-Mail bei der Untersuchung

E-Mails spielen eine sehr wichtige Rolle in der Geschäftskommunikation und haben sich zu einer der wichtigsten Anwendungen im Internet entwickelt. Sie sind ein praktischer Modus zum Senden von Nachrichten und Dokumenten, nicht nur von Computern, sondern auch von anderen elektronischen Geräten wie Mobiltelefonen und Tablets.

Die negative Seite von E-Mails ist, dass Kriminelle wichtige Informationen über ihr Unternehmen verlieren können. Daher hat die Rolle von E-Mails in der digitalen Forensik in den letzten Jahren zugenommen. In der digitalen Forensik werden E-Mails als entscheidende Beweise angesehen, und die E-Mail-Header-Analyse ist wichtig geworden, um Beweise während des forensischen Prozesses zu sammeln.

Ein Ermittler hat die folgenden Ziele bei der Durchführung der E-Mail-Forensik:

  • Den Hauptverbrecher identifizieren
  • Notwendige Beweise sammeln
  • Zur Präsentation der Ergebnisse
  • Um den Fall zu bauen

Herausforderungen in der E-Mail-Forensik

Die E-Mail-Forensik spielt eine sehr wichtige Rolle bei der Untersuchung, da der Großteil der Kommunikation in der heutigen Zeit auf E-Mails beruht. Ein forensischer E-Mail-Ermittler kann sich jedoch während der Untersuchung den folgenden Herausforderungen stellen:

Gefälschte E-Mails

Die größte Herausforderung in der E-Mail-Forensik ist die Verwendung gefälschter E-Mails, die durch Manipulieren und Erstellen von Skripten für Header usw. erstellt werden. In dieser Kategorie verwenden Kriminelle auch temporäre E-Mails, bei denen ein registrierter Benutzer E-Mails an einer temporären Adresse empfangen kann, die abläuft nach einer bestimmten Zeit.

Spoofing

Eine weitere Herausforderung in der E-Mail-Forensik ist das Spoofing, bei dem Kriminelle eine E-Mail als die einer anderen Person präsentierten. In diesem Fall erhält das Gerät sowohl eine gefälschte als auch eine ursprüngliche IP-Adresse.

Anonymes erneutes E-Mailen

Hier entfernt der E-Mail-Server identifizierende Informationen aus der E-Mail-Nachricht, bevor er sie weiterleitet. Dies führt zu einer weiteren großen Herausforderung für E-Mail-Untersuchungen.

In der forensischen E-Mail-Untersuchung verwendete Techniken

E-Mail-Forensik ist die Untersuchung der Quelle und des Inhalts von E-Mails als Beweismittel zur Identifizierung des tatsächlichen Absenders und Empfängers einer Nachricht sowie einiger anderer Informationen wie Datum / Uhrzeit der Übermittlung und Absicht des Absenders. Es umfasst die Untersuchung von Metadaten, das Scannen von Ports sowie die Suche nach Schlüsselwörtern.

Einige der gängigen Techniken, die für forensische E-Mail-Untersuchungen verwendet werden können, sind:

  • Header-Analyse
  • Serveruntersuchung
  • Untersuchung von Netzwerkgeräten
  • Absender Mailer Fingerabdrücke
  • Software Embedded Identifiers

In den folgenden Abschnitten erfahren Sie, wie Sie Informationen mit Python zum Zwecke der E-Mail-Untersuchung abrufen.

Extraktion von Informationen aus EML-Dateien

EML-Dateien sind im Grunde E-Mails im Dateiformat, die häufig zum Speichern von E-Mail-Nachrichten verwendet werden. Es handelt sich um strukturierte Textdateien, die mit mehreren E-Mail-Clients wie Microsoft Outlook, Outlook Express und Windows Live Mail kompatibel sind.

In einer EML-Datei werden E-Mail-Header, Textinhalte und Anhangsdaten als einfacher Text gespeichert. Es verwendet base64 zum Codieren von Binärdaten und QP-Codierung (Quoted-Printable) zum Speichern von Inhaltsinformationen. Das Python-Skript, mit dem Informationen aus der EML-Datei extrahiert werden können, ist unten angegeben:

Importieren Sie zunächst die folgenden Python-Bibliotheken wie unten gezeigt:

from __future__ import print_function
from argparse import ArgumentParser, FileType
from email import message_from_file

import os
import quopri
import base64

In den oben genannten Bibliotheken quopriwird verwendet, um die QP-codierten Werte aus EML-Dateien zu dekodieren. Alle Base64-codierten Daten können mit Hilfe von decodiert werdenbase64 Bibliothek.

Als nächstes geben wir ein Argument für den Befehlszeilenhandler an. Beachten Sie, dass hier nur ein Argument akzeptiert wird, das der Pfad zur EML-Datei ist (siehe unten).

if __name__ == '__main__':
   parser = ArgumentParser('Extracting information from EML file')
   parser.add_argument("EML_FILE",help="Path to EML File", type=FileType('r'))
   args = parser.parse_args()
   main(args.EML_FILE)

Jetzt müssen wir definieren main() Funktion, in der wir die genannte Methode verwenden message_from_file()aus der E-Mail-Bibliothek, um das dateiähnliche Objekt zu lesen. Hier greifen wir mithilfe der resultierenden Variablen mit dem Namen auf die Header, den Body-Inhalt, die Anhänge und andere Nutzdateninformationen zuemlfile wie im unten angegebenen Code gezeigt -

def main(input_file):
   emlfile = message_from_file(input_file)
   for key, value in emlfile._headers:
      print("{}: {}".format(key, value))
print("\nBody\n")

if emlfile.is_multipart():
   for part in emlfile.get_payload():
      process_payload(part)
else:
   process_payload(emlfile[1])

Jetzt müssen wir definieren process_payload() Methode, mit der wir den Inhalt des Nachrichtentexts mithilfe von extrahieren get_payload()Methode. Wir werden QP-codierte Daten mit dekodierenquopri.decodestring()Funktion. Wir werden auch den MIME-Inhaltstyp überprüfen, damit er die Speicherung der E-Mail ordnungsgemäß handhaben kann. Beachten Sie den unten angegebenen Code -

def process_payload(payload):
   print(payload.get_content_type() + "\n" + "=" * len(payload.get_content_type()))
   body = quopri.decodestring(payload.get_payload())
   
   if payload.get_charset():
      body = body.decode(payload.get_charset())
else:
   try:
      body = body.decode()
   except UnicodeDecodeError:
      body = body.decode('cp1252')

if payload.get_content_type() == "text/html":
   outfile = os.path.basename(args.EML_FILE.name) + ".html"
   open(outfile, 'w').write(body)
elif payload.get_content_type().startswith('application'):
   outfile = open(payload.get_filename(), 'wb')
   body = base64.b64decode(payload.get_payload())
   outfile.write(body)
   outfile.close()
   print("Exported: {}\n".format(outfile.name))
else:
   print(body)

Nach dem Ausführen des obigen Skripts erhalten wir die Header-Informationen zusammen mit verschiedenen Nutzdaten auf der Konsole.

Analysieren von MSG-Dateien mit Python

E-Mail-Nachrichten gibt es in vielen verschiedenen Formaten. MSG ist ein solches Format, das von Microsoft Outlook und Exchange verwendet wird. Dateien mit der Erweiterung MSG können einfachen ASCII-Text für die Header und den Hauptnachrichtentext sowie Hyperlinks und Anhänge enthalten.

In diesem Abschnitt erfahren Sie, wie Sie mithilfe der Outlook-API Informationen aus MSG-Dateien extrahieren. Beachten Sie, dass das folgende Python-Skript nur unter Windows funktioniert. Dazu müssen wir die Python-Bibliothek eines Drittanbieters mit dem Namen installierenpywin32 wie folgt -

pip install pywin32

Importieren Sie nun die folgenden Bibliotheken mit den angezeigten Befehlen:

from __future__ import print_function
from argparse import ArgumentParser

import os
import win32com.client
import pywintypes

Lassen Sie uns nun ein Argument für den Befehlszeilenhandler angeben. Hier werden zwei Argumente akzeptiert, eines wäre der Pfad zur MSG-Datei und das andere wäre der gewünschte Ausgabeordner wie folgt:

if __name__ == '__main__':
   parser = ArgumentParser(‘Extracting information from MSG file’)
   parser.add_argument("MSG_FILE", help="Path to MSG file")
   parser.add_argument("OUTPUT_DIR", help="Path to output folder")
   args = parser.parse_args()
   out_dir = args.OUTPUT_DIR
   
   if not os.path.exists(out_dir):
      os.makedirs(out_dir)
   main(args.MSG_FILE, args.OUTPUT_DIR)

Jetzt müssen wir definieren main() Funktion, in der wir aufrufen werden win32com Bibliothek zum Einrichten Outlook API Dies ermöglicht den Zugriff auf die MAPI Namespace.

def main(msg_file, output_dir):
   mapi = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
   msg = mapi.OpenSharedItem(os.path.abspath(args.MSG_FILE))
   
   display_msg_attribs(msg)
   display_msg_recipients(msg)
   
   extract_msg_body(msg, output_dir)
   extract_attachments(msg, output_dir)

Definieren Sie nun verschiedene Funktionen, die wir in diesem Skript verwenden. Der unten angegebene Code zeigt die Definition derdisplay_msg_attribs() Funktion, mit der wir verschiedene Attribute einer Nachricht anzeigen können, z. B. Betreff, BCC, CC, Größe, Absendername, gesendet usw.

def display_msg_attribs(msg):
   attribs = [
      'Application', 'AutoForwarded', 'BCC', 'CC', 'Class',
      'ConversationID', 'ConversationTopic', 'CreationTime',
      'ExpiryTime', 'Importance', 'InternetCodePage', 'IsMarkedAsTask',
      'LastModificationTime', 'Links','ReceivedTime', 'ReminderSet',
      'ReminderTime', 'ReplyRecipientNames', 'Saved', 'Sender',
      'SenderEmailAddress', 'SenderEmailType', 'SenderName', 'Sent',
      'SentOn', 'SentOnBehalfOfName', 'Size', 'Subject',
      'TaskCompletedDate', 'TaskDueDate', 'To', 'UnRead'
   ]
   print("\nMessage Attributes")
   for entry in attribs:
      print("{}: {}".format(entry, getattr(msg, entry, 'N/A')))

Definieren Sie nun die display_msg_recipeints() Funktion, die die Nachrichten durchläuft und die Empfängerdetails anzeigt.

def display_msg_recipients(msg):
   recipient_attrib = ['Address', 'AutoResponse', 'Name', 'Resolved', 'Sendable']
   i = 1
   
   while True:
   try:
      recipient = msg.Recipients(i)
   except pywintypes.com_error:
      break
   print("\nRecipient {}".format(i))
   print("=" * 15)
   
   for entry in recipient_attrib:
      print("{}: {}".format(entry, getattr(recipient, entry, 'N/A')))
   i += 1

Als nächstes definieren wir extract_msg_body() Funktion, die den Textinhalt, HTML sowie Nur-Text, aus der Nachricht extrahiert.

def extract_msg_body(msg, out_dir):
   html_data = msg.HTMLBody.encode('cp1252')
   outfile = os.path.join(out_dir, os.path.basename(args.MSG_FILE))
   
   open(outfile + ".body.html", 'wb').write(html_data)
   print("Exported: {}".format(outfile + ".body.html"))
   body_data = msg.Body.encode('cp1252')
   
   open(outfile + ".body.txt", 'wb').write(body_data)
   print("Exported: {}".format(outfile + ".body.txt"))

Als nächstes werden wir die definieren extract_attachments() Funktion, die Anhangsdaten in das gewünschte Ausgabeverzeichnis exportiert.

def extract_attachments(msg, out_dir):
   attachment_attribs = ['DisplayName', 'FileName', 'PathName', 'Position', 'Size']
   i = 1 # Attachments start at 1
   
   while True:
      try:
         attachment = msg.Attachments(i)
   except pywintypes.com_error:
      break

Sobald alle Funktionen definiert sind, drucken wir alle Attribute mit der folgenden Codezeile auf die Konsole:

print("\nAttachment {}".format(i))
print("=" * 15)
   
for entry in attachment_attribs:
   print('{}: {}'.format(entry, getattr(attachment, entry,"N/A")))
outfile = os.path.join(os.path.abspath(out_dir),os.path.split(args.MSG_FILE)[-1])
   
if not os.path.exists(outfile):
os.makedirs(outfile)
outfile = os.path.join(outfile, attachment.FileName)
attachment.SaveAsFile(outfile)
   
print("Exported: {}".format(outfile))
i += 1

Nach dem Ausführen des obigen Skripts erhalten wir die Attribute der Nachricht und ihrer Anhänge im Konsolenfenster zusammen mit mehreren Dateien im Ausgabeverzeichnis.

Strukturieren von MBOX-Dateien aus Google Takeout mit Python

MBOX-Dateien sind Textdateien mit spezieller Formatierung, die darin gespeicherte Nachrichten aufteilen. Sie werden häufig in Verbindung mit UNIX-Systemen, Thunderbolt und Google Takeouts gefunden.

In diesem Abschnitt sehen Sie ein Python-Skript, in dem wir MBOX-Dateien strukturieren, die von Google Takeouts bezogen wurden. Zuvor müssen wir jedoch wissen, wie wir diese MBOX-Dateien mithilfe unseres Google- oder Google Mail-Kontos generieren können.

Erfassen des Google-Konto-Postfachs im MBX-Format

Wenn Sie das Postfach eines Google-Kontos erwerben, müssen Sie eine Sicherungskopie unseres Google Mail-Kontos erstellen. Das Backup kann aus verschiedenen persönlichen oder beruflichen Gründen erstellt werden. Beachten Sie, dass Google die Sicherung von Google Mail-Daten bereitstellt. Um unser Google-Konto-Postfach im MBOX-Format zu erhalten, müssen Sie die folgenden Schritte ausführen:

  • Öffnen My account Instrumententafel.

  • Gehen Sie zum Abschnitt "Persönliche Informationen und Datenschutz" und wählen Sie den Link "Inhalt kontrollieren".

  • Sie können ein neues Archiv erstellen oder ein vorhandenes verwalten. Wenn wir klicken,CREATE ARCHIVE Link, dann erhalten wir einige Kontrollkästchen für jedes Google-Produkt, das wir einschließen möchten.

  • Nach Auswahl der Produkte haben wir die Freiheit, den Dateityp und die maximale Größe für unser Archiv zusammen mit der Versandmethode zur Auswahl aus der Liste auszuwählen.

  • Schließlich erhalten wir dieses Backup im MBOX-Format.

Python-Code

Jetzt kann die oben beschriebene MBOX-Datei mit Python wie unten gezeigt strukturiert werden -

Zunächst müssen Python-Bibliotheken wie folgt importiert werden:

from __future__ import print_function
from argparse import ArgumentParser

import mailbox
import os
import time
import csv
from tqdm import tqdm

import base64

Alle Bibliotheken wurden in früheren Skripten verwendet und erklärt, mit Ausnahme der mailbox Bibliothek, die zum Parsen von MBOX-Dateien verwendet wird.

Geben Sie nun ein Argument für den Befehlszeilenhandler an. Hier werden zwei Argumente akzeptiert - eines ist der Pfad zur MBOX-Datei und das andere ist der gewünschte Ausgabeordner.

if __name__ == '__main__':
   parser = ArgumentParser('Parsing MBOX files')
   parser.add_argument("MBOX", help="Path to mbox file")
   parser.add_argument(
      "OUTPUT_DIR",help = "Path to output directory to write report ""and exported content")
   args = parser.parse_args()
   main(args.MBOX, args.OUTPUT_DIR)

Nun wird definiert main() Funktion und Aufruf mbox Klasse der Postfachbibliothek, mit deren Hilfe wir eine MBOX-Datei analysieren können, indem wir ihren Pfad angeben -

def main(mbox_file, output_dir):
   print("Reading mbox file")
   mbox = mailbox.mbox(mbox_file, factory=custom_reader)
   print("{} messages to parse".format(len(mbox)))

Definieren Sie nun eine Lesemethode für mailbox Bibliothek wie folgt -

def custom_reader(data_stream):
   data = data_stream.read()
   try:
      content = data.decode("ascii")
   except (UnicodeDecodeError, UnicodeEncodeError) as e:
      content = data.decode("cp1252", errors="replace")
   return mailbox.mboxMessage(content)

Erstellen Sie nun einige Variablen für die weitere Verarbeitung wie folgt:

parsed_data = []
attachments_dir = os.path.join(output_dir, "attachments")

if not os.path.exists(attachments_dir):
   os.makedirs(attachments_dir)
columns = [
   "Date", "From", "To", "Subject", "X-Gmail-Labels", "Return-Path", "Received", 
   "Content-Type", "Message-ID","X-GM-THRID", "num_attachments_exported", "export_path"]

Als nächstes verwenden tqdm um einen Fortschrittsbalken zu generieren und den Iterationsprozess wie folgt zu verfolgen:

for message in tqdm(mbox):
   msg_data = dict()
   header_data = dict(message._headers)
for hdr in columns:
   msg_data[hdr] = header_data.get(hdr, "N/A")

Überprüfen Sie jetzt, ob die Wettermeldung Nutzdaten enthält oder nicht. Wenn ja, werden wir definierenwrite_payload() Methode wie folgt -

if len(message.get_payload()):
   export_path = write_payload(message, attachments_dir)
   msg_data['num_attachments_exported'] = len(export_path)
   msg_data['export_path'] = ", ".join(export_path)

Jetzt müssen Daten angehängt werden. Dann werden wir anrufencreate_report() Methode wie folgt -

parsed_data.append(msg_data)
create_report(
   parsed_data, os.path.join(output_dir, "mbox_report.csv"), columns)
def write_payload(msg, out_dir):
   pyld = msg.get_payload()
   export_path = []
   
if msg.is_multipart():
   for entry in pyld:
      export_path += write_payload(entry, out_dir)
else:
   content_type = msg.get_content_type()
   if "application/" in content_type.lower():
      content = base64.b64decode(msg.get_payload())
      export_path.append(export_content(msg, out_dir, content))
   elif "image/" in content_type.lower():
      content = base64.b64decode(msg.get_payload())
      export_path.append(export_content(msg, out_dir, content))

   elif "video/" in content_type.lower():
      content = base64.b64decode(msg.get_payload())
      export_path.append(export_content(msg, out_dir, content))
   elif "audio/" in content_type.lower():
      content = base64.b64decode(msg.get_payload())
      export_path.append(export_content(msg, out_dir, content))
   elif "text/csv" in content_type.lower():
      content = base64.b64decode(msg.get_payload())
      export_path.append(export_content(msg, out_dir, content))
   elif "info/" in content_type.lower():
      export_path.append(export_content(msg, out_dir,
      msg.get_payload()))
   elif "text/calendar" in content_type.lower():
      export_path.append(export_content(msg, out_dir,
      msg.get_payload()))
   elif "text/rtf" in content_type.lower():
      export_path.append(export_content(msg, out_dir,
      msg.get_payload()))
   else:
      if "name=" in msg.get('Content-Disposition', "N/A"):
         content = base64.b64decode(msg.get_payload())
      export_path.append(export_content(msg, out_dir, content))
   elif "name=" in msg.get('Content-Type', "N/A"):
      content = base64.b64decode(msg.get_payload())
      export_path.append(export_content(msg, out_dir, content))
return export_path

Beachten Sie, dass die obigen if-else-Anweisungen leicht zu verstehen sind. Jetzt müssen wir eine Methode definieren, die den Dateinamen aus dem extrahiertmsg Objekt wie folgt -

def export_content(msg, out_dir, content_data):
   file_name = get_filename(msg)
   file_ext = "FILE"
   
   if "." in file_name: file_ext = file_name.rsplit(".", 1)[-1]
   file_name = "{}_{:.4f}.{}".format(file_name.rsplit(".", 1)[0], time.time(), file_ext)
   file_name = os.path.join(out_dir, file_name)

Mit Hilfe der folgenden Codezeilen können Sie die Datei nun tatsächlich exportieren -

if isinstance(content_data, str):
   open(file_name, 'w').write(content_data)
else:
   open(file_name, 'wb').write(content_data)
return file_name

Definieren wir nun eine Funktion zum Extrahieren von Dateinamen aus dem message um die Namen dieser Dateien wie folgt genau darzustellen -

def get_filename(msg):
   if 'name=' in msg.get("Content-Disposition", "N/A"):
      fname_data = msg["Content-Disposition"].replace("\r\n", " ")
      fname = [x for x in fname_data.split("; ") if 'name=' in x]
      file_name = fname[0].split("=", 1)[-1]
   elif 'name=' in msg.get("Content-Type", "N/A"):
      fname_data = msg["Content-Type"].replace("\r\n", " ")
      fname = [x for x in fname_data.split("; ") if 'name=' in x]
      file_name = fname[0].split("=", 1)[-1]
   else:
      file_name = "NO_FILENAME"
   fchars = [x for x in file_name if x.isalnum() or x.isspace() or x == "."]
   return "".join(fchars)

Jetzt können wir eine CSV-Datei schreiben, indem wir die definieren create_report() Funktion wie folgt -

def create_report(output_data, output_file, columns):
   with open(output_file, 'w', newline="") as outfile:
      csvfile = csv.DictWriter(outfile, columns)
      csvfile.writeheader()
      csvfile.writerows(output_data)

Sobald Sie das oben angegebene Skript ausführen, erhalten wir den CSV-Bericht und das Verzeichnis voller Anhänge.

In diesem Kapitel werden verschiedene Konzepte der Microsoft Windows-Forensik und die wichtigen Artefakte erläutert, die ein Ermittler aus dem Untersuchungsprozess erhalten kann.

Einführung

Artefakte sind Objekte oder Bereiche innerhalb eines Computersystems, die wichtige Informationen zu den vom Computerbenutzer ausgeführten Aktivitäten enthalten. Art und Speicherort dieser Informationen hängen vom Betriebssystem ab. Während der forensischen Analyse spielen diese Artefakte eine sehr wichtige Rolle bei der Genehmigung oder Ablehnung der Beobachtung des Ermittlers.

Bedeutung von Windows-Artefakten für die Forensik

Windows-Artefakte gewinnen aus folgenden Gründen an Bedeutung:

  • Rund 90% des weltweiten Datenverkehrs kommt von Computern, die Windows als Betriebssystem verwenden. Aus diesem Grund sind Windows-Artefakte für Prüfer der digitalen Forensik sehr wichtig.

  • Das Windows-Betriebssystem speichert verschiedene Arten von Beweisen, die sich auf die Benutzeraktivität auf dem Computersystem beziehen. Dies ist ein weiterer Grund, der die Bedeutung von Windows-Artefakten für die digitale Forensik zeigt.

  • Oft dreht sich der Ermittler um alte und traditionelle Bereiche wie Benutzerdaten. Windows-Artefakte können die Untersuchung auf nicht traditionelle Bereiche wie vom System erstellte Daten oder Artefakte lenken.

  • Windows bietet eine große Fülle von Artefakten, die sowohl für Ermittler als auch für Unternehmen und Einzelpersonen, die informelle Ermittlungen durchführen, hilfreich sind.

  • Die Zunahme der Cyberkriminalität in den letzten Jahren ist ein weiterer Grund dafür, dass Windows-Artefakte wichtig sind.

Windows-Artefakte und ihre Python-Skripte

In diesem Abschnitt werden einige Windows-Artefakte und Python-Skripte erläutert, um Informationen von ihnen abzurufen.

Papierkorb

Es ist eines der wichtigsten Windows-Artefakte für forensische Untersuchungen. Der Windows-Papierkorb enthält die Dateien, die vom Benutzer gelöscht, aber vom System noch nicht physisch entfernt wurden. Selbst wenn der Benutzer die Datei vollständig aus dem System entfernt, dient sie als wichtige Untersuchungsquelle. Dies liegt daran, dass der Prüfer aus den gelöschten Dateien wertvolle Informationen wie den ursprünglichen Dateipfad sowie die Zeit, zu der sie an den Papierkorb gesendet wurden, extrahieren kann.

Beachten Sie, dass die Speicherung von Papierkorbnachweisen von der Windows-Version abhängt. Im folgenden Python-Skript werden wir uns mit Windows 7 befassen, wo zwei Dateien erstellt werden:$R Datei, die den tatsächlichen Inhalt der recycelten Datei enthält und $I Datei, die den ursprünglichen Dateinamen, den Pfad und die Dateigröße enthält, als die Datei gelöscht wurde.

Für Python-Skripte müssen wir nämlich Module von Drittanbietern installieren pytsk3, pyewf und unicodecsv. Wir können benutzenpipum sie zu installieren. Wir können die folgenden Schritte ausführen, um Informationen aus dem Papierkorb zu extrahieren:

  • Zuerst müssen wir eine rekursive Methode verwenden, um das zu scannen $Recycle.bin Ordner und wählen Sie alle Dateien aus, die mit beginnen $I.

  • Als nächstes werden wir den Inhalt der Dateien lesen und die verfügbaren Metadatenstrukturen analysieren.

  • Nun werden wir nach der zugehörigen $ R-Datei suchen.

  • Zuletzt werden wir die Ergebnisse zur Überprüfung in die CSV-Datei schreiben.

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

Zuerst müssen wir die folgenden Python-Bibliotheken importieren -

from __future__ import print_function
from argparse import ArgumentParser

import datetime
import os
import struct

from utility.pytskutil import TSKUtil
import unicodecsv as csv

Als Nächstes müssen wir ein Argument für den Befehlszeilenhandler angeben. Beachten Sie, dass hier drei Argumente akzeptiert werden: 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('Recycle Bin evidences')
   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)

Definieren Sie nun die main()Funktion, die die gesamte Verarbeitung übernimmt. Es wird nach suchen$I Datei wie folgt -

def main(evidence, image_type, report_file):
   tsk_util = TSKUtil(evidence, image_type)
   dollar_i_files = tsk_util.recurse_files("$I", path = '/$Recycle.bin',logic = "startswith") if dollar_i_files is not None: processed_files = process_dollar_i(tsk_util, dollar_i_files) write_csv(report_file,['file_path', 'file_size', 'deleted_time','dollar_i_file', 'dollar_r_file', 'is_directory'],processed_files) else: print("No $I files found")

Nun, wenn wir gefunden haben $I Datei, dann muss es gesendet werden process_dollar_i() Funktion, die die akzeptiert tsk_util Objekt sowie die Liste von $I Dateien, wie unten gezeigt -

def process_dollar_i(tsk_util, dollar_i_files):
   processed_files = []
   
   for dollar_i in dollar_i_files:
      file_attribs = read_dollar_i(dollar_i[2])
      if file_attribs is None:
         continue
      file_attribs['dollar_i_file'] = os.path.join('/$Recycle.bin', dollar_i[1][1:])

Suchen Sie nun wie folgt nach $ R-Dateien:

recycle_file_path = os.path.join('/$Recycle.bin',dollar_i[1].rsplit("/", 1)[0][1:]) dollar_r_files = tsk_util.recurse_files( "$R" + dollar_i[0][2:],path = recycle_file_path, logic = "startswith")
   
   if dollar_r_files is None:
      dollar_r_dir = os.path.join(recycle_file_path,"$R" + dollar_i[0][2:])
      dollar_r_dirs = tsk_util.query_directory(dollar_r_dir)
   
   if dollar_r_dirs is None:
      file_attribs['dollar_r_file'] = "Not Found"
      file_attribs['is_directory'] = 'Unknown'
   
   else:
      file_attribs['dollar_r_file'] = dollar_r_dir
      file_attribs['is_directory'] = True
   
   else:
      dollar_r = [os.path.join(recycle_file_path, r[1][1:])for r in dollar_r_files]
      file_attribs['dollar_r_file'] = ";".join(dollar_r)
      file_attribs['is_directory'] = False
      processed_files.append(file_attribs)
   return processed_files

Definieren Sie nun read_dollar_i() Methode zum Lesen der $IMit anderen Worten, Dateien analysieren die Metadaten. Wir werden verwendenread_random()Methode zum Lesen der ersten acht Bytes der Signatur. Dies gibt keine zurück, wenn die Signatur nicht übereinstimmt. Danach müssen wir die Werte von lesen und entpacken$I Datei, wenn dies eine gültige Datei ist.

def read_dollar_i(file_obj):
   if file_obj.read_random(0, 8) != '\x01\x00\x00\x00\x00\x00\x00\x00':
      return None
   raw_file_size = struct.unpack('<q', file_obj.read_random(8, 8))
   raw_deleted_time = struct.unpack('<q',   file_obj.read_random(16, 8))
   raw_file_path = file_obj.read_random(24, 520)

Nachdem wir diese Dateien extrahiert haben, müssen wir die Ganzzahlen mithilfe von in von Menschen lesbare Werte interpretieren sizeof_fmt() Funktion wie unten gezeigt -

file_size = sizeof_fmt(raw_file_size[0])
deleted_time = parse_windows_filetime(raw_deleted_time[0])

file_path = raw_file_path.decode("utf16").strip("\x00")
return {'file_size': file_size, 'file_path': file_path,'deleted_time': deleted_time}

Jetzt müssen wir definieren sizeof_fmt() Funktion wie folgt -

def sizeof_fmt(num, suffix = 'B'):
   for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
      if abs(num) < 1024.0:
         return "%3.1f%s%s" % (num, unit, suffix)
      num /= 1024.0
   return "%.1f%s%s" % (num, 'Yi', suffix)

Definieren Sie nun eine Funktion für interpretierte Ganzzahlen in formatiertem Datum und Uhrzeit wie folgt:

def parse_windows_filetime(date_value):
   microseconds = float(date_value) / 10
   ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(
      microseconds = microseconds)
   return ts.strftime('%Y-%m-%d %H:%M:%S.%f')

Nun werden wir definieren write_csv() Methode zum Schreiben der verarbeiteten Ergebnisse in eine CSV-Datei wie folgt:

def write_csv(outfile, fieldnames, data):
   with open(outfile, 'wb') as open_outfile:
      csvfile = csv.DictWriter(open_outfile, fieldnames)
      csvfile.writeheader()
      csvfile.writerows(data)

Wenn Sie das obige Skript ausführen, erhalten wir die Daten aus den Dateien $ I und $ R.

Haftnotizen

Windows Sticky Notes ersetzt die reale Gewohnheit, mit Stift und Papier zu schreiben. Diese Notizen wurden verwendet, um auf dem Desktop mit verschiedenen Optionen für Farben, Schriftarten usw. zu schweben. In Windows 7 wird die Haftnotizdatei als OLE-Datei gespeichert. Daher werden wir im folgenden Python-Skript diese OLE-Datei untersuchen, um Metadaten aus Haftnotizen zu extrahieren.

Für dieses Python-Skript müssen wir nämlich Module von Drittanbietern installieren olefile, pytsk3, pyewfund unicodecsv. Wir können den Befehl verwendenpip um sie zu installieren.

Wir können die unten beschriebenen Schritte ausführen, um die Informationen aus der Haftnotizdatei zu extrahieren StickyNote.sn - -

  • Öffnen Sie zunächst die Beweisdatei und suchen Sie alle StickyNote.snt-Dateien.

  • Analysieren Sie dann die Metadaten und Inhalte aus dem OLE-Stream und schreiben Sie den RTF-Inhalt in Dateien.

  • Zuletzt erstellen Sie einen CSV-Bericht dieser Metadaten.

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 unicodecsv as csv
import os
import StringIO

from utility.pytskutil import TSKUtil
import olefile

Definieren Sie als Nächstes eine globale Variable, die in diesem Skript verwendet wird.

REPORT_COLS = ['note_id', 'created', 'modified', 'note_text', 'note_file']

Als Nächstes müssen wir ein Argument für den Befehlszeilenhandler angeben. Beachten Sie, dass hier drei Argumente akzeptiert werden: Erstens der Pfad zur Beweisdatei, zweitens der Typ der Beweisdatei und drittens der gewünschte Ausgabepfad wie folgt:

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Evidence from Sticky Notes')
   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_FOLDER', help="Path to report folder")
   args = parser.parse_args()
   main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT_FOLDER)

Nun werden wir definieren main() Funktion, die dem vorherigen Skript ähnlich ist, wie unten gezeigt -

def main(evidence, image_type, report_folder):
   tsk_util = TSKUtil(evidence, image_type)
   note_files = tsk_util.recurse_files('StickyNotes.snt', '/Users','equals')

Lassen Sie uns nun die resultierenden Dateien durchlaufen. Dann werden wir anrufenparse_snt_file() Funktion, um die Datei zu verarbeiten und dann werden wir RTF-Datei mit dem schreiben write_note_rtf() Methode wie folgt -

report_details = []
for note_file in note_files:
   user_dir = note_file[1].split("/")[1]
   file_like_obj = create_file_like_obj(note_file[2])
   note_data = parse_snt_file(file_like_obj)
   
   if note_data is None:
      continue
   write_note_rtf(note_data, os.path.join(report_folder, user_dir))
   report_details += prep_note_report(note_data, REPORT_COLS,"/Users" + note_file[1])
   write_csv(os.path.join(report_folder, 'sticky_notes.csv'), REPORT_COLS,report_details)

Als nächstes müssen wir verschiedene Funktionen definieren, die in diesem Skript verwendet werden.

Zunächst werden wir definieren create_file_like_obj() Funktion zum Lesen der Größe der Datei durch Nehmen pytskDateiobjekt. Dann werden wir definierenparse_snt_file() Funktion, die das dateiähnliche Objekt als Eingabe akzeptiert und zum Lesen und Interpretieren der Haftnotizdatei verwendet wird.

def parse_snt_file(snt_file):
   
   if not olefile.isOleFile(snt_file):
      print("This is not an OLE file")
      return None
   ole = olefile.OleFileIO(snt_file)
   note = {}
   
   for stream in ole.listdir():
      if stream[0].count("-") == 3:
         if stream[0] not in note:
            note[stream[0]] = {"created": ole.getctime(stream[0]),"modified": ole.getmtime(stream[0])}
         content = None
         if stream[1] == '0':
            content = ole.openstream(stream).read()
         elif stream[1] == '3':
            content = ole.openstream(stream).read().decode("utf-16")
         if content:
            note[stream[0]][stream[1]] = content
	return note

Erstellen Sie nun eine RTF-Datei, indem Sie definieren write_note_rtf() Funktion wie folgt

def write_note_rtf(note_data, report_folder):
   if not os.path.exists(report_folder):
      os.makedirs(report_folder)
   
   for note_id, stream_data in note_data.items():
      fname = os.path.join(report_folder, note_id + ".rtf")
      with open(fname, 'w') as open_file:
         open_file.write(stream_data['0'])

Jetzt übersetzen wir das verschachtelte Wörterbuch in eine flache Liste von Wörterbüchern, die für eine CSV-Tabelle besser geeignet sind. Dies erfolgt durch Definierenprep_note_report()Funktion. Zuletzt werden wir definierenwrite_csv() Funktion.

def prep_note_report(note_data, report_cols, note_file):
   report_details = []
   
   for note_id, stream_data in note_data.items():
      report_details.append({
         "note_id": note_id,
         "created": stream_data['created'],
         "modified": stream_data['modified'],
         "note_text": stream_data['3'].strip("\x00"),
         "note_file": note_file
      })
   return report_details
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 Metadaten aus der Sticky Notes-Datei.

Registrierungsdateien

Windows-Registrierungsdateien enthalten viele wichtige Details, die für einen forensischen Analysten wie ein Schatz an Informationen sind. Es handelt sich um eine hierarchische Datenbank, die Details zur Betriebssystemkonfiguration, Benutzeraktivität, Softwareinstallation usw. enthält. Im folgenden Python-Skript greifen wir auf allgemeine Basisinformationen aus dem zuSYSTEM und SOFTWARE Nesselsucht.

Für dieses Python-Skript müssen wir nämlich Module von Drittanbietern installieren pytsk3, pyewf und registry. Wir können benutzenpip um sie zu installieren.

Wir können die folgenden Schritte ausführen, um die Informationen aus der Windows-Registrierung zu extrahieren.

  • Suchen Sie zunächst die zu verarbeitenden Registrierungsstrukturen nach Namen und Pfad.

  • Anschließend öffnen wir diese Dateien mithilfe der Module StringIO und Registry.

  • Zuletzt müssen wir jeden einzelnen Bienenstock verarbeiten und die analysierten Werte zur Interpretation an die Konsole drucken.

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 datetime
import StringIO
import struct

from utility.pytskutil import TSKUtil
from Registry import Registry

Geben Sie nun ein Argument für den Befehlszeilenhandler an. Hier werden zwei Argumente akzeptiert - erstens der Pfad zur Beweisdatei, zweitens der Typ der Beweisdatei, wie unten gezeigt -

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

Jetzt werden wir definieren main() Funktion für die Suche SYSTEM und SOFTWARE Bienenstöcke im Inneren /Windows/System32/config Ordner wie folgt -

def main(evidence, image_type):
   tsk_util = TSKUtil(evidence, image_type)
   tsk_system_hive = tsk_util.recurse_files('system', '/Windows/system32/config', 'equals')
   tsk_software_hive = tsk_util.recurse_files('software', '/Windows/system32/config', 'equals')
   system_hive = open_file_as_reg(tsk_system_hive[0][2])
   software_hive = open_file_as_reg(tsk_software_hive[0][2])
   process_system_hive(system_hive)
   process_software_hive(software_hive)

Definieren Sie nun die Funktion zum Öffnen der Registrierungsdatei. Zu diesem Zweck müssen wir die Größe der Datei erfassenpytsk Metadaten wie folgt -

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 können wir mit Hilfe der folgenden Methode verarbeiten SYSTEM> Bienenstock -

def process_system_hive(hive):
   root = hive.root()
   current_control_set = root.find_key("Select").value("Current").value()
   control_set = root.find_key("ControlSet{:03d}".format(current_control_set))
   raw_shutdown_time = struct.unpack(
      '<Q', control_set.find_key("Control").find_key("Windows").value("ShutdownTime").value())
   
   shutdown_time = parse_windows_filetime(raw_shutdown_time[0])
   print("Last Shutdown Time: {}".format(shutdown_time))
   
   time_zone = control_set.find_key("Control").find_key("TimeZoneInformation")
      .value("TimeZoneKeyName").value()
   
   print("Machine Time Zone: {}".format(time_zone))
   computer_name = control_set.find_key("Control").find_key("ComputerName").find_key("ComputerName")
      .value("ComputerName").value()
   
   print("Machine Name: {}".format(computer_name))
   last_access = control_set.find_key("Control").find_key("FileSystem")
      .value("NtfsDisableLastAccessUpdate").value()
   last_access = "Disabled" if last_access == 1 else "enabled"
   print("Last Access Updates: {}".format(last_access))

Nun müssen wir eine Funktion für interpretierte Ganzzahlen in formatiertem Datum und Uhrzeit wie folgt definieren:

def parse_windows_filetime(date_value):
   microseconds = float(date_value) / 10
   ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds = microseconds)
   return ts.strftime('%Y-%m-%d %H:%M:%S.%f')

def parse_unix_epoch(date_value):
   ts = datetime.datetime.fromtimestamp(date_value)
   return ts.strftime('%Y-%m-%d %H:%M:%S.%f')

Jetzt können wir mit Hilfe der folgenden Methode verarbeiten SOFTWARE Bienenstock -

def process_software_hive(hive):
   root = hive.root()
   nt_curr_ver = root.find_key("Microsoft").find_key("Windows NT")
      .find_key("CurrentVersion")
   
   print("Product name: {}".format(nt_curr_ver.value("ProductName").value()))
   print("CSD Version: {}".format(nt_curr_ver.value("CSDVersion").value()))
   print("Current Build: {}".format(nt_curr_ver.value("CurrentBuild").value()))
   print("Registered Owner: {}".format(nt_curr_ver.value("RegisteredOwner").value()))
   print("Registered Org: 
      {}".format(nt_curr_ver.value("RegisteredOrganization").value()))
   
   raw_install_date = nt_curr_ver.value("InstallDate").value()
   install_date = parse_unix_epoch(raw_install_date)
   print("Installation Date: {}".format(install_date))

Nach dem Ausführen des obigen Skripts werden die Metadaten in Windows-Registrierungsdateien gespeichert.

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.

In diesem Kapitel werden weitere Artefakte erläutert, die ein Ermittler während der forensischen Analyse unter Windows erhalten kann.

Ereignisprotokolle

Windows-Ereignisprotokolldateien sind als Namensempfehlungen spezielle Dateien, in denen wichtige Ereignisse gespeichert werden, z. B. wenn sich Benutzer am Computer anmelden, wenn ein Programmfehler auftritt, Systemänderungen, RDP-Zugriff, anwendungsspezifische Ereignisse usw. Cyber-Ermittler sind immer an Ereignissen interessiert Protokollinformationen, da sie viele nützliche historische Informationen zum Zugriff auf das System enthalten. Im folgenden Python-Skript werden sowohl ältere als auch aktuelle Windows-Ereignisprotokollformate verarbeitet.

Für Python-Skripte müssen wir nämlich Module von Drittanbietern installieren pytsk3, pyewf, unicodecsv, pyevt and pyevtx. Wir können die folgenden Schritte ausführen, um Informationen aus Ereignisprotokollen zu extrahieren.

  • Suchen Sie zunächst nach allen Ereignisprotokollen, die dem Eingabeargument entsprechen.

  • Führen Sie dann die Überprüfung der Dateisignatur durch.

  • Verarbeiten Sie nun jedes gefundene Ereignisprotokoll mit der entsprechenden Bibliothek.

  • Zuletzt schreiben Sie die Ausgabe in eine Tabelle.

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
import unicodecsv as csv
import os
import pytsk3
import pyewf
import pyevt
import pyevtx
import sys
from utility.pytskutil import TSKUtil

Geben Sie nun die Argumente für den Befehlszeilenhandler an. Beachten Sie, dass hier drei Argumente akzeptiert werden: Erstens der Pfad zur Beweisdatei, zweitens der Typ der Beweisdatei und drittens der Name des zu verarbeitenden Ereignisprotokolls.

if __name__ == "__main__":
   parser = argparse.ArgumentParser('Information from Event Logs')
   parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
   parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
   parser.add_argument(
      "LOG_NAME",help = "Event Log Name (SecEvent.Evt, SysEvent.Evt, ""etc.)")
   
   parser.add_argument(
      "-d", help = "Event log directory to scan",default = "/WINDOWS/SYSTEM32/WINEVT")
   
   parser.add_argument(
      "-f", help = "Enable fuzzy search for either evt or"" evtx extension", action = "store_true")
   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.LOG_NAME, args.d, args.f)
   else:
      print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
   sys.exit(1)

Interagieren Sie jetzt mit Ereignisprotokollen, um die Existenz des vom Benutzer angegebenen Pfads abzufragen, indem Sie unseren erstellen TSKUtilObjekt. Dies kann mit Hilfe von erfolgenmain() Methode wie folgt -

def main(evidence, image_type, log, win_event, fuzzy):
   tsk_util = TSKUtil(evidence, image_type)
   event_dir = tsk_util.query_directory(win_event)
   
   if event_dir is not None:
      if fuzzy is True:
         event_log = tsk_util.recurse_files(log, path=win_event)
   else:
      event_log = tsk_util.recurse_files(log, path=win_event, logic="equal")
   
   if event_log is not None:
      event_data = []
      for hit in event_log:
         event_file = hit[2]
         temp_evt = write_file(event_file)

Jetzt müssen wir eine Signaturüberprüfung durchführen und anschließend eine Methode definieren, mit der der gesamte Inhalt in das aktuelle Verzeichnis geschrieben wird.

def write_file(event_file):
   with open(event_file.info.name.name, "w") as outfile:
      outfile.write(event_file.read_random(0, event_file.info.meta.size))
   return event_file.info.name.name
      if pyevt.check_file_signature(temp_evt):
         evt_log = pyevt.open(temp_evt)
         print("[+] Identified {} records in {}".format(
            evt_log.number_of_records, temp_evt))
         
         for i, record in enumerate(evt_log.records):
            strings = ""
            for s in record.strings:
               if s is not None:
                  strings += s + "\n"
            event_data.append([
               i, hit[0], record.computer_name,
               record.user_security_identifier,
               record.creation_time, record.written_time,
               record.event_category, record.source_name,
               record.event_identifier, record.event_type,
               strings, "",
               os.path.join(win_event, hit[1].lstrip("//"))
            ])
      elif pyevtx.check_file_signature(temp_evt):
         evtx_log = pyevtx.open(temp_evt)
         print("[+] Identified {} records in {}".format(
            evtx_log.number_of_records, temp_evt))
         for i, record in enumerate(evtx_log.records):
            strings = ""
            for s in record.strings:
			   if s is not None:
               strings += s + "\n"
         event_data.append([
            i, hit[0], record.computer_name,
            record.user_security_identifier, "",
            record.written_time, record.event_level,
            record.source_name, record.event_identifier,
            "", strings, record.xml_string,
            os.path.join(win_event, hit[1].lstrip("//"))
      ])
      else:
         print("[-] {} not a valid event log. Removing temp" file...".format(temp_evt))
         os.remove(temp_evt)
      continue
      write_output(event_data)
   else:
      print("[-] {} Event log not found in {} directory".format(log, win_event))
      sys.exit(3)
else:
   print("[-] Win XP Event Log Directory {} not found".format(win_event))
   sys.exit(2

Definieren Sie abschließend eine Methode zum Schreiben der Ausgabe in eine Tabelle wie folgt:

def write_output(data):
   output_name = "parsed_event_logs.csv"
   print("[+] Writing {} to current working directory: {}".format(
      output_name, os.getcwd()))
   
   with open(output_name, "wb") as outfile:
      writer = csv.writer(outfile)
      writer.writerow([
         "Index", "File name", "Computer Name", "SID",
         "Event Create Date", "Event Written Date",
         "Event Category/Level", "Event Source", "Event ID",
         "Event Type", "Data", "XML Data", "File Path"
      ])
      writer.writerows(data)

Sobald Sie das obige Skript erfolgreich ausgeführt haben, erhalten wir die Informationen zum Ereignisprotokoll in der Tabelle.

Internet-Geschichte

Die Internet-Historie ist für forensische Analysten sehr nützlich. da die meisten Cyber-Verbrechen nur über das Internet geschehen. Lassen Sie uns sehen, wie Sie den Internetverlauf aus dem Internet Explorer extrahieren, während wir uns mit Windows-Forensik befassen. Internet Explorer wird standardmäßig mit Windows geliefert.

Im Internet Explorer wird der Internetverlauf in gespeichert index.datDatei. Schauen wir uns ein Python-Skript an, aus dem die Informationen extrahiert werdenindex.dat Datei.

Wir können die folgenden Schritte ausführen, um Informationen daraus zu extrahieren index.dat Dateien -

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

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

  • Schreiben Sie nun alle diese Informationen in einen 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
import argparse

from datetime import datetime, timedelta
import os
import pytsk3
import pyewf
import pymsiecf
import sys
import unicodecsv as csv

from utility.pytskutil import TSKUtil

Geben Sie nun Argumente für den Befehlszeilenhandler an. Beachten Sie, dass hier zwei Argumente akzeptiert werden - erstens der Pfad zur Beweisdatei und zweitens der Typ der Beweisdatei -

if __name__ == "__main__":
parser = argparse.ArgumentParser('getting information from internet history')
   parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
   parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
   parser.add_argument("-d", help = "Index.dat directory to scan",default = "/USERS")
   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.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 TSKUtilund iterieren Sie durch das Dateisystem, um index.dat-Dateien zu finden. Dies kann durch Definieren dermain() Funktion wie folgt -

def main(evidence, image_type, path):
   tsk_util = TSKUtil(evidence, image_type)
   index_dir = tsk_util.query_directory(path)
   
   if index_dir is not None:
      index_files = tsk_util.recurse_files("index.dat", path = path,logic = "equal")
      
      if index_files is not None:
         print("[+] Identified {} potential index.dat files".format(len(index_files)))
         index_data = []
         
         for hit in index_files:
            index_file = hit[2]
            temp_index = write_file(index_file)

Definieren Sie nun eine Funktion, mit deren Hilfe wir die Informationen der Datei index.dat in das aktuelle Arbeitsverzeichnis kopieren und später von einem Drittanbieter-Modul verarbeiten können.

def write_file(index_file):
   with open(index_file.info.name.name, "w") as outfile:
   outfile.write(index_file.read_random(0, index_file.info.meta.size))
return index_file.info.name.name

Verwenden Sie nun den folgenden Code, um die Signaturüberprüfung mit Hilfe der integrierten Funktion durchzuführen check_file_signature() - -

if pymsiecf.check_file_signature(temp_index):
   index_dat = pymsiecf.open(temp_index)
   print("[+] Identified {} records in {}".format(
   index_dat.number_of_items, temp_index))

   for i, record in enumerate(index_dat.items):
   try:
      data = record.data
   if data is not None:
      data = data.rstrip("\x00")
   except AttributeError:
   
   if isinstance(record, pymsiecf.redirected):
      index_data.append([
         i, temp_index, "", "", "", "", "",record.location, "", "", record.offset,os.path.join(path, hit[1].lstrip("//"))])
   
   elif isinstance(record, pymsiecf.leak):
      index_data.append([
         i, temp_index, record.filename, "","", "", "", "", "", "", record.offset,os.path.join(path, hit[1].lstrip("//"))])
   continue
   
   index_data.append([
      i, temp_index, record.filename,
      record.type, record.primary_time,
      record.secondary_time,
      record.last_checked_time, record.location,
      record.number_of_hits, data, record.offset,
      os.path.join(path, hit[1].lstrip("//"))
   ])
   else:
      print("[-] {} not a valid index.dat file. Removing "
      "temp file..".format(temp_index))
      os.remove("index.dat")
      continue
      os.remove("index.dat")
      write_output(index_data)
   else:
      print("[-] Index.dat files not found in {} directory".format(path))
   sys.exit(3)
   else:
      print("[-] Directory {} not found".format(win_event))
   sys.exit(2)

Definieren Sie nun eine Methode, mit der die Ausgabe in einer CSV-Datei gedruckt wird (siehe unten).

def write_output(data):
   output_name = "Internet_Indexdat_Summary_Report.csv"
   print("[+] Writing {} with {} parsed index.dat files to current "
   "working directory: {}".format(output_name, len(data),os.getcwd()))
   
   with open(output_name, "wb") as outfile:
      writer = csv.writer(outfile)
      writer.writerow(["Index", "File Name", "Record Name",
      "Record Type", "Primary Date", "Secondary Date",
      "Last Checked Date", "Location", "No. of Hits",
      "Record Data", "Record Offset", "File Path"])
      writer.writerows(data)

Nachdem wir das obige Skript ausgeführt haben, erhalten wir die Informationen aus der Datei index.dat in der CSV-Datei.

Volumenschattenkopien

Eine Schattenkopie ist die in Windows enthaltene Technologie zum manuellen oder automatischen Erstellen von Sicherungskopien oder Schnappschüssen von Computerdateien. Es wird auch als Volume Snapshot Service oder Volume Shadow Service (VSS) bezeichnet.

Mithilfe dieser VSS-Dateien können Forensiker historische Informationen darüber erhalten, wie sich das System im Laufe der Zeit geändert hat und welche Dateien auf dem Computer vorhanden waren. Für die Schattenkopiertechnologie muss das Dateisystem NTFS sein, um Schattenkopien erstellen und speichern zu können.

In diesem Abschnitt sehen wir ein Python-Skript, mit dessen Hilfe Sie auf alle im forensischen Bild vorhandenen Schattenkopien zugreifen können.

Für Python-Skripte müssen wir nämlich Module von Drittanbietern installieren pytsk3, pyewf, unicodecsv, pyvshadow und vss. Wir können die folgenden Schritte ausführen, um Informationen aus VSS-Dateien zu extrahieren

  • Greifen Sie zunächst auf das Volume des Rohabbilds zu und identifizieren Sie alle NTFS-Partitionen.

  • Extrahieren Sie dann die Informationen aus diesen Schattenkopien, indem Sie sie durchlaufen.

  • Jetzt müssen wir endlich eine Dateiliste mit Daten innerhalb der Snapshots erstellen.

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 pyvshadow
import sys
import unicodecsv as csv

from utility import vss
from utility.pytskutil import TSKUtil
from utility import pytskutil

Geben Sie nun Argumente für den Befehlszeilenhandler an. Hier werden zwei Argumente akzeptiert - erstens der Pfad zur Beweisdatei und zweitens die Ausgabedatei.

if __name__ == "__main__":
   parser = argparse.ArgumentParser('Parsing Shadow Copies')
   parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
   parser.add_argument("OUTPUT_CSV", help = "Output CSV with VSS file listing")
   args = parser.parse_args()

Überprüfen Sie nun die Existenz des Eingabedateipfads und trennen Sie das Verzeichnis von der Ausgabedatei.

directory = os.path.dirname(args.OUTPUT_CSV)
if not os.path.exists(directory) and directory != "":
   os.makedirs(directory)
if os.path.exists(args.EVIDENCE_FILE) and \ os.path.isfile(args.EVIDENCE_FILE):
   main(args.EVIDENCE_FILE, args.OUTPUT_CSV)
else:
   print("[-] Supplied input file {} does not exist or is not a "
   "file".format(args.EVIDENCE_FILE))
   
   sys.exit(1)

Interagieren Sie jetzt mit dem Volume der Beweisdatei, indem Sie das erstellen TSKUtilObjekt. Dies kann mit Hilfe von erfolgenmain() Methode wie folgt -

def main(evidence, output):
   tsk_util = TSKUtil(evidence, "raw")
   img_vol = tsk_util.return_vol()

if img_vol is not None:
   for part in img_vol:
      if tsk_util.detect_ntfs(img_vol, part):
         print("Exploring NTFS Partition for VSS")
         explore_vss(evidence, part.start * img_vol.info.block_size,output)
      else:
         print("[-] Must be a physical preservation to be compatible ""with this script")
         sys.exit(2)

Definieren Sie nun eine Methode zum Durchsuchen der analysierten Volume-Schattendatei wie folgt:

def explore_vss(evidence, part_offset, output):
   vss_volume = pyvshadow.volume()
   vss_handle = vss.VShadowVolume(evidence, part_offset)
   vss_count = vss.GetVssStoreCount(evidence, part_offset)
   
   if vss_count > 0:
      vss_volume.open_file_object(vss_handle)
      vss_data = []
      
      for x in range(vss_count):
         print("Gathering data for VSC {} of {}".format(x, vss_count))
         vss_store = vss_volume.get_store(x)
         image = vss.VShadowImgInfo(vss_store)
         vss_data.append(pytskutil.openVSSFS(image, x))
write_csv(vss_data, output)

Definieren Sie abschließend die Methode zum Schreiben des Ergebnisses in eine Tabelle wie folgt:

def write_csv(data, output):
   if data == []:
      print("[-] No output results to write")
      sys.exit(3)
   print("[+] Writing output to {}".format(output))
   if os.path.exists(output):
      append = True
with open(output, "ab") as csvfile:
      csv_writer = csv.writer(csvfile)
      headers = ["VSS", "File", "File Ext", "File Type", "Create Date",
         "Modify Date", "Change Date", "Size", "File Path"]
      if not append:
         csv_writer.writerow(headers)
      for result_list in data:
         csv_writer.writerows(result_list)

Sobald Sie dieses Python-Skript erfolgreich ausgeführt haben, erhalten wir die in VSS enthaltenen Informationen in einer Tabelle.

Bis jetzt haben wir gesehen, wie man mit Python Artefakte in Windows erhält. In diesem Kapitel erfahren Sie mehr über die Untersuchung protokollbasierter Artefakte mit Python.

Einführung

Protokollbasierte Artefakte sind der Schatz an Informationen, die für einen Experten für digitale Forensik sehr nützlich sein können. Obwohl wir über verschiedene Überwachungssoftware zum Sammeln der Informationen verfügen, besteht das Hauptproblem beim Analysieren nützlicher Informationen darin, dass wir viele Daten benötigen.

Verschiedene log-basierte Artefakte und Untersuchungen in Python

Lassen Sie uns in diesem Abschnitt verschiedene logbasierte Artefakte und ihre Untersuchung in Python diskutieren -

Zeitstempel

Der Zeitstempel übermittelt die Daten und die Zeit der Aktivität im Protokoll. Es ist eines der wichtigen Elemente jeder Protokolldatei. Beachten Sie, dass diese Daten- und Zeitwerte in verschiedenen Formaten vorliegen können.

Das unten gezeigte Python-Skript verwendet die unformatierte Datums- und Uhrzeitangabe als Eingabe und stellt einen formatierten Zeitstempel als Ausgabe bereit.

Für dieses Skript müssen wir die folgenden Schritte ausführen:

  • Richten Sie zunächst die Argumente ein, die den Rohdatenwert zusammen mit der Datenquelle und dem Datentyp verwenden.

  • Stellen Sie jetzt eine Klasse für die Bereitstellung einer gemeinsamen Schnittstelle für Daten in verschiedenen Datumsformaten bereit.

Python-Code

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

Importieren Sie zunächst die folgenden Python-Module:

from __future__ import print_function
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from datetime import datetime as dt
from datetime import timedelta

Jetzt müssen wir wie üblich Argumente für den Befehlszeilen-Handler bereitstellen. Hier werden drei Argumente akzeptiert: erstens der zu verarbeitende Datumswert, zweitens die Quelle dieses Datumswerts und drittens der Typ -

if __name__ == '__main__':
   parser = ArgumentParser('Timestamp Log-based artifact')
   parser.add_argument("date_value", help="Raw date value to parse")
   parser.add_argument(
      "source", help = "Source format of date",choices = ParseDate.get_supported_formats())
   parser.add_argument(
      "type", help = "Data type of input value",choices = ('number', 'hex'), default = 'int')
   
   args = parser.parse_args()
   date_parser = ParseDate(args.date_value, args.source, args.type)
   date_parser.run()
   print(date_parser.timestamp)

Jetzt müssen wir eine Klasse definieren, die die Argumente für Datumswert, Datumsquelle und Werttyp akzeptiert.

class ParseDate(object):
   def __init__(self, date_value, source, data_type):
      self.date_value = date_value
      self.source = source
      self.data_type = data_type
      self.timestamp = None

Jetzt definieren wir eine Methode, die sich wie die main () -Methode wie ein Controller verhält -

def run(self):
   if self.source == 'unix-epoch':
      self.parse_unix_epoch()
   elif self.source == 'unix-epoch-ms':
      self.parse_unix_epoch(True)
   elif self.source == 'windows-filetime':
      self.parse_windows_filetime()
@classmethod
def get_supported_formats(cls):
   return ['unix-epoch', 'unix-epoch-ms', 'windows-filetime']

Jetzt müssen wir zwei Methoden definieren, die die Unix-Epochenzeit bzw. FILETIME verarbeiten -

def parse_unix_epoch(self, milliseconds=False):
   if self.data_type == 'hex':
      conv_value = int(self.date_value)
      if milliseconds:
         conv_value = conv_value / 1000.0
   elif self.data_type == 'number':
      conv_value = float(self.date_value)
      if milliseconds:
         conv_value = conv_value / 1000.0
   else:
      print("Unsupported data type '{}' provided".format(self.data_type))
      sys.exit('1')
   ts = dt.fromtimestamp(conv_value)
   self.timestamp = ts.strftime('%Y-%m-%d %H:%M:%S.%f')
def parse_windows_filetime(self):
   if self.data_type == 'hex':
      microseconds = int(self.date_value, 16) / 10.0
   elif self.data_type == 'number':
      microseconds = float(self.date_value) / 10
   else:
      print("Unsupported data type '{}'   provided".format(self.data_type))
      sys.exit('1')
   ts = dt(1601, 1, 1) + timedelta(microseconds=microseconds)
   self.timestamp = ts.strftime('%Y-%m-%d %H:%M:%S.%f')

Nach dem Ausführen des obigen Skripts können wir durch Angabe eines Zeitstempels den konvertierten Wert in einem einfach zu lesenden Format erhalten.

Webserver-Protokolle

Aus Sicht des Experten für digitale Forensik sind Webserverprotokolle ein weiteres wichtiges Artefakt, da sie nützliche Benutzerstatistiken sowie Informationen über den Benutzer und die geografischen Standorte enthalten können. Das folgende Python-Skript erstellt nach der Verarbeitung der Webserver-Protokolle eine Tabelle zur einfachen Analyse der Informationen.

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

from __future__ import print_function
from argparse import ArgumentParser, FileType

import re
import shlex
import logging
import sys
import csv

logger = logging.getLogger(__file__)

Jetzt müssen wir die Muster definieren, die aus den Protokollen analysiert werden -

iis_log_format = [
   ("date", re.compile(r"\d{4}-\d{2}-\d{2}")),
   ("time", re.compile(r"\d\d:\d\d:\d\d")),
   ("s-ip", re.compile(
      r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}")),
   ("cs-method", re.compile(
      r"(GET)|(POST)|(PUT)|(DELETE)|(OPTIONS)|(HEAD)|(CONNECT)")),
   ("cs-uri-stem", re.compile(r"([A-Za-z0-1/\.-]*)")),
   ("cs-uri-query", re.compile(r"([A-Za-z0-1/\.-]*)")),
   ("s-port", re.compile(r"\d*")),
   ("cs-username", re.compile(r"([A-Za-z0-1/\.-]*)")),
   ("c-ip", re.compile(
      r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}")),
   ("cs(User-Agent)", re.compile(r".*")),
   ("sc-status", re.compile(r"\d*")),
   ("sc-substatus", re.compile(r"\d*")),
   ("sc-win32-status", re.compile(r"\d*")),
   ("time-taken", re.compile(r"\d*"))]

Geben Sie nun ein Argument für den Befehlszeilenhandler an. Hier werden zwei Argumente akzeptiert: erstens das zu verarbeitende IIS-Protokoll und zweitens der gewünschte CSV-Dateipfad.

if __name__ == '__main__':
   parser = ArgumentParser('Parsing Server Based Logs')
   parser.add_argument('iis_log', help = "Path to IIS Log",type = FileType('r'))
   parser.add_argument('csv_report', help = "Path to CSV report")
   parser.add_argument('-l', help = "Path to processing log",default=__name__ + '.log')
   args = parser.parse_args()
   logger.setLevel(logging.DEBUG)
   msg_fmt = logging.Formatter(
      "%(asctime)-15s %(funcName)-10s ""%(levelname)-8s %(message)s")
   
   strhndl = logging.StreamHandler(sys.stdout)
   strhndl.setFormatter(fmt = msg_fmt)
   fhndl = logging.FileHandler(args.log, mode = 'a')
   fhndl.setFormatter(fmt = msg_fmt)
   
   logger.addHandler(strhndl)
   logger.addHandler(fhndl)
   logger.info("Starting IIS Parsing ")
   logger.debug("Supplied arguments: {}".format(", ".join(sys.argv[1:])))
   logger.debug("System " + sys.platform)
   logger.debug("Version " + sys.version)
   main(args.iis_log, args.csv_report, logger)
   iologger.info("IIS Parsing Complete")

Jetzt müssen wir die main () -Methode definieren, die das Skript für Massenprotokollinformationen verarbeitet.

def main(iis_log, report_file, logger):
   parsed_logs = []

for raw_line in iis_log:
   line = raw_line.strip()
   log_entry = {}

if line.startswith("#") or len(line) == 0:
   continue

if '\"' in line:
   line_iter = shlex.shlex(line_iter)
else:
   line_iter = line.split(" ")
   for count, split_entry in enumerate(line_iter):
      col_name, col_pattern = iis_log_format[count]

      if col_pattern.match(split_entry):
         log_entry[col_name] = split_entry
else:
   logger.error("Unknown column pattern discovered. "
      "Line preserved in full below")
      logger.error("Unparsed Line: {}".format(line))
      parsed_logs.append(log_entry)
      
      logger.info("Parsed {} lines".format(len(parsed_logs)))
      cols = [x[0] for x in iis_log_format]
      
      logger.info("Creating report file: {}".format(report_file))
      write_csv(report_file, cols, parsed_logs)
      logger.info("Report created")

Zuletzt müssen wir eine Methode definieren, die die Ausgabe in die Tabelle schreibt -

def write_csv(outfile, fieldnames, data):
   with open(outfile, 'w', newline="") as open_outfile:
      csvfile = csv.DictWriter(open_outfile, fieldnames)
      csvfile.writeheader()
      csvfile.writerows(data)

Nach dem Ausführen des obigen Skripts erhalten wir die Webserver-basierten Protokolle in einer Tabelle.

Scannen wichtiger Dateien mit YARA

YARA (Noch ein rekursiver Algorithmus) ist ein Dienstprogramm zur Mustererkennung, das zur Identifizierung von Malware und zur Reaktion auf Vorfälle entwickelt wurde. Wir werden YARA zum Scannen der Dateien verwenden. Im folgenden Python-Skript verwenden wir YARA.

Wir können YARA mit Hilfe des folgenden Befehls installieren:

pip install YARA

Wir können die folgenden Schritte ausführen, um YARA-Regeln zum Scannen von Dateien zu verwenden.

  • Richten Sie zunächst YARA-Regeln ein und kompilieren Sie sie

  • Scannen Sie dann eine einzelne Datei und durchlaufen Sie die Verzeichnisse, um einzelne Dateien zu verarbeiten.

  • Zuletzt werden wir das Ergebnis in CSV exportieren.

Python-Code

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

Zuerst müssen wir die folgenden Python-Module importieren -

from __future__ import print_function
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter

import os
import csv
import yara

Geben Sie als Nächstes ein Argument für den Befehlszeilenhandler an. Beachten Sie, dass hier zwei Argumente akzeptiert werden: Erstens der Pfad zu den YARA-Regeln, zweitens die zu scannende Datei.

if __name__ == '__main__':
   parser = ArgumentParser('Scanning files by YARA')
   parser.add_argument(
      'yara_rules',help = "Path to Yara rule to scan with. May be file or folder path.")
   parser.add_argument('path_to_scan',help = "Path to file or folder to scan")
   parser.add_argument('--output',help = "Path to output a CSV report of scan results")
   args = parser.parse_args()
   main(args.yara_rules, args.path_to_scan, args.output)

Jetzt definieren wir die main () - Funktion, die den Pfad zu den zu scannenden Yara-Regeln und -Dateien akzeptiert.

def main(yara_rules, path_to_scan, output):
   if os.path.isdir(yara_rules):
      yrules = yara.compile(yara_rules)
   else:
      yrules = yara.compile(filepath=yara_rules)
   if os.path.isdir(path_to_scan):
      match_info = process_directory(yrules, path_to_scan)
   else:
      match_info = process_file(yrules, path_to_scan)
   columns = ['rule_name', 'hit_value', 'hit_offset', 'file_name',
   'rule_string', 'rule_tag']
   
   if output is None:
      write_stdout(columns, match_info)
   else:
      write_csv(output, columns, match_info)

Definieren Sie nun eine Methode, die das Verzeichnis durchläuft und das Ergebnis zur weiteren Verarbeitung an eine andere Methode weitergibt.

def process_directory(yrules, folder_path):
   match_info = []
   for root, _, files in os.walk(folder_path):
      for entry in files:
         file_entry = os.path.join(root, entry)
         match_info += process_file(yrules, file_entry)
   return match_info

Definieren Sie als Nächstes zwei Funktionen. Beachten Sie, dass wir zuerst verwenden werdenmatch() Methode zu yrulesobject und ein anderes melden diese übereinstimmenden Informationen an die Konsole, wenn der Benutzer keine Ausgabedatei angibt. Beachten Sie den unten gezeigten Code -

def process_file(yrules, file_path):
   match = yrules.match(file_path)
   match_info = []
   
   for rule_set in match:
      for hit in rule_set.strings:
         match_info.append({
            'file_name': file_path,
            'rule_name': rule_set.rule,
            'rule_tag': ",".join(rule_set.tags),
            'hit_offset': hit[0],
            'rule_string': hit[1],
            'hit_value': hit[2]
         })
   return match_info
def write_stdout(columns, match_info):
   for entry in match_info:
      for col in columns:
         print("{}: {}".format(col, entry[col]))
   print("=" * 30)

Zuletzt definieren wir eine Methode, die die Ausgabe in die CSV-Datei schreibt, wie unten gezeigt -

def write_csv(outfile, fieldnames, data):
   with open(outfile, 'w', newline="") as open_outfile:
      csvfile = csv.DictWriter(open_outfile, fieldnames)
      csvfile.writeheader()
      csvfile.writerows(data)

Sobald Sie das obige Skript erfolgreich ausgeführt haben, können wir entsprechende Argumente in der Befehlszeile bereitstellen und einen CSV-Bericht erstellen.