Python Digital Network Forensics-II

Il capitolo precedente ha trattato alcuni dei concetti di network forensics usando Python. In questo capitolo, cerchiamo di comprendere la rete forense utilizzando Python a un livello più profondo.

Conservazione della pagina Web con una bella zuppa

Il World Wide Web (WWW) è una risorsa di informazioni unica. Tuttavia, la sua eredità è ad alto rischio a causa della perdita di contenuti a un ritmo allarmante. Un certo numero di istituzioni accademiche e del patrimonio culturale, organizzazioni senza scopo di lucro e imprese private hanno esplorato le problematiche coinvolte e hanno contribuito allo sviluppo di soluzioni tecniche per l'archiviazione web.

La conservazione della pagina Web o l'archiviazione sul Web è il processo di raccolta dei dati dal World Wide Web, garantendo che i dati siano conservati in un archivio e rendendoli disponibili per futuri ricercatori, storici e pubblico. Prima di procedere ulteriormente nella conservazione della pagina web, discutiamo di alcune questioni importanti relative alla conservazione della pagina web come indicato di seguito:

  • Change in Web Resources - Le risorse Web continuano a cambiare ogni giorno, il che rappresenta una sfida per la conservazione delle pagine Web.

  • Large Quantity of Resources - Un altro problema relativo alla conservazione delle pagine web è la grande quantità di risorse che deve essere preservata.

  • Integrity - Le pagine Web devono essere protette da modifiche, eliminazioni o eliminazioni non autorizzate per proteggerne l'integrità.

  • Dealing with multimedia data - Pur preservando le pagine web, dobbiamo occuparci anche dei dati multimediali, e questi potrebbero causare problemi nel farlo.

  • Providing access - Oltre a preservare, deve essere risolta anche la questione della fornitura di accesso alle risorse web e la gestione dei problemi di proprietà.

In questo capitolo, useremo la libreria Python denominata Beautiful Soup per la conservazione della pagina web.

Cos'è Beautiful Soup?

Beautiful Soup è una libreria Python per estrarre dati da file HTML e XML. Può essere utilizzato conurlibperché ha bisogno di un input (documento o URL) per creare un oggetto soup, in quanto non può recuperare la pagina web stessa. Puoi saperne di più in dettaglio su www.crummy.com/software/BeautifulSoup/bs4/doc/

Nota che prima di usarlo, dobbiamo installare una libreria di terze parti utilizzando il seguente comando:

pip install bs4

Successivamente, utilizzando il gestore di pacchetti Anaconda, possiamo installare Beautiful Soup come segue:

conda install -c anaconda beautifulsoup4

Script Python per la conservazione delle pagine Web

Lo script Python per preservare le pagine web utilizzando la libreria di terze parti chiamata Beautiful Soup è discusso qui -

Innanzitutto, importa le librerie richieste come segue:

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

Nota che questo script prenderà due argomenti posizionali, uno è l'URL che deve essere preservato e l'altro è la directory di output desiderata come mostrato di seguito -

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

Ora, configura la registrazione per lo script specificando un file e un gestore di flusso per essere in loop e documenta il processo di acquisizione come mostrato -

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)

Ora, eseguiamo la convalida dell'input sulla directory di output desiderata come segue:

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

Ora definiremo il file main() funzione che estrarrà il nome di base del sito Web rimuovendo gli elementi non necessari prima del nome effettivo insieme a una convalida aggiuntiva sull'URL di input come segue:

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

Ora, dobbiamo aprire una connessione con l'URL usando il metodo urlopen (). Usiamo il blocco try-tranne come segue:

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

Le successive righe di codice includono tre funzioni come spiegato di seguito:

  • write_output() per scrivere la prima pagina web nella directory di output

  • find_links() funzione per identificare i collegamenti su questa pagina web

  • recurse_pages() funzione per scorrere e scoprire tutti i collegamenti nella pagina 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))

Ora, definiamo write_output() metodo come segue -

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)

Abbiamo bisogno di registrare alcuni dettagli sulla pagina web e quindi registriamo l'hash dei dati utilizzando hash_data() metodo come segue -

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

Adesso definisci hash_data() metodo con l'aiuto del quale leggiamo il UTF-8 dati codificati e quindi generare il file SHA-256 hash di esso come segue -

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

Ora, creiamo un file Beautifulsoup oggetto fuori dai dati della pagina web sotto find_links() metodo come segue -

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

Ora, dobbiamo definire recurse_pages() fornendogli gli input dell'URL del sito Web, della coda di collegamento corrente, del contesto SSL non verificato e della directory di output come segue:

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

Ora, scrivi l'output di ciascuna pagina web a cui si accede in un file passando il nome del collegamento, i dati della pagina, la directory di output e il contatore come segue:

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

Ora, quando eseguiamo questo script fornendo l'URL del sito Web, la directory di output e un percorso al file di registro, otterremo i dettagli su quella pagina Web che può essere utilizzata per un utilizzo futuro.

Caccia al virus

Ti sei mai chiesto come gli analisti forensi, i ricercatori sulla sicurezza e gli intervistati sugli incidenti possano capire la differenza tra software utile e malware? La risposta sta nella domanda stessa, perché senza studiare il malware, generato rapidamente dagli hacker, è del tutto impossibile per ricercatori e specialisti capire la differenza tra software utile e malware. In questa sezione, discutiamo diVirusShare, uno strumento per eseguire questa operazione.

Capire VirusShare

VirusShare è la più grande raccolta privata di campioni di malware per fornire a ricercatori di sicurezza, soccorritori in caso di incidenti e analisti forensi campioni di codice dannoso in tempo reale. Contiene oltre 30 milioni di campioni.

Il vantaggio di VirusShare è l'elenco degli hash di malware che è disponibile gratuitamente. Chiunque può utilizzare questi hash per creare un set di hash molto completo e utilizzarlo per identificare file potenzialmente dannosi. Ma prima di utilizzare VirusShare, ti consigliamo di visitarehttps://virusshare.com per ulteriori dettagli.

Creazione di un elenco hash delimitato da una nuova riga da VirusShare utilizzando Python

Un elenco hash di VirusShare può essere utilizzato da vari strumenti forensi come X-ways ed EnCase. Nello script discusso di seguito, automatizzeremo il download di elenchi di hash da VirusShare per creare un elenco di hash delimitato da una nuova riga.

Per questo script, abbiamo bisogno di una libreria Python di terze parti tqdm che può essere scaricato come segue -

pip install tqdm

Nota che in questo script, prima leggeremo la pagina hash di VirusShare e identificheremo dinamicamente l'elenco hash più recente. Quindi inizializzeremo la barra di avanzamento e scaricheremo l'elenco hash nell'intervallo desiderato.

Innanzitutto, importa le seguenti librerie:

from __future__ import print_function

import argparse
import os
import ssl
import sys
import tqdm

from urllib.request import urlopen
import urllib.error

Questo script prenderà un argomento posizionale, che sarebbe il percorso desiderato per il set di hash -

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

Ora eseguiremo la convalida dell'input standard come segue:

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)

Ora dobbiamo definire main() funzione con **kwargs come argomento perché questo creerà un dizionario a cui possiamo fare riferimento per supportare gli argomenti chiave forniti come mostrato di seguito -

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

Ora, dobbiamo aprire la pagina hash di VirusShare utilizzando urlib.request.urlopen()metodo. Useremo il blocco try-tranne come segue:

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

Ora, identifica l'ultimo elenco hash dalle pagine scaricate. Puoi farlo trovando l'ultima istanza di HTMLhreftag nell'elenco hash di VirusShare. Può essere fatto con le seguenti righe di codice:

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

Ora useremo tqdm.trange() metodo per creare un ciclo e una barra di avanzamento come segue:

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

Dopo aver eseguito correttamente i passaggi precedenti, apriremo il file di testo del set di hash in modalità + da aggiungere alla fine del file di testo.

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

Dopo aver eseguito lo script precedente, otterrai l'ultimo elenco hash contenente i valori hash MD5 in formato testo.