# Off by one overflow
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
Маючи доступ лише до 1B переповнення, зловмисник може змінити поле `size` наступного шматка. Це дозволяє маніпулювати тим, які шматки насправді звільнені, потенційно створюючи шматок, що містить інший легітимний шматок. Експлуатація подібна до [double free](double-free.md) або перекриваючих шматків.
Існує 2 типи вразливостей off by one:
- Довільний байт: Цей тип дозволяє перезаписати цей байт будь-яким значенням
- Нульовий байт (off-by-null): Цей тип дозволяє перезаписати цей байт лише значенням 0x00
- Загальний приклад цієї вразливості можна побачити в наступному коді, де поведінка `strlen` і `strcpy` є непослідовною, що дозволяє встановити байт 0x00 на початку наступного шматка.
- Це можна експлуатувати за допомогою [House of Einherjar](house-of-einherjar.md).
- Якщо використовувати Tcache, це можна використати для ситуації [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;
}
```
Серед інших перевірок, тепер щоразу, коли шматок вільний, попередній розмір порівнюється з розміром, налаштованим у метаданих шматка, що робить цю атаку досить складною з версії 2.28.
### Приклад коду:
- [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)
- Ця атака більше не працює через використання Tcaches.
- Більше того, якщо ви спробуєте зловживати нею, використовуючи більші шматки (щоб tcaches не були залучені), ви отримаєте помилку: `malloc(): invalid next size (unsorted)`
### Мета
- Зробити шматок, що міститься всередині іншого шматка, так що запис доступу до цього другого шматка дозволяє перезаписати вміщений.
### Вимоги
- Off by one overflow для зміни інформації про розмір метаданих.
### Загальна атака off-by-one
- Виділити три шматки `A`, `B` і `C` (скажімо, розміри 0x20), і ще один, щоб запобігти консолідації з top-chunk.
- Вивільнити `C` (вставлений у 0x20 Tcache free-list).
- Використати шматок `A`, щоб переповнити `B`. Зловживати off-by-one, щоб змінити поле `size` у `B` з 0x21 на 0x41.
- Тепер у нас є `B`, що містить вільний шматок `C`.
- Вивільнити `B` і виділити шматок 0x40 (він знову буде розміщений тут).
- Ми можемо змінити вказівник `fd` з `C`, який все ще вільний (отруєння Tcache).
### Атака off-by-null
- 3 шматки пам'яті (a, b, c) резервуються один за одним. Потім середній шматок звільняється. Перший містить вразливість переповнення off by one, і зловмисник зловживає нею з 0x00 (якщо попередній байт був 0x10, це змусить середній шматок вказувати, що він на 0x10 менший, ніж є насправді).
- Потім у середньому звільненому шматку (b) виділяються ще 2 менші шматки, однак, оскільки `b + b->size` ніколи не оновлює шматок c, тому що вказана адреса менша, ніж повинна бути.
- Потім b1 і c звільняються. Оскільки `c - c->prev_size` все ще вказує на b (тепер b1), обидва консолідуються в один шматок. Однак b2 все ще знаходиться між b1 і c.
- Нарешті, виконується новий malloc, що відновлює цю область пам'яті, яка насправді буде містити b2, дозволяючи власнику нового malloc контролювати вміст b2.
Це зображення ідеально пояснює атаку:
## Інші приклади та посилання
- [**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 через `strlen`, що враховує поле `size` наступного шматка.
- Використовується Tcache, тому загальні атаки off-by-one працюють для отримання довільного запису з отруєнням Tcache.
- [**Asis CTF 2016 b00ks**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#1-asis-ctf-2016-b00ks)
- Можливо зловживати off by one, щоб витягнути адресу з купи, оскільки байт 0x00 в кінці рядка перезаписується наступним полем.
- Довільний запис отримується шляхом зловживання записом off by one, щоб вказівник вказував на інше місце, де буде побудована фейкова структура з фейковими вказівниками. Потім можна слідувати за вказівником цієї структури, щоб отримати довільний запис.
- Адреса libc витікає, оскільки якщо купа розширена за допомогою mmap, пам'ять, виділена mmap, має фіксований зсув від libc.
- Нарешті, довільний запис зловживає для запису в адресу \_\_free_hook з адресою одного гаджета.
- [**plaidctf 2015 plaiddb**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#instance-2-plaidctf-2015-plaiddb)
- Існує вразливість NULL off by one у функції `getline`, яка читає рядки введення користувача. Ця функція використовується для читання "ключа" вмісту, а не самого вмісту.
- У звіті створюється 5 початкових шматків:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- chunk defense (0x400), щоб уникнути консолідації з top chunk.
- Потім шматки 1, 5 і 3 звільняються, тому:
- ```python
[ 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`.
- Зверніть увагу, що розміри спочатку виділених шматків 1, 2, 5 і 3 плюс заголовки 4 з цих шматків дорівнюють `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Потім шматок 4 звільняється, генеруючи шматок, що споживає всі шматки до початку:
- ```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 ]
```
- Потім виділяються `0x200` байтів, заповнюючи оригінальний шматок 1.
- І ще один шматок 0x200 виділяється, і chunk2 знищується, і тому немає ніякого витоку, і це не працює? Можливо, це не слід робити.
- Потім виділяється ще один шматок з 0x58 "a"s (перезаписуючи chunk2 і досягаючи chunk5) і змінюється `fd` швидкого бінарного шматка chunk5, вказуючи на `__malloc_hook`.
- Потім виділяється шматок 0x68, так що фейковий швидкий бінарний шматок у `__malloc_hook` є наступним швидким бінарним шматком.
- Нарешті, виділяється новий швидкий бінарний шматок 0x68, і `__malloc_hook` перезаписується адресою `one_gadget`.
{{#include ../../banners/hacktricks-training.md}}