Без слов понятно, что если противник может задать форматную строку, передаваемую функции scanf и ей подобным, то беда неминуема.
В отличие от многих других рассматриваемых нами ошибок, эту обнаружить довольно легко. Такой код неправилен:
а вот такой – правилен:
printf(«%s», user_input);
Многие программисты легкомысленно полагают, что ошибку достаточно исправить только в таких местах. Однако нередко встречаются ситуации, когда форматную строку с помощью sprintf помещают в буфер, а потом забывают об этом и пишут примерно такой код:
fprintf(STDOUT, err_msg);
Противнику нужно лишь подготовить входные данные так, чтобы спецификаторы формата экранировались, и обычно написать эксплойт для такой ошибки даже проще, потому что буфер err_msg часто выделяется в стеке. Получив возможность пройти вверх по стеку, противник сможет управлять тем, в какое место будет записана информация, определяемая поданными им на вход данными.
Хотя самая очевидная атака связана с дефектом в коде программы, нередко форматные строки помещают во внешние файлы, чтобы упростить локализацию. Если такой файл недостаточно защищен, то противник сможет просто подставить собственные форматные строки.
Еще один близкий грех – это недостаточный контроль входных данных. В некоторых системах информация о местных привязках (locale) хранится в переменных окружения и определяет, в частности, каталог, где находятся файлы на нужном языке. Иногда противник может даже заставить приложение искать файлы в произвольных каталогах.