Найти тему

Простейший пример атаки через переполнение буфера

Посмотрим на конкретном примере, как работает взлом программы через так называемое "переполнение буфера".

Возьмём простейшую программу на Си, которая запрашивает у пользователя пароль и выполняет те или иные действия в зависимости от того, правильный ли пароль был введён:

Компилируем и проверяем, что программа работает корректно:

доступ разрешается только в случае ввода правильного пароля
доступ разрешается только в случае ввода правильного пароля

Итак, наш crackme выдаёт сообщение "Access allowed" только в случае, если был указан суперсекретный пароль Qwerty123. Но что будет, если введённая строка окажется слишком длинной?

программа падает с ошибкой
программа падает с ошибкой

Вот те раз! Программа вылетела с ошибкой "stack smashing detected". А что самое интересное, сравнение происходило не со строкой Qwerty123, а с чередой единиц.

Дело в том, что scanf() записывает в память введённую строку целиком. Если буфер под неё окажется короче самой строки, будут переписаны соседние ячейки памяти. Этот эффект и называется "переполнением буфера".

Опытным путём установим минимальное количество символов, которое нужно ввести для получения непредсказуемого поведения. Им окажется степень двойки, 32 символа. Падения при этом уже не происходит:

всё ещё доступ запрещён, но вместо пароля пустая строка
всё ещё доступ запрещён, но вместо пароля пустая строка

Теперь заменим первый символ нашей строки на символ с кодом x00:

опаньки!
опаньки!

Что же мы видим? Не зная пароля, мы добились от crackme сообщения о разрешении доступа. Поздравляю, мы взломали программу!

Подобрать нужную для взлома длину строки — это быстрее, чем подобрать сам пароль или найти его дизассемблированием. К тому же эта атака продолжит работать, даже если пароль будет изменён.

Меры противодействия

Как же бороться с мамкиным хакером, чтобы он не смог так просто взломать нашу программу? К счастью, достаточно заменить "%s" на "%20s" в параметрах scanf. Это наложит ограничение (20 символов в нашем случае) на длину вводимого буфера. Компилируем исправленную программу и проверяем эксплойт:

ну вот теперь другое дело
ну вот теперь другое дело

Теперь доступ запрещён, как и должно быть. Кроме того, исправленная программа не будет падать с ошибкой при получении слишком длинных строк.

Это простой пример взлома, и защита от него тоже выглядит элементарно. Однако настоящие программы на несколько порядков сложнее, равно как и способы их взломать. Поэтому так важно проводить аудит кода на безопасность и как можно быстрее выпускать патчи для найденных уязвимостей.

Темы: #программирование #взлом #безопасность

Есть вопросы или дополнения к статье? Напишите их в комментариях!

Наука
7 млн интересуются