Python Forensics - Guida rapida
Python è un linguaggio di programmazione generico con codice facile e leggibile che può essere facilmente compreso sia dagli sviluppatori professionisti che dai programmatori alle prime armi. Python comprende molte utili librerie che possono essere utilizzate con qualsiasi framework di stack. Molti laboratori si affidano a Python per creare modelli di base per le previsioni e per eseguire esperimenti. Aiuta anche a controllare i sistemi operativi critici.
Python dispone di funzionalità integrate per supportare l'indagine digitale e proteggere l'integrità delle prove durante un'indagine. In questo tutorial, spiegheremo i concetti fondamentali dell'applicazione di Python nell'analisi forense digitale o computazionale.
Cos'è la Computational Forensics?
La Computational Forensics è un dominio di ricerca emergente. Si occupa della risoluzione di problemi forensi utilizzando metodi digitali. Utilizza la scienza computazionale per studiare le prove digitali.
Computation Forensics include una vasta gamma di soggetti su cui vengono studiati oggetti, sostanze e processi, principalmente sulla base di prove di modelli, come segni di utensili, impronte digitali, impronte di scarpe, documenti ecc., E include anche modelli fisiologici e comportamentali, DNA e prove digitali a scene del crimine.
Il diagramma seguente mostra l'ampia gamma di argomenti trattati in Computational Forensics.
L'analisi forense computazionale è implementata con l'aiuto di alcuni algoritmi. Questi algoritmi vengono utilizzati per l'elaborazione di segnali e immagini, la visione artificiale e la grafica. Include anche data mining, machine learning e robotica.
L'analisi forense computazionale coinvolge diversi metodi digitali. La soluzione migliore per semplificare tutti i metodi digitali in ambito forense è utilizzare un linguaggio di programmazione generico come Python.
Poiché abbiamo bisogno di Python per tutte le attività di informatica forense, muoviamoci passo dopo passo e capiamo come installarlo.
Step 1 - Vai a https://www.python.org/downloads/ e scarica i file di installazione di Python in base al sistema operativo che hai sul tuo sistema.
Step 2 - Dopo aver scaricato il pacchetto / programma di installazione, fare clic sul file exe per avviare il processo di installazione.
Vedrai la seguente schermata al termine dell'installazione.
Step 3 - Il prossimo passo è impostare le variabili d'ambiente di Python nel tuo sistema.
Step 4 - Una volta impostate le variabili d'ambiente, digita il comando "python" sul prompt dei comandi per verificare se l'installazione è andata a buon fine o meno.
Se l'installazione è andata a buon fine, otterrai il seguente output sulla console.
I codici scritti in Python sembrano abbastanza simili ai codici scritti in altri linguaggi di programmazione convenzionali come C o Pascal. Si dice anche che la sintassi di Python sia ampiamente presa in prestito da C. Ciò include molte delle parole chiave Python che sono simili al linguaggio C.
Python include istruzioni condizionali e cicliche, che possono essere utilizzate per estrarre i dati in modo accurato per la scientifica. Per il controllo del flusso, fornisceif/else, whilee un livello elevato for istruzione che esegue il ciclo su qualsiasi oggetto "iterabile".
if a < b:
max = b
else:
max = a
L'area principale in cui Python differisce da altri linguaggi di programmazione è il suo utilizzo di dynamic typing. Utilizza nomi di variabili che si riferiscono a oggetti. Queste variabili non devono essere dichiarate.
Tipi di dati
Python include una serie di tipi di dati incorporati come stringhe, booleani, numeri, ecc. Esistono anche tipi immutabili, il che significa che i valori non possono essere modificati durante l'esecuzione.
Python ha anche tipi di dati incorporati composti che includono tuples che sono array immutabili, lists, e dictionariesche sono tabelle hash. Tutti sono utilizzati nella medicina legale digitale per memorizzare valori durante la raccolta di prove.
Moduli e pacchetti di terze parti
Python supporta gruppi di moduli e / o pacchetti che vengono anche chiamati third-party modules (codice correlato raggruppato in un unico file sorgente) utilizzato per l'organizzazione dei programmi.
Python include una vasta libreria standard, che è uno dei motivi principali della sua popolarità nell'analisi forense.
Ciclo di vita del codice Python
All'inizio, quando esegui un codice Python, l'interprete controlla il codice per errori di sintassi. Se l'interprete rileva errori di sintassi, vengono visualizzati immediatamente come messaggi di errore.
Se non sono presenti errori di sintassi, il codice viene compilato per produrre un file bytecode e inviato a PVM (Python Virtual Machine).
Il PVM controlla il bytecode per eventuali errori di runtime o logici. Nel caso in cui PVM rilevi errori di runtime, questi vengono segnalati immediatamente come messaggi di errore.
Se il bytecode è privo di errori, il codice viene elaborato e si ottiene il suo output.
La seguente illustrazione mostra graficamente come il codice Python viene interpretato per la prima volta per produrre un bytecode e come il bytecode viene elaborato da PVM per produrre l'output.
Per creare un'applicazione secondo le linee guida forensi, è importante comprendere e seguire le sue convenzioni e modelli di denominazione.
Convenzioni di denominazione
Durante lo sviluppo di applicazioni forensi Python, le regole e le convenzioni da seguire sono descritte nella tabella seguente.
Costanti | Maiuscolo con separazione di sottolineatura | ALTA TEMPERATURA |
Nome della variabile locale | Minuscolo con maiuscole irregolari (i trattini bassi sono facoltativi) | currentTemperature |
Nome della variabile globale | Prefisso gl minuscolo con maiuscole irregolari (i trattini bassi sono facoltativi) | gl_mamostRecordedTemperature |
Nome funzioni | Maiuscolo con maiuscole irregolari (trattini bassi opzionali) con voce attiva | ConvertFarenheitToCentigrade (...) |
Nome oggetto | Prefisso ob_ minuscolo con maiuscole irregolari | ob_myTempRecorder |
Modulo | Un trattino basso seguito da lettere minuscole con maiuscole irregolari | _tempRecorder |
Nomi delle classi | Prefisso class_ poi maiuscole irregolari e mantieniti breve | class_TempSystem |
Prendiamo uno scenario per comprendere l'importanza delle convenzioni di denominazione in Computational Forensics. Supponiamo di avere un algoritmo di hashing che viene normalmente utilizzato per crittografare i dati. L'algoritmo di hashing unidirezionale accetta l'input come flusso di dati binari; potrebbe essere una password, un file, dati binari o qualsiasi dato digitale. L'algoritmo di hashing produce quindi un filemessage digest (md) rispetto ai dati ricevuti in ingresso.
È praticamente impossibile creare un nuovo input binario che genererà un dato digest del messaggio. Anche un singolo bit dei dati di input binari, se modificato, genererà un messaggio univoco, diverso dal precedente.
Esempio
Dai un'occhiata al seguente programma di esempio che segue le convenzioni sopra menzionate.
import sys, string, md5 # necessary libraries
print "Please enter your full name"
line = sys.stdin.readline()
line = line.rstrip()
md5_object = md5.new()
md5_object.update(line)
print md5_object.hexdigest() # Prints the output as per the hashing algorithm i.e. md5
exit
Il programma precedente produce il seguente output.
In questo programma, lo script Python accetta l'input (il tuo nome completo) e lo converte secondo l'algoritmo di hashing md5. Crittografa i dati e protegge le informazioni, se necessario. Secondo le linee guida forensi, il nome delle prove o qualsiasi altra prova può essere protetto in questo modello.
UN hash functionè definita come la funzione che mappa su una grande quantità di dati un valore fisso con una lunghezza specificata. Questa funzione garantisce che lo stesso input restituisca lo stesso output, che è effettivamente definito come somma hash. La somma hash include una caratteristica con informazioni specifiche.
Questa funzione è praticamente impossibile da ripristinare. Pertanto, qualsiasi attacco di terze parti come l'attacco di forza bruta è praticamente impossibile. Inoltre, viene chiamato questo tipo di algoritmoone-way cryptographic algorithm.
Una funzione hash crittografica ideale ha quattro proprietà principali:
- Deve essere facile calcolare il valore hash per ogni dato input.
- Deve essere impossibile generare l'input originale dal suo hash.
- Non deve essere possibile modificare l'input senza cambiare l'hash.
- Non deve essere possibile trovare due diversi input con lo stesso hash.
Esempio
Considera il seguente esempio che aiuta a far corrispondere le password utilizzando caratteri in formato esadecimale.
import uuid
import hashlib
def hash_password(password):
# userid is used to generate a random number
salt = uuid.uuid4().hex #salt is stored in hexadecimal value
return hashlib.sha256(salt.encode() + password.encode()).hexdigest() + ':' + salt
def check_password(hashed_password, user_password):
# hexdigest is used as an algorithm for storing passwords
password, salt = hashed_password.split(':')
return password == hashlib.sha256(salt.encode()
+ user_password.encode()).hexdigest()
new_pass = raw_input('Please enter required password ')
hashed_password = hash_password(new_pass)
print('The string to store in the db is: ' + hashed_password)
old_pass = raw_input('Re-enter new password ')
if check_password(hashed_password, old_pass):
print('Yuppie!! You entered the right password')
else:
print('Oops! I am sorry but the password does not match')
Diagramma di flusso
Abbiamo spiegato la logica di questo programma con l'aiuto del seguente diagramma di flusso:
Produzione
Il nostro codice produrrà il seguente output:
La password inserita due volte corrisponde alla funzione hash. Ciò garantisce che la password inserita due volte sia accurata, il che aiuta a raccogliere dati utili e salvarli in un formato crittografato.
In questo capitolo, impareremo a decifrare i dati di un testo recuperati durante l'analisi e le prove.
Un testo normale in crittografia è un normale testo leggibile, come un messaggio. Un testo cifrato, d'altra parte, è l'output di un algoritmo di crittografia recuperato dopo aver inserito il testo normale.
Il semplice algoritmo di come trasformiamo un messaggio di testo semplice in un testo cifrato è il cifrario Cesare, inventato da Giulio Cesare per mantenere segreto il testo semplice ai suoi nemici. Questa cifra implica lo spostamento di ogni lettera del messaggio "in avanti" di tre posizioni nell'alfabeto.
Di seguito è riportata un'illustrazione demo.
a → D
b → E
c → F
....
w → Z
x → A
y → B
z → C
Esempio
Un messaggio inserito quando esegui uno script Python offre tutte le possibilità dei caratteri, che viene utilizzato per l'evidenza del modello.
I tipi di prove di pattern utilizzati sono i seguenti:
- Tracce e segni di pneumatici
- Impressions
- Fingerprints
Ogni dato biometrico comprende dati vettoriali, che dobbiamo decifrare per raccogliere prove complete.
Il seguente codice Python mostra come è possibile produrre un testo cifrato da testo normale -
import sys
def decrypt(k,cipher):
plaintext = ''
for each in cipher:
p = (ord(each)-k) % 126
if p < 32:
p+=95
plaintext += chr(p)
print plaintext
def main(argv):
if (len(sys.argv) != 1):
sys.exit('Usage: cracking.py')
cipher = raw_input('Enter message: ')
for i in range(1,95,1):
decrypt(i,cipher)
if __name__ == "__main__":
main(sys.argv[1:])
Produzione
Ora controlla l'output di questo codice. Quando inseriamo un semplice testo "Radhika", il programma produrrà il seguente testo cifrato.
Virtualizationè il processo di emulazione di sistemi IT come server, workstation, reti e archiviazione. Non è altro che la creazione di una versione virtuale piuttosto che effettiva di qualsiasi sistema operativo, server, dispositivo di archiviazione o processi di rete.
Il componente principale che aiuta nell'emulazione dell'hardware virtuale è definito come un file hyper-visor.
La figura seguente spiega i due principali tipi di virtualizzazione del sistema utilizzati.
La virtualizzazione è stata utilizzata in informatica forense in diversi modi. Aiuta l'analista in modo tale che la workstation possa essere utilizzata in uno stato convalidato per ogni indagine. Il recupero dei dati è possibile allegando l'immagine dd di un'unità come unità secondaria su una macchina virtuale in particolare. La stessa macchina può essere utilizzata come software di recupero per raccogliere le prove.
Il seguente esempio aiuta a comprendere la creazione di una macchina virtuale con l'aiuto del linguaggio di programmazione Python.
Step 1 - Assegna alla macchina virtuale il nome "dummy1".
Ogni macchina virtuale deve avere 512 MB di memoria nella capacità minima, espressa in byte.
vm_memory = 512 * 1024 * 1024
Step 2 - La macchina virtuale deve essere collegata al cluster predefinito, che è stato calcolato.
vm_cluster = api.clusters.get(name = "Default")
Step 3 - La macchina virtuale deve essere avviata dall'unità disco rigido virtuale.
vm_os = params.OperatingSystem(boot = [params.Boot(dev = "hd")])
Tutte le opzioni vengono combinate in un oggetto parametro della macchina virtuale, prima di utilizzare il metodo di aggiunta della raccolta vms alla macchina virtuale.
Esempio
Di seguito è riportato lo script Python completo per l'aggiunta di una macchina virtuale.
from ovirtsdk.api import API #importing API library
from ovirtsdk.xml import params
try: #Api credentials is required for virtual machine
api = API(url = "https://HOST",
username = "Radhika",
password = "a@123",
ca_file = "ca.crt")
vm_name = "dummy1"
vm_memory = 512 * 1024 * 1024 #calculating the memory in bytes
vm_cluster = api.clusters.get(name = "Default")
vm_template = api.templates.get(name = "Blank")
#assigning the parameters to operating system
vm_os = params.OperatingSystem(boot = [params.Boot(dev = "hd")])
vm_params = params.VM(name = vm_name,
memory = vm_memory,
cluster = vm_cluster,
template = vm_template
os = vm_os)
try:
api.vms.add(vm = vm_params)
print "Virtual machine '%s' added." % vm_name #output if it is successful.
except Exception as ex:
print "Adding virtual machine '%s' failed: %s" % (vm_name, ex)
api.disconnect()
except Exception as ex:
print "Unexpected error: %s" % ex
Produzione
Il nostro codice produrrà il seguente output:
Lo scenario dei moderni ambienti di rete è tale che l'indagine può essere complicata a causa di una serie di difficoltà. Questo può accadere sia che tu stia rispondendo a un supporto per violazione, indagando su attività interne, eseguendo valutazioni relative alla vulnerabilità o convalidando una conformità normativa.
Concetto di programmazione di rete
Le seguenti definizioni vengono utilizzate nella programmazione di rete.
Client - Il client è una parte dell'architettura client-server della programmazione di rete che viene eseguita su un personal computer e una workstation.
Server - Il server fa parte dell'architettura client-server che fornisce servizi ad altri programmi per computer nello stesso o in altri computer.
WebSockets- I WebSocket forniscono un protocollo tra il client e il server, che funziona su una connessione TCP persistente. Attraverso questo, i messaggi bidirezionali possono essere inviati tra la connessione socket TCP (simultaneamente).
I WebSocket vengono dopo molte altre tecnologie che consentono ai server di inviare informazioni al client. Oltre all'handshaking dell'intestazione di aggiornamento, WebSocket è indipendente da HTTP.
Questi protocolli vengono utilizzati per convalidare le informazioni inviate o ricevute dagli utenti di terze parti. Poiché la crittografia è uno dei metodi utilizzati per proteggere i messaggi, è anche importante proteggere il canale attraverso il quale i messaggi sono stati trasferiti.
Considera il seguente programma Python, che il client usa per handshaking.
Esempio
# client.py
import socket
# create a socket object
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = socket.gethostname()
port = 8080
# connection to hostname on the port.
s.connect((host, port))
# Receive no more than 1024 bytes
tm = s.recv(1024)
print("The client is waiting for connection")
s.close()
Produzione
Produrrà il seguente output:
Il server che accetta la richiesta di canale di comunicazione includerà il seguente script.
# server.py
import socket
import time
# create a socket object
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = socket.gethostname()
port = 8080
# bind to the port
serversocket.bind((host, port))
# queue up to 5 requests
serversocket.listen(5)
while True:
# establish a connection
clientsocket,addr = serversocket.accept()
print("Got a connection from %s" % str(addr))
currentTime = time.ctime(time.time()) + "\r\n"
clientsocket.send(currentTime.encode('ascii'))
clientsocket.close()
Il client e il server creati con l'aiuto della programmazione Python ascoltano il numero di host. Inizialmente, il client invia una richiesta al server rispetto ai dati inviati nel numero host e il server accetta la richiesta e invia immediatamente una risposta. In questo modo, possiamo avere un canale di comunicazione sicuro.
I moduli nei programmi Python aiutano nell'organizzazione del codice. Aiutano a raggruppare il codice correlato in un singolo modulo, che lo rende più facile da capire e da usare. Include valori con nomi arbitrari, che possono essere utilizzati per l'associazione e il riferimento. In parole semplici, un modulo è un file costituito da codice Python che include funzioni, classi e variabili.
Il codice Python per un modulo (file) viene salvato con .py estensione che viene compilata come e quando necessario.
Example
def print_hello_func( par ):
print "Hello : ", par
return
Dichiarazione di importazione
Il file sorgente Python può essere utilizzato come modulo eseguendo un file importistruzione che importa altri pacchetti o librerie di terze parti. La sintassi utilizzata è la seguente:
import module1[, module2[,... moduleN]
Quando l'interprete Python incontra l'istruzione import, importa il modulo specificato che è presente nel percorso di ricerca.
Example
Considera il seguente esempio.
#!/usr/bin/python
# Import module support
import support
# Now you can call defined function that module as follows
support.print_func("Radhika")
Produrrà il seguente output:
Un modulo viene caricato una sola volta, indipendentemente dal numero di volte in cui è stato importato dal codice Python.
Da ... dichiarazione di importazione
Fromattributo aiuta a importare attributi specifici da un modulo in uno spazio dei nomi corrente. Ecco la sua sintassi.
from modname import name1[, name2[, ... nameN]]
Example
Per importare la funzione fibonacci dal modulo fib, usa la seguente dichiarazione.
from fib import fibonacci
Individuazione dei moduli
Quando il modulo viene importato, l'interprete Python cerca le seguenti sequenze:
La directory corrente.
Se il modulo non esiste, Python cerca quindi ogni directory nella variabile di shell PYTHONPATH.
Se la posizione della variabile di shell fallisce, Python controlla il percorso predefinito.
L'analisi forense utilizza moduli Python e moduli di terze parti per ottenere le informazioni ed estrarre prove con maggiore facilità. Ulteriori capitoli si concentrano sull'implementazione dei moduli per ottenere l'output necessario.
DShell
Dshellè un toolkit di analisi forense di rete basato su Python. Questo toolkit è stato sviluppato dallo US Army Research Laboratory. Il rilascio di questo toolkit open source risale al 2014. L'obiettivo principale di questo toolkit è quello di effettuare facilmente le indagini forensi.
Il toolkit è costituito da un gran numero di decoder elencati nella tabella seguente.
Sr.No. | Nome e descrizione del decodificatore |
---|---|
1 | dns Viene utilizzato per estrarre le query relative al DNS |
2 | reservedips Identifica le soluzioni per i problemi DNS |
3 | large-flows Elenco dei netflow |
4 | rip-http Viene utilizzato per estrarre i file dal traffico HTTP |
5 | Protocols Utilizzato per l'identificazione di protocolli non standard |
L'US Army Laboratory ha mantenuto il repository di cloni in GitHub nel seguente link:
https://github.com/USArmyResearchLab/Dshell
Il clone è costituito da uno script install-ubuntu.py () utilizzato per l'installazione di questo toolkit.
Una volta completata l'installazione, creerà automaticamente gli eseguibili e le dipendenze che verranno utilizzate in seguito.
Le dipendenze sono le seguenti:
dependencies = {
"Crypto": "crypto",
"dpkt": "dpkt",
"IPy": "ipy",
"pcap": "pypcap"
}
Questo toolkit può essere utilizzato contro i file pcap (packet capture), che di solito vengono registrati durante gli incidenti o durante l'avviso. Questi file pcap vengono creati da libpcap su piattaforma Linux o WinPcap su piattaforma Windows.
Scapy
Scapy è uno strumento basato su Python utilizzato per analizzare e manipolare il traffico di rete. Di seguito è riportato il link per Scapy toolkit -
http://www.secdev.org/projects/scapy/
Questo toolkit viene utilizzato per analizzare la manipolazione dei pacchetti. È molto capace di decodificare i pacchetti di un ampio numero di protocolli e catturarli. Scapy differisce dal toolkit Dshell poiché fornisce una descrizione dettagliata all'investigatore sul traffico di rete. Queste descrizioni sono state registrate in tempo reale.
Scapy ha la capacità di tracciare utilizzando strumenti di terze parti o fingerprinting del sistema operativo.
Considera il seguente esempio.
import scapy, GeoIP #Imports scapy and GeoIP toolkit
from scapy import *
geoIp = GeoIP.new(GeoIP.GEOIP_MEMORY_CACHE) #locates the Geo IP address
def locatePackage(pkg):
src = pkg.getlayer(IP).src #gets source IP address
dst = pkg.getlayer(IP).dst #gets destination IP address
srcCountry = geoIp.country_code_by_addr(src) #gets Country details of source
dstCountry = geoIp.country_code_by_addr(dst) #gets country details of destination
print src+"("+srcCountry+") >> "+dst+"("+dstCountry+")\n"
Questo script fornisce la descrizione dettagliata dei dettagli del paese nel pacchetto di rete, che stanno comunicando tra loro.
Lo script precedente produrrà il seguente output.
Searchingè sicuramente uno dei pilastri delle indagini forensi. Al giorno d'oggi, la ricerca è valida solo quanto l'investigatore che gestisce le prove.
La ricerca di una parola chiave dal messaggio gioca un ruolo vitale nella scientifica, quando cerchiamo una prova con l'aiuto di una parola chiave. La conoscenza di ciò che deve essere cercato in un particolare file insieme a quelli nei file eliminati richiede esperienza e conoscenza.
Python ha vari meccanismi integrati con moduli di libreria standard da supportare searchoperazione. Fondamentalmente, gli investigatori utilizzano l'operazione di ricerca per trovare risposte a domande come "chi", "cosa", "dove", "quando" e così via.
Esempio
Nell'esempio seguente, abbiamo dichiarato due stringhe e quindi abbiamo utilizzato la funzione find per verificare se la prima stringa contiene la seconda stringa o meno.
# Searching a particular word from a message
str1 = "This is a string example for Computational forensics of gathering evidence!";
str2 = "string";
print str1.find(str2)
print str1.find(str2, 10)
print str1.find(str2, 40)
Lo script precedente produrrà il seguente output.
“find”la funzione in Python aiuta nella ricerca di una parola chiave in un messaggio o in un paragrafo. Questo è fondamentale per raccogliere prove appropriate.
Indexingfornisce effettivamente all'investigatore una visione completa di un file e raccogliere potenziali prove da esso. L'evidenza potrebbe essere contenuta in un file, un'immagine del disco, un'istantanea della memoria o una traccia di rete.
L'indicizzazione aiuta a ridurre il tempo per attività che richiedono tempo come keyword searching. L'indagine forense prevede anche la fase di ricerca interattiva, in cui l'indice viene utilizzato per individuare rapidamente le parole chiave.
L'indicizzazione aiuta anche a elencare le parole chiave in un elenco ordinato.
Esempio
Il seguente esempio mostra come puoi usare indexing in Python.
aList = [123, 'sample', 'zara', 'indexing'];
print "Index for sample : ", aList.index('sample')
print "Index for indexing : ", aList.index('indexing')
str1 = "This is sample message for forensic investigation indexing";
str2 = "sample";
print "Index of the character keyword found is "
print str1.index(str2)
Lo script precedente produrrà il seguente output.
L'estrazione di informazioni preziose dalle risorse disponibili è una parte vitale della digital forensics. Ottenere l'accesso a tutte le informazioni disponibili è essenziale per un processo di indagine in quanto aiuta a recuperare le prove appropriate.
Le risorse che contengono dati possono essere semplici strutture di dati come database o complesse strutture di dati come un'immagine JPEG. È possibile accedere facilmente a strutture di dati semplici utilizzando semplici strumenti desktop, mentre l'estrazione di informazioni da strutture di dati complesse richiede strumenti di programmazione sofisticati.
Libreria di immagini Python
La Python Imaging Library (PIL) aggiunge funzionalità di elaborazione delle immagini al tuo interprete Python. Questa libreria supporta molti formati di file e fornisce potenti capacità grafiche e di elaborazione delle immagini. Puoi scaricare i file sorgente di PIL da:http://www.pythonware.com/products/pil/
La figura seguente mostra il diagramma di flusso completo dell'estrazione di dati da immagini (strutture di dati complesse) in PIL.
Esempio
Ora, facciamo un esempio di programmazione per capire come funziona effettivamente.
Step 1 - Supponiamo di avere la seguente immagine da cui dobbiamo estrarre le informazioni.
Step 2- Quando apriamo questa immagine utilizzando PIL, annotare prima i punti necessari richiesti per l'estrazione delle prove, che include vari valori di pixel. Ecco il codice per aprire l'immagine e registrare i suoi valori in pixel -
from PIL import Image
im = Image.open('Capture.jpeg', 'r')
pix_val = list(im.getdata())
pix_val_flat = [x for sets in pix_val for x in sets]
print pix_val_flat
Step 3 - Il nostro codice produrrà il seguente output, dopo aver estratto i valori dei pixel dell'immagine.
L'output fornito rappresenta i valori dei pixel della combinazione RGB, che fornisce un'immagine migliore di quali dati sono necessari per la prova. I dati recuperati sono rappresentati sotto forma di un array.
L'indagine e l'analisi forense dell'hardware standard del computer come i dischi rigidi si sono sviluppate in una disciplina stabile ed è seguita con l'aiuto di tecniche per analizzare hardware non standard o prove transitorie.
Sebbene gli smartphone siano sempre più utilizzati nelle indagini digitali, sono ancora considerati non standard.
Analisi forense
Le indagini forensi cercano dati come chiamate ricevute o numeri composti dallo smartphone. Può includere messaggi di testo, foto o qualsiasi altra prova incriminante. La maggior parte degli smartphone dispone di funzionalità di blocco dello schermo tramite password o caratteri alfanumerici.
Qui, faremo un esempio per mostrare come Python può aiutare a decifrare la password di blocco dello schermo per recuperare i dati da uno smartphone.
Esame manuale
Android supporta il blocco della password con numero PIN o password alfanumerica. Il limite di entrambe le passphrase deve essere compreso tra 4 e 16 cifre o caratteri. La password di uno smartphone è memorizzata nel sistema Android in un file speciale chiamatopassword.key in /data/system.
Android memorizza un hash SHA1 salato e un hash MD5 della password. Queste password possono essere elaborate nel codice seguente.
public byte[] passwordToHash(String password) {
if (password == null) {
return null;
}
String algo = null;
byte[] hashed = null;
try {
byte[] saltedPassword = (password + getSalt()).getBytes();
byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
hashed = (toHex(sha1) + toHex(md5)).getBytes();
} catch (NoSuchAlgorithmException e) {
Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
}
return hashed;
}
Non è possibile decifrare la password con l'aiuto di dictionary attack poiché la password con hash è archiviata in un file salt file. Questosaltè una stringa di rappresentazione esadecimale di un numero intero casuale di 64 bit. È facile accedere al filesalt usando Rooted Smartphone o JTAG Adapter.
Smartphone con root
Il dump del file /data/system/password.key è memorizzato nel database SQLite sotto il lockscreen.password_saltchiave. Sottosettings.db, la password viene memorizzata e il valore è chiaramente visibile nello screenshot seguente.
Adattatore JTAG
Un hardware speciale noto come adattatore JTAG (Joint Test Action Group) può essere utilizzato per accedere al file salt. Allo stesso modo, aRiff-Box o a JIG-Adapter può essere utilizzato anche per la stessa funzionalità.
Utilizzando le informazioni ottenute da Riff-box, possiamo trovare la posizione dei dati crittografati, ovvero il file salt. Di seguito sono riportate le regole:
Cerca la stringa associata "lockscreen.password_salt".
Il byte rappresenta la larghezza effettiva del sale, che è la sua length.
Questa è la lunghezza effettivamente ricercata per ottenere la password / il pin memorizzati degli smartphone.
Questo insieme di regole aiuta a ottenere i dati salini appropriati.
Il protocollo più utilizzato per la sincronizzazione dell'ora e che è stato ampiamente accettato come pratica viene eseguito tramite Network Time Protocol (NTP).
NTP utilizza il protocollo UDP (User Datagram Protocol) che utilizza il tempo minimo per comunicare i pacchetti tra il server e il client che desidera sincronizzarsi con l'origine dell'ora specificata.
Le caratteristiche di Network Time Protocol sono le seguenti:
La porta del server predefinita è 123.
Questo protocollo è costituito da molti time server accessibili sincronizzati con i laboratori nazionali.
Lo standard del protocollo NTP è regolato dall'IETF e lo standard proposto è RFC 5905, intitolato "Network Time Protocol Version 4: Protocol and Algorithms Specification" [NTP RFC]
I sistemi operativi, i programmi e le applicazioni utilizzano NTP per sincronizzare l'ora in modo corretto.
In questo capitolo, ci concentreremo sull'uso di NTP con Python, che è fattibile dalla libreria Python di terze parti ntplib. Questa libreria gestisce in modo efficiente il lavoro pesante, che confronta i risultati con l'orologio di sistema locale.
Installazione della libreria NTP
Il ntplib è disponibile per il download all'indirizzo https://pypi.python.org/pypi/ntplib/ come mostrato nella figura seguente.
La libreria fornisce una semplice interfaccia ai server NTP con l'aiuto di metodi in grado di tradurre i campi del protocollo NTP. Ciò consente di accedere ad altri valori chiave come i secondi intercalari.
Il seguente programma Python aiuta a comprendere l'utilizzo di NTP.
import ntplib
import time
NIST = 'nist1-macon.macon.ga.us'
ntp = ntplib.NTPClient()
ntpResponse = ntp.request(NIST)
if (ntpResponse):
now = time.time()
diff = now-ntpResponse.tx_time
print diff;
Il programma precedente produrrà il seguente output.
La differenza di tempo viene calcolata nel programma sopra. Questi calcoli aiutano nelle indagini forensi. I dati di rete ottenuti sono fondamentalmente diversi dall'analisi dei dati trovati sul disco rigido.
La differenza nei fusi orari o l'ottenimento di fusi orari precisi può aiutare a raccogliere prove per acquisire i messaggi attraverso questo protocollo.
Gli specialisti forensi normalmente trovano difficile applicare soluzioni digitali per analizzare le montagne di prove digitali in crimini comuni. La maggior parte degli strumenti di indagine digitale sono a thread singolo e possono eseguire un solo comando alla volta.
In questo capitolo, ci concentreremo sulle capacità di multiprocessing di Python, che possono essere correlate alle comuni sfide forensi.
Multiprocessing
Il multiprocessing è definito come la capacità del sistema informatico di supportare più di un processo. I sistemi operativi che supportano il multiprocessing consentono a più programmi di essere eseguiti contemporaneamente.
Esistono vari tipi di multiprocessing come symmetric e asymmetric processing. Il diagramma seguente si riferisce a un sistema multiprocessing simmetrico che viene solitamente seguito nelle indagini forensi.
Esempio
Il codice seguente mostra come i diversi processi sono elencati internamente nella programmazione Python.
import random
import multiprocessing
def list_append(count, id, out_list):
#appends the count of number of processes which takes place at a time
for i in range(count):
out_list.append(random.random())
if __name__ == "__main__":
size = 999
procs = 2
# Create a list of jobs and then iterate through
# the number of processes appending each process to
# the job list
jobs = []
for i in range(0, procs):
out_list = list() #list of processes
process1 = multiprocessing.Process(
target = list_append, args = (size, i, out_list))
# appends the list of processes
jobs.append(process)
# Calculate the random number of processes
for j in jobs:
j.start() #initiate the process
# After the processes have finished execution
for j in jobs:
j.join()
print "List processing complete."
Qui, la funzione list_append() aiuta a elencare l'insieme di processi nel sistema.
Produzione
Il nostro codice produrrà il seguente output:
In questo capitolo, ci concentreremo sull'analisi della memoria volatile con l'aiuto di Volatility, un framework forense basato su Python applicabile sulle seguenti piattaforme: Android e Linux.
Memoria volatile
La memoria volatile è un tipo di memoria in cui i contenuti vengono cancellati quando il sistema viene spento o interrotto. La RAM è il miglior esempio di una memoria volatile. Significa che se stavi lavorando su un documento che non è stato salvato in una memoria non volatile, come un disco rigido, e il computer ha perso l'alimentazione, tutti i dati andranno persi.
In generale, le indagini forensi sulla memoria volatile seguono lo stesso modello di altre indagini forensi -
- Selezione del target dell'indagine
- Acquisizione di dati forensi
- Analisi forense
La base volatility plugins che vengono utilizzati per Android raccoglie RAM dumpper l'analisi. Una volta che il dump della RAM viene raccolto per l'analisi, è importante iniziare a cercare malware nella RAM.
Regole YARA
YARA è uno strumento popolare che fornisce un linguaggio robusto, è compatibile con le espressioni regolari basate su Perl e viene utilizzato per esaminare i file / directory sospetti e le stringhe di corrispondenza.
In questa sezione, utilizzeremo YARA in base all'implementazione del pattern matching e li combineremo con l'alimentazione di rete. Il processo completo sarà utile per l'analisi forense.
Esempio
Considera il codice seguente. Questo codice aiuta a estrarre il codice.
import operator
import os
import sys
sys.path.insert(0, os.getcwd())
import plyara.interp as interp
# Plyara is a script that lexes and parses a file consisting of one more Yara
# rules into a python dictionary representation.
if __name__ == '__main__':
file_to_analyze = sys.argv[1]
rulesDict = interp.parseString(open(file_to_analyze).read())
authors = {}
imps = {}
meta_keys = {}
max_strings = []
max_string_len = 0
tags = {}
rule_count = 0
for rule in rulesDict:
rule_count += 1
# Imports
if 'imports' in rule:
for imp in rule['imports']:
imp = imp.replace('"','')
if imp in imps:
imps[imp] += 1
else:
imps[imp] = 1
# Tags
if 'tags' in rule:
for tag in rule['tags']:
if tag in tags:
tags[tag] += 1
else:
tags[tag] = 1
# Metadata
if 'metadata' in rule:
for key in rule['metadata']:
if key in meta_keys:
meta_keys[key] += 1
else:
meta_keys[key] = 1
if key in ['Author', 'author']:
if rule['metadata'][key] in authors:
authors[rule['metadata'][key]] += 1
else:
authors[rule['metadata'][key]] = 1
#Strings
if 'strings' in rule:
for strr in rule['strings']:
if len(strr['value']) > max_string_len:
max_string_len = len(strr['value'])
max_strings = [(rule['rule_name'], strr['name'], strr['value'])]
elif len(strr['value']) == max_string_len:
max_strings.append((rule['rule_name'], strr['key'], strr['value']))
print("\nThe number of rules implemented" + str(rule_count))
ordered_meta_keys = sorted(meta_keys.items(), key = operator.itemgetter(1),
reverse = True)
ordered_authors = sorted(authors.items(), key = operator.itemgetter(1),
reverse = True)
ordered_imps = sorted(imps.items(), key = operator.itemgetter(1), reverse = True)
ordered_tags = sorted(tags.items(), key = operator.itemgetter(1), reverse = True)
Il codice precedente produrrà il seguente output.
Il numero di regole YARA implementate aiuta a fornire un'immagine migliore dei file sospetti. Indirettamente, l'elenco dei file sospetti aiuta a raccogliere informazioni appropriate per la scientifica.
Di seguito è riportato il codice sorgente in GitHub: https://github.com/radhikascs/Python_yara
La principale preoccupazione delle indagini digitali è proteggere le prove oi dati importanti con la crittografia o qualsiasi altro formato. L'esempio di base è memorizzare le password. È quindi necessario comprendere l'utilizzo del sistema operativo Linux per l'implementazione forense digitale per proteggere questi dati preziosi.
Le informazioni per tutti gli utenti locali sono per lo più memorizzate nei seguenti due file:
- /etc/passwd
- etc/shadow
Il primo è obbligatorio, che memorizza tutte le password. Il secondo file è facoltativo e memorizza le informazioni sugli utenti locali comprese le password con hash.
Sorgono problemi riguardanti il problema di sicurezza dell'archiviazione delle informazioni sulla password in un file, che è leggibile da ogni utente. Pertanto, le password con hash vengono archiviate in/etc/passwd, dove il contenuto è sostituito da un valore speciale "x".
Gli hash corrispondenti devono essere cercati in /etc/shadow. Le impostazioni in/etc/passwd può sovrascrivere i dettagli in /etc/shadow.
Entrambi i file di testo in Linux includono una voce per riga e la voce è composta da più campi, separati da due punti.
Il formato di /etc/passwd è il seguente -
Sr.No. | Nome campo e descrizione |
---|---|
1 | Username Questo campo è costituito dagli attributi del formato leggibile dall'uomo |
2 | Password hash Consiste nella password in una forma codificata secondo la funzione crypt di Posix |
Se la password hash viene salvata come empty, quindi l'utente corrispondente non richiederà alcuna password per accedere al sistema. Se questo campo contiene un valore che non può essere generato dall'algoritmo hash, come un punto esclamativo, l'utente non può accedere utilizzando una password.
Un utente con una password bloccata può comunque accedere utilizzando altri meccanismi di autenticazione, ad esempio le chiavi SSH. Come accennato in precedenza, il valore speciale "x"significa che l'hash della password deve essere trovato nel file shadow.
Il password hash include quanto segue:
Encrypted salt - Il encrypted salt aiuta a mantenere i blocchi dello schermo, i pin e le password.
Numerical user ID- Questo campo denota l'ID dell'utente. Il kernel Linux assegna questo ID utente al sistema.
Numerical group ID - Questo campo si riferisce al gruppo principale dell'utente.
Home directory - I nuovi processi vengono avviati con un riferimento di questa directory.
Command shell - Questo campo facoltativo denota la shell predefinita che deve essere avviata dopo un accesso riuscito al sistema.
La digital forensics include la raccolta delle informazioni rilevanti per il monitoraggio di una prova. Quindi, gli ID utente sono utili per mantenere i record.
Utilizzando Python, tutte queste informazioni possono essere automaticamente analizzate per gli Indicatori di Analisi, ricostruendo l'attività recente del sistema. Il monitoraggio è semplice e facile con l'implementazione di Linux Shell.
Programmazione Python con Linux
Esempio
import sys
import hashlib
import getpass
def main(argv):
print '\nUser & Password Storage Program in Linux for forensic detection v.01\n'
if raw_input('The file ' + sys.argv[1] + ' will be erased or overwrite if
it exists .\nDo you wish to continue (Y/n): ') not in ('Y','y') :
sys.exit('\nChanges were not recorded\n')
user_name = raw_input('Please Enter a User Name: ')
password = hashlib.sha224(getpass.getpass('Please Enter a Password:')).hexdigest()
# Passwords which are hashed
try:
file_conn = open(sys.argv[1],'w')
file_conn.write(user_name + '\n')
file_conn.write(password + '\n')
file_conn.close()
except:
sys.exit('There was a problem writing the passwords to file!')
if __name__ == "__main__":
main(sys.argv[1:])
Produzione
La password è memorizzata in un formato esadecimale in pass_db.txtcome mostrato nello screenshot seguente. I file di testo vengono salvati per un ulteriore utilizzo nell'analisi forense.
Gli indicatori di compromissione (IOC) sono definiti come "pezzi di dati forensi, che includono dati trovati in voci o file del registro di sistema, che identificano attività potenzialmente dannose su un sistema o una rete".
Monitorando il CIO, le organizzazioni possono rilevare gli attacchi e agire rapidamente per prevenire il verificarsi di tali violazioni o limitare i danni bloccando gli attacchi nelle fasi precedenti.
Esistono alcuni casi d'uso, che consentono di interrogare gli artefatti forensi come:
- Alla ricerca di un file specifico da MD5
- Ricerca di un'entità specifica, che è effettivamente archiviata nella memoria
- Voce specifica o insieme di voci, memorizzata nel registro di Windows
La combinazione di tutto quanto sopra fornisce risultati migliori nella ricerca di artefatti. Come accennato in precedenza, il registro di Windows offre una piattaforma perfetta per la generazione e il mantenimento di IOC, che aiuta direttamente nella forense computazionale.
Metodologia
Cerca le posizioni nel file system e in particolare per ora nel registro di Windows.
Cerca il set di artefatti, che sono stati progettati da strumenti forensi.
Cerca i segni di attività avverse.
Ciclo di vita investigativo
Investigative Life Cycle segue IOC e cerca voci specifiche in un registro.
Stage 1: Initial Evidence- La prova della compromissione viene rilevata su un host o sulla rete. I soccorritori indagheranno e identificheranno la soluzione esatta, che è un indicatore forense concreto.
Stage 2: Create IOCs for Host & Network- A seguito dei dati raccolti, viene creato il CIO, che è facilmente possibile con il registro di Windows. La flessibilità di OpenIOC offre un numero illimitato di permutazioni su come un indicatore può essere creato.
Stage 3: Deploy IOCs in the Enterprise - Una volta creato il CIO specificato, l'investigatore distribuirà queste tecnologie con l'aiuto dell'API nei registri di Windows.
Stage 4: Identification of Suspects- Il dispiegamento del CIO aiuta nell'identificazione dei sospetti in modo normale. Verranno identificati anche sistemi aggiuntivi.
Stage 5: Collect and Analyze Evidence - Le prove contro i sospettati vengono raccolte e analizzate di conseguenza.
Stage 6: Refine & Create New IOCs - Il team investigativo può creare nuovi IOC sulla base delle prove e dei dati trovati nell'azienda e di informazioni aggiuntive e continuare a perfezionare il loro ciclo.
La figura seguente mostra le fasi del ciclo di vita investigativo:
Cloud computingpuò essere definito come una raccolta di servizi ospitati forniti agli utenti su Internet. Consente alle organizzazioni di utilizzare o persino calcolare la risorsa, che include macchine virtuali (VM), archiviazione o un'applicazione come utilità.
Uno dei vantaggi più importanti della creazione di applicazioni nel linguaggio di programmazione Python è che include la possibilità di distribuire applicazioni virtualmente su qualsiasi piattaforma, che include cloudanche. Ciò implica che Python può essere eseguito su server cloud e può anche essere avviato su dispositivi pratici come desktop, tablet o smartphone.
Una delle prospettive interessanti è la creazione di una base cloud con la generazione di Rainbow tables. Aiuta a integrare versioni singole e multiprocessing dell'applicazione, il che richiede alcune considerazioni.
Pi Cloud
Pi Cloud è la piattaforma di cloud computing, che integra il linguaggio di programmazione Python con la potenza di calcolo di Amazon Web Services.
Diamo un'occhiata a un esempio di implementazione di cloud Pi con rainbow tables.
Tabelle arcobaleno
UN rainbow table è definito come un elenco di tutte le possibili permutazioni di testo normale di password crittografate specifiche per un dato algoritmo hash.
Le tabelle arcobaleno seguono uno schema standard, che crea un elenco di password con hash.
Un file di testo viene utilizzato per generare password, che includono caratteri o testo semplice di password da crittografare.
Il file viene utilizzato dal cloud Pi, che chiama la funzione principale da memorizzare.
Anche l'output delle password con hash viene memorizzato nel file di testo.
Questo algoritmo può essere utilizzato anche per salvare le password nel database e disporre di un archivio di backup nel sistema cloud.
Il seguente programma integrato crea un elenco di password crittografate in un file di testo.
Esempio
import os
import random
import hashlib
import string
import enchant #Rainbow tables with enchant
import cloud #importing pi-cloud
def randomword(length):
return ''.join(random.choice(string.lowercase) for i in range(length))
print('Author- Radhika Subramanian')
def mainroutine():
engdict = enchant.Dict("en_US")
fileb = open("password.txt","a+")
# Capture the values from the text file named password
while True:
randomword0 = randomword(6)
if engdict.check(randomword0) == True:
randomkey0 = randomword0+str(random.randint(0,99))
elif engdict.check(randomword0) == False:
englist = engdict.suggest(randomword0)
if len(englist) > 0:
randomkey0 = englist[0]+str(random.randint(0,99))
else:
randomkey0 = randomword0+str(random.randint(0,99))
randomword3 = randomword(5)
if engdict.check(randomword3) == True:
randomkey3 = randomword3+str(random.randint(0,99))
elif engdict.check(randomword3) == False:
englist = engdict.suggest(randomword3)
if len(englist) > 0:
randomkey3 = englist[0]+str(random.randint(0,99))
else:
randomkey3 = randomword3+str(random.randint(0,99))
if 'randomkey0' and 'randomkey3' and 'randomkey1' in locals():
whasher0 = hashlib.new("md5")
whasher0.update(randomkey0)
whasher3 = hashlib.new("md5")
whasher3.update(randomkey3)
whasher1 = hashlib.new("md5")
whasher1.update(randomkey1)
print(randomkey0+" + "+str(whasher0.hexdigest())+"\n")
print(randomkey3+" + "+str(whasher3.hexdigest())+"\n")
print(randomkey1+" + "+str(whasher1.hexdigest())+"\n")
fileb.write(randomkey0+" + "+str(whasher0.hexdigest())+"\n")
fileb.write(randomkey3+" + "+str(whasher3.hexdigest())+"\n")
fileb.write(randomkey1+" + "+str(whasher1.hexdigest())+"\n")
jid = cloud.call(randomword) #square(3) evaluated on PiCloud
cloud.result(jid)
print('Value added to cloud')
print('Password added')
mainroutine()
Produzione
Questo codice produrrà il seguente output:
Le password vengono memorizzate nei file di testo, che è visibile, come mostrato nello screenshot seguente.