19 смертных грехов, угрожающих безопасности программ
Шрифт:
Но – полагаете вы – если мы просили адрес одной системы, а получили адрес совсем другой, то определитель должен проигнорировать непрошеную информацию. Увы, в большинстве случаев это не так. Но если мы просили IP–адрес одной системы, а получили ответ для другой, но с затребованным нами IP–адресом, то уж тогда–то клиент точно отбросит лишние данные, ведь так? И снова ответ отрицательный: может и принять.
Сейчас вы, наверное, недоумеваете, как же при таких условиях Интернет вообще умудряется работать, и думаете, что хуже уже и быть не может. Разочаруем вас. Следующая проблема в том, что в каждом DNS–ответе есть время кэширования. И угадайте, кто контролирует время, в течение которого мы можем доверять результату? В пакете, содержащем ответ, эта информация хранится в поле TTL (time–to–live – время жизни), и клиенты обычно слепо ему доверяют.
Далее, можно задаться вопросом, откуда DNS–сервер знает, что получает ответы
Возможно, вы слыхали о DNSSEC, то есть безопасном DNS, и думаете, что с его помощью сможете решить все проблемы. Только беда в том, что он обещает эти проблемы решить вот уже десять лет, так что уж извините наш скептицизм. Прекрасное обсуждение этой проблемы имеется на странице www.watersprings.org/ pub/id/draft–itf–dnsext–dns–threats–07.txt. Вот выдержка из реферата:
Хотя система DNS Security Extensions (DNSSEC) разрабатывается уже десять лет, IETF так и не сформулировал конкретные угрозы, от которых DNSSEC должен защитить. Не говоря уже о прочих недостатках, эта ситуация с «телегой впереди лошади» затрудняет оценку того, достиг ли DNSSEC заявленных при проектировании целей, поскольку эти цели не были явно специфицированы.
Что еще плохого может случиться? Примите во внимание, что в наши дни большая часть клиентов пользуется протоколом динамического конфигурирования хостов (DHCP – Dynamic Host Configuration Protocol) для получения своего IP–адреса и адреса обслуживающего DNS–сервера. Часто по тому же протоколу они извещают DNS–сервер о своем имени. По сравнению с DHCP система DNS выглядит неприступной крепостью. Не будем вдаваться в детали, отметим лишь, что имя клиентской системы можно принять лишь условно, но считать эту информацию надежной было бы опрометчиво.
Как видите, атака на службу разрешения имен не особенно трудна, хотя и не тривиальна. Если терять вам особо нечего, можете не принимать ее в расчет. Если же ваши активы достойны защиты, то следует заложить при проектировании предположение о ненадежности DNS и отсутствии доверия к этой службе. Ваши клиентские программы могут быть направлены на подложные серверы, идентификация клиента по его доменному имени столь же недостоверна.
Греховные приложения
В качестве классического примера неудачного проектирования обычно приводят сервер удаленного получения оболочки 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) и установить соединение от имени подложного клиента. Если сервер не обнаружит подмены, значит, вы столкнулись с проблемой.