Выбрать главу

Добиться этого можно, например, поручив выполнение задачи компилятору. Если вы исключите объявления функций strcpy, strcat, sprintf и им подобных из заголовочных файлов, то компилятор укажет все места в коде, где они встречаются. Но имейте в виду, что некоторые приложения полностью или частично переопределяют библиотеку времени исполнения для языка С.

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

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

Тестирование

Одной из наиболее эффективных методик является рандомизированное тестирование (fuzz testing), когда на вход подаются полуслучайные данные. Попробуйте увеличить длину входных строк и понаблюдайте за поведением приложения. Обратите внимание на одну особенность: иногда множество неправильных значений входных данных довольно мало. Например, в одном месте программы проверяется, что длина входной строки должна быть меньше 260 байтов, а в другом месте выделяется буфер длиной 256. Если вы подадите на вход очень длинную строку, то она, конечно, будет отвергнута, но стоит попасть точно в неконтролируемый интервал–и можно писать эксплойт. Часто проблему можно найти, используя при тестировании степени двойки или степени двойки плюс–минус единица.

Стоит также поискать те места, где пользователь может задать длину чего–либо. Измените длину так, чтобы она не соответствовала строке, и особое внимание обращайте на возможность переполнения целого: опасность представляют случаи, когда длина +1 = 0.

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

Если вы используете утверждения для контроля входных данных, то имеет смысл перейти от такой формы:

...

assert(len < MAX_PATH);

к следующей

...

if(len >= MAX_PATH)

{

assert(false);

return false;

}

Всегда следует тестировать программу с помощью какой–либо утилиты обнаружения ошибок при работе с памятью, например AppVerifier для Windows (см. ссылку в разделе «Другие ресурсы»). Это позволит выявить ошибки, связанные с небольшим или трудноуловимым переполнением буфера.

Примеры из реальной жизни

Ниже приведены некоторые примеры переполнения буфера, взятые из базы данных типичных уязвимостей и брешей (CVE) на сайте http://cve.mitre.org. Интересно, что когда мы работали над этой книгой, в базе CVE по запросу «buffer overrim» находилось 1734 записи. Поиск по бюллетеням CERT, в которых документируются самые широко распространенные и серьезные уязвимости, по тому же запросу дал 107 документов.

CVE–1999–0042

Цитата из описания ошибки: «Переполнение буфера в реализации серверов IMAP и POP Вашингтонского университета». Эта же ошибка очень подробно документирована в бюллетене CERT за номером СА–1997–09. Переполнение происходит во время аутентификации для доступа к серверам, реализующим протоколы Post Office Protocol (POP) и Internet Message Access Protocol (IMAP). Связанная с ней уязвимость состоит в том, что сервер электронной почты не мог отказаться от избыточных привилегий, поэтому эксплойт давал противнику права пользователя root. Это переполнение поставило под удар довольно много систем.

Контрольная программа, созданная для поиска уязвимых версий этого сервера, обнаружила аналогичные дефекты в программе SLMail 2.5 производства Seattle Labs, о чем помещен отчет на странице www.winnetmag.com/Article/ArticleID/9223/ 9223.html.

CVE–2000–0389 – CVE–2000–0392

Из CVE–2000–0389: «Переполнение буфера в функции krb_rd_req в Kerberos версий 4 и 5 позволяет удаленному противнику получить привилегии root».