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



А теперь посмотрим, что происходит, когда буфер buf переполняется. Сразу вслед за buf находится сохраненное значение регистра EBP (Extended Base Pointer – расширенный указатель на базу). ЕВР содержит указатель кадра стека; при ошибке на одну позицию его значение будет затерто. Если противник сможет получить контроль над областью памяти, начинающейся с адреса 0x0012fe00 (последний байт вследствие ошибки обнулен), то программа перейдет по этому адресу и выполнит помещенный туда противником код.

Если не ограничиваться переполнением на один байт, то следующим будет затерт адрес возврата. Коль скоро противник сумеет получить контроль над этим значением и записать в буфер, адрес которого известен, достаточное число байтов ассемблерного кода, то мы будем иметь классический пример переполнения буфера, допускающего написание эксплойта. Отметим, что ассемблерный код (его обычно называют shell–кодом, потому что чаще всего задача эксплойта – получить доступ к оболочке (shell)) необязательно размещать именно в перезаписываемом буфере. Это типичный случай, но, вообще говоря, код можно внедрить в любое место вашей программы. Не обольщайтесь, полагая, что переполнению подвержен только очень небольшой участок.

После того как адрес возврата переписан, в распоряжении противника оказываются аргументы атакуемой функции. Если функция перед возвратом каким–то образом модифицирует переданные ей аргументы, то открываются новые соблазнительные возможности. Это следует иметь в виду, оценивая эффективность таких средств борьбы с переполнением стека, как программа Stackguard Криспина Коуэена (Crispin Cowan), программа ProPolice, распространяемая IBM, и флаг /GS в компиляторе Microsoft.

Как видите, мы предоставили противнику как минимум три возможности получить контроль над нашим приложением, а это ведь была очень простая функция. Если в стеке объявлен объект класса С++ с виртуальными функциями, то станет доступна таблица указателей на виртуальные функции; такая ошибка тоже легко эксплуатируется. Если одним из аргументов функции является указатель на функцию, что часто бывает в оконных системах (например, в X Window System или Microsoft Windows), то перезапись этого указателя перед использованием–очевидный способ получить контроль над приложением.

Есть множество хитроумных способов перехватить управление программой, гораздо больше, чем способен измыслить наш слабый ум. Существует несоответствие между возможностями и ресурами, доступными разработчику и хакеру. В своей работе вы ограничены сроками, тогда как противник может тратить все свое свободное время на то, чтобы придумать, как заставить вашу программу делать то, что нужно ему. Ваша программа может защищать ресурс, достаточно ценный, чтобы потратить на ее взлом несколько месяцев. Хакер тратит массу времени на то, чтобы быть в курсе последних достижений в области взлома. К его услугам – такие ресурсы, как www.metasploit.com, позволяющие в несколько «кликов» создать shell–код, который будет делать что угодно и при этом включать только символы из ограниченного набора.

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