19 смертных грехов, угрожающих безопасности программ
Шрифт:
Как видите, атака на службу разрешения имен не особенно трудна, хотя и не тривиальна. Если терять вам особо нечего, можете не принимать ее в расчет. Если же ваши активы достойны защиты, то следует заложить при проектировании предположение о ненадежности DNS и отсутствии доверия к этой службе. Ваши клиентские программы могут быть направлены на подложные серверы, идентификация клиента по его доменному имени столь же недостоверна.
Греховные приложения
В качестве классического примера неудачного проектирования обычно приводят сервер удаленного получения оболочки rsh. Его работа зависит от файла .rhosts, который хранится в хорошо известном месте и содержит информацию о системах, от которых разрешено принимать команды. Предполагалось, что работа ведется на уровне систем в целом, то есть личность пользователя
Другой пример – это служба Microsoft Terminal Services. При проектировании протокола не была учтена возможность поддельного сервера, а криптографические методы защиты передаваемых данных были уязвимы для атаки с «человеком посередине» со стороны сервера, выступающего в роли посредника между клиентом и конечным сервером. Для устранения этой проблемы было предложено использовать протокол IPSec, о чем можно прочитать в статье 816521 из базы знаний на странице http://support.microsoft.com/default.aspx?scid=kb;en–us;816521.
Не будем называть имен, но существует очень дорогая коммерческая программа архивирования, позволяющая получить копию любой информации с вашего жесткого диска и, хуже того, подменить эту информацию чем–то другим, если клиента удастся убедить в том, что ваше имя такое же, как у сервера архивации. Эта программа была разработана несколько лет назад, и хочется надеяться, что с тех пор она стала лучше.
Родственные грехи
Близким грехом является использование имени чего–либо для принятия решения. Получение канонического представления имени – вообще распространенная проблема. Например, www.example.com и www.example.com. (обратите внимание на точку в конце) – это одно и то же. Смысл завершающей точки в том, что к локальным системам люди часто предпочитают обращаться по простому имени, а если это не получается, то в конец добавляется имя домена. Так, если вы пытаетесь найти сервер foo и при этом находитесь в домене example.org, то будет произведен поиск по имени foo.example.org. Если же в запросе будет указано имя foo.example.org., то наличие точки в конце говорит определителю имен, что это полностью определенное доменное имя (FQDN), поэтому ничего дописывать к нему не надо. Заметим кстати, что хотя в современных операционных системах так уже не делают, но несколько лет назад определитель имен в системах Microsoft пытался подставлять поочередно все части доменного имени. Иными словами, если имя foo.example.org отсутствовало, то проверялось имя foo.org. В результате человек мог случайно попасть не на тот сервер, на который собирался.
Еще одна проблема – это применение криптографических протоколов, уязвимых для атак с «человеком посередине», или полное пренебрежение криптографией в тех случаях, когда она необходима. Мы еще вернемся к этому вопросу в разделе «Искупление греха».
Где искать ошибку
Этому греху подвержено любое приложение, выступающее в роли клиента или сервера в сети, где соединения аутентифицируются, а также в тех случаях, когда по какой–то причине нужно знать, кто находится на другом конце соединения. Если вы просто решили переписать службы chargen, echo или tod (время дня), то никаких причин для беспокойства у вас нет. Но большинство из нас занимаются вещами посложнее, поэтому следует хотя бы знать о существовании проблемы.
Для аутентификации сервера лучше всего применять протокол SSL (точнее SSL/TLS), и если клиентом является стандартный браузер, то большую часть работы
Выявление ошибки на этапе анализа кода
Поскольку грех доверия серверу имен, как правило, встраивается в приложение еще на уровне проекта, то мы не можем конкретно сказать, на что именно надо обращать внимание в ходе анализа кода. Впрочем, есть места, в которых надо поднять красный флажок: всякий раз, видя обращение к функциям hostname или gethostbyaddr (либо ее новую версию, работающую и для протокола IPv6), вы должны задуматься над тем, что произойдет, если имя хоста окажется подложным.
Кроме того, надо посмотреть, по какому протоколу происходит взаимодействие. Подделать TCP–соединение значительно сложнее, чем UDP–пакет. Если в качестве транспортного протокола используется UDP, то вы можете получать данные практически из любого источника вне зависимости от того, скомпрометирован DNS–сервер или нет. Вообще говоря, лучше избегать применения UDP.
Тестирование
Методы, применяемые для тестирования приложения на наличие этой ошибки, подходят и для тестирования любого сетевого приложения. Прежде всего нужно создать некорректных клиента и сервера. Можно одним махом сделать то и другое. Для этого следует вставить между клиентом и сервером посредника. На первом этапе вы просто протоколируете и просматриваете всю передаваемую информацию. Если обнаруживается нечто, что вызовет проблемы в случае перехвата, надо провести более глубокое исследование. В частности, проверьте, не представлены ли данные в кодировке base64 или ASN1. То и другое с точки зрения безопасности эквивалентно открытому тексту, поскольку ни о каком шифровании здесь речь не идет.
Следующий шаг – выяснить, что произойдет с клиентом, если ему укажут на контролируемый противником сервер. Попробуйте подать на вход случайные и заведомо вредоносные данные, обращайте особое внимание на возможность кражи верительных грамот. В зависимости от применяемого механизма аутентификации противник, перехватив ваши верительные грамоты, может получить доступ к системе, даже не зная пароля.
Если сервер делает какие–то предположения относительно клиентской системы, а не просто аутентифицирует пользователя, то это повод пересмотреть проект приложения: подобные вещи делать рискованно. Если же для такого решения есть основания, попробуйте занести некорректную запись в файл hosts на сервере (значение IP–адреса в такой записи имеет более высокий приоритет по сравнению с запросом к DNS) и установить соединение от имени подложного клиента. Если сервер не обнаружит подмены, значит, вы столкнулись с проблемой.
Примеры из реальной жизни
Следующие примеры взяты из базы данных CVE .
CVE–2002–0676
Цитата из бюллетеня CVE:
Подсистема SoftwareUpdate для MacOS 10.1.x не проводит аутентификацию при загрузке обновлений программ. Это открывает удаленному противнику возможность выполнить произвольный код, выдав себя за сервер обновления Apple с помощью подлога DNS или отравления кэша. В результате вместо настоящего обновления противник может подсунуть троянца.
Более подробно об этой проблеме можно прочитать на сайте www.cunap.com/ ~hardingr/projects/osx/exploit.html. Приведем выдержку с этой Web–страницы–описание нормальной работы службы:
При запуске (по умолчанию раз в неделю) программа SoftwareUpdate устанавливает соединение по протоколу HTTP с сервером swscan.apple.com и посылает простой GET–запрос на файл /scanningpoints/scanningpointX.xml. В ответ сервер возвращает перечень программ и их текущих версий, которые система OS X должна проверить. По результатам проверки OS X посылает перечень установленных программ странице /WebObjects/ SoftwareUpdatesServer на сервере swquery.apple.com в виде запроса HTTP POST. Если имеются новые программы, то SoftwareUpdatesServer возвращает в ответ местоположение, размер и краткое описание каждого файла. В противном случае сервер посылает пустую страницу с комментарием «No Updates».