Stack Canaries
Last updated
Last updated
Dowiedz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Dowiedz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
StackGuard wstawia specjalną wartość znaną jako kanarka przed EIP (Extended Instruction Pointer), konkretnie 0x000aff0d
(reprezentującą null, newline, EOF, powrót karetki) w celu ochrony przed przepełnieniem bufora. Jednak funkcje takie jak recv()
, memcpy()
, read()
i bcopy()
pozostają podatne, a także nie chroni EBP (Base Pointer).
StackShield stosuje bardziej zaawansowane podejście niż StackGuard, utrzymując Globalny Stos Powrotu, który przechowuje wszystkie adresy powrotu (EIP). Ten układ zapewnia, że przepełnienie nie spowoduje szkód, ponieważ umożliwia porównanie przechowywanych i rzeczywistych adresów powrotu w celu wykrycia wystąpienia przepełnienia. Dodatkowo, StackShield może sprawdzić adres powrotu względem wartości granicznej, aby wykryć, czy EIP wskazuje poza oczekiwaną przestrzeń danych. Jednak ta ochrona może zostać obejścia za pomocą technik takich jak Return-to-libc, ROP (Return-Oriented Programming) lub ret2ret, co oznacza, że StackShield również nie chroni zmiennych lokalnych.
-fstack-protector
:Ten mechanizm umieszcza kanarkę przed EBP i przestawia zmienne lokalne tak, aby bufory znajdowały się na wyższych adresach pamięci, uniemożliwiając nadpisywanie innych zmiennych. Dodatkowo bezpiecznie kopiuje argumenty przekazywane na stosie powyżej zmiennych lokalnych i używa tych kopii jako argumentów. Jednak nie chroni tablic o mniej niż 8 elementach ani buforów w strukturze użytkownika.
Kanarka to losowa liczba pochodząca z /dev/urandom
lub domyślna wartość 0xff0a0000
. Jest przechowywana w TLS (Thread Local Storage), co pozwala na współużytkowanie przestrzeni pamięci między wątkami dla zmiennych globalnych lub statycznych specyficznych dla wątku. Te zmienne są początkowo kopiowane z procesu nadrzędnego, a procesy potomne mogą zmieniać swoje dane bez wpływu na proces nadrzędny lub rodzeństwo. Niemniej jednak, jeśli używane jest fork()
bez tworzenia nowej kanarki, wszystkie procesy (rodzic i dzieci) dzielą tę samą kanarkę, co czyni ją podatną. Na architekturze i386, kanarka jest przechowywana pod adresem gs:0x14
, a na x86_64 pod adresem fs:0x28
.
Ta lokalna ochrona identyfikuje funkcje z buforami podatnymi na ataki i wstrzykuje kod na początku tych funkcji, aby umieścić kanarkę, a na końcu weryfikuje jej integralność.
Gdy serwer WWW używa fork()
, umożliwia atak brutalnej siły, aby zgadywać bajt kanarki po bajcie. Jednak użycie execve()
po fork()
nadpisuje przestrzeń pamięci, unieważniając atak. vfork()
pozwala procesowi potomnemu wykonywać się bez duplikacji, aż spróbuje zapisać, wtedy tworzony jest duplikat, oferując inny sposób tworzenia procesów i zarządzania pamięcią.
W binariach x64
, ciasteczko kanarki to 0x8
bajtów qword. Pierwsze siedem bajtów jest losowe, a ostatni bajt to bajt null.
W binariach x86
, ciasteczko kanarki to 0x4
bajty dword. Pierwsze trzy bajty są losowe, a ostatni bajt to bajt null.
Najmniej znaczący bajt obu kanarek to bajt null, ponieważ będzie pierwszy na stosie pochodzącym z niższych adresów i dlatego funkcje czytające ciągi znaków zatrzymają się przed jego odczytaniem.
Ujawnienie kanarki a następnie nadpisanie jej (np. przepełnienie bufora) własną wartością.
Jeśli kanarka jest klonowana w procesach potomnych, może być możliwe brutalne siłowe jej odgadnięcie po jednym bajcie:
Jeśli w binarnym pliku istnieje ujawnienie lub arbitralna podatność na odczyt to możliwe jest jej ujawnienie:
Nadpisanie wskaźników przechowywanych na stosie
Stos podatny na przepełnienie bufora może zawierać adresy do ciągów znaków lub funkcji, które można nadpisać w celu wykorzystania podatności bez konieczności dotarcia do kanarki stosu. Sprawdź:
Pointer RedirectingModyfikacja zarówno kanarki głównej, jak i wątkowej
Przepełnienie bufora w funkcji wątkowej chronionej kanarką może być użyte do zmodyfikowania kanarki głównej wątku. W rezultacie zastosowanie zabezpieczenia jest bezużyteczne, ponieważ sprawdzanie jest wykonywane z użyciem dwóch kanarek, które są identyczne (choć zmodyfikowane).
Co więcej, przepełnienie bufora w funkcji wątkowej chronionej kanarką może być użyte do zmodyfikowania kanarki głównej przechowywanej w TLS. Jest to możliwe, ponieważ można dotrzeć do pozycji pamięci, w której przechowywane jest TLS (a zatem kanarka) za pomocą bof na stosie wątku. W rezultacie zastosowanie zabezpieczenia jest bezużyteczne, ponieważ sprawdzanie jest wykonywane z użyciem dwóch kanarek, które są identyczne (choć zmodyfikowane). Ten atak jest przeprowadzany w opisie: 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
i gdy tworzony jest stos wątku, jest on również generowany przez mmap
, co może umożliwić przepełnienie, jak pokazano w poprzednim opisie.
Modyfikacja wpisu GOT __stack_chk_fail
Jeśli binarny plik ma Partial RELRO, można użyć zapisu arbitralnego do zmodyfikowania wpisu GOT __stack_chk_fail
na funkcję-dummy, która nie blokuje programu, jeśli kanarka zostanie zmodyfikowana.
Ten atak jest przeprowadzany w opisie: https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
Ucz się i praktykuj Hacking AWS:HackTricks Szkolenie AWS Red Team Expert (ARTE) Ucz się i praktykuj Hacking GCP: HackTricks Szkolenie GCP Red Team Expert (GRTE)