Вход/Регистрация
19 смертных грехов, угрожающих безопасности программ
вернуться

Виега Джон

Шрифт:

Подверженные греху языки

Как и во многих других случаях, гонка может возникнуть в программе, написанной на любом языке. Языки высокого уровня, не поддерживающие потоков и разветвления процессов, не подвержены некоторым видам гонок, но сравнительно низкая производительность таких языков делает их уязвимыми для атак, основанных на разнице во времени между моментом проверки и моментом использования ресурса (time of check to time of use – TOCTOU).

Как происходит грехопадение

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

...

list<unsigned long> g_TheList;

unsigned long getNextFromList

{

unsigned long ret = 0;

if (!g_TheList.empty)

{

ret = g_TheList.front;

g_TheList.pop_front;

}

return ret;

}

Возможно, вы надеетесь, что шансы на то, что два потока одновременно окажутся в этой функции, малы. Однако немногие приведенные выше предложения на С++ транслируются в тысячи машинных команд. Достаточно, чтобы один поток закончил проверку наличия элементов в списке, перед тем как другой извлечет из списка последний элемент с помощью вызова pop_front. Как говорил Клинт Иствуд в фильме «Грязный Гарри»: «Ну и как ты себя теперь чувствуешь?» Очень похожий код как раз и привел к тому, что провайдер чуть ли не сутки отказывал в обслуживании клиентам.

Другое проявление проблемы – это возникновение гонки при обработке сигналов. Впервые ЭТс1 Э.ТЭ.КЭ. была публично описана в статье Михала Залевски «Delivering Signals for Fun and Profit: Understanding, Exploiting and Preventing Signal Handling Related Vulnerabilities» («Доставка сигналов для забавы и к собственной выгоде: описание, эксплуатация и предотвращение уязвимостей, связанных с обработкой сигналов»). Ее текст можно найти на странице h.org/files/4/signals.txt. Проблема в том, что многие приложения для UNIX не готовы к ситуациям, встречающимся в многопоточных программах. Ведь даже параллельные приложения, написанные для UNIX и UNIX–подобных систем, обычно порождают новый процесс, а после изменения какой–нибудь глобальной переменной этот процесс получает собственную копию страницы памяти (это гарантируется семантикой копирования при записи). Многие программы далее реализуют обработчики сигналов, причем иногда один обработчик ассоциируется с несколькими сигналами. Приложение спокойно занимается своей работой, как вдруг противник посылает ему пару сигналов, разделенных очень коротким промежутком времени. И вот внезапно ваше приложение становится по сути дела многопоточным! Довольно трудно писать многопоточные программы, даже если знаешь, к чему готовиться; что уж говорить о том, когда такой «подлости» не ожидаешь.

Целый класс ошибок касается взаимодействий с файлами и другими объектами. Способов попасть в беду так много, что даже не перечесть. Вот лишь несколько примеров. Ваша программа должна создать временный файл, поэтому она сначала проверяет, нет ли уже файла с тем же именем, и если нет, то создает его.

Обычное дело, не правда ли? Так–то оно так, но этой сценарий открывает возможность для атаки – противник угадывает имя временного файла и после запуска вашей программы создает ссылку на что–нибудь важное. Вашей программе не повезло, она открывает ссылку, которая ведет на файл, выбранный противником, после чего некоторые ее действия могут привести к эскалации привилегий. Если вы удалите файл, противник сможет подставить вместо него вредоносную программу. Если вы затрете файл, то в дальнейшем это может стать причиной сбоя в какой–то другой программе. Если файл доступен непривилегированным процессам, то вы можете изменить его права и предоставить противнику право записи в какой–то конфиденциальный файл. При наихудшем развитии событий ваша программа может установить для файла режим запуска от имени пользователя root (setuid root), и в результате приложение, выбранное противником, получит административные привилегии.

А, вы работаете на платформе Windows и довольно ухмыляетесь, полагая, что все это к вам не относится? Заблуждение! Вот что может произойти в Windows. При запуске любого сервиса создается именованный канал, по которому диспетчер сервисов (Service Control Manager) посылает сервису управляющие команды. Диспетчер работает от имени System – самой привилегированной учетной записи в системе. Противник определяет, как называется канал, находит сервис, запускаемый от имени обычного пользователя (по умолчанию таких несколько), а затем присоединяется к каналу, притворившись диспетчером сервисов. Для устранения ошибки были предприняты следующие меры: во–первых, имя канала сделано непредсказуемым, что заметно уменьшает шансы противника, а во–вторых, в Windows Server 2003 олицетворение другого пользователя стало привилегией. Если вы думаете, что Windows не поддерживает ссылки, то ошибаетесь; поищите в документации раздел CreateHardLink. Но ссылки на файлы – не единственная возможность. В Windows есть множество других именованных объектов: файлы, каналы, мьютексы, участки разделяемой памяти, рабочие столы и т. д. Любой может стать источником проблем, если программа не ожидает, что он вообще существует.

Греховность кода

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

...

char* temp;

FILE* pTempFile;

tmp = _tempnam("/tmp", "MyApp");

pTempFile = fopen(tmp, "w+");

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

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

Мы рассмотрели несколько взаимосвязанных проблем. Основной грех заключается в неумении писать код, корректно работающий в условиях одновременного исполнения. С ним также связаны ошибки контроля доступа, описанные в грехе 12, и генерирование недостаточно случайных чисел (см. грех 18). Почти все гонки при работе с временными файлами возникают вследствие ошибок установки прав доступа, усугубленных использованием старых версий операционных систем, в которых нет надлежащим образом защищенных каталогов для хранения временных файлов, создаваемых конкретным пользователем. В большинстве современных операционных систем каждому пользователю выделяется собственное рабочее пространство, а даже если это не так, всегда можно создать такую область внутри начального каталога пользователя.

  • Читать дальше
  • 1
  • ...
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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