Off by one overflow
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Podstawowe informacje
Posiadając jedynie 1B overflow, atakujący może zmodyfikować pole size następnego chunka. Pozwala to manipulować tym, które chunk są faktycznie zwalniane, potencjalnie generując chunk, który zawiera inny prawidłowy chunk. Eksploatacja jest podobna do double free lub overlapping chunks.
Istnieją 2 rodzaje podatności off by one:
- Arbitrary byte: Ten rodzaj pozwala nadpisać ten bajt dowolną wartością
- Null byte (off-by-null): Ten rodzaj pozwala nadpisać ten bajt jedynie wartością 0x00
- Typowy przykład tej podatności można zobaczyć w poniższym kodzie, gdzie zachowanie
strlenistrcpyjest niespójne, co pozwala ustawić bajt 0x00 na początku następnego chunka. - This can be expoited with the House of Einherjar.
- Jeśli używany jest Tcache, można to wykorzystać do sytuacji double free.
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; } ```Między innymi, teraz za każdym razem gdy chunk jest zwolniony, poprzedni rozmiar jest porównywany z rozmiarem zapisanym w metadanych chunka, co sprawia, że ten atak jest dość skomplikowany od wersji 2.28.
Przykład kodu:
- https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c
- This attack is no longer working due to the use of Tcaches.
- Moreover, if you try to abuse it using larger chunks (so tcaches aren’t involved), you will get the error:
malloc(): invalid next size (unsorted)
Cel
- Spraw, aby jeden chunk był zawarty w innym chunku, tak aby zapis do tego drugiego chunka pozwalał nadpisać zawarty chunk
Wymagania
- Off by one overflow umożliwiający modyfikację informacji o rozmiarze w metadanych
Ogólny off-by-one attack
- Zarezerwuj trzy chunki
A,BiC(np. rozmiary 0x20), oraz jeszcze jeden, aby zapobiec konsolidacji z top-chunk. - Zwolnij
C(wstawiony do 0x20 Tcache free-list). - Użyj chunka
A, aby przepełnićB. Wykorzystaj off-by-one, aby zmodyfikować polesizechunkaBz 0x21 na 0x41. - Teraz mamy
Bzawierający wolny chunkC - Zwolnij
Bi zaalokuj chunk 0x40 (zostanie umieszczony tutaj ponownie) - Możemy zmodyfikować wskaźnik
fdzC, który jest wciąż wolny (Tcache poisoning)
Off-by-null attack
- Trzy chunki pamięci (a, b, c) są zarezerwowane kolejno jeden po drugim. Następnie środkowy jest zwolniony. Pierwszy zawiera podatność off by one overflow, a atakujący wykorzystuje ją przez zapis 0x00 (jeśli poprzedni bajt miał wartość 0x10, spowodowałoby to, że środkowy chunk będzie wskazywał, że jest o 0x10 mniejszy niż w rzeczywistości).
- Następnie w zwolnionym środkowym chunku (b) alokowane są jeszcze 2 mniejsze chunki, jednakże
b + b->sizenigdy nie aktualizuje chunka c, ponieważ wskazywany adres jest mniejszy niż powinien być. - Następnie b1 i c są zwalniane. Ponieważ
c - c->prev_sizewciąż wskazuje na b (teraz b1), oba są skonsolidowane w jeden chunk. Jednak b2 wciąż pozostaje pomiędzy b1 a c. - Na końcu wykonywany jest nowy malloc, odzyskujący ten obszar pamięci, który w rzeczywistości zawiera b2, co pozwala właścicielowi nowego malloca kontrolować zawartość b2.
This image explains perfectly the attack:
.png)
https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
Wzmocnienia glibc i uwagi dotyczące obejść (>=2.32)
- Safe-Linking teraz chroni każdy singly linked bin pointer przez przechowywanie
fd = ptr ^ (chunk_addr >> 12), więc off-by-one, który zmienia tylko najmłodszy bajtsize, zazwyczaj potrzebuje również heap leak, aby ponownie obliczyć maskę XOR zanim Tcache poisoning zadziała. - A practical leakless trick is to “double-protect” a pointer: encode a pointer you already control with
PROTECT_PTR, then reuse the same gadget to encode your forged pointer so the alignment check passes without revealing new addresses. - Workflow for safe-linking + single-byte corruptions:
- Grow the victim chunk until it fully covers a freed chunk you already control (overlapping-chunk setup).
- Leak any heap pointer (stdout, UAF, partially controlled struct) and derive the key
heap_base >> 12. - Re-encode free-list pointers before writing them—stage the encoded value inside user data and memcpy it later if you only own single-byte writes.
- Combine with Tcache bin attacks to redirect allocations into
__free_hookortcache_perthread_structentries once the forged pointer is properly encoded.
Minimalny helper do przećwiczenia kroku kodowania/odkodowywania podczas debugowania nowoczesnych exploitów:
def protect(ptr, chunk_addr):
return ptr ^ (chunk_addr >> 12)
def reveal(encoded, chunk_addr):
return encoded ^ (chunk_addr >> 12)
chunk = 0x55555555c2c0
encoded_fd = protect(0xdeadbeefcaf0, chunk)
print(hex(reveal(encoded_fd, chunk))) # 0xdeadbeefcaf0
Niedawny cel w rzeczywistym świecie: glibc __vsyslog_internal off-by-one (CVE-2023-6779)
- W styczniu 2024 Qualys opisał CVE-2023-6779, off-by-one wewnątrz
__vsyslog_internal(), który wyzwala się, gdy format stringisyslog()/vsyslog()przekraczająINT_MAX, więc znak kończący\0korumpuje najmniej znaczący bajt polasizenastępnego chunku na systemach z glibc 2.37–2.39 (Qualys advisory). - Ich exploit pipeline na Fedora 38:
- Sporządzić zbyt długi ident dla
openlog()tak, abyvasprintfzwrócił heap buffer obok danych kontrolowanych przez atakującego. - Wywołać
syslog(), aby nadpisać sąsiedni bajtsize | prev_inuse, zwolnić go i wymusić konsolidację, która nachodzi na dane atakującego. - Użyć nachodzącego widoku do skorumpowania metadanych
tcache_perthread_structi skierować następne przydzielenie pod__free_hook, nadpisując jesystem/a one_gadget dla roota.
- Aby odtworzyć zapis powodujący korupcję w harnessie, fork z gigantycznym
argv[0], wywołaćopenlog(NULL, LOG_PID, LOG_USER)a potemsyslog(LOG_INFO, "%s", payload)gdziepayload = b"A" * 0x7fffffff;pwndbg’sheap binsnatychmiast pokaże jednobajtowe nadpisanie. - Ubuntu śledzi ten błąd jako CVE-2023-6779, dokumentując to samo obcięcie do INT, które czyni to wiarygodnym off-by-one prymitywem.
Other Examples & References
- https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
- Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022
- Off-by-one spowodowany przez
strlenuwzględniający polesizenastępnego chunku. - Tcache jest używany, więc ogólne ataki off-by-one działają, żeby uzyskać arbitralny write prymityw przez Tcache poisoning.
- Asis CTF 2016 b00ks
- Można wykorzystać off-by-one do leak adresu z heap ponieważ bajt
0x00na końcu stringa jest nadpisywany przez następne pole. - Arbitrary write uzyskuje się przez wykorzystanie off-by-one do ustawienia wskaźnika na inne miejsce, gdzie zbudowany zostanie fałszywy struct z fałszywymi wskaźnikami. Następnie można podążać za wskaźnikiem tego structu, aby uzyskać arbitrary write.
- Adres libc jest leakowany, ponieważ jeśli heap jest rozszerzony przy użyciu mmap, pamięć alokowana przez mmap ma ustalony offset względem libc.
- W końcu arbitrary write jest wykorzystany do zapisania do adresu
__free_hookz one_gadget. - plaidctf 2015 plaiddb
- Istnieje NULL off-by-one w funkcji
getline, która czyta linie wejścia od użytkownika. Funkcja ta jest używana do czytania “key” zawartości, a nie samej zawartości. - W writeupie tworzy się 5 początkowych chunków:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- chunk defense (0x400) aby uniknąć konsolidacji z top chunk
- Następnie chunk 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 ]
- Potem, wykorzystując chunk3 (0x1f8) null off-by-one jest nadużyty do zapisania prev_size na `0x4e0`.
- Zauważ jak rozmiary początkowo alokowanych chunków1, 2, 5 i 3 plus nagłówki 4 z tych chunków sumują się do `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Następnie chunk 4 jest zwalniany, generując chunk który pochłania wszystkie chunky aż do początku:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
- Potem alokowane jest `0x200` bajtów wypełniając oryginalny chunk 1
- I kolejne `0x200` bajtów jest alokowane i chunk2 zostaje zniszczony i dlatego nie ma żadnego fucking leak i to nie działa? Może tego nie powinno się robić
- Potem alokuje się kolejny chunk z 0x58 "a"s (nadpisując chunk2 i sięgając chunk5) i modyfikuje `fd` fast bin chunku chunk5 wskazując go na `__malloc_hook`
- Następnie alokowany jest chunk o rozmiarze 0x68, więc fałszywy fast bin chunk w `__malloc_hook` staje się następnym fast bin chunkiem
- W końcu, nowy fast bin chunk 0x68 jest alokowany i `__malloc_hook` zostaje nadpisany adresem `one_gadget`
## References
- [Qualys Security Advisory – CVE-2023-6246/6779/6780](https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt)
- [Ubuntu Security – CVE-2023-6779](https://ubuntu.com/security/CVE-2023-6779)
- [Breaking Safe-Linking in Modern Glibc – Google CTF 2022 "saas" analysis](https://blog.csdn.net/2402_86373248/article/details/148717274)
> [!TIP]
> Ucz się i ćwicz Hacking AWS:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Ucz się i ćwicz Hacking GCP: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Ucz się i ćwicz Hacking Azure: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>Wsparcie dla HackTricks</summary>
>
> - Sprawdź [**plany subskrypcyjne**](https://github.com/sponsors/carlospolop)!
> - **Dołącz do** 💬 [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Dziel się trikami hackingowymi, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repozytoriów na githubie.
>
> </details>
HackTricks

