# 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:
## 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}}