Admin
Администратор
Переполнение буфера: Великая классика киберугроз и щиты современной ОС
Переполнение буфера (Buffer Overflow) — это одна из самых старых и «результативных» уязвимостей в истории компьютерной безопасности. Несмотря на десятилетия борьбы, она до сих пор входит в топ самых опасных ошибок по версии CWE/SANS. В этой статье мы разберем механику атаки на стек и то, как современные операционные системы пытаются ей противостоять.
1. Механика атаки: Что происходит в памяти?
Для понимания атаки нужно вспомнить, как работает Стек (Stack) — область памяти, где хранятся локальные переменные функций и, что самое важное, адреса возврата.
Как выглядит стек функции:
- Локальные переменные: (например, массив char buffer[64]).
- Указатель кадра (EBP/RBP): служебная информация.
- Адрес возврата (Return Address): адрес инструкции, которую процессор должен выполнить после завершения функции.
Суть уязвимости
Если программа использует «небезопасные» функции (например, gets(), strcpy() или scanf() в языке C), которые не проверяют размер вводимых данных, злоумышленник может подать на вход строку, превышающую размер буфера.Процесс взлома:
- Атакующий заполняет буфер «мусором».
- Данные выходят за границы буфера и перезаписывают указатель кадра.
- Данные перезаписывают Адрес возврата.
- Вместо оригинального адреса атакующий подставляет адрес своего вредоносного кода (шеллкода), который он также внедрил в память.
Когда функция завершается, процессор «смотрит» на адрес возврата, видит там адрес шеллкода и начинает исполнять команды хакера (например, открытие командной строки с правами администратора).
2. DEP (Data Execution Prevention) — Запрет на исполнение
Первым серьезным барьером стал DEP (в Linux известен как NX-бит — No-eXecute).
Принцип работы:
Раньше память была «перемешана»: в любой области можно было и хранить данные, и исполнять код. DEP разделяет области памяти. Стек и Куча (Heap) помечаются как только для данных.
- Результат: Даже если хакер перезапишет адрес возврата и направит процессор на свой шеллкод в стеке, ОС мгновенно завершит программу с ошибкой, так как исполнение кода в этой области запрещено на уровне процессора.
Как обходят DEP?
С помощью техники ROP (Return-Oriented Programming). Атакующий не пишет свой код, а использует цепочки из маленьких фрагментов уже существующего кода самой программы (гаджетов), которые заканчиваются инструкцией возврата.
3. ASLR (Address Space Layout Randomization) — Игра в прятки
Если DEP запрещает исполнять свой код, то ASLR делает невозможным нахождение чужого.
Принцип работы:
При каждом запуске программы операционная система случайным образом меняет базовые адреса:
- Стека.
- Кучи.
- Библиотек (DLL или .so).
- Самого исполняемого файла.
- Результат: Атакующий не знает, по какому адресу находится функция system() или его гаджеты для ROP-цепочки. Попытка угадать адрес с вероятностью 99.9% приведет к крашу приложения.
Как обходят ASLR?
Обычно через утечки памяти (Memory Leaks). Если в программе есть другая уязвимость, позволяющая прочитать данные из памяти, хакер может вычислить смещение и узнать реальные адреса.
4. Stack Canaries — «Канарейка» в стеке
Еще один метод защиты — Stack Canaries (назван в честь канареек, которых шахтеры брали в шахты для обнаружения газа).
Принцип работы:
Между локальными переменными и адресом возврата компилятор вставляет случайное число (куки). Перед тем как функция вернет управление, программа проверяет: «Жива ли канарейка?». Если буфер переполнился, канарейка будет затерта мусором. Программа увидит несовпадение значений и немедленно завершится до того, как управление перейдет к коду хакера.
Резюме
Сегодня эксплуатация переполнения буфера превратилась в сложнейшее искусство. Хакеру нужно:
- Найти утечку памяти, чтобы обойти ASLR.
- Построить сложную цепочку ROP-гаджетов, чтобы обойти DEP.
- И при этом не задеть «канарейку».
Именно поэтому современные безопасные языки программирования (Rust, Go, Swift) стараются вообще исключить возможность прямой работы с памятью, которая есть в C/C++.