Post

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.

  1. unsorted bin attack ;
  2. unsorted bin leak.

1️⃣ unsorted bin attack

Écrire l’adresse de la unsorted bin à une adresse arbitraire.

📋 Exploitabilité selon les versions

VersionExploitabilité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.

  1. libération d’un bloc A (victim) de n octets (n assez grand pour aller dans la unsorted bin) ;
  2. modification de victim->bk pour pointer vers l’adresse cible ;
  3. allocation d’un bloc de n octets.

🔥 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->bk si 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, alors victim->bk peut être modifié ;
  • écriture arbitraire : en ayant une primitive d’écriture arbitraire victim->bk peut ê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 :

  1. le bloc peut être réutilisé tel quel, lorsqu’il a la même taille que celle de l’allocation ;
  2. le bloc peut être scindé, lorsqu’il est plus grand que la taille de l’allocation ;
  3. le bloc est trop petit et doit être recyclé dans une small bin ou large 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 victim doit ê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 :

  1. allouer un bloc de taille n assez grande pour qu’il aille dans la unsorted bin ;
  2. libérer ce bloc ;
  3. utiliser une primitive d’exploitation pour modifier le champ bk de ce bloc vers adresse_cible - 0x10 ;
  4. 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 bk avec adresse_cible - 0x10 et pas directement adresse_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 :

 x86x86_64
Taille min du bloc0x100x20
Taille max du bloc0x4000x410

Bah y qu’à utiliser des blocs plus grands que 0x410 et comme ça on fait comme si le tcache n’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

VersionExploitabilitéCommentaire
≤ 2.41🟢Exploitable.
≥ 2.42Pas 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 champ fd ;
  • 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 fd voire le champ bk ;
  • affichage d’un bloc alloué : lorsqu’un bloc est alloué à partir d’un bloc libre recyclé depuis la unsorted bin, ses champs fd et bk ne 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 champ fd.

📃 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 :

  1. le bloc est le seul de la liste : ses deux champs fd et bk pointent vers la unsorted bin (adresse de la libc) ;
  2. il s’agit du premier ou dernier bloc : au moins un de ses champs pointe vers la unsorted bin (adresse de la libc) ;
  3. 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 :

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 fd affiché sera bien un pointeur de la libc mais ce ne sera pas celui de la unsorted bin. Ce sera l’adresse une small bin ou large bin ce qui implique un écart de quelques octets avec l’adresse de la unsorted 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 fd ne 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 bin plutôt que la unsorted 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 :

  1. 8 blocs de taille n sont alloués ainsi qu’un petit bloc pour éviter la consolidation avec le bloc du sommet ;
  2. les 7 premiers blocs (bloc_tcache[i]) sont libérés : la corbeille de taille n du tcache est saturée et ne peut plus accueillir de nouveau bloc ;
  3. le 8ème (bloc_unsorted_bin) bloc est libéré et se retrouve bien dans la unsorted_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 :

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 taille 0x2a0 du tcache qui est vide (contrairement à celle de taille 0x150 🙃).

Conteneur Docker :

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 :

  1. en plus des 8 blocs de taille 0x150 déjà libérés, nous en libérons un 9ème ;
  2. étant donné que les deux derniers blocs sont dans la unsorted bin et se jouxtent : ils sont fusionnés en un bloc de taille 0x150 + 0x150 = 0x2a0 ;
  3. les 7 premières allocations réutilisent des blocs dans le tcache tandis que la 8ème provoque une fragmentation du bloc de 0x2a0 octets. De ce fait, le bloc fragmenté de 0x150 octets est directement retourné, sans passer par le tcache 😎.
This post is licensed under CC BY 4.0 by the author.