Python Digital Network Forensics-II

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, indem die Eingaben der Website-URL, der aktuellen Link-Warteschlange, des nicht verifizierten SSL-Kontexts und des Ausgabeverzeichnisses wie folgt bereitgestellt werden:

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, um Sicherheitsforschern, Einsatzkräften und forensischen Analysten die Beispiele für Live-Schadcode bereitzustellen. 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.