Чтение онлайн

на главную - закладки

Жанры

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

22.3.1. Переполнение буфера

Пожалуй, наиболее распространенной программной ошибкой, которая становится причиной локальных и удаленных эксплуатаций, является переполнение буфера. Ниже приведен пример программы с возможностью переполнения буфера.

 1: /* bufferoverflow.с */

 2:

 3: #include <limits.h>

 4: #include <stdio.h>

 5: #include <string.h>

 6:

 7: int main(int argc, char ** argv) {

 8: char path[_POSIX_PATH_MAX];

 9:

10: printf("копирование
строки длиной %d\n", strlen(argv[1]));

11:

12: strcpy(path, argv[1]);

13:

14: return 0;

15: }

16:

На первый взгляд код кажется довольно безопасным; хотя в итоге эта программа фактически даже ничего не делает. Она копирует строку, передаваемую пользователем, в фиксированное пространство стека, даже не проверяя, есть ли в стеке для этого свободное место. Попробуйте запустить эту программу с одним длинным аргументом командной строки (скажем, 300 символов). Это вызовет ошибку сегментации, когда

strcpy
попытается записать информацию, превышающую пространство, выделенное для массива
path
.

Чтобы лучше понять, как происходит распределение памяти для программного стека, взгляните на рис. 22.1. В большинстве систем стек процессора растет вниз; то есть, чем раньше какой-либо объект размещается в стеке, тем больший адрес логической памяти он получает. К тому же первый элемент стека является защищенной областью памяти; любая попытка получить к нему доступ приводит к ошибке сегментации.

Рис. 22.1. Карта памяти стека приложения

Следующий участок стека содержит локальные переменные, используемые кодом, который запускает остальную часть программы. Здесь мы вызываем функцию

_main
, несмотря на то что это может принести дополнительные сложности, поскольку касается таких моментов, как динамическая загрузка. Когда запускающий код вызывает для программы метод
main
, он сохраняет адрес, который метод
main
возвращает при завершении работы со стеком. Когда активизируется
main
, может понадобиться сохранение некоторых регистров микропроцессора в стеке с возможностью повторного использования этих регистров. Затем метод выделяет пространство для своих локальных переменных.

Возвращаясь к нашему примеру переполнения буфера, следует отметить, что для переменной

path
выделяется память на верхушке стека. Байт
path[0]
находится на самом верху, затем следующий байт —
path[1]
и так далее. Если наша программа-пример записывает в
path
более _
POSIX_PATH_MAX
байтов, то начинается перезапись остальных элементов стека. Если этот процесс продолжается, то происходит попытка записи за пределами верхушки стека, что вызывает ошибку сегментации.

Существенная проблема возникает, если программа записывает возвращаемый адрес вне пределов стека, но не порождает ошибку сегментации. Это позволяет изменять адрес, возвращаемый из работающей функции, на любой случайный адрес в памяти. Когда функция возвращает управление, программа переходит к данному случайному адресу и продолжает выполнение с этой точки.

Реализации, использующие переполнение буфера, как правило, включают некоторый код в массив, записываемый в стек, и возвращаемый адрес устанавливается на этот код. Этот прием позволяет взломщику запускать любой произвольно выбранный код с теми правами доступа, которыми обладает атакуемая программа. Если эта программа является сетевым демоном, работающим как root, то любой удаленный пользователь получает доступ root к локальной системе!

Обработка строк — не единственное место, в котором встречается переполнение буфера (хотя, пожалуй, наиболее распространенное). Еще одним уязвимым моментом является чтение файлов. Файловые форматы нередко сохраняют размер элемента данных, за которым следуют сами данные. Если размер сохранения используется для выделения буфера, а конец поля данных определяется каким-то другим способом, может произойти ошибка переполнения буфера. Этот тип ошибки сделал возможным для Web-сайтов обращение к файлам, которые искажены так, чтобы предоставить удаленное пользование.

Чтение данных через сетевое соединение предоставляет еще одну возможность для переполнения буфера. Многие сетевые протоколы указывают максимальный размер для полей данных. Например, протокол ВООТР [160] фиксирует для всех пакетов размер 300 байтов. Это, однако, не мешает другой машине передать через сеть 350-байтовый пакет ВООТР. Если в сети работают программы с дефектами, то они попытаются скопировать этот нестандартный 350-байтовый пакет в пространство, выделенное для корректного 300-байтового пакета ВООТР, тем самым вызовут переполнение буфера.

160

ВООТР — это предшественник DHCP, позволяющий компьютерам автоматически узнавать свои IP-адреса при запуске сетевых интерфейсов.

Локализация и трансляция служат еще двумя побудителями переполнения буфера. Если программа написана для английского языка, то без сомнения для хранения названия месяца, загружаемого из таблицы, будет достаточно десятисимвольной строки. Когда эта программа переводится на испанский, "September" превращается в "Septiembre" и может произойти переполнение буфера. Всякий раз, когда программа поддерживает различные языки и локали, большинство первоначально статических строк становятся динамическими, и внутренние строковые буферы должны это учитывать.

Теперь уже очевидно, что переполнение буфера представляет собой критическую проблему в системе безопасности. Ее очень легко упустить из виду во время программирования (в конце концов, кто должен волноваться о файловых именах, длина которых превышает

_POSIX_PATH_MAX
?), и этим чрезвычайно легко воспользоваться.

Существует несколько приемов для устранения из кода возможности переполнения буфера. Хорошо продуманные программы используют множество способов для внимательного выделения буферов соответствующих размеров.

Лучшим способом распределения памяти для объектов является метод

malloc
, который устраняет проблемы, возникающие из-за перезаписывания возвращаемого адреса, поскольку
malloc
не выделяет память из стека. Аккуратное применение функции
strlen
для вычисления необходимого размера и динамическое выделение буфера в программной куче обеспечивает хорошую защиту от переполнения. К сожалению, при этом также расходуется память, поскольку каждый вызов метод
malloc
требует вызова метода
free
. В главе 7 обсуждалось несколько способов отслеживания ненужных расходов памяти, однако даже с описанными инструментами трудно точно знать, когда можно освободить память, занимаемую объектом. Особенно в том случае, если динамическое распределение памяти для объекта подстроено под уже существующий код. Функция
alloca
предлагает альтернативу
malloc
.

Поделиться:
Популярные книги

Школа. Первый пояс

Игнатов Михаил Павлович
2. Путь
Фантастика:
фэнтези
7.67
рейтинг книги
Школа. Первый пояс

Лейб-хирург

Дроздов Анатолий Федорович
2. Зауряд-врач
Фантастика:
альтернативная история
7.34
рейтинг книги
Лейб-хирург

Не грози Дубровскому! Том VIII

Панарин Антон
8. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не грози Дубровскому! Том VIII

Вернуть невесту. Ловушка для попаданки

Ардова Алиса
1. Вернуть невесту
Любовные романы:
любовно-фантастические романы
8.49
рейтинг книги
Вернуть невесту. Ловушка для попаданки

Идеальный мир для Лекаря

Сапфир Олег
1. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря

Последний Паладин. Том 4

Саваровский Роман
4. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 4

Титан империи 7

Артемов Александр Александрович
7. Титан Империи
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Титан империи 7

На руинах Мальрока

Каменистый Артем
2. Девятый
Фантастика:
боевая фантастика
9.02
рейтинг книги
На руинах Мальрока

Сопряжение 9

Астахов Евгений Евгеньевич
9. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
технофэнтези
рпг
5.00
рейтинг книги
Сопряжение 9

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

Генерал-адмирал. Тетралогия

Злотников Роман Валерьевич
Генерал-адмирал
Фантастика:
альтернативная история
8.71
рейтинг книги
Генерал-адмирал. Тетралогия

Машенька и опер Медведев

Рам Янка
1. Накосячившие опера
Любовные романы:
современные любовные романы
6.40
рейтинг книги
Машенька и опер Медведев

Беглец. Второй пояс

Игнатов Михаил Павлович
8. Путь
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
5.67
рейтинг книги
Беглец. Второй пояс

Защитник. Второй пояс

Игнатов Михаил Павлович
10. Путь
Фантастика:
фэнтези
5.25
рейтинг книги
Защитник. Второй пояс