Off by one overflow

Reading time: 5 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Підтримайте HackTricks

Basic Information

Маючи доступ лише до 1B переповнення, зловмисник може змінити поле size наступного шматка. Це дозволяє маніпулювати тим, які шматки насправді звільнені, потенційно створюючи шматок, що містить інший легітимний шматок. Експлуатація подібна до double free або перекриваючих шматків.

Існує 2 типи вразливостей off by one:

  • Довільний байт: Цей тип дозволяє перезаписати цей байт будь-яким значенням
  • Нульовий байт (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;
}

Серед інших перевірок, тепер щоразу, коли шматок вільний, попередній розмір порівнюється з розміром, налаштованим у метаданих шматка, що робить цю атаку досить складною з версії 2.28.

Приклад коду:

Мета

  • Зробити шматок, що міститься всередині іншого шматка, так що запис доступу до цього другого шматка дозволяє перезаписати вміщений.

Вимоги

  • 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
  • Off-by-one через strlen, що враховує поле size наступного шматка.
  • Використовується Tcache, тому загальні атаки off-by-one працюють для отримання довільного запису з отруєнням Tcache.
  • Asis CTF 2016 b00ks
  • Можливо зловживати off by one, щоб витягнути адресу з купи, оскільки байт 0x00 в кінці рядка перезаписується наступним полем.
  • Довільний запис отримується шляхом зловживання записом off by one, щоб вказівник вказував на інше місце, де буде побудована фейкова структура з фейковими вказівниками. Потім можна слідувати за вказівником цієї структури, щоб отримати довільний запис.
  • Адреса libc витікає, оскільки якщо купа розширена за допомогою mmap, пам'ять, виділена mmap, має фіксований зсув від libc.
  • Нарешті, довільний запис зловживає для запису в адресу __free_hook з адресою одного гаджета.
  • 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 звільняються, тому:

[ 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 ]

[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]