Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Du 22 au 24 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Hacking et Forensic
  3. Forensic
Extrait - Hacking et Forensic Développez vos propres outils en Python (2ième édition)
Extraits du livre
Hacking et Forensic Développez vos propres outils en Python (2ième édition)
3 avis
Revenir à la page d'achat du livre

Forensic

Introduction

On désigne par informatique légale ou investigation numérique légale l’application de techniques et de protocoles d’investigation numériques respectant les procédures légales et destinée à apporter des preuves numériques à la demande d’une institution de type judiciaire par réquisition, ordonnance ou jugement. On peut donc également la définir comme l’ensemble des connaissances et méthodes qui permettent de collecter, conserver et analyser des preuves issues de supports numériques en vue de les produire dans le cadre d’une action en justice.

Le but de ce chapitre est donc de comprendre l’utilisation de Python pour créer de petits scripts qui vont nous permettre de trouver des preuves informatiques, de retrouver des éléments dispersés dans le disque dur ou sur d’autres médias. Nous découvrirons en plus de celles déjà vues dans les chapitres précédents, d’autres bibliothèques Python telles que Volatility et libPST.

Il existe sur le Web de multiples outils de Forensic tels que Autopsy par exemple, des outils sont regroupés dans les distributions telles que BackTrack ou Bugtraq mais que se passe-t-il quand l’outil que l’on souhaite n’existe pas ?

Les experts en Forensic savent très bien que souvent...

Cryptographie et autres

Souvent, nous allons être confrontés à des fichiers cryptés ; la cible va en effet essayer de cacher l’information.

1. ROT13

Selon Wikipédia, "Le ROT13 (rotate by 13 places) est un cas particulier du chiffre de César, un algorithme simpliste de chiffrement de texte. Comme son nom l’indique, il s’agit d’un décalage de 13 caractères de chaque lettre du texte à chiffrer. Le défaut de ce chiffrement est que s’il s’occupe des lettres, il ne s’occupe pas des symboles et de la ponctuation. C’est pourquoi on doit supprimer toute accentuation du texte à chiffrer. Il ne s’occupe pas non plus des chiffres, ce qui était sans importance puisque les Romains écrivaient leurs chiffres avec des lettres (I, V, X, L, M, etc.). Pour l’utiliser aujourd’hui, il suffit de convertir d’abord les chiffres en utilisant la notation romaine, ou en lettres ("UN" pour1, "DEUX" pour 2...)."

La lettre O devient B, la lettre P devient C...

La librairie string de Python contient une fonction appelée maketrans qui permet de substituer un caractère à un autre.


ROT13=string.maketrans 
('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ',  
'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM')
 

Dans le script suivant, nous allons ouvrir tous les fichiers .txt et lancer le cryptage ROT13 pour chaque ligne de chaque fichier. Nous allons ensuite regarder si la ligne contient un mot contenu dans le dictionnaire que l’on ouvre au début.

Si c’est le cas, nous afficherons un message indiquant que nous avons trouvé un message encodé en ROT13.

chap8_script1.py


#!/usr/bin/env python  
import sys, os, string  
ROT13=string.maketrans('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP 
QRSTUVWXYZ','nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM' 
)  
fichier = open("dictionnaire")  
Fichier = fichier.readlines()  
for root, dir, files in os.walk(str(sys.argv[1])):  
        for file in files:  
                if ".txt" in str(file):  
                       trouvemot = 0  
      ...

Extraction des métadonnées dans les fichiers

Les métadonnées dans les fichiers vont nous permettre de connaître la date de création du fichier, qui l’a créé et avec quel outil.

Nous allons commencer par un script assez amusant qui récupère les métadonnées d’un fichier MP3

1. Métadonnées MP3

La bibliothèque eyeD3 va nous permettre d’examiner les métadonnées des fichiers MP3.

Nous pouvons récupérer grâce à getArtist(), getAlbum(), getTitle() par exemple les données propres au fichier MP3 obtenues par eyeD3.tag().

chap8_script9.py


#!/usr/bin/env python  
import eyeD3  
tag = eyeD3.Tag()  
chemin=raw_input("donnez le chemin du fichier mp3\n")  
tag.link(chemin)  
print tag.getArtist()  
print tag.getAlbum()  
print tag.getTitle()
 
images/06EP05.png

Nous pouvons aussi lire le fichier et accéder à son tag.


if eyeD3.isMp3File(f): 
      audioFile = eyeD3.Mp3AudioFile(f) 
      tag = audioFile.getTag()
 

Nous pouvons aussi récupérer les frames si elles existent.


import eyeD3  
tag = eyeD3.Tag()  
tag.link("/home/fasm/personnel/chansons/thiefaine/01_113_Cigarette mp3")  
for frame in tag.frames:  
    print frame
 

Il nous est possible aussi d’ajouter des informations aux tags


tag = eyeD3.Tag() 
tag.link('/home/fasm/personnel/chansons/thiefaine/01_113_Cigarette mp3') ...

Fichiers ZIP

1. Lire dans un fichier ZIP

Nous voulons examiner directement un ou plusieurs fichiers contenus dans une archive au format ZIP, sans la décompacter sur le disque.

Une bibliothèque existe, zipfile, qui va nous permettre de travailler directement sur les données contenues dans des fichiers ZIP.


#!/usr/bin/env python 
import zipfile 
z=zipfile.ZipFile("fichier.zip","r") 
for nom in z.namelist() : 
      print 'le fichier', nom, 
      nb_octets=z.read(nom) 
      print 'contient ', len(nb_octets),'octets.'
 

Nous pouvons aussi consulter le contenu des fichiers.


#!/usr/bin/env python 
import zipfile 
z = zipfile.ZipFile('test.zip', 'r') 
names = z.namelist() 
for name in names: 
    print 'Attente de %s' % name 
    print z.read(name) 
for name in names: 
    print 'en Attente de %s' % name 
    f = z.open(name) 
    contents = f.read()
 

2. Attaque brute force de mots de passe

Certains fichiers ZIP sont protégés par un mot de passe. Nous pouvons essayer de craquer ces mots de passe en partant d’un dictionnaire, appelé ici passFile et fourni en argument 2 lors du lancement du script, l’argument 1 étant le fichier ZIP.


#!/usr/bin/env python 
import...

Lire dans un fichier OpenOffice ou Word

1. Parcourir une arborescence

Nous devons examiner un répertoire ou toute une arborescence de répertoires situés dans un répertoire donné pour itérer sur les fichiers dont les noms correspondent à certains motifs.

Le générateur os.walk, déjà utilisé dans d’autres parties de ce livre, suffit à cette tâche.


#!/usr/bin/env python 
import os, fnmatch 
def tous_les_fichiers( racine, motifs='*', un_seul_niveau=False,  
repertoires = False): 
      motifs=motifs.split(';') 
      for chemin, sous_reps, fichiers in os.walk(racine): 
            if repertoires: 
                  fichiers.extend(sous_reps) 
            fichiers.sort() 
            for nom in fichiers: 
                  for motif in motifs: 
                        if fnmatch.fnmatch(nom,motif): 
                              yeld os.path.join(chemin,nom) 
                              break ...

E-mail

1. Retrouver des e-mails dans des fichiers

Si nous souhaitons récupérer à partir d’une liste de fichiers toutes les adresses e-mail contenues dans ces fichiers, le script suivant pourra nous être très utile.

chap8_script12.py


def grab_email(files = []): 
    found = [] 
    if files != None: 
        mailsrch = re.compile(r'[\w\-][\w\-\.]+@[\w\-][\w\-\.] 
+[a-zA-Z]{1,4}') 
         
        for file in files: 
            for line in open(file,'r'): 
                found.extend(mailsrch.findall(line)) 
    u = {} 
    for item in found: 
        u[item] = 1 
    return u.keys() 
file=['texte1.txt','texte2.txt','texte3.txt'] 
 
retour=grab_email(file) 
print retour 
 

Dans le même répertoire, nous allons placer trois fichiers texte, texte1.txt, texte2.txt et texte3.txt ; voici leur contenu :


::::::::::::::  
texte1.txt  
::::::::::::::  
un petit texte tout sympa  
qui contient un mail fasm@acissi.net et pis c'est tout  
mais regardons le prochain  
::::::::::::::  
texte2.txt  
::::::::::::::  
la il n'y a pas de mail mais...

Stéganographie

La stéganographie est une branche particulière de la cryptographie qui consiste non pas à rendre le message inintelligible, mais à le camoufler dans un conteneur de manière à masquer sa présence.

1. Rechercher des informations dans une image

Pour appliquer Python à la stéganographie, nous allons prendre une image, oxygen.png, disponible en téléchargement sur le Net, qui contient des données cachées.

Nous remarquons que cette image comporte une barre avec un dégradé de gris, le message caché doit être ici.

images/oxygen.png

Nous allons utiliser de nouveau la bibliothèque PIL déjà vue et en particulier Image.


#!/usr/bin/env python 
import Image 
im = Image.open("oxygen.png") 
print "Image info:",im.format, im.size, im.mode 
#limitation de la zone grise 
y_begin = 0 
while True: 
      p = im.getpixel((0, y_begin)) 
      if p[0] == p[1] == p[2]: 
            break 
      y_begin += 1 
x_end = 0 
while True: 
      p = im.getpixel((x_end, y_begin)) 
      if not p[0] == p[1] == p[2]: 
            break 
      x_end += 1 
print "Y first coordinate:", y_begin,"nX last coordinate:",x_end 
message=[] 
for i in range(0,x_end,7): 
      p = im.getpixel((i, y_begin)) 
      message.append(chr(p[0])) 
print ''.join(message), 
#First run gives: [105, 110, 116, 101, 103, 114, 105, 116, 121] 
message=[105, 110, 116, 101, 103, 114, 105, 116, 121] 
print '(',''.join([chr(x) for x in message]),')'
 

Toutes les librairies, fonctions et méthodes ont déjà été vues précédemment, nous n’y reviendrons donc pas ici.

2. Cacher un message dans une image

Chaque pixel est défini par un triplet de trois nombres entiers compris entre 0 et 255, le premier donnant la composante rouge, le deuxième...

Volatility

L’analyse du contenu de la mémoire volatile (RAM) permet de trouver différentes informations, sur l’état du système par exemple.

L’analyse de la mémoire volatile va permettre de découvrir des connexions réseau ouvertes, les mots de passe utilisés récemment, les fichiers effacés, le contenu du registre Windows...

Volatility est un des plus grands projets Open Source pour le Forensic. C’est un framework Python avec de nombreuses librairies permettant d’extraire des données des mémoires volatiles.

La structure de Volatility permet de développer des modules pour extraire des données spécifiques de la RAM.

Par défaut les modules sont :

  • Affichage de la liste des connexions réseau ouvertes et scan des objets de connexion.

  • Affichage de la liste des DLL chargées par chaque processus.

  • Affichage des fichiers ouverts pour chaque processus.

  • Réalisation de différents dump.

  • Identification de la propriété des images incluant les données, l’horaire, la date et le lieu.

  • Affichage d’une liste des clés de registre pour chaque processus trouvé dans la table des processus.

Des plugins ont été ajoutés par diverses personnes, dont ceux-ci :

  • CryptoScan : trouve les passphrases TrueCrypt.

  • Suspicious : trouve les processus suspects.

  • Keyboardbuffer : extrait le buffer de clavier utilisé par le BIOS.

  • Getsids : trouve les informations de l’utilisateur qui a lancé les processus (SID).

1. Informations sur l’image

Volatility est assez simple d’installation, des exemples d’utilisation sont très bien documentés sur le site. Voici, pour vous donner l’eau à la bouche, un exemple issu du site de Volatility.

Recherche dans le fichier dump des informations sur le système :

images/06EP09.png

2. Processus et DLL

Recherche dans le fichier dump des processus et DLL lancés et utilisés par le système :

images/06EP10.png

3. Capture de mots de passe hachés

Obtenir les mots de passe hachés après la pénétration d’un système Windows est commun pour un attaquant.

Volatility fait cela très facilement. Nous allons d’abord regarder comment utiliser les plug-ins nécessaires à cela et essayer de trouver...

Analyse des points d’accès sans fil dans la base de registre

Le registre Windows contient une base de données hiérarchique contenant la configuration du système où se trouvent les informations relatives aux accès sans fil.

Sous Windows Vista par exemple, nous retrouverons ces informations dans : HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ NetworkList\Signatures\Unmanaged.

Nous pouvons à partir du shell (cmd.exe) lister tout cela :


C:\Windows\system32>reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\  
Windows NT\ CurrentVersion\NetworkList\Signatures\Unmanaged" /s  
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows  
NT\CurrentVersion\NetworkList\Signatures\ 
Unmanaged\010103000F0000F0080000000F0000F04BCC2360E4B8F7DC8BDAF  
AB8AE4DAD8 62E3960B979A7AD52FA5F70188E103148 
ProfileGuid REG_SZ {3B24CE70-AA79-4C9A-B9CC-83F90C2C9C0D}  
Description REG_SZ Hooters_San_Pedro  
Source REG_DWORD 0x8  
DnsSuffix REG_SZ  
FirstNetwork REG_SZ Public_Library  
DefaultGatewayMac REG_BINARY 00115024687F0000
 

Le registre stocke l’adresse MAC de la passerelle comme type REG_Binary. Dans l’exemple précédent, nous la retrouvons sous la forme 00115024687F0000, soit \x00\x11\x50\x24\x68\x7F\x00\x00, mais conventionnellement, l’écriture de l’adresse MAC serait 00:11:50:24:68:7F:00:00.

Créons donc une fonction...

Retrouver les éléments supprimés (dans la corbeille)

La corbeille, en fonction des systèmes d’exploitation, peut avoir un nom différent dans l’arborescence.

Nous pouvons créer un petit script qui va tester cela et nous donner le bon chemin. Nous devrons bien sûr renseigner plus amplement la liste définie pour des systèmes dans d’autres langues.


import os  
def returnDir():  
    dirs=['C:\\Recycler\\','C:\\Recycled\\','C:\\$Recycle.Bin\\']  
    for recycleDir in dirs:  
        if os.path.isdir(recycleDir):  
            return recycleDir  
    return None
 

Après avoir découvert le chemin de la corbeille Windows, nous devrons inspecter son contenu.


C:\RECYCLER>dir /a  
    Volume in drive C has no label.  
    Volume Serial Number is 882A-6E93  
    Directory of C:\RECYCLER  
04/12/2011 09:24 AM     <DIR>        . 
04/12/2011 09:24 AM     <DIR>        ..  
04/12/2011 09:56 AM     <DIR>        S-1-5-21-1275210071-1715567821-
725345543-1005  
04/12/2011 09:20 AM     <DIR>        S-1-5-21-1275210071-1715567821-
725345543- 500  
    0...

Mise en pratique

1. Décryptage

Énoncé

Nous avons cette phrase :

nkxtg uwt nc ugewtkvg kphqtocvkswg gv ng gvjkecn jcemkpi : vqwv kphqtocvkekgp ugpukdknkug cw eqpegrv fg nc ugewtkvg kphqtocvkswg ocku- pqxkeg qw fgdwvcpv fcpu ng fqockpg fg nc ugewtkvg fgu uauvgogu f’kphqtocvkqpu. Sqp cfcig guv crrtgpftg ngu cvvcswgu rqwt okgwz ug fghgpftg.

Créez un script qui la décrypte.

Correction


import string 
cyphertext = "nkxtg uwt nc ugewtkvg kphqtocvkswg gv ng gvjkecn 
jcemkpi : vqwv kphqtocvkekgp ugpukdknkug cw eqpegrv fg nc ugewtkvg 
kphqtocvkswg ocku pqxkeg qw fgdwvcpv fcpu ng fqockpg fg nc 
ugewtkvg fgu uauvgogu f'kphqtocvkqpu. Sqp cfcig guv crrtgpftg ngu 
cvvcswgu rqwt okgwz ug fghgpftg." 
 
fromlist = "abcdefghijklmnopqrstuvwxyz" 
tolist = "cdefghijklmnopqrstuvwxyzab" 
 
transtable = string.maketrans(fromlist, tolist) 
 
print string.translate(cyphertext, transtable)
 

2. OCR

Énoncé

Vous trouverez en téléchargement depuis la page Informations générales un fichier texte nommé ocr.txt.

Un mot y est caché et chacune de ses lettres est très « rare » dans le fichier. Recherchez les lettres qui n’apparaissent qu’une seule fois.

Correction


mess = open("ocr.txt").read() 
dict = {} 
for ch in mess: 
     ...