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

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

Добиться этого можно, например, поручив выполнение задачи компилятору. Если вы исключите объявления функций 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».

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

Из CVE–2000–0391: «Переполнение буфера в программе krshd, входящей в состав Kerberos 5, позволяет удаленному противнику получить привилегии root».

Из CVE–2000–0392: «Переполнение буфера в программе krshd, входящей в состав Kerberos 5, позволяет удаленному противнику получить привилегии root».

Эти ошибки в реализации системы Kerberos производства МТИ документированы в бюллетене CERT СА–2000–06 по адресу www.cert.org/advisories/CA–2000–06.html. Хотя исходные тексты открыты уже несколько лет и проблема коренится в использовании опасных функций работы со строками (strcat), отчет о ней появился только в 2000 году.


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.