# Off by one overflow {{#include ../../banners/hacktricks-training.md}} ## Podstawowe informacje Mając dostęp tylko 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](double-free.md) lub nakładających się kawałków. Istnieją 2 typy podatności off by one: - Dowolny bajt: Ten typ pozwala na nadpisanie tego bajtu dowolną wartością - Bajt null (off-by-null): Ten typ 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](house-of-einherjar.md). - Jeśli używasz Tcache, można to wykorzystać do sytuacji [double free](double-free.md).
Off-by-null ```c // From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/ int main(void) { char buffer[40]=""; void *chunk1; chunk1 = malloc(24); puts("Get Input"); gets(buffer); if(strlen(buffer)==24) { strcpy(chunk1,buffer); } return 0; } ```
Wśród innych kontroli, teraz za każdym razem, gdy kawałek 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. ### Przykład kodu: - [https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c](https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c) - 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)` ### Cel - 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. ### Wymagania - Off by one overflow, aby zmodyfikować informacje o rozmiarze metadanych. ### Ogólny atak off-by-one - Przydziel trzy kawałki `A`, `B` i `C` (powiedzmy rozmiar 0x20), oraz kolejny, aby zapobiec konsolidacji z top-chunk. - Zwalnij `C` (wstawiony do listy zwolnionych kawałków 0x20 Tcache). - Użyj kawałka `A`, aby przepełnić `B`. Nadużyj off-by-one, aby zmodyfikować pole `size` `B` z 0x21 na 0x41. - Teraz mamy `B` zawierający zwolniony kawałek `C`. - Zwalnij `B` i przydziel kawałek 0x40 (zostanie umieszczony tutaj ponownie). - Możemy zmodyfikować wskaźnik `fd` z `C`, który wciąż jest zwolniony (zatrucie Tcache). ### Atak off-by-null - 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, spowodowałoby to, ż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` wciąż wskazuje na b (b1 teraz), 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:

https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks

## Inne przykłady i odniesienia - [**https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks**](https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks) - [**Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/bon-nie-appetit/) - Off-by-one z powodu `strlen` uwzględniającego pole `size` następnego kawałka. - Używane jest Tcache, więc ogólne ataki off-by-one działają, aby uzyskać dowolną prymitywę zapisu z zatruciem Tcache. - [**Asis CTF 2016 b00ks**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#1-asis-ctf-2016-b00ks) - Możliwe jest nadużycie off by one, aby wyciekł 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ł w 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. - [**plaidctf 2015 plaiddb**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#instance-2-plaidctf-2015-plaiddb) - Istnieje luka NULL off by one w funkcji `getline`, która odczytuje linie wejściowe 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 obronny (0x400), aby uniknąć konsolidacji z top chunk. - Następnie kawałki 1, 5 i 3 są zwalniane, więc: - ```python [ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ] ``` - Następnie nadużywając chunk3 (0x1f8), luka null off-by-one jest nadużywana, zapisując `prev_size` na `0x4e0`. - Zauważ, jak rozmiary początkowo przydzielonych kawałków 1, 2, 5 i 3 oraz nagłówki 4 z tych kawałków sumują się do `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0` - Następnie kawałek 4 jest zwalniany, generując kawałek, który pochłania wszystkie kawałki aż do początku: - ```python [ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ] ``` - ```python [ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ] ``` - Następnie przydzielane są `0x200` bajtów, wypełniając oryginalny kawałek 1. - A następnie przydzielane są kolejne 0x200 bajtów, a kawałek 2 jest niszczony, więc nie ma żadnego wycieku i to nie działa? Może tego nie powinno się robić. - Następnie przydzielany jest kolejny kawałek z 0x58 "a"s (nadpisując kawałek 2 i sięgając kawałka 5) i modyfikuje `fd` szybkiego kawałka kawałka 5, wskazując go na `__malloc_hook`. - Następnie przydzielany jest kawałek 0x68, więc fałszywy szybki kawałek w `__malloc_hook` jest następnym szybkim kawałkiem. - Na koniec przydzielany jest nowy szybki kawałek 0x68, a `__malloc_hook` jest nadpisywany adresem `one_gadget`. {{#include ../../banners/hacktricks-training.md}}