Stack Canaries

Wesprzyj HackTricks

StackGuard i StackShield

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.

Protector Stack Smash (ProPolice) -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ą.

Długoś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.

Ominięcia

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:

BF Forked & Threaded Stack Canaries
  • Jeśli w binarnym pliku istnieje ujawnienie lub arbitralna podatność na odczyt to możliwe jest jej ujawnienie:

Print Stack Canary
  • 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 Redirecting
  • Modyfikacja 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/

Odnośniki

Wesprzyj HackTricks

Last updated