Pamięć stosu jądra można chronić przed uszkodzeniem pamięci i atakami przepełnienia w taki sam sposób, jak jej odpowiednik w przestrzeni użytkownika, za pomocą Kernel Stack Canaries. Ta funkcja łagodzenia zagrożeń w czasie kompilacji działa jak Stack Canaries w przestrzeni użytkownika, o którym dowiedzieliśmy się i który wykorzystaliśmy w poprzednim rozdziale. Ponownie skompilowaliśmy niestandardowe jądro z włączoną funkcją CONFIG_STACKPROTECTOR, aby używać Stack Canaries w tym i kolejnych laboratoriach. Aby zobaczyć to w akcji, wykonaj run2.sh i spróbuj nadpisać rejestr RIP podczas dołączania GDB do systemu docelowego. Najpierw otwórz okno terminala w folderze ~/GHHv6/ch12 i wykonaj run2.sh, ale nie uruchamiaj jeszcze exploita:
$ ./run2.sh
W nowym oknie terminala dołącz GDB, a następnie ustaw dwa punkty przerwania, aby zobaczyć, kiedy canary zostanie przypisany i kiedy zostanie sprawdzony przed powrotem z podatnej funkcji. Następnie wygenerujemy wzorzec, który pomoże nam zidentyfikować, gdzie w naszym ładunku powinniśmy umieścić canary, aby został naprawiony po nadpisaniu stosu. Na koniec kontynuujemy wykonywanie. Oto kod:
Teraz skopiuj ten cykliczny wzór z terminala QEMU i zapisz go w interfejsie modułu:
W momencie trafienia pierwszego punktu przerwania, kanarek będzie już skopiowany do rbp-0x10. Sprawdźmy jego wartość i przejdźmy do drugiego punktu przerwania:
W tym momencie zapisany kanarek (rbp-0x10) został skopiowany do rejestru rdx i zostanie odjęty od oryginalnego kanarka. Jeśli wynik nie jest zerem, zostanie wykonane __stack_chk_fail zamiast powrotu. Zobaczmy zawartość rdx i użyjmy narzędzia przesunięcia wzorca, aby zidentyfikować, gdzie kanarek musi zostać umieszczony:
Jeśli będziemy kontynuować wykonywanie, w oknie QEMU pojawi się panika jądra:
Naszym ostatnim krokiem jest wykorzystanie luki w zabezpieczeniach arbitralnego odczytu w celu wycieku adresów pamięci i zidentyfikowanie, czy nasz kanarek jest wyciekany i w którym miejscu. W folderze ~/GHHv6/ch12/shared znajduje się mały program C, który otworzy interfejs /proc/ghh, odczyta 40 bajtów do tablicy unsigned long i zapisze nasz ładunek, aby nadpisać RIP. Najpierw skompilujmy ten program i uruchommy run2.sh:
Podłącz GDB w nowym terminalu, ustaw punkt przerwania po skopiowaniu kanarka do rejestru rax (ghh_write+25) i kontynuuj wykonywanie:
Podłącz GDB w nowym terminalu, ustaw punkt przerwania po skopiowaniu kanarka do rejestru rax (ghh_write+25) i kontynuuj wykonywanie:
Podłącz GDB w nowym terminalu, ustaw punkt przerwania po skopiowaniu kanarka do rejestru rax (ghh_write+25) i kontynuuj wykonywanie:
Podłącz GDB w nowym terminalu, ustaw punkt przerwania po skopiowaniu kanarka do rejestru rax (ghh_write+25) i kontynuuj wykonywanie:
Teraz, gdy udało nam się ominąć ochronę Stack Canary, włączmy ochronę SMEP i KPTI i zobaczmy, jak możemy ją obejść.