1. PIE et ASLR
Idée générale : PIE dépend d’ASLR pour être utile
PIE fournit la capacité technique… mais c’est ASLR qui fournit la randomisation.
En effet :
- ASLR est la mécanique du noyau qui décide où placer les zones mémoire d’un processus (pile, heap, libs, parfois exécutable, VDSO)1.
- PIE (Position Independent Executable) transforme l’exécutable principal en un binaire de type ET_DYN (comme une lib partagée), c’est-à-dire :
- le code est adressé en relatif,
- le loader peut donc choisir arbitrairement la base à laquelle il charge les segments
PT_LOADde ce binaire1.
Résultat :
- Sans ASLR (ou avec
kernel.randomize_va_space=0), un binaire PIE sera toujours chargé à la même base → on peut quand même faire du ROP / ret2text dès qu’on connaît cette adresse2. - Avec ASLR activé, la base du binaire PIE est randomisée à chaque exec (comme une lib)1.
Nuance importante : « code, tas et sections de données »
- Ce que PIE + ASLR randomisent pour l’exécutable, ce sont les segments
PT_LOADdu binaire ELF : typiquement text + rodata (R-X) et data + bss (RW) → c’est bien le code et les données statiques du programme3. - Le heap (tas), lui, n’est pas un segment de l’exécutable :
- il vient de
brket/ou d’mmapanonymes, - c’est le noyau qui randomise sa base via le paramètre
kernel.randomize_va_space(valeur 2)2.
- il vient de
Donc pour être techniquement correct :
- Le PIE permet à l’ASLR de randomiser la base des segments
PT_LOADde l’exécutable (code + données statiques). - Indépendamment, l’ASLR randomise :
- la pile,
- la zone mmap (dont les libs),
- et, pour
randomize_va_space=2, le heap2.
En somme :
Si le binaire est compilé en PIE, l’ASLR peut également randomiser la base de l’exécutable lui-même (ses segments de code et de données). La pile, le heap et les bibliothèques partagées sont randomisés par l’ASLR via les mécanismes génériques (mmap / brk), indépendamment du fait que le binaire principal soit PIE ou non.
2. Qualité d’une implémentation ASLR : entropie, granularité, couverture
2.1 Entropie et « gamme de randomisation »
La qualité dépend de la gamme de randomisation (entropie) : c’est exactement ce que disent les papiers et la page Wikipédia1.
En gros :
-
On mesure la robustesse par le nombre de bits d’entropie pour :
- base de l’exécutable (),
- base du heap (),
- base du stack (),
- base de la zone
mmap/ libs ()1.
-
Plus l’espace de recherche () est grand, plus un bruteforce est coûteux (en supposant qu’on peut retenter plusieurs fois sans se faire blacklister)1.
Sur Linux moderne :
- Pour x86-64, la documentation et les analyses donnent typiquement beaucoup plus d’entropie que sur 32 bits (où l’on n’a qu’une poignée de bits réellement exploitables)1.
- Mais des travaux récents montrent que certains changements (par exemple alignement 2 MiB pour les libs afin de profiter des huge pages) ont réduit l’entropie effective du placement de la
libc(28 bits → 19 bits dans certains cas)1.
Le critère « plus la plage est grande, plus c’est bon » est donc exact — et en pratique, il faut aussi tenir compte des alignements (4K pages, parfois 2 MiB hugepages) qui réduisent l’entropie effective.
2.2 Granularité (par page, voire plus gros)
- Sur Linux, la randomisation est typiquement au niveau page (4K sur x86-64) pour la plupart des zones4.
- Depuis Linux 5.18, avec les mappings 2 MiB alignés pour de grosses libs, certaines choses sont même alignées sur 2 MiB → on perd de l’entropie1.
La granularité est donc un critère réel (page 4K vs 2 MiB).
2.3 Ce qui est randomisé : exécutable PIE, libs, stack, heap
Sur Linux, le comportement est gouverné par kernel.randomize_va_space2 :
-
0: pas de randomisation. -
1:- randomisation de la base mmap, de la pile, de la VDSO, etc. ;
- les libs (chargées via
mmap) sont donc randomisées ; - les binaires PIE voient aussi leur code randomisé (car ils sont traités comme
ET_DYN).
-
2:- tout ce qui est dans
1+ randomisation du heap (brk)2.
- tout ce qui est dans
Donc « bonne ASLR = randomiser pile + tas + libs + exécutable PIE » est vrai, avec cette nuance :
Le heap n’est pas « un segment de l’exécutable », c’est une zone anonyme gérée par le noyau, dont la base est randomisée indépendamment.
2.4 Résistance aux fuites d’info
L’ASLR est contournée si une fuite d’une seule adresse a lieu.
C’est exactement ce que dit la littérature :
- ASLR repose sur le fait que l’attaquant ne connaît pas les adresses des zones clés ;
- si l’on obtient un info leak (par exemple, fuite d’une adresse de libc, d’un gadget dans l’ELF, d’un pointeur de stack/heap), on peut en général reconstruire la base de tout ce qui nous intéresse, car les offsets internes à un ELF sont fixes5.
Donc la « résistance aux fuites d’information » est bien un vrai sujet : une ASLR parfaite est inutile si l’application donne des adresses.
3. « Historiquement la pile » vs « aujourd’hui plus que la pile »
Historiquement, l’ASLR a randomisé la pile…
C’est schématiquement vrai pour les tout premiers déploiements (stack randomization) avant que les implémentations ne deviennent plus complètes1.
Aujourd’hui, pour Linux mainline :
- ASLR (avec
randomize_va_space=2) randomise :- base de la pile,
- base de la zone mmap (donc libs, VDSO, mappings fichiers),
- base du heap,
- base de l’exécutable principal si PIE2.
La phrase est donc OK si on la lit comme une remarque historique, à condition de préciser que ce n’est plus le cas des systèmes modernes : l’ASLR ne se limite plus du tout à la pile.
4. « Une page mappée sur l’exécutable » : est-ce exact ?
Une « page mappée sur l’exécutable » est une unité de mémoire virtuelle dont le contenu est directement chargé (mappé) à partir du fichier binaire ELF.
Techniquement, oui :
-
Un ELF a des segments
PT_LOADdécrits dans la table des Program Headers. -
Lors de
execve, le noyau lit ces Program Headers et pour chaquePT_LOAD:- fait un
mmapdu fichier à l’adresse virtuellep_vaddr, - sur la longueur
p_filesz/p_memsz, - avec les droits
p_flags(R/W/X)6.
- fait un
-
Le tout est aligné sur des pages (4K en x86-64 en général)4.
Du coup :
- On peut parler de « pages mappées depuis l’exécutable » pour désigner les pages virtuelles dont le contenu vient du fichier ELF (segment texte, données statiques, etc.).
- Ça correspond en pratique aux lignes
/proc/<pid>/mapsqui mentionnent le chemin du binaire, par exemple :
00400000-0041c000 r-xp 00000000 08:01 /bin/ls # PT_LOAD (R-X)
0061e000-0061f000 rw-p 0001e000 08:01 /bin/ls # PT_LOAD (RW-)La définition est donc correcte et colle parfaitement à ce que fait le loader ELF.
5. Synthèse pwn / reverse : ce que ça change en examen
Cas 1 — binaire non PIE, ASLR activé
-
L’exécutable principal est de type
ET_EXEC: son adresse de base est fixe (e.g.0x400000en 64 bits)7. -
L’ASLR randomise :
- pile, heap, libs, VDSO, etc.
-
Résultat :
- attaques ret2text (saut direct dans
.text) restent triviales : les offsets sont toujours les mêmes entre runs ; - attaques ret2libc nécessitent souvent un leak d’adresse dans libc (ASLR sur libs), mais une fois que l’on connaît
libc_base, tous les offsets sont déterministes.
- attaques ret2text (saut direct dans
Cas 2 — binaire PIE, ASLR activé (cas « durci » classique moderne)
-
L’exécutable principal est traité comme une lib partagée : sa base est randomisée à chaque exec1.
-
Avec
randomize_va_space=2, randomisation aussi de :- heap,
- stack,
- zone mmap / libs.
-
Résultat :
- pas de ret2text direct sans info leak → il faut fuiter au moins une adresse dans l’ELF ou dans une lib, puis reconstruire les offsets (ASLR « cassé » localement) ;
- les chaînes ROP, ret2libc, etc. demandent en général :
- un info leak,
- puis un calcul d’adresse (base + offset).
Qualité réelle de l’ASLR
-
Sur 64 bits, l’espace d’adressage est vaste, mais :
-
Dans la pratique exploit, on ne se contente jamais d’ASLR comme « mur absolu » :
- on cherche à la bypasser via une fuite,
- ou à l’affaiblir (brute force si service redémarré en boucle, information partielle).
6. TL;DR — reformulations à retenir
En version corrigée / serrée :
-
PIE :
Un exécutable PIE est compilé de façon à pouvoir être chargé à n’importe quelle adresse virtuelle ; il est de type
ET_DYN, comme une bibliothèque partagée. Sans ASLR, il sera généralement chargé toujours au même endroit ; avec ASLR, son adresse de base est randomisée à chaque exec, comme les libs. -
ASLR :
ASLR randomise la disposition de l’espace d’adressage d’un processus : pile, heap (si
randomize_va_space=2), zone mmap (dont les libs), VDSO, et, si le binaire est PIE, la base de l’exécutable. La robustesse se mesure en bits d’entropie, dépendant de la plage de randomisation et des contraintes d’alignement. -
Qualité de l’ASLR :
Bonne ASLR = forte entropie, granularité fine, randomisation de toutes les zones critiques (pile, heap, libs, exécutable PIE), et absence d’info leak. Une fuite d’une seule adresse dans un ELF (ou une lib) suffit en général à reconstruire toutes les autres adresses de ce fichier.
-
« Page mappée » :
Une page mappée sur l’exécutable est une page virtuelle dont le contenu est issu d’un segment
PT_LOADdu fichier ELF, mappé viammap()à l’adressep_vaddravec les droitsp_flags. C’est ce que l’on voit dans/proc/<pid>/mapspour les lignes qui pointent vers le binaire.
Footnotes
-
Wikipedia — Address space layout randomization. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12
-
sysctl-explorer — kernel.randomize_va_space. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Shiori’s Coffee Nook — ELF sections, segments, and their mapping in memory. ↩ ↩2
-
Address Space Layout Randomization — lettieri.iet.unipi.it. ↩ ↩2
-
Learning ELF: The Foundation of Linux Binary Analysis — Can Özkan. ↩
-
linuxvox — Why Do Linux Binaries Start at Virtual Memory Address 0x8048000?. ↩