Новое Распределяем каналы MAX по категориям и территориям. Читать новость

Репост из «Хакер | Этичный хакинг с Михаилом Тарасовым»

Почему программы на Си больше нельзя сломать «по методичкам из нулевых»: разбираем переполнение буфера на ARM64



Когда новички приходят в тему бинарных уязвимостей, классический Buffer Overflow (переполнение буфера) часто преподносят как простую формулу: залил в строку 100 символов, перезаписал адрес возврата и получил шелл.

Сегодня я решил развернуть лабораторный стенд в Parrot Security OS на архитектуре ARM64, написать уязвимый микросервис на Си и разобрать на реальных регистрах процессора, почему в современных системах всё устроено значительно глубже и надежнее.

Делюсь выводами и наглядными логами из терминала.

1. В чем корень проблемы?
В коде на Си классическая функция strcpy() не проверяет длину входящих данных. Если я выделяю под строку локальный массив размером 64 байта, а пользователь передает 80, лишние байты физически выходят за границы массива и начинают затирать соседние данные на стеке: сохраненный указатель фрейма и адрес возврата из функции.

2. Эксперимент №1: намеренно отключаем все щиты
Чтобы увидеть механику без помех, я скомпилировал файл с отключенными защитами компилятора (-fno-stack-protector -z execstack -no-pie).

Утилита checksec сразу подсветила мне беззащитный бинарник (первый скриншот):

- No canary found - нет контроля целостности стека;
- NX disabled - стек исполняемый;
- No PIE - адреса функций зафиксированы и не меняются.

Я рассчитал смещение и попытался направить поток выполнения на скрытую функцию по адресу 0x40070c.

И вот тут сработала аппаратная специфика (второй скриншот):
Процессор выбил ошибку SIGSEGV на странном адресе 0x0000ffff0040070c.

Почему так произошло?
В 64-битной архитектуре адрес функции содержит нулевые байты (\x00). Функция strcpy честно скопировала первые байты пейлоада, наткнулась на ноль и посчитала строку завершенной. В итоге младшая часть адреса перезаписалась, а старшая осталась от старого системного адреса libc (0xffff...). Программа упала в сегфолт, доказав: бинарные данные и строковые функции Си фундаментально несовместимы.

3. Эксперимент №2: компилируем по современным стандартам
Дальше я пересобрал тот же самый исходник так, как собираются пакеты в современных дистрибутивах Linux:
gcc -O2 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -o target_hardened target.c

Смотрим в checksec (третий скриншот):

- Включена канарейка (Canary found);
- Стек закрыт для исполнения кода (NX enabled);
- Включена рандомизация адресов (PIE enabled);
- Активирован динамический контроль функций (FORTIFY: Yes).

Подаю ту же самую длинную строку - и программа мгновенно прерывает выполнение:
*** buffer overflow detected ***: terminated (Aborted)

Никакого неконтролируемого падения и никаких шансов добраться до управления регистрами.

4. Взгляд под капот: ассемблер AArch64 (четвертый скриншот)
Самое интересное видно при дизассемблировании скомпилированного файла (objdump -d):
Компилятор еще на этапе сборки вычислил, что размер буфера равен ровно 64 байтам.

Он автоматически вырезал небезопасный вызов strcpy и заменил его на библиотечную проверку __strcpy_chk:

- Строка mov x2, #0x40 - жестко заносит лимит буфера (64 в шестнадцатеричной системе) в служебный регистр;
- Строка bl <__strcpy_chk@plt> - вызывает проверку границ до того, как байты попадут в память.

Если длина ввода превышает 64 байта, программа не ждет перезаписи адресов, а немедленно завершает процесс через аварийный сигнал.

Резюме для практики
Этот разбор наглядно показывает, почему безопасность создается на стыке кода и компилятора:

1. Заменяйте небезопасные функции (strcpy, sprintf, gets) на строгие аналоги с контролем размера буфера (snprintf, strlcpy).
2. Никогда не отключайте базовые флаги защиты компилятора в продакшене.
3. Проверяйте результирующие бинарники через checksec и статические анализаторы кода.
Просмотры: 17
Открыть в MAX Сообщить о неточности

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти