Partie 16 - Exploiter les vulnérabilités de la unsorted bin - primitives et scénarios (3/4)
Exploiter les vulnérabilités de la unsorted bin : primitives et scénarios (3/4)
Après avoir passé un certain temps à comprendre les différentes vérifications ajoutées au fil du temps, passons aux attaques et vulnérabilités exploitables via la unsorted bin.
- unsorted bin attack ;
- unsorted bin leak.
1️⃣ unsorted bin attack
Écrire l’adresse de la unsorted bin à une adresse arbitraire.
📋 Exploitabilité selon les versions
| Version | Exploitabilité | Commentaire |
|---|---|---|
| ≤ 2.27 | 🟢 | Exploitable. |
| 2.28 | 🟡 | Exploitable sous certaines conditions Il faut s’assurer que le champ fd de l’adresse cible pointe bien vers le bloc victim à corrompre afin que la vérification victim->bk->fd == victim n’échoue pas. |
| ≥ 2.29 | 🟠 | Très difficilement exploitable. Pas moins de six vérifications doivent être contournées pour que l’attaque réussisse. L’effort nécessaire pour contourner tous ces obstacles remet en question la pertinence même de cette attaque. |
⚡ Résumé
La unsorted bin attack est une attaque généralement utilisée comme étape intermédiaire lors de l’exploitation du tas. Elle consiste à écrire l’adresse de la unsorted bin (plus précisément l’adresse située dans l’arène : &av->bins[0]) à une adresse choisie. Cela permet notamment de faire fuiter une adresse de la libc et trouver où celle-ci est chargée en mémoire.
- libération d’un bloc
A(victim) denoctets (nassez grand pour aller dans launsorted bin) ; - modification de
victim->bkpour pointer vers l’adresse cible ; - allocation d’un bloc de
noctets.
🔥 Conséquences
En exploitant cette vulnérabilité, il est possible d’aboutir à :
- une écriture (de données non arbitraires) à une adresse arbitraire.
🔧 Primitives d’exploitation
Cette attaque peut notamment être réalisée à l’aide des primitives suivantes :
- use-after-free : en ayant la possibilité de modifier directement un bloc libre, il est possible de modifier
victim->bksi l’écriture permet d’atteindre ce champ ; - buffer overflow dans le tas : s’il est possible de réaliser un dépassement de mémoire depuis un des blocs situés avant le bloc
victim, alorsvictim->bkpeut être modifié ; - écriture arbitraire : en ayant une primitive d’écriture arbitraire
victim->bkpeut être facilement modifié. Cette primitive peut également rendre l’attaque inutile si l’on a déjà la possibilité d’écrire n’importe quoi n’importe où 😅.
📃 Détails de l’exploitation
Sur le papier, cette attaque peut sembler assez complexe en raison des magouilles réalisées dans la liste doublement chaînée. Pourtant, toute la magie de la unsorted bin attack repose sur cette seule ligne dans malloc.c, dans la fonction _int_malloc :
1
2
3
4
5
6
7
// bck = victim->bk;
/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av); // <--- Ici
C’est précisément cette affectation qui écrit l’adresse de la unsorted bin (aka unsorted_chunks (av) ) à l’emplacement victim->bk->fd.
Savoir d’où provient l’écriture de l’adresse de la unsorted bin, c’est bien, mais il faut surtout comprendre comment amener l’exécution jusque-là.
Réutilisation d’un bloc libre de la unsorted bin
Une chose qu’il faut savoir concernant le traitement des blocs de la unsorted bin dans l’algorithme de malloc est que le bloc victim est d’abord retiré de la unsorted bin puis ensuite analysé afin de savoir si :
- le bloc peut être réutilisé tel quel, lorsqu’il a la même taille que celle de l’allocation ;
- le bloc peut être scindé, lorsqu’il est plus grand que la taille de l’allocation ;
- le bloc est trop petit et doit être recyclé dans une
small binoularge bin.
C’est au moment où le bloc est retiré de la unsorted bin qu’est exécutée bck->fd = unsorted_chunks (av);, c’est-à-dire avant qu’il ne soit traité. Bon. Cela signifie que ce n’est pas très compliqué d’arriver ici.
Parmi les trois cas de figure précédemment listés, seul un cas permet de réaliser l’attaque sans qu’une erreur ne soit renvoyée : lorsque l’allocation est de la même taille que le bloc retiré.
Lorsque le bloc
victimdoit être scindé, il semblerait qu’il y ait plus de vérifications effectuées. En tout cas, c’est ce qui arrive dans la version 2.27 de la glibc, je n’ai pas testé ce cas de figure dans les versions précédentes afin de voir si une erreur est également renvoyée.
Mise en œuvre pratique de l’attaque
Voici les étapes à suivre afin de mettre en place cette attaque :
- allouer un bloc de taille
nassez grande pour qu’il aille dans launsorted bin; - libérer ce bloc ;
- utiliser une primitive d’exploitation pour modifier le champ
bkde ce bloc versadresse_cible - 0x10; - réaliser une allocation de taille
n.
Pas très compliqué au final, non 😇 ?
Si la version de la libc est inférieure à la 2.28, n’ayez pas peur d’écraser le champ
fd(du bloc modifié) avec une valeur quelconque ; cela n’entravera pas l’attaque étant donné que le programme ne détectera pas cette anomalie.
Pourquoi faut-il modifier le champ
bkavecadresse_cible - 0x10et pas directementadresse_cible?
Bonne question ! Pour y répondre revoyons de plus près la ligne qui écrit l’adresse de la unsorted bin en mémoire :
1
2
3
4
5
// bck = victim->bk;
bck->fd = unsorted_chunks (av); // <--- Ici
// C'est-à-dire :
victim->bk->fd = unsorted_chunks (av);
Le programme n’écrit pas directement l’adresse de la unsorted bin à l’adresse pointée par victim->bk mais l’écrit à l’adresse &(victim->bk->fd). Par exemple, si on souhaite écrire l’adresse de la unsorted bin à l’adresse 0x555555559900, sans retirer 0x10 octets, nous obtenons ceci :
On a loupé la cible de 0x10 octets 😶.
Que faire de cette attaque ?
On peut seulement réécrire l’adresse de la
unsorted bin, tu veux que je fasse quoi avec ça 😆 ?
Bon, c’est vrai que dit comme ça, c’est pas ouf 😅. Encore une fois, cette attaque est généralement une étape intermédiaire pour une exploitation plus avancée du programme. Nous pouvons notamment imaginer les scénarios suivants :
Faire fuiter une adresse de la libc depuis la pile
- Hypothèse : savoir où est située la pile (grâce à un leak via des format strings par exemple).
Si on a la possibilité de faire fuiter le contenu de la pile, il est possible d’utiliser cette attaque pour y écrire une adresse de la libc, la faire fuiter et trouver ensuite où est chargée la libc en mémoire.
Faire fuiter une adresse de la libc depuis le tas
- Hypothèses :
- il est possible d’afficher le contenu de l’adresse cible ;
- l’adresse à laquelle est chargé le tas est connue (via une fuite par exemple).
S’il n’est pas possible d’afficher le contenu des blocs de grande taille et réaliser une fuite de données via la unsorted bin leak, nous pouvons envisager d’écrire son adresse dans un bloc de plus petite taille qui pourra ensuite être affiché et ainsi faire fuiter une adresse de la libc.
Modifier la variable global_max_fast
Hypothèse : savoir à quelle adresse est située global_max_fast.
Lors du chapitre dédié aux fastbins, nous avions très brièvement parlé de la variable globale global_max_fast. Nous avions alors affirmé qu’un attaquant pouvant modifier sa valeur peut augmenter la taille maximale d’un bloc pouvant aller dans une fastbin.
La possibilité de modifier global_max_fast permet de mettre en place les attaques (avancées) suivantes :
La liste n’est pas exhaustive. Ces attaques avancées ne seront pas détaillées dans le cadre de ce cours d’introduction au pwn.
Vous remarquerez que bon nombre d’attaques dans le tas ont pour nom “House of quelque chose”. Il semblerait que ce soit pour une raison historique 🤔.
De manière générale, ayez de l’imagination ! Si une variable ayant une petite valeur vous semble contraignante, n’hésitez pas à la modifier avec cette attaque pour voir si cela vous permet d’aller plus loin.
Exemple : une variable qui limite le nombre d’allocations alors que vous avez besoin de bien plus d’allocations pour réaliser une autre attaque dans le tas.
🚧 Obstacles et contraintes
ASLR
Lorsque l’ASLR est active, il est souvent nécessaire d’avoir un leak permettant de connaître les octets de poids fort (aléatoires) de l’adresse cible.
💡Contournement
Plusieurs cas sont possibles en fonction de la localisation de l’adresse cible :
- dans la même zone mémoire que celle de la libc : l’adresse cible aura, par conséquent, les mêmes octets de poids fort aléatoires que l’adresse initialement présente dans
bk. Il suffit seulement de modifier les octets de poids faible, avec un peu de force brute s’il y a besoin de modifier plus que l’octet de poids faible ; - en dehors de la libc : une fuite sera sûrement nécessaire pour connaître l’adresse cible.
Présence du tcache
Comme vous le savez, le tcache a été introduit lors de la version 2.26 de la libc. Nous avons vu que les tailles de blocs gérées par le tcache sont les suivantes :
| x86 | x86_64 | |
|---|---|---|
| Taille min du bloc | 0x10 | 0x20 |
| Taille max du bloc | 0x400 | 0x410 |
Bah y qu’à utiliser des blocs plus grands que
0x410et comme ça on fait comme si letcachen’existait pas 🤓.
Merci Sherlock 🕵️♂️. Le tcache ne pose pas tellement de soucis lorsque l’on manipule des blocs de très grande taille étant donné qu’ils vont directement dans la unsorted bin.
Le problème apparaît lorsqu’il n’est, justement, pas possible d’allouer des blocs de grande taille et que l’on a besoin d’accéder à la unsorted bin afin d’avancer dans l’exploitation.
💡Contournement
Voir la section Comment accéder à la unsorted bin quand le tcache ne le permet pas ? un peu plus bas.
2️⃣ unsorted bin leak
Faire fuiter l’adresse de la unsorted bin ou une adresse du tas.
📋 Exploitabilité selon les versions
| Version | Exploitabilité | Commentaire |
|---|---|---|
| ≤ 2.41 | 🟢 | Exploitable. |
| ≥ 2.42 | ❓ | Pas testé. |
⚡ Résumé
Cette attaque consiste simplement à afficher les champs fd et bk d’un bloc libre appartenant, ou ayant appartenu, à la unsorted bin. Cette méthode permet de faire fuiter, selon le cas, une adresse de la libc ou une adresse du tas.
🔥 Conséquences
En exploitant cette vulnérabilité, il est possible d’obtenir :
- une fuite d’une adresse de la libc ;
- une fuite d’une adresse mémoire du tas.
🔧 Primitives d’exploitation
Cette attaque peut notamment être réalisée à l’aide des primitives suivantes :
- use-after-free : dès lors que l’on peut afficher le contenu d’un bloc libre de la
unsorted bin, il est possible d’en afficher le champfd; - buffer overflow dans le tas : s’il est possible de réaliser un dépassement de mémoire depuis un des blocs situés avant le bloc à faire fuiter et d’afficher le bloc à partir duquel le dépassement a eu lieu, il est possible d’afficher le champ
fdvoire le champbk; - affichage d’un bloc alloué : lorsqu’un bloc est alloué à partir d’un bloc libre recyclé depuis la
unsorted bin, ses champsfdetbkne sont généralement pas mis à zéro. Ainsi, en affichant le contenu du bloc nouvellement alloué, il est possible d’observer (au moins) la valeur du champfd.
📃 Détails de l’exploitation
Tout d’abord, sachez que le mécanisme derrière cette attaque n’est pas très compliqué : lorsqu’un bloc est libéré et va dans la unsorted bin , ses champs fd et bk sont remplis. Trois cas de figure existent concernant le bloc dont on veut afficher les pointeurs fd et bk :
- le bloc est le seul de la liste : ses deux champs
fdetbkpointent vers launsorted bin(adresse de la libc) ; - il s’agit du premier ou dernier bloc : au moins un de ses champs pointe vers la
unsorted bin(adresse de la libc) ; - il s’agit d’un bloc intermédiaire : ses deux champs pointent vers une adresse située dans le tas.
Vous l’aurez compris, en fonction de la position du bloc, dans la unsorted bin, nous ne pourrons pas faire fuiter les mêmes informations. En fonction de ce que vous avez besoin de faire fuiter (adresse du tas ou de la libc), il va falloir choisir le bon bloc pour y parvenir.
Afficher fd et bk
La question qui se pose réellement est : comment afficher fd et bk ? Plusieurs méthodes sont utilisables. Voyons-en quelques-unes (sans pour autant être exhaustifs).
Utiliser un use-after-free
L’un des cas les plus simples dans l’exploitation de cette attaque est tout simplement d’utiliser un use-after-free afin d’afficher le champ fd d’un bloc libre de la unsorted bin.
Voici un petit bout de code qui utilise un use-after-free pour faire fuiter le champ fd :
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdlib.h>
#include <stdio.h>
int main()
{
void *a = malloc(0x500);
malloc(1); // Evite la consolidation
free(a);
printf("fd vaut : %p\n",*((unsigned long long *)a)); // Use-after-free
}
On le compile et l’exécute :
1
2
$ ./unsorted_bin_leak
fd vaut : 0x72850741ace0
Simple et efficace 😎.
Pour le conteneur Docker :
- ⬇️ Téléchargement : pwn-unsorted-bin-leak.zip
- 🔎 SHA256 & Analyse Virus Total : 96e4ce8fc610b780094aa6ecf2ab56640a0b4c95cd01ea0e644d41ae1e86ae0c
- ⚙️ Construction et lancement du conteneur :
1
2
3
docker build -t pwn-unsorted-bin-leak .
docker run -it --rm -p 1234:1234 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined pwn-unsorted-bin-leak
Utiliser un buffer overflow
En utilisant un dépassement de mémoire tampon, l’idée est de remplir toute la zone mémoire du bloc jusqu’au champ fd (sans l’écraser évidemment) avec des octets non nuls puis d’afficher le bloc où le buffer overflow a eu lieu. Naturellement, fd sera affiché, sauf s’il y a une limite sur la taille des données affichées.
Dans l’exemple ci-dessous, le dépassement de mémoire permet de remplir tous les octets jusqu’au champ fd. En affichant le bloc 🔵 avec une fonction comme printf, le résultat sera de ce type : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xe0\xac\xc2\xf7\xff\x7f.
Ce qui est intéressant avec cette technique est qu’il est possible d’afficher également bk en augmentant la taille du dépassement de 8 octets, en écrasant fd.
Allouer le bloc à faire fuiter
Dans le cas où il n’est pas possible d’afficher le champ fd alors que le bloc est libre (via un use-after-free par exemple) il est toujours envisageable d’allouer le bloc de la unsorted bin et d’en afficher le contenu.
Voici un code d’exemple qui ne diffère pas beaucoup de celui qui se base sur le use-after-free :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdlib.h>
#include <stdio.h>
int main()
{
void *a = malloc(0x500);
malloc(1); // Evite la consolidation
free(a);
void *b = malloc(0x500); // Allocation du bloc à faire fuiter
printf("fd vaut (en allouant le bloc): %p\n",*((unsigned long long *)b));
}
Il n’est pas nécessaire que l’allocation soit de la même taille. Cette méthode fonctionne même avec une allocation plus petite que celle du bloc à faire fuiter.
Si vous utilisez une allocation de plus petite taille, le champ
fdaffiché sera bien un pointeur de la libc mais ce ne sera pas celui de launsorted bin. Ce sera l’adresse unesmall binoularge bince qui implique un écart de quelques octets avec l’adresse de launsorted bin.
Cette méthode repose sur deux hypothèses principales :
- il est possible d’afficher un bloc alloué ;
- il est possible d’allouer un bloc sans que le champ
fdne soit écrasé.
🚧 Obstacles et contraintes
Impossibilité d’afficher un bloc
Il peut arriver que lors de certains challenges ou contextes d’exploitation, il ne soit pas possible d’afficher le contenu d’un quelconque bloc. C’est triste mais bon, on fait avec 🥹.
💡Contournement
Malheureusement cette contrainte nous complexifie davantage la tâche. Il est même possible que cette attaque devienne inutilisable dans un tel contexte.
Il existe tout de même une manière de faire fuiter des informations en utilisant la structure FILE de stdout. Il s’agit d’une technique avancée d’exploitation du tas que l’on ne détaillera pas ici. Pour les plus curieux, vous pouvez jeter un œil à ce lien.
Présence du tcache
Comme pour la précédente attaque, la présence du tcache rend la fuite de données un peu plus complexe.
💡Contournement
Voir la section Comment accéder à la unsorted bin quand le tcache ne le permet pas ? ci-dessous.
❓ Comment accéder à la unsorted bin quand le tcache ne le permet pas ?
Problème
Il ne s’agit pas d’une attaque mais plutôt d’une section afin de traiter le problème suivant : j’ai besoin d’accéder à la unsorted bin en ne pouvant allouer et libérer que de petits blocs (qui iront dans le tcache en cas de libération), comment faire ?
Solution
Pour pouvoir allouer un bloc de taille n (n étant inférieur à 0x400 ) il suffit de remplir la corbeille du tcache qui gère les blocs de taille n. Par “remplir” on entend : libérer au moins 7 blocs de taille n pour que la corbeille en question ne puisse plus accueillir de bloc de taille n et que ce dernier aille directement dans la unsorted bin.
Voici un bout de code qui illustre ce contournement :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdlib.h>
int main()
{
// ----- Phase d'allocation des blocs -----
void* blocs_tcache[7] = {0};
void* bloc_unsorted_bin = NULL;
for(int i = 0; i < 7; i++)
blocs_tcache[i] = malloc(0x150);
bloc_unsorted_bin = malloc(0x150);
malloc(1); // Eviter la consolidation avec top_chunk
// ----- Phase de liberation des blocs -----
for(int i = 0; i < 7; i++)
free(blocs_tcache[i]); // Vers le tcache
free(bloc_unsorted_bin); // Vers la unsorted bin
return 0;
}
Dans les versions les plus récentes de la libc (ex : 2.41) se retrouve dans une
small binplutôt que launsorted bin. Je ne sais pas pourquoi et je vous avoue que j’ai eu la flemme de chercher 😅.En tout cas cela fonctionne dans la version 2.33 et sûrement avec les précédentes.
Voici ce que ça donne dans un schéma :
- 8 blocs de taille
nsont alloués ainsi qu’un petit bloc pour éviter la consolidation avec le bloc du sommet ; - les 7 premiers blocs (
bloc_tcache[i]) sont libérés : la corbeille de taillendutcacheest saturée et ne peut plus accueillir de nouveau bloc ; - le 8ème (
bloc_unsorted_bin) bloc est libéré et se retrouve bien dans launsorted_bin.
Faire fuiter une adresse grâce à la unsorted bin
Reprenons le précédent bout de code et tentons d’accéder au bloc situé dans la unsorted bin pour en afficher le contenu en effectuant plusieurs allocations successives :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdlib.h>
#include <stdio.h>
int main()
{
// ----- Phase d'allocation des blocs -----
void* blocs_tcache[7] = {0};
void* bloc_unsorted_bin = NULL;
for(int i = 0; i < 7; i++)
blocs_tcache[i] = malloc(0x150);
bloc_unsorted_bin = malloc(0x150);
malloc(1); // Eviter la consolidation avec top_chunk
// ----- Phase de liberation des blocs -----
for(int i = 0; i < 7; i++)
free(blocs_tcache[i]); // Vers le tcache
free(bloc_unsorted_bin); // Vers la unsorted bin
// ----- Acceder au bloc de la unsorted bin -----
for(int i = 0; i < 7; i++)
malloc(0x150);
bloc_unsorted_bin = malloc(0x150);
printf("La valeur du champ 'fd' de ce bloc est : %p\n",*(unsigned long long *)bloc_unsorted_bin);
return 0;
}
L’accès au conteneur Docker :
- ⬇️ Téléchargement : pwn-unsorted-bin-leak-2.zip
- 🔎 SHA256 & Analyse Virus Total : 1818f6784eacb8d11babaddc7c3f3ef0cbddd1497181e8b139b0c2f22b912d9d
- ⚙️ Construction et lancement du conteneur :
1
2
3
docker build -t pwn-unsorted-bin-leak-2 .
docker run -it --rm -p 1234:1234 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined pwn-unsorted-bin-leak-2
On compile le programme avec la libc 2.33 et on l’ouvre dans gdb. Quel est le contenu de fd ?
Or il s’agit des bits de poids fort des adresses du tas et non de la libc. Ce n’est donc pas une adresse de la libc, ce à quoi on s’attendait 😞.
Pour comprendre ce comportement il faut pas mal investiguer le code de _int_malloc et comparer deux versions avant et après l’avènement du tcache (ex : 2.25 et 2.33). On tombe notamment sur cette différence :
Le programme entre dans la condition if (size == nb) lorsque le bloc victim de la unsorted bin a pile poil la taille de l’allocation demandée.
Lorsque le tcache est disponible et qu’il y a de la place dans sa corbeille de taille n, avant de retourner directement le bloc victim … il est d’abord inséré dans le tcache 😮.
Revenons à nos moutons 🐏. En ce qui nous concerne, nous voulons faire fuiter une adresse de la libc comme au bon vieux temps via le champ fd (ou bk). Il y a une astuce pour cela. En effet, nous venons de voir que lorsque la taille n de l’allocation est la même que la taille du bloc, cela ne fonctionne pas.
En revanche, en provoquant une fragmentation d’un bloc de plus grande taille, le bloc victim sera directement retourné par malloc sans passer par le tcache. Ainsi, nous aurons nos champs fd et bk intacts et qui pointeront vers l’arène (dans la libc).
Cela peut se faire ainsi :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdlib.h>
#include <stdio.h>
int main()
{
// ----- Phase d'allocation des blocs -----
void* blocs_tcache[7] = {0};
void* bloc_unsorted_bin= NULL;
// Modification ici :
void* bloc_unsorted_bin_bis = NULL;
for(int i = 0; i < 7; i++)
blocs_tcache[i] = malloc(0x150);
bloc_unsorted_bin = malloc(0x150);
// Modification ici :
bloc_unsorted_bin_bis = malloc(0x150); // Nouveau bloc
malloc(1); // Eviter la consolidation avec top_chunk
// ----- Phase de liberation des blocs -----
for(int i = 0; i < 7; i++)
free(blocs_tcache[i]); // Vers le tcache
free(bloc_unsorted_bin); // Vers la unsorted bin
// Modification ici :
free(bloc_unsorted_bin_bis); // Idem + consolidation avec le precedent bloc
// ----- Acceder au bloc de la unsorted bin -----
for(int i = 0; i < 7; i++)
malloc(0x150);
bloc_unsorted_bin = malloc(0x150);
printf("La valeur du champ 'fd' de ce bloc est : %p\n",*(unsigned long long *)bloc_unsorted_bin);
return 0;
}
Nous ne pouvons pas allouer directement un plus grand bloc (ex :
bloc_unsorted_bin = malloc(0x2a0);) car ce bloc, une fois libéré, ira dans la corbeille de taille0x2a0dutcachequi est vide (contrairement à celle de taille0x150🙃).
Conteneur Docker :
- ⬇️ Téléchargement : pwn-unsorted-bin-leak-3.zip
- 🔎 SHA256 & Analyse Virus Total : 34df07402ab891ad81eeae215b9060092563ebac5a0338b02c960754c4194cf0
- ⚙️ Construction et lancement du conteneur :
1
2
3
docker build -t pwn-unsorted-bin-leak-3 .
docker run -it --rm -p 1234:1234 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined pwn-unsorted-bin-leak-3
On recompile le programme avec la libc 2.33 et voyons ce qui est affiché dans gdb :
Super ! Il s’agit bien d’une adresse de la libc ! Pour ceux qui y voient plus clair avec un schéma, voici ce qui a été fait :
- en plus des 8 blocs de taille
0x150déjà libérés, nous en libérons un 9ème ; - étant donné que les deux derniers blocs sont dans la
unsorted binet se jouxtent : ils sont fusionnés en un bloc de taille0x150 + 0x150 = 0x2a0; - les 7 premières allocations réutilisent des blocs dans le
tcachetandis que la 8ème provoque une fragmentation du bloc de0x2a0octets. De ce fait, le bloc fragmenté de0x150octets est directement retourné, sans passer par letcache😎.










