Heap 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.
Basic Information
Переповнення купи - це як переповнення стеку, але в купі. В основному це означає, що деякий простір було зарезервовано в купі для зберігання деяких даних, і збережені дані були більшими за зарезервований простір.
У випадку переповнень стеку ми знаємо, що деякі регістри, такі як вказівник інструкцій або стековий фрейм, будуть відновлені зі стеку, і це може бути можливим для зловживання. У випадку переповнень купи немає жодної чутливої інформації, що зберігається за замовчуванням в частині купи, яка може бути переповнена. Однак це можуть бути чутливі дані або вказівники, тому критичність цієї вразливості залежить від того, які дані можуть бути перезаписані і як зловмисник може цим зловживати.
tip
Щоб знайти зсуви переповнення, ви можете використовувати ті ж шаблони, що й у переповненнях стеку.
Stack Overflows vs Heap Overflows
У переповненнях стеку розташування та дані, які будуть присутні в стеку в момент, коли вразливість може бути активована, є досить надійними. Це пов'язано з тим, що стек є лінійним, завжди збільшується в зіткненні пам'яті, у конкретних місцях виконання програми стекова пам'ять зазвичай зберігає подібні дані і має певну структуру з деякими вказівниками в кінці частини стеку, що використовується кожною функцією.
Однак у випадку переповнення купи використана пам'ять не є лінійною, а використані частини зазвичай знаходяться в окремих позиціях пам'яті (не одна біля одної) через контейнери та зони, які розділяють алокації за розміром, і через те, що попередньо звільнена пам'ять використовується перед алокацією нових частин. Це ускладнює визначення об'єкта, який буде зіткненням з вразливим до переповнення купи. Тому, коли виявляється переповнення купи, потрібно знайти надійний спосіб зробити так, щоб бажаний об'єкт був наступним у пам'яті після того, що може бути переповнене.
Одна з технік, що використовується для цього, - це Heap Grooming, яка використовується, наприклад, в цьому пості. У пості пояснюється, як у ядрі iOS, коли зона вичерпується пам'яттю для зберігання частин пам'яті, вона розширюється на сторінку ядра, і ця сторінка ділиться на частини очікуваних розмірів, які будуть використовуватися в порядку (до версії iOS 9.2, потім ці частини використовуються випадковим чином, щоб ускладнити експлуатацію цих атак).
Отже, у попередньому пості, де відбувається переповнення купи, щоб примусити переповнений об'єкт зіткнутися з об'єктом жертви, кілька kallocs
примушуються кількома потоками, щоб спробувати забезпечити заповненість усіх вільних частин і створення нової сторінки.
Щоб примусити це заповнення об'єктами певного розміру, алокація поза лінією, пов'язана з iOS mach port, є ідеальним кандидатом. Шляхом формування розміру повідомлення можна точно вказати розмір алокації kalloc
, і коли відповідний mach port знищується, відповідна алокація буде негайно звільнена назад до kfree
.
Тоді деякі з цих заповнювачів можуть бути звільнені. Список вільних kalloc.4096
звільняє елементи в порядку останній прийшов - перший вийшов, що в основному означає, що якщо деякі заповнювачі звільнені, і експлуатація намагається алокувати кілька об'єктів жертви, намагаючись алокувати об'єкт, вразливий до переповнення, ймовірно, що цей об'єкт буде слідувати за об'єктом жертви.
Example libc
На цій сторінці можна знайти базову емуляцію переповнення купи, яка показує, як перезаписуючи біт prev in use наступної частини та позицію prev size, можна консолідувати використану частину (зробивши її такою, що вона не використовується) і потім знову алокувати її, маючи можливість перезаписати дані, які використовуються в іншому вказівнику.
Ще один приклад з protostar heap 0 показує дуже базовий приклад CTF, де переповнення купи може бути використано для виклику функції переможця, щоб отримати прапор.
У прикладі protostar heap 1 можна побачити, як зловживаючи переповненням буфера, можна перезаписати в сусідній частині адресу, куди будуть записані довільні дані від користувача.
Example ARM64
На сторінці https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/ ви можете знайти приклад переповнення купи, де команда, яка буде виконана, зберігається в наступній частині від переповненої частини. Таким чином, можна змінити виконувану команду, перезаписавши її простим експлойтом, таким як:
python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt
Інші приклади
- Auth-or-out. Hack The Box
- Ми використовуємо вразливість цілочисельного переповнення, щоб отримати переповнення купи.
- Ми корумпуємо вказівники на функцію всередині
struct
переповненого блоку, щоб встановити функцію, таку якsystem
, і отримати виконання коду.
Приклад з реального світу: CVE-2025-40597 – Неправильне використання __sprintf_chk
У прошивці SonicWall SMA100 версії 10.2.1.15 модуль зворотного проксі mod_httprp.so
виділяє 0x80-байтовий блок купи, а потім конкатенує кілька рядків у нього за допомогою __sprintf_chk
:
char *buf = calloc(0x80, 1);
/* … */
__sprintf_chk(buf, /* destination (0x80-byte chunk) */
-1, /* <-- size argument !!! */
0, /* flags */
"%s%s%s%s", /* format */
"/", "https://", path, host);
__sprintf_chk
є частиною _FORTIFY_SOURCE. Коли він отримує позитивний параметр size
, він перевіряє, що отриманий рядок поміщається в буфер призначення. Передаючи -1
(0xFFFFFFFFFFFFFFFF), розробники фактично відключили перевірку меж, перетворивши укріплений виклик назад у класичний, небезпечний sprintf
.
Отже, надання надто довгого Host:
заголовка дозволяє зловмиснику переповнити 0x80-байтовий шматок і знищити метадані наступного шматка купи (tcache / fast-bin / small-bin в залежності від аллокатора). Збій можна відтворити за допомогою:
import requests, warnings
warnings.filterwarnings('ignore')
requests.get(
'https://TARGET/__api__/',
headers={'Host': 'A'*750},
verify=False
)
Практична експлуатація вимагатиме heap grooming для розміщення контрольованого об'єкта безпосередньо після вразливого блоку, але корінна причина підкреслює два важливі висновки:
- _FORTIFY_SOURCE не є панацеєю – неправильне використання може знищити захист.
- Завжди передавайте правильний розмір буфера до сімейства
_chk
(або, ще краще, використовуйтеsnprintf
).
References
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.