Stack Canaries
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
StackGuard вставляє спеціальне значення, відоме як canary, перед EIP (Розширений вказівник інструкцій), зокрема 0x000aff0d
(що представляє null, новий рядок, EOF, повернення каретки) для захисту від переповнень буфера. Однак функції, такі як recv()
, memcpy()
, read()
, і bcopy()
, залишаються вразливими, і це не захищає EBP (Базовий вказівник).
StackShield використовує більш складний підхід, ніж StackGuard, підтримуючи Глобальний стек повернень, який зберігає всі адреси повернення (EIPs). Ця конфігурація забезпечує, що будь-яке переповнення не завдає шкоди, оскільки дозволяє порівняти збережені та фактичні адреси повернення для виявлення випадків переповнення. Крім того, StackShield може перевіряти адресу повернення на наявність граничного значення, щоб виявити, чи EIP вказує за межі очікуваного простору даних. Однак цей захист можна обійти за допомогою таких технік, як Return-to-libc, ROP (Програмування, орієнтоване на повернення) або ret2ret, що вказує на те, що StackShield також не захищає локальні змінні.
-fstack-protector
:Цей механізм розміщує canary перед EBP і реорганізовує локальні змінні, щоб розмістити буфери на вищих адресах пам'яті, запобігаючи їх перезапису інших змінних. Він також безпечно копіює аргументи, передані на стеку, вище локальних змінних, і використовує ці копії як аргументи. Однак він не захищає масиви з менше ніж 8 елементами або буфери в структурі користувача.
Canary є випадковим числом, отриманим з /dev/urandom
або значенням за замовчуванням 0xff0a0000
. Він зберігається в TLS (Локальне зберігання потоків), що дозволяє спільним просторам пам'яті між потоками мати глобальні або статичні змінні, специфічні для потоку. Ці змінні спочатку копіюються з батьківського процесу, а дочірні процеси можуть змінювати свої дані, не впливаючи на батьківський або братні процеси. Проте, якщо fork()
використовується без створення нового canary, всі процеси (батьківський і дочірні) ділять один і той же canary, що робить його вразливим. На архітектурі i386 canary зберігається за адресою gs:0x14
, а на x86_64 — за адресою fs:0x28
.
Цей локальний захист ідентифікує функції з буферами, вразливими до атак, і впроваджує код на початку цих функцій для розміщення canary, а в кінці для перевірки його цілісності.
Коли веб-сервер використовує fork()
, це дозволяє провести грубу атаку для вгадування байта canary по одному. Однак використання execve()
після fork()
перезаписує простір пам'яті, заперечуючи атаку. vfork()
дозволяє дочірньому процесу виконуватися без дублювання, поки він не намагається записати, в цей момент створюється дублікат, пропонуючи інший підхід до створення процесів і обробки пам'яті.
У бінарних файлах x64
cookie canary є 0x8
байтовим qword. Перші сім байтів випадкові, а останній байт — нульовий байт.
У бінарних файлах x86
cookie canary є 0x4
байтовим dword. Перші три байти випадкові, а останній байт — нульовий байт.
Найменший значущий байт обох canaries є нульовим байтом, оскільки він буде першим у стеку, що походить з нижчих адрес, і тому функції, які читають рядки, зупиняться перед його читанням.
Витік canary і потім перезапис його (наприклад, переповнення буфера) своїм значенням.
Якщо canary розгалужується в дочірніх процесах, може бути можливим грубо вгадати його по одному байту:
Якщо в бінарному файлі є цікава вразливість витоку або довільного читання, може бути можливим витікати його:
Перезапис вказівників, що зберігаються в стеку
Стек, вразливий до переповнення стека, може містити адреси рядків або функцій, які можна перезаписати, щоб експлуатувати вразливість без необхідності досягати canary. Перевірте:
Модифікація як майстерного, так і потокового canary
Переповнення буфера в потоковій функції, захищеній canary, може бути використане для модифікації майстерного canary потоку. В результаті, пом'якшення є марним, оскільки перевірка використовується з двома canaries, які є однаковими (хоча модифікованими).
Більше того, переповнення буфера в потоковій функції, захищеній canary, може бути використане для модифікації майстерного canary, збереженого в TLS. Це пов'язано з тим, що може бути можливим досягти позиції пам'яті, де зберігається TLS (а отже, і canary) через bof у стеку потоку. В результаті, пом'якшення є марним, оскільки перевірка використовується з двома canaries, які є однаковими (хоча модифікованими). Ця атака виконується в описі: http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
Перевірте також презентацію https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015, яка згадує, що зазвичай TLS зберігається за допомогою mmap
, і коли стек потоку створюється, він також генерується за допомогою mmap
, що може дозволити переповнення, як показано в попередньому описі.
Модифікація запису GOT __stack_chk_fail
Якщо бінарний файл має Partial RELRO, то ви можете використовувати довільний запис, щоб змінити запис GOT __stack_chk_fail
на фіктивну функцію, яка не блокує програму, якщо canary буде змінено.
Ця атака виконується в описі: https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)