Python Digital Network Forensics-II

Le chapitre précédent a traité de certains des concepts de la criminalistique de réseau utilisant Python. Dans ce chapitre, apprenons à un niveau plus approfondi la criminalistique réseau utilisant Python.

Conservation de la page Web avec une belle soupe

Le World Wide Web (WWW) est une source d'information unique. Cependant, son héritage est à haut risque en raison de la perte de contenu à un rythme alarmant. Un certain nombre d'institutions patrimoniales culturelles et universitaires, d'organisations à but non lucratif et d'entreprises privées ont exploré les problèmes en jeu et contribué au développement de solutions techniques pour l'archivage Web.

La préservation des pages Web ou l'archivage Web est le processus de collecte des données à partir du World Wide Web, en s'assurant que les données sont conservées dans une archive et en les rendant disponibles pour les futurs chercheurs, historiens et le public. Avant d'aller plus loin dans la préservation de la page Web, laissez-nous discuter de certaines questions importantes liées à la préservation de la page Web, comme indiqué ci-dessous -

  • Change in Web Resources - Les ressources Web changent chaque jour, ce qui est un défi pour la préservation des pages Web.

  • Large Quantity of Resources - Un autre problème lié à la préservation des pages Web est la grande quantité de ressources à préserver.

  • Integrity - Les pages Web doivent être protégées contre les modifications, les suppressions ou les suppressions non autorisées afin de protéger leur intégrité.

  • Dealing with multimedia data - Tout en préservant les pages Web, nous devons également traiter les données multimédias, ce qui peut entraîner des problèmes.

  • Providing access - Outre la préservation, la question de l'accès aux ressources Web et du traitement des problèmes de propriété doit également être résolue.

Dans ce chapitre, nous allons utiliser la bibliothèque Python nommée Beautiful Soup pour la préservation des pages Web.

Qu'est-ce que la belle soupe?

Beautiful Soup est une bibliothèque Python permettant d'extraire des données de fichiers HTML et XML. Il peut être utilisé avecurlibcar il a besoin d'une entrée (document ou url) pour créer un objet soupe, car il ne peut pas récupérer la page Web elle-même. Vous pouvez en savoir plus à ce sujet sur www.crummy.com/software/BeautifulSoup/bs4/doc/

Notez qu'avant de l'utiliser, nous devons installer une bibliothèque tierce à l'aide de la commande suivante -

pip install bs4

Ensuite, en utilisant le gestionnaire de paquets Anaconda, nous pouvons installer Beautiful Soup comme suit -

conda install -c anaconda beautifulsoup4

Script Python pour préserver les pages Web

Le script Python pour la préservation des pages Web à l'aide d'une bibliothèque tierce appelée Beautiful Soup est discuté ici -

Tout d'abord, importez les bibliothèques requises comme suit -

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

Notez que ce script prendra deux arguments de position, l'un est l'URL qui doit être préservée et l'autre est le répertoire de sortie souhaité comme indiqué ci-dessous -

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

Maintenant, configurez la journalisation du script en spécifiant un fichier et un gestionnaire de flux pour être en boucle et documentez le processus d'acquisition comme indiqué -

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)

Maintenant, faisons la validation d'entrée sur le répertoire de sortie souhaité comme suit -

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

Maintenant, nous allons définir le main() fonction qui extraira le nom de base du site Web en supprimant les éléments inutiles avant le nom réel avec une validation supplémentaire sur l'URL d'entrée comme suit -

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

Maintenant, nous devons ouvrir une connexion avec l'URL en utilisant la méthode urlopen (). Utilisons le bloc try-except comme suit -

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

Les lignes de code suivantes incluent trois fonctions comme expliqué ci-dessous -

  • write_output() pour écrire la première page Web dans le répertoire de sortie

  • find_links() fonction pour identifier les liens sur cette page Web

  • recurse_pages() fonction pour parcourir et découvrir tous les liens sur la page Web.

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

Maintenant, définissons write_output() méthode comme suit -

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)

Nous devons enregistrer certains détails sur la page Web, puis nous enregistrons le hachage des données en utilisant hash_data() méthode comme suit -

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

Maintenant, définissez hash_data() méthode à l'aide de laquelle nous lisons le UTF-8 données encodées, puis générez le SHA-256 hachage de celui-ci comme suit -

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

Maintenant, créons un Beautifulsoup objet hors des données de la page Web sous find_links() méthode comme suit -

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

Maintenant, nous devons définir recurse_pages() méthode en lui fournissant les entrées de l'URL du site Web, la file d'attente de liens actuelle, le contexte SSL non vérifié et le répertoire de sortie comme suit -

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

Maintenant, écrivez la sortie de chaque page Web accédée dans un fichier en passant le nom du lien, les données de la page, le répertoire de sortie et le compteur comme suit -

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

Maintenant, lorsque nous exécutons ce script en fournissant l'URL du site Web, le répertoire de sortie et un chemin vers le fichier journal, nous obtiendrons les détails de cette page Web qui peuvent être utilisés pour une utilisation future.

Chasse aux virus

Vous êtes-vous déjà demandé comment les analystes légistes, les chercheurs en sécurité et les répondants aux incidents peuvent comprendre la différence entre les logiciels utiles et les logiciels malveillants? La réponse réside dans la question elle-même, car sans étudier les logiciels malveillants, générés rapidement par les pirates, il est tout à fait impossible pour les chercheurs et les spécialistes de faire la différence entre les logiciels utiles et les logiciels malveillants. Dans cette section, parlons deVirusShare, un outil pour accomplir cette tâche.

Comprendre VirusShare

VirusShare est la plus grande collection privée d'échantillons de logiciels malveillants destinée à fournir aux chercheurs en sécurité, aux intervenants en cas d'incident et aux analystes légistes des échantillons de code malveillant en direct. Il contient plus de 30 millions d'échantillons.

L'avantage de VirusShare est la liste des hachages de logiciels malveillants disponibles gratuitement. N'importe qui peut utiliser ces hachages pour créer un ensemble de hachages très complet et l'utiliser pour identifier les fichiers potentiellement malveillants. Mais avant d'utiliser VirusShare, nous vous suggérons de visiterhttps://virusshare.com pour plus de détails.

Création d'une liste de hachage délimitée par une nouvelle ligne à partir de VirusShare à l'aide de Python

Une liste de hachage de VirusShare peut être utilisée par divers outils médico-légaux tels que X-Ways et EnCase. Dans le script décrit ci-dessous, nous allons automatiser le téléchargement des listes de hachages depuis VirusShare pour créer une liste de hachage délimitée par une nouvelle ligne.

Pour ce script, nous avons besoin d'une bibliothèque Python tierce tqdm qui peut être téléchargé comme suit -

pip install tqdm

Notez que dans ce script, nous allons d'abord lire la page de hachage de VirusShare et identifier dynamiquement la liste de hachage la plus récente. Ensuite, nous initialiserons la barre de progression et téléchargerons la liste de hachage dans la plage souhaitée.

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

from __future__ import print_function

import argparse
import os
import ssl
import sys
import tqdm

from urllib.request import urlopen
import urllib.error

Ce script prendra un argument de position, qui serait le chemin souhaité pour le jeu de hachage -

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

Maintenant, nous allons effectuer la validation d'entrée standard comme suit -

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)

Maintenant, nous devons définir main() fonction avec **kwargs comme argument car cela créera un dictionnaire auquel nous pouvons nous référer pour prendre en charge les arguments clés fournis comme indiqué ci-dessous -

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

Maintenant, nous devons ouvrir la page de hachage de VirusShare en utilisant urlib.request.urlopen()méthode. Nous utiliserons le bloc try-except comme suit -

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

Maintenant, identifiez la dernière liste de hachage des pages téléchargées. Vous pouvez le faire en trouvant la dernière instance du HTMLhrefbalise à la liste de hachage VirusShare. Cela peut être fait avec les lignes de code suivantes -

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

Maintenant, nous allons utiliser tqdm.trange() méthode pour créer une boucle et une barre de progression comme suit -

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

Après avoir exécuté les étapes ci-dessus avec succès, nous ouvrirons le fichier texte du jeu de hachage en mode + pour l'ajouter au bas du fichier texte.

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

Après avoir exécuté le script ci-dessus, vous obtiendrez la dernière liste de hachage contenant les valeurs de hachage MD5 au format texte.