Другое

Переполнение буфера: технические особенности, ошибки и предупреждение

Lorem ipsum dolor

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

Переполнение буфера чаще возникает в программах, разработанных на языках С-семейства: С, С++, Objective-C. Это обстоятельство связано с тем, что данная группа языков может напрямую воздействовать на память, в отличие от других языков. Бывает, что этой их «уникальностью» неправильно пользуются разработчики, поэтому возникает вероятность переполнения буфера.

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

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

Переполнение буфера и безопасность

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

Рассмотрим простой гипотетический пример. Допустим, у нас есть программка, которая обладает преимуществами «суперадминистратора». Эта программка может менять пароль администратора устройства. Из-за неправильной реализации наша программка не контролирует размер нового пароля, хотя размер буфера для паролей выделен. Такой уязвимостью сможет воспользоваться хакер. Так как длина пароля не проверяется, значит, «поверх него» можно записать любую информацию. Хакер сможет поверх нового пароля записать некий зловред на низкоуровневом языке, который будет располагаться за пределами буфера пароля. Наша программка передает пароль из буфера и инструкции хакера вне буфера дальше по цепочке, то есть код запустится. Программка не «видит» проблему с переполнением буфера. А хакер в машинном коде может записать что угодно, причем его код будет выполняться с преимуществами «суперпользователя», так как сама программа ими обладает. Что из этого может получиться остается только догадываться.

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

В программах на Си-языках программисты самостоятельно управляют размером выделенной памяти. Чтобы это сделать качественно, нужно обладать хорошими знаниями не только самого языка, но и по особенностям и архитектуре устройств, для которых ведется разработка программ. Устранение ошибок с переполнением буфера в новых программах очень слабо автоматизировано. Из этого следует, что от профессионализма и внимательности Си-программиста зависит безопасность его программы, зависящая, в свою очередь, от переполнения буфера. В других языках, например Java или Lips, такие ситуации практически отсутствуют, так как они самостоятельно контролируют выделение памяти. Поэтому их программистам в этом плане полегче.

Переполнение буфера: меры предотвращения

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

Исключить из программирования компилируемые языки никак не получится. Поэтому есть еще одна общая рекомендация: будьте более внимательны, когда распределяете память в программе. Большинство проблем с программами возникают по невнимательности самих программистов.

Как уменьшить вероятность переполнения буфера:

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

  2. Используйте компиляторы, которые могут найти большинство небезопасных функций, инициирующих переполнение буфера.

  3. Применяйте в своей практике стековый индикатор «канарейка». Это произвольный скрипт, который компилятор вставляет непосредственно перед адресом возврата. Перед возвращением из функции компилятор проверит значение «канарейки»; если что-то поменялось, значит, на код кто-то воздействовал, поэтому можно остановить дальнейшее выполнение программы.

  4. Применяйте системы обнаружения вторжений. При помощи такой системы можно быстрее обнаружить и обезвредить атаку через переполнение буфера.

  5. Применяйте защиту от поврежденного стека. Такая защита организуется при помощи плагинов для компиляторов. Суть ее в том, что компилятор проверяет стек на наличие повреждений. Если стек поврежден, тогда программа заканчивает свое выполнение.

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

Заключение

Переполнение буфера всегда будет проблемой. «Не уследить» за буфером могут как новички, так и профессиональные разработчики. От проблем с переполнением могут избавить только две вещи:

• внимательность программиста;

• использование инструментов, которые снижают риск возникновения переполнения.

Схожие статьи

Разработка UWP приложений с помощью Visual Studio и языка C
Другое

Разработка UWP приложений с помощью Visual Studio и языка C

Makefile: что это, как запустить Makefile на Linux и на Windows
Другое

Makefile: что это, как запустить Makefile на Linux и на Windows

Что такое ProcDump, как пользоваться утилитой и зачем она нужна
Другое

Что такое ProcDump, как пользоваться утилитой и зачем она нужна

Парадигмы программирования: определение, виды и их особенности
Другое

Парадигмы программирования: определение, виды и их особенности