Stack Canaries
Last updated
Last updated
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
StackGuard wstawia specjalną wartość znaną jako canary przed EIP (Extended Instruction Pointer), konkretnie 0x000aff0d
(reprezentujący null, newline, EOF, carriage return), aby chronić przed przepełnieniem bufora. Jednak funkcje takie jak recv()
, memcpy()
, read()
, i bcopy()
pozostają podatne, a ochrona nie obejmuje EBP (Base Pointer).
StackShield przyjmuje bardziej zaawansowane podejście niż StackGuard, utrzymując Global Return Stack, który przechowuje wszystkie adresy powrotu (EIPs). Ta konfiguracja zapewnia, że każde przepełnienie nie powoduje szkód, ponieważ pozwala na porównanie przechowywanych i rzeczywistych adresów powrotu w celu wykrycia wystąpień przepełnienia. Dodatkowo, StackShield może sprawdzić adres powrotu w stosunku do wartości granicznej, aby wykryć, czy EIP wskazuje poza oczekiwaną przestrzeń danych. Jednak ta ochrona może być obejściem za pomocą technik takich jak Return-to-libc, ROP (Return-Oriented Programming) lub ret2ret, co wskazuje, że StackShield również nie chroni zmiennych lokalnych.
-fstack-protector
:Ten mechanizm umieszcza canary przed EBP i reorganizuje zmienne lokalne, aby umieścić bufory na wyższych adresach pamięci, zapobiegając ich nadpisywaniu innych zmiennych. Bezpiecznie kopiuje również argumenty przekazywane na stosie powyżej zmiennych lokalnych i używa tych kopii jako argumentów. Jednak nie chroni tablic z mniej niż 8 elementami ani buforów w strukturze użytkownika.
Canary to losowa liczba pochodząca z /dev/urandom
lub domyślna wartość 0xff0a0000
. Jest przechowywana w TLS (Thread Local Storage), co pozwala na współdzielenie przestrzeni pamięci między wątkami, aby miały one specyficzne dla wątku zmienne globalne lub statyczne. Te zmienne są początkowo kopiowane z procesu macierzystego, a procesy potomne mogą zmieniać swoje dane bez wpływu na rodzica lub rodzeństwo. Niemniej jednak, jeśli fork()
jest używane bez tworzenia nowego canary, wszystkie procesy (rodzic i dzieci) dzielą ten sam canary, co czyni go podatnym. W architekturze i386 canary jest przechowywane w gs:0x14
, a w x86_64, w fs:0x28
.
Ta lokalna ochrona identyfikuje funkcje z buforami podatnymi na ataki i wstrzykuje kod na początku tych funkcji, aby umieścić canary, a na końcu, aby zweryfikować jego integralność.
Gdy serwer internetowy używa fork()
, umożliwia to atak brute-force w celu odgadnięcia bajtu canary po bajcie. Jednak użycie execve()
po fork()
nadpisuje przestrzeń pamięci, niwecząc atak. vfork()
pozwala procesowi potomnemu na wykonanie bez duplikacji, aż spróbuje zapisać, w którym momencie tworzona jest duplikacja, oferując inne podejście do tworzenia procesów i zarządzania pamięcią.
W binariach x64
, cookie canary to 0x8
bajtowy qword. Pierwsze siedem bajtów jest losowych, a ostatni bajt to null byte.
W binariach x86
, cookie canary to 0x4
bajtowy dword. Pierwsze trzy bajty są losowe, a ostatni bajt to null byte.
Najmniej znaczący bajt obu canary to null byte, ponieważ będzie pierwszym na stosie pochodzącym z niższych adresów i dlatego funkcje, które odczytują ciągi, zatrzymają się przed jego odczytaniem.
Wyciekanie canary i następnie nadpisywanie go (np. przepełnienie bufora) jego własną wartością.
Jeśli canary jest forkowany w procesach potomnych, może być możliwe brute-force go jeden bajt na raz:
Jeśli w binarnym kodzie występuje interesujące wyciekanie lub podatność na dowolne odczyty, może być możliwe jego wyciekanie:
Nadpisywanie wskaźników przechowywanych na stosie
Stos podatny na przepełnienie stosu może zawierać adresy do ciągów lub funkcji, które można nadpisać, aby wykorzystać podatność bez potrzeby dotarcia do canary. Sprawdź:
Pointer RedirectingModyfikacja zarówno master, jak i thread canary
Przepełnienie bufora w funkcji wątkowej chronionej canary może być użyte do modyfikacji master canary w wątku. W rezultacie, łagodzenie jest bezużyteczne, ponieważ sprawdzenie jest używane z dwoma canary, które są takie same (choć zmodyfikowane).
Ponadto, przepełnienie bufora w funkcji wątkowej chronionej canary mogłoby być użyte do modyfikacji master canary przechowywanego w TLS. Dzieje się tak, ponieważ może być możliwe dotarcie do pozycji pamięci, w której przechowywane jest TLS (a tym samym canary) za pomocą bof na stosie wątku. W rezultacie, łagodzenie jest bezużyteczne, ponieważ sprawdzenie jest używane z dwoma canary, które są takie same (choć zmodyfikowane). Ten atak jest opisany w artykule: http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
Sprawdź również prezentację https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015, która wspomina, że zazwyczaj TLS jest przechowywane przez mmap
, a gdy stos wątku jest tworzony, jest również generowany przez mmap
, co może umożliwić przepełnienie, jak pokazano w poprzednim artykule.
Modyfikacja wpisu GOT __stack_chk_fail
Jeśli binarny kod ma Partial RELRO, można użyć dowolnego zapisu, aby zmodyfikować wpis GOT __stack_chk_fail
na funkcję zastępczą, która nie blokuje programu, jeśli canary zostanie zmodyfikowane.
Ten atak jest opisany w artykule: https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)