19 смертных грехов, угрожающих безопасности программ - страница 25

Шрифт
Интервал


Без слов понятно, что если противник может задать форматную строку, передаваемую функции scanf и ей подобным, то беда неминуема.

Греховность C/C++

В отличие от многих других рассматриваемых нами ошибок, эту обнаружить довольно легко. Такой код неправилен:

printf(user_input);

а вот такой – правилен:

printf(«%s», user_input);

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

fprintf(STDOUT, err_msg);

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

Родственные грехи

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

Еще один близкий грех – это недостаточный контроль входных данных. В некоторых системах информация о местных привязках (locale) хранится в переменных окружения и определяет, в частности, каталог, где находятся файлы на нужном языке. Иногда противник может даже заставить приложение искать файлы в произвольных каталогах.

Где искать ошибку

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

Выявление ошибки на этапе анализа кода

В программе на C/C++ обращайте внимание на функции семейства printf, особенно на такие конструкции:

printf(user_input);

fprintf(STDOUT, user_input);

Если встретится что–то похожее на

fprintf(STDOUT, msg_format, arg1, arg2);

проверьте, где хранится строка, на которую указывает msg_format, и насколько хорошо она защищена.

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