Stack 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.
Що таке Stack Overflow
Stack overflow - це вразливість, яка виникає, коли програма записує більше даних у стек, ніж йому виділено. Ці надмірні дані перезаписують сусідній простір пам'яті, що призводить до пошкодження дійсних даних, порушення контролю потоку виконання та потенційного виконання шкідливого коду. Ця проблема часто виникає через використання небезпечних функцій, які не виконують перевірку меж на вхідних даних.
Основна проблема цього перезапису полягає в тому, що збережений вказівник інструкцій (EIP/RIP) та збережений базовий вказівник (EBP/RBP) для повернення до попередньої функції зберігаються в стеці. Тому зловмисник зможе перезаписати їх і контролювати потік виконання програми.
Вразливість зазвичай виникає, оскільки функція копіює в стек більше байтів, ніж виділено для неї, тим самим здатна перезаписати інші частини стека.
Деякі загальні функції, вразливі до цього, це: strcpy
, strcat
, sprintf
, gets
... Також функції, такі як fgets
, read
та memcpy
, які приймають аргумент довжини, можуть бути використані в уразливий спосіб, якщо вказана довжина перевищує виділену.
Наприклад, наступні функції можуть бути вразливими:
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
Знаходження зсувів стекових переповнень
Найпоширеніший спосіб знайти стекові переповнення - це ввести дуже великий вхід з A
s (наприклад, python3 -c 'print("A"*1000)'
) і очікувати Segmentation Fault
, що вказує на те, що адресу 0x41414141
намагалися отримати доступ.
Більше того, як тільки ви виявите, що існує вразливість стекового переповнення, вам потрібно буде знайти зсув, поки не стане можливим перезаписати адресу повернення, для цього зазвичай використовується послідовність Де Брюйна. Яка для даного алфавіту розміру k і підпослідовностей довжини n є циклічною послідовністю, в якій кожна можлива підпослідовність довжини n з'являється точно один раз як безперервна підпослідовність.
Таким чином, замість того, щоб вручну з'ясовувати, який зсув потрібен для контролю EIP, можна використовувати в якості заповнювача одну з цих послідовностей, а потім знайти зсув байтів, які закінчилися перезаписом.
Для цього можна використовувати pwntools:
from pwn import *
# Generate a De Bruijn sequence of length 1000 with an alphabet size of 256 (byte values)
pattern = cyclic(1000)
# This is an example value that you'd have found in the EIP/IP register upon crash
eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value) # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")
або GEF:
#Patterns
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 викликах).
Ret2win
У цьому типі CTF викликів є функція всередині бінарного файлу, яка ніколи не викликається і яку вам потрібно викликати, щоб виграти. Для цих викликів вам просто потрібно знайти зсув для перезапису адреси повернення та знайти адресу функції, яку потрібно викликати (зазвичай ASLR буде вимкнено), щоб, коли вразлива функція повертається, прихована функція буде викликана:
{{#ref}} ret2win/ {{#endref}}
Stack Shellcode
У цьому сценарії зловмисник може помістити shellcode у стек і зловживати контрольованим EIP/RIP, щоб стрибнути до shellcode і виконати довільний код:
{{#ref}} stack-shellcode/ {{#endref}}
ROP & Ret2... техніки
Ця техніка є основною основою для обходу основного захисту попередньої техніки: Не виконавчий стек (NX). І вона дозволяє виконувати кілька інших технік (ret2lib, ret2syscall...), які закінчать виконання довільних команд, зловживаючи існуючими інструкціями в бінарному файлі:
{{#ref}} ../rop-return-oriented-programing/ {{#endref}}
Переповнення купи
Переповнення не завжди буде в стеку, воно також може бути в купі, наприклад:
{{#ref}} ../libc-heap/heap-overflow.md {{#endref}}
Типи захисту
Існує кілька захистів, які намагаються запобігти експлуатації вразливостей, перевірте їх у:
{{#ref}} ../common-binary-protections-and-bypasses/ {{#endref}}
Приклад з реального світу: CVE-2025-40596 (SonicWall SMA100)
Добра демонстрація того, чому sscanf
ніколи не слід довіряти для парсингу ненадійного вводу, з'явилася в 2025 році в SonicWall’s SMA100 SSL-VPN пристрої. Вразлива рутина всередині /usr/src/EasyAccess/bin/httpd
намагається витягти версію та кінцеву точку з будь-якого URI, який починається з /__api__/
:
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
- Перше перетворення (
%2s
) безпечно зберігає два байти вversion
(наприклад,"v1"
). - Друге перетворення (
%s
) не має специфікатора довжини, томуsscanf
буде копіювати до першого байта NUL. - Оскільки
endpoint
знаходиться на стеку і має 0x800 байт, надання шляху довше ніж 0x800 байт пошкоджує все, що знаходиться після буфера ‑ включаючи стековий канар і збережену адресу повернення.
Однорядковий доказ концепції достатній, щоб викликати збій до аутентифікації:
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
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.