Python Digital Network Forensics-I

Este capítulo explicará os fundamentos envolvidos na execução de análise forense de rede usando Python.

Noções básicas sobre análise forense de rede

Network forensics é um ramo da perícia digital que trata do monitoramento e análise do tráfego de redes de computadores, tanto locais quanto WAN (rede de longa distância), para fins de coleta de informações, coleta de evidências ou detecção de intrusão. A perícia de rede desempenha um papel fundamental na investigação de crimes digitais, como roubo de propriedade intelectual ou vazamento de informações. Uma imagem das comunicações de rede ajuda um investigador a resolver algumas questões cruciais como segue -

  • Quais sites foram acessados?

  • Que tipo de conteúdo foi carregado em nossa rede?

  • Que tipo de conteúdo foi baixado de nossa rede?

  • Quais servidores estão sendo acessados?

  • Alguém está enviando informações confidenciais fora dos firewalls da empresa?

Internet Evidence Finder (IEF)

O IEF é uma ferramenta digital forense para encontrar, analisar e apresentar evidências digitais encontradas em diferentes mídias digitais como computador, smartphones, tablets etc. É muito popular e utilizado por milhares de profissionais forenses.

Uso de IEF

Devido à sua popularidade, o IEF é amplamente utilizado por profissionais forenses. Alguns dos usos do IEF são os seguintes -

  • Devido aos seus poderosos recursos de pesquisa, ele é usado para pesquisar vários arquivos ou mídia de dados simultaneamente.

  • Ele também é usado para recuperar dados excluídos do espaço não alocado da RAM por meio de novas técnicas de escultura.

  • Se os investigadores quiserem reconstruir as páginas da web em seu formato original na data em que foram abertas, eles podem usar o IEF.

  • Ele também é usado para pesquisar volumes de disco lógico ou físico.

Relatórios de despejo de IEF para CSV usando Python

O IEF armazena dados em um banco de dados SQLite e o script Python seguinte identifica dinamicamente as tabelas de resultados no banco de dados IEF e as despeja nos respectivos arquivos CSV.

Este processo é feito nas etapas mostradas abaixo

  • Primeiro, gere o banco de dados de resultados do IEF, que será um arquivo de banco de dados SQLite terminando com a extensão .db.

  • Em seguida, consulte esse banco de dados para identificar todas as tabelas.

  • Por último, grave essas tabelas de resultados em um arquivo CSV individual.

Código Python

Vamos ver como usar o código Python para esse propósito -

Para o script Python, importe as bibliotecas necessárias da seguinte maneira -

from __future__ import print_function

import argparse
import csv
import os
import sqlite3
import sys

Agora, precisamos fornecer o caminho para o arquivo de banco de dados IEF -

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

Agora, vamos confirmar a existência do banco de dados IEF da seguinte forma -

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)

Agora, como fizemos em scripts anteriores, faça a conexão com o banco de dados SQLite da seguinte forma para executar as consultas por meio do cursor -

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

As seguintes linhas de código buscarão os nomes das tabelas no banco de dados -

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

Agora, vamos selecionar todos os dados da tabela e usando fetchall() método no objeto cursor, iremos armazenar a lista de tuplas contendo os dados da tabela em sua totalidade em uma variável -

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

Agora, usando CSV_Writer() método, vamos escrever o conteúdo em arquivo CSV -

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)

O script acima irá buscar todos os dados das tabelas do banco de dados IEF e escrever o conteúdo no arquivo CSV de nossa escolha.

Trabalho com dados em cache

No banco de dados de resultados do IEF, podemos buscar mais informações que não são necessariamente suportadas pelo próprio IEF. Podemos buscar os dados em cache, um produto bi para informações, de um provedor de serviços de e-mail como Yahoo, Google etc. usando o banco de dados de resultados do IEF.

A seguir está o script Python para acessar as informações de dados em cache do correio do Yahoo, acessado no Google Chrome, usando o banco de dados IEF. Observe que as etapas seriam mais ou menos iguais às seguidas no último script Python.

Primeiro, importe as bibliotecas necessárias para Python da seguinte maneira -

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

Agora, forneça o caminho para o arquivo de banco de dados IEF junto com dois argumentos posicionais aceitos pelo manipulador de linha de comando como feito no último script -

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

Agora, confirme a existência do banco de dados IEF da seguinte forma -

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)

Agora, faça a conexão com o banco de dados SQLite da seguinte forma para executar as consultas por meio do cursor -

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

Você pode usar as seguintes linhas de código para buscar as instâncias do registro de cache de contato do Yahoo Mail -

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)

Agora, a lista de tuplas retornada da consulta acima para ser salva em uma variável da seguinte maneira -

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

Observe que aqui vamos usar dois métodos, a saber process_contacts() para configurar a lista de resultados, bem como iterar através de cada registro de cache de contato e json.loads() para armazenar os dados JSON extraídos da tabela em uma variável para posterior manipulação -

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

Agora, para empresa, título e notas, o método get é usado conforme mostrado abaixo -

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

Agora, vamos acrescentar a lista de metadados e elementos de dados extraídos à lista de resultados da seguinte forma -

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

Agora, usando CSV_Writer() método, vamos escrever o conteúdo em arquivo CSV -

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)

Com a ajuda do script acima, podemos processar os dados em cache do correio do Yahoo usando o banco de dados IEF.