Off by one overflow
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Posiadając dostęp do przepełnienia 1B, atakujący może zmodyfikować pole size
następnego kawałka. Umożliwia to manipulację tym, które kawałki są faktycznie zwalniane, potencjalnie generując kawałek, który zawiera inny legalny kawałek. Eksploatacja jest podobna do double free lub nakładających się kawałków.
Istnieją 2 typy podatności off by one:
Dowolny bajt: Ten rodzaj pozwala na nadpisanie tego bajtu dowolną wartością
Bajt null (off-by-null): Ten rodzaj pozwala na nadpisanie tego bajtu tylko wartością 0x00
Typowym przykładem tej podatności można zobaczyć w poniższym kodzie, gdzie zachowanie strlen
i strcpy
jest niespójne, co pozwala ustawić bajt 0x00 na początku następnego kawałka.
Może to być wykorzystane z House of Einherjar.
Jeśli używasz Tcache, można to wykorzystać w sytuacji double free.
Wśród innych kontroli, teraz za każdym razem, gdy kawałek pamięci jest zwalniany, poprzedni rozmiar jest porównywany z rozmiarem skonfigurowanym w metadanych kawałka, co sprawia, że atak ten jest dość skomplikowany od wersji 2.28.
Ten atak nie działa już z powodu użycia Tcaches.
Co więcej, jeśli spróbujesz go nadużyć, używając większych kawałków (więc tcaches nie są zaangażowane), otrzymasz błąd: malloc(): invalid next size (unsorted)
Sprawić, aby kawałek był zawarty w innym kawałku, tak aby dostęp do zapisu w tym drugim kawałku pozwalał na nadpisanie zawartego.
Off by one overflow, aby zmodyfikować informacje o rozmiarze w metadanych.
Przydziel trzy kawałki A
, B
i C
(powiedzmy rozmiar 0x20), oraz kolejny, aby zapobiec konsolidacji z top-chunk.
Zwalniamy C
(wstawiony do listy wolnych kawałków Tcache 0x20).
Użyj kawałka A
, aby przepełnić B
. Nadużyj off-by-one, aby zmodyfikować pole size
w B
z 0x21 na 0x41.
Teraz mamy B
zawierający wolny kawałek C
.
Zwalniamy B
i przydzielamy kawałek 0x40 (zostanie umieszczony tutaj ponownie).
Możemy zmodyfikować wskaźnik fd
z C
, który jest nadal wolny (trucizna Tcache).
3 kawałki pamięci (a, b, c) są rezerwowane jeden po drugim. Następnie środkowy kawałek jest zwalniany. Pierwszy kawałek zawiera lukę off by one, a atakujący nadużywa jej z 0x00 (jeśli poprzedni bajt był 0x10, to sprawiłoby, że środkowy kawałek wskazywałby, że jest o 0x10 mniejszy niż w rzeczywistości).
Następnie w zwolnionym kawałku (b) przydzielane są 2 mniejsze kawałki, jednak b + b->size
nigdy nie aktualizuje kawałka c, ponieważ wskazywany adres jest mniejszy niż powinien.
Następnie, b1 i c są zwalniane. Ponieważ c - c->prev_size
nadal wskazuje na b (teraz b1), oba są konsolidowane w jeden kawałek. Jednak b2 wciąż znajduje się pomiędzy b1 a c.
Na koniec wykonywana jest nowa alokacja malloc, odzyskując ten obszar pamięci, który w rzeczywistości będzie zawierał b2, co pozwala właścicielowi nowego malloca kontrolować zawartość b2.
Ten obrazek doskonale wyjaśnia atak:
Off-by-one z powodu strlen
, które uwzględnia pole size
następnego kawałka.
Używane jest Tcache, więc ogólne ataki off-by-one działają, aby uzyskać dowolny zapis z trucizną Tcache.
Możliwe jest nadużycie off by one, aby wycieknąć adres z sterty, ponieważ bajt 0x00 na końcu ciągu jest nadpisywany przez następne pole.
Dowolny zapis uzyskuje się przez nadużycie zapisu off by one, aby wskaźnik wskazywał na inne miejsce, gdzie zostanie zbudowana fałszywa struktura z fałszywymi wskaźnikami. Następnie możliwe jest podążanie za wskaźnikiem tej struktury, aby uzyskać dowolny zapis.
Adres libc jest wyciekany, ponieważ jeśli sterta jest rozszerzana za pomocą mmap, pamięć przydzielona przez mmap ma stały offset od libc.
Na koniec dowolny zapis jest nadużywany, aby zapisać w adresie __free_hook z adresem one gadget.
Istnieje luka NULL off by one w funkcji getline
, która odczytuje linie wejściowe od użytkownika. Ta funkcja jest używana do odczytu "klucza" treści, a nie samej treści.
W opisie pięć początkowych kawałków jest tworzonych:
chunk1 (0x200)
chunk2 (0x50)
chunk5 (0x68)
chunk3 (0x1f8)
chunk4 (0xf0)
chunk defense (0x400), aby uniknąć konsolidacji z top chunk.
Następnie kawałki 1, 5 i 3 są zwalniane, więc:
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]