Off by one overflow
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Основна інформація
Маючи доступ лише до 1B overflow, атакувальник може змінити поле size наступного чанка. Це дозволяє підміняти, які чанки фактично звільняються, потенційно створюючи чанк, який містить інший легітимний чанк. Експлуатація схожа на double free або overlapping chunks.
Існує 2 типи вразливостей off by one:
- Arbitrary byte: Цей тип дозволяє перезаписати цей байт будь-яким значенням
- Null byte (off-by-null): Цей тип дозволяє перезаписати цей байт лише значенням 0x00
- Поширений приклад цієї вразливості можна побачити в наведеному нижче коді, де поведінка
strlenіstrcpyє неконсистентною, що дозволяє встановити байт 0x00 на початку наступного чанка. - Це можна експлуатувати за допомогою House of Einherjar.
- Якщо використовується Tcache, це може призвести до ситуації 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; } ```Серед інших перевірок, тепер коли chunk вільний, попередній size порівнюється з size, сконфігурованим у metadata’s chunk, що робить цю атаку доволі складною з версії 2.28.
Code example:
- https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c
- Ця атака більше не працює через використання Tcaches.
- Крім того, якщо спробувати зловживати цим з більшими chunks (щоб tcaches не брали участь), ви отримаєте помилку:
malloc(): invalid next size (unsorted)
Goal
- Зробити так, щоб один chunk опинявся всередині іншого, щоб запис у другий chunk дозволяв перезаписати вкладений.
Requirements
- Off by one overflow для модифікації інформації size у метаданих
General off-by-one attack
- Allocate three chunks
A,BandC(say sizes 0x20), and another one to prevent consolidation with the top-chunk. - Free
C(inserted into 0x20 Tcache free-list). - Use chunk
Ato overflow onB. Abuse off-by-one to modify thesizefield ofBfrom 0x21 to 0x41. - Now we have
Bcontaining the free chunkC - Free
Band allocate a 0x40 chunk (it will be placed here again) - We can modify the
fdpointer fromC, which is still free (Tcache poisoning)
Off-by-null attack
- 3 chunks of memory (a, b, c) are reserved one after the other. Then the middle one is freed. The first one contains an off by one overflow vulnerability and the attacker abuses it with a 0x00 (if the previous byte was 0x10 it would make he middle chunk indicate that it’s 0x10 smaller than it really is).
- Then, 2 more smaller chunks are allocated in the middle freed chunk (b), however, as
b + b->sizenever updates the c chunk because the pointed address is smaller than it should. - Then, b1 and c gets freed. As
c - c->prev_sizestill points to b (b1 now), both are consolidated in one chunk. However, b2 is still inside in between b1 and c. - Finally, a new malloc is performed reclaiming this memory area which is actually going to contain b2, allowing the owner of the new malloc to control the content of b2.
This image explains perfectly the attack:
.png)
https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
Modern glibc hardening & bypass notes (>=2.32)
- Safe-Linking now protects every singly linked bin pointer by storing
fd = ptr ^ (chunk_addr >> 12), so an off-by-one that only flips the low byte ofsizeusually also needs a heap leak to recompute the XOR mask before Tcache poisoning works. - 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.
A minimal helper to rehearse the encode/decode step while debugging modern exploits:
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
Недавня реальна ціль: glibc __vsyslog_internal off-by-one (CVE-2023-6779)
- У січні 2024 Qualys детально описав CVE-2023-6779 — off-by-one всередині
__vsyslog_internal(), який тригериться, коли форматні рядкиsyslog()/vsyslog()перевищуютьINT_MAX, через що термінуючий\0пошкоджує найменш значущий байт поляsizeнаступного chunk’а на системах glibc 2.37–2.39 (Qualys advisory). - Їхній Fedora 38 exploit pipeline:
- Згенерувати наддовгий ident для
openlog(), щобvasprintfповернув heap buffer поруч із даними, контрольованими атакуючим. - Викликати
syslog()щоб пошкодити байтsize | prev_inuseсусіднього чанка, звільнити його і примусити консолідацію, яка перехоплює attacker data. - Використати перекритий вигляд, щоб пошкодити метадані
tcache_perthread_structі направити наступне виділення в__free_hook, перезаписавши йогоsystem/one_gadget для отримання root.
- Щоб відтворити пошкоджувальний запис у harness, форкнутися з гігантським
argv[0], викликатиopenlog(NULL, LOG_PID, LOG_USER)і потімsyslog(LOG_INFO, "%s", payload), деpayload = b"A" * 0x7fffffff;pwndbg’sheap binsмиттєво показує одно-байтове перезаписування. - Ubuntu відслідковує баг як CVE-2023-6779, документуючи те саме INT truncation, що робить це надійним примітивом off-by-one.
Інші приклади та посилання
- https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
- Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022
- Off-by-one через те, що
strlenвраховує полеsizeнаступного chunk’а. - Використовується Tcache, тож загальна атака типу off-by-one працює для отримання примітива arbitrary write через Tcache poisoning.
- Asis CTF 2016 b00ks
- Можна зловживати off by one, щоб leak адресу з heap, оскільки байт 0x00 в кінці рядка перезаписується наступним полем.
- Arbitrary write отримується шляхом зловживання off by one записом, щоб змусити покажчик вказувати в інше місце, де буде побудовано фейкову структуру з фейковими покажчиками. Потім можна пройти за покажчиком цієї структури, щоб отримати arbitrary write.
- Адреса libc leak’иться, бо якщо heap розширюється через mmap, пам’ять, виділена mmap, має фіксований зсув відносно libc.
- Нарешті arbitrary write зловживають, щоб записати в адресу
__free_hookone_gadget’ом. - plaidctf 2015 plaiddb
- Існує NULL off by one у функції
getline, яка читає рядки вводу користувача. Ця функція використовується для читання “key” контенту, а не самого контенту. - У writeup створюються 5 початкових чанків:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- chunk defense (0x400) щоб уникнути консолідації з top chunk
- Потім chunk1, chunk5 і chunk3 звільняються, тож:
-
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
- Потім, зловживаючи chunk3 (0x1f8), NULL off-by-one використано для запису prev_size в `0x4e0`.
- Зверніть увагу, що сума розмірів початково алокованих chunk1, 2, 5 і 3 плюс заголовки 4 з цих чанків дорівнює `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Потім chunk4 звільняється, породжуючи chunk, який поглинає всі попередні до початку:
- ```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 ]
- Далі алокується 0x200 байт, заповнюючи початковий chunk1
- І ще одні 0x200 байт алокуються і chunk2 знищується, і тому немає ніякого fucking leak і це не працює? Можливо цього не слід робити
- Потім алокують ще один chunk з 0x58 "a" (перезаписуючи chunk2 і доходячи до chunk5) і змінюють `fd` fast bin чанка chunk5, вказуючи його в `__malloc_hook`
- Далі алокується chunk розміром 0x68, тож фейковий fast bin chunk у `__malloc_hook` стає наступним fast bin чанком
- Нарешті алокується новий fast bin chunk 0x68 і `__malloc_hook` перезаписується адресою `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]
> Вивчайте та практикуйте AWS Hacking:<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;">\
> Вивчайте та практикуйте GCP Hacking: <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;">
> Вивчайте та практикуйте Azure Hacking: <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>Підтримайте HackTricks</summary>
>
> - Перевірте [**плани підписки**](https://github.com/sponsors/carlospolop)!
> - **Приєднуйтесь до** 💬 [**групи Discord**](https://discord.gg/hRep4RUj7f) або [**групи telegram**](https://t.me/peass) або **слідкуйте** за нами в **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Діліться хакерськими трюками, надсилаючи PR до** [**HackTricks**](https://github.com/carlospolop/hacktricks) та [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) репозиторіїв на github.
>
> </details>
HackTricks

