Дэвид Лебланк - 19 смертных грехов, угрожающих безопасности программ
Греховные приложения
В качестве классического примера неудачного проектирования обычно приводят сервер удаленного получения оболочки rsh. Его работа зависит от файла .rhosts, который хранится в хорошо известном месте и содержит информацию о системах, от которых разрешено принимать команды. Предполагалось, что работа ведется на уровне систем в целом, то есть личность пользователя на другом конце не имеет значения. Главное, чтобы запрос исходил из зарезервированного порта (с номером от 1 до 1023) и от системы, которой данный сервер доверяет. Против rsh существует огромное количество атак, поэтому сейчас этот сервер практически вышел из употребления. Именно сервис rsh стал жертвой Кэвина Митника в атаке против Цуму Шимомуры. Эта история описана в книге Tsumu Shimomura, John Markoff «Takedown: The Pursuit and Capture of Kevin Mitnick, America's Most Wanted Computer Outlaw – By the Man Who Did It» (Warner Books, 1996) (Финал: история преследования и захвата Кэвина Митника, самого разыскиваемого в Америке компьютерного преступника, описанная человеком, который это сделал). Для организации атаки Митник воспользовался брешами в протоколе TCP, но стоит отметить, что той же цели можно было достичь, просто подделав DNS–ответы.
Другой пример – это служба 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), и если клиентом является стандартный браузер, то большую часть работы за вас уже проделала фирма–производитель. Если же клиент представляет собой что–то иное, то нужно проверить две вещи: совпадает ли имя сервера с тем, что прописано в сертификате, и не был ли сертификат отозван. Не слишком широко известно, что SSL позволяет также серверу аутентифицировать клиента.
Выявление ошибки на этапе анализа кода
Поскольку грех доверия серверу имен, как правило, встраивается в приложение еще на уровне проекта, то мы не можем конкретно сказать, на что именно надо обращать внимание в ходе анализа кода. Впрочем, есть места, в которых надо поднять красный флажок: всякий раз, видя обращение к функциям hostname или gethostbyaddr (либо ее новую версию, работающую и для протокола IPv6), вы должны задуматься над тем, что произойдет, если имя хоста окажется подложным.
Кроме того, надо посмотреть, по какому протоколу происходит взаимодействие. Подделать TCP–соединение значительно сложнее, чем UDP–пакет. Если в качестве транспортного протокола используется UDP, то вы можете получать данные практически из любого источника вне зависимости от того, скомпрометирован DNS–сервер или нет. Вообще говоря, лучше избегать применения UDP.
Тестирование
Методы, применяемые для тестирования приложения на наличие этой ошибки, подходят и для тестирования любого сетевого приложения. Прежде всего нужно создать некорректных клиента и сервера. Можно одним махом сделать то и другое. Для этого следует вставить между клиентом и сервером посредника. На первом этапе вы просто протоколируете и просматриваете всю передаваемую информацию. Если обнаруживается нечто, что вызовет проблемы в случае перехвата, надо провести более глубокое исследование. В частности, проверьте, не представлены ли данные в кодировке base64 или ASN1. То и другое с точки зрения безопасности эквивалентно открытому тексту, поскольку ни о каком шифровании здесь речь не идет.
Следующий шаг – выяснить, что произойдет с клиентом, если ему укажут на контролируемый противником сервер. Попробуйте подать на вход случайные и заведомо вредоносные данные, обращайте особое внимание на возможность кражи верительных грамот. В зависимости от применяемого механизма аутентификации противник, перехватив ваши верительные грамоты, может получить доступ к системе, даже не зная пароля.
Если сервер делает какие–то предположения относительно клиентской системы, а не просто аутентифицирует пользователя, то это повод пересмотреть проект приложения: подобные вещи делать рискованно. Если же для такого решения есть основания, попробуйте занести некорректную запись в файл hosts на сервере (значение IP–адреса в такой записи имеет более высокий приоритет по сравнению с запросом к DNS) и установить соединение от имени подложного клиента. Если сервер не обнаружит подмены, значит, вы столкнулись с проблемой.
Примеры из реальной жизни
Следующие примеры взяты из базы данных CVE (http://cve.mitre.org).
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».
Несложное моделирование угрозы обнаруживает изъяны, свойственные описанному подходу. Первый состоит в том, что перечень проверяемых программ не аутентифицируется. Перехватив ответ или просто подставив фальшивый сервер, противник может сказать клиенту, что тот должен проверять. В частности, он может подавить проверку заведомо уязвимых программ или заменить безупречную программу уязвимой.
CVE–1999–0024
Цитата из бюллетеня CVE: «Отравление кэша DNS через систему BIND в результате предсказания идентификатора запроса».
Более подробно об этой проблеме можно прочитать на странице www.securityfocus.com/bid/678/discussion. Суть дела в том, что предсказание порядкового номера DNS–запроса позволяет противнику включить некорректную информацию в DNS–ответ. Подробное описание проблемы см. на странице www.cert.org/advisories/CA–1997–22.html. Если вы думаете, что новость устарела, познакомьтесь с сообщением в BugTraq, озаглавленном «The Impact of RFC Guidelines on DNS Spoofing Attacks» (12 июля 2004) («Рекомендации RFC и атаки с подлогом DNS»), на странице www.securityfocus.eom/archive/l/368975. Хотя о проблеме известно уже много лет, многие операционные системы повторяют эту ошибку. Стоит отметить, что большинство отмеченных проблем отсутствовали в Windows Server 2003 с момента выхода в свет и были устранены в Windows ХР Service Pack 2.