Взлом без хакераКрис Касперски Хакер, номер #105, стр. 036 Автоматический пен-тестинг на пальцахВ последнее время появилось множество утилит для автоматического поиска уязвимостей, не требующих от хакера никакой квалификации и подвластных даже юзерам. Просто запусти программу — и пожинай плоды ее работы в виде многочисленных дыр и ошибок, найденных в исследуемых приложениях или сервисах. Однако… если бы все было так просто, интернет уже давно загнулся бы и медленно умирал среди дымящихся руин. Автоматизированный поиск имеет свои ограничения, о которых полезно знать, прежде чем хачить, поэтому немного теории не помешает. Скажу тебе по секрету. Ручной поиск дыр — крайне трудоемкое занятие, требующее обширных знаний в самых различных областях, причем целенаправленный поиск крайне неэффективен. Так, практически все крупные уязвимости были обнаружены случайно. Ну не совсем случайно, конечно. Тысячи хакеров не отрываются от дизассемблера, но фортуна стоит к ним задом и удача улыбается лишь немногим. Зачастую даже не самым умным, талантливым, продвинутым… просто более везучим. Здесь все как у золотоискателей, даже хуже. Ареал поиска настолько широк, что совершенно непонятно, куда рыть, где искать и, самое главное, что именно надо искать. Природа дыр довольно разнообразна, и, за исключением классических случаев (например, ошибки переполнения или синхронизации), их четкой классификации до сих пор нет. Короткий исторический экскурсПопытки механизировать, тьфу, то есть автоматизировать процесс добычи дыр из недр программного кода предпринимались неоднократно. Уже в самом начале 90-х годов количество отрытых уязвимостей исчислялось сотнями, что позволило задействовать математический аппарат статистического анализа. Выяснилось, что многие баги имеют сходную природу и программисты зачастую совершают одни и те же ошибки: например, выделяют буфер фиксированного размера, куда копируют полученную по сети строку, забыв предварительно проверить ее длину. Такие оплошности могут быть обнаружены чисто механически, путем передачи серверу строк различной длины в надежде, что случится переполнение и произойдет крах системы. В 1993 году появился первый автоматический сканер уязвимостей, предназначенный для удовлетворения потребностей системных администраторов и ориентированный на мирные цели. Однако хакеры быстро осознали, какие перспективы открывает это мощное оружие, и прибрали его к своим рукам. Речь идет о знаменитой утилите SATAN (Security Administrator Tool for Analyzing Networks — Инструмент администратора для анализа безопасности сетей), созданной Дэном Фармером (Dan Farmer) и Вице Винемом (Wietse Venema). Проект развивался вплоть до 1995 года, а потом был заброшен и, в попытке откреститься от хакерской составляющей, переименован в SANTA (Дед Мороз). Сегодня любой желающий может скачать исходные тексты (смесь Perl'а с Си) с www.porcupine.org/satan и вывести Сатану на орбиту, но… реальной опасности она уже не представляет. Так, чисто музейный экспонат. Кстати говоря, к аресту известного хакера Кэвина Митника Сатана имеет самое непосредственное отношение. Тсутому Шимомура (Tsutomu Shimomura) – эксперт по безопасности — получил заказ от военных ведомств США на разработку улучшенной модели Сатаны, с помощью которой военные надеялись контролировать интернет, что технически вполне возможно, главное — дыры иметь (достаточно вспомнить червя Морриса). Вот в поисках исходных текстов этого монстра Кевин и вломился к Шимомуре на компьютер. А тот, обнаружив, что его поимели, в панике поднял военных по тревоге, и они прищемили Кевина, как молодого. Впрочем, существенно улучшенной модели Сатаны так и не появилось. Автоматизированный поиск дыр оказался недостаточно эффективным — сканер обнаруживал лишь единичные уязвимости. Попытка взять интернет под контроль угасла, как бычок в писсуаре, а Шимомура всю оставшуюся жизнь зарабатывал рассказами о том, как круто он щемил Митника. Современные утилиты автоматизированного поиска, конечно же, ушли далеко вперед, но реальной угрозы они не представляют. Так, развлечение для пионеров, атакующих пионерские сайты, создатели которых совершенно не озабочены безопасностью (хинт: что мешает им скачать тот же самый сканер и проверить самих себя на вшивость?!). Автоматизированный поиск дыр без сорцовВ большинстве случаев хакерам приходится атаковать узлы без прикрытия со стороны танков и артиллерии, то есть без исходных текстов, что существенно усложняет задачу автоматического сканирования. Даже если целевой узел завязан на open source проектах, очень трудно (а порой и невозможно) определить, какая версия программы там установлена и с какими заплатками. А уж о том, что при перекомпиляции другой версией компилятора или другими ключами часть дыр может исчезать (допустим, использован ключ, форсирующий проверку границ буферов в реальном времени), лучше вообще промолчать. Короче, мы будем исходить из того, что исходных текстов у нас нет. Что мы можем сделать? Атакуемая программа представляет собой черный ящик со входом и выходом. Устройство черного ящика неизвестно, и потому нам приходится искать золото без карты в полной темноте, да еще и с завязанными глазами и связанными руками. Просто поразительно, что коммерческие (да и некоммерческие) сканеры безопасности ухитряются в таких условиях находить дыры. Как же они, черт возьми, это делают?! А никак. То есть вообще никак. Движок, дающий основной выхлоп, основан на базе уже известных уязвимостей и потому для эффективной работы требует постоянной дозаправки, в смысле скачки свежих обновлений. Ведь старые дыры постепенно затыкаются, и мощь сканера неуклонно падает. Чтобы написать подобный сканер, много ума не надо, и потому можно выбирать любой из десятков готовых (лично мыщъх предпочитает XSpider, но навязывать свои вкусы никому не собирается). Лень системных администраторов (не говоря уже о домашних пользователях) приводит к тому, что количество уязвимых узлов в любой произвольно взятый момент времени исчисляется миллионами! Достаточно заправить сканер свежим топливом, выбрать диапазон IP-адресов пошире и… немного подождать. Сканер будет методично перебирать все IP один за другим, проверяя их на предмет установки всех обновлений. Кто не подсуетился, тот уже хрустит у нас на зубах. Ну и кто же там у нас хрустит? Домашние пользователи — это понятно. Их будет большинство. Да только что с домашних пользователей возьмешь? Конфиденциальных документов у них нет, вычислительные мощности слабые, сетевые каналы узкие, как медицинская игла… Попадется и какое-то количество серверов различных организаций, обычно государственных, где на месте администратора сидит вообще непонятно кто… или что… Тут уже можно развернуться и пошерстить в локальной сети на предмет поиска чего-нибудь интересного. А широта каналов позволит использовать их в самых разных целях: от DDoS-атак до банальной рассылки спама. А вот серверы крупных компаний таким методом уже не взломать. Там за безопасностью следят весьма добросовестно, и хотя ленивые (тупые) администраторы все-таки встречаются, эти встречи носят разовый характер. Так что вся надежда на алгоритмы, позволяющие обнаруживать ранее неизвестные дыры, против которых еще не существует вакцины и заплатки еще не написаны. Самое простое (но не самое умное), что может делать сканер, - это искать ошибки переполнения (благо они самые распространенные), посылая серверу запросы с полями различной длины. Почему различной? Разве не логично бомбардировать сервер строками сумасшедшей длины, чтобы сразу выловить все ошибки переполнения? Увы… Обработка запросов включает в себя несколько этапов, и данные в процессе продвижения по пищеварительному тракту проходят через множество буферов, часть из которых выполняет проверку, а часть, возможно, и нет. В результате этого ошибка переполнения проявляется только при обработке строк определенной длины. Более короткие строки полностью помещаются в буфер (и переполнения не происходит), более длинные отлавливаются другими проверками. Чем больше полей в запросе и чем сложнее структура самого поля, тем больше вариаций мы получаем. Сканер вынужден перебирать огромное количество комбинаций, а это не только трафик, но еще и время. Плюс подозрительно возросшая сетевая активность, регистрируемая системами обнаружения вторжений. Вот, чисто для примера, возьмем простейшее поле FROM вида «john.smith@domen.com <John Smith>». Как нетрудно догадаться, в процессе синтаксического анализа сервер разделит одну строку на несколько частей: «john.smith», «domen.com» и «<John Smith>», каждая из которых пройдет через свою цепочку буферов, и потому, чтобы найти ошибку переполнения (даже если она там есть), необходимо поизвращаться со всеми подполями. Автор реально сталкивался с ситуаций, когда почтовый сервер ограничивал длину поля FROM 1024 байтами и копировал имя пользователя, заключенное в угловые кавычки, в буфер длиной 1000 байт без проверки на переполнение, причем, чтобы добраться до адреса возврата (который и являлся главным объектом атаки), требовалось поместить в буфер еще 12 байт. Плюс 4 байта самого адреса возврата. Итого на все остальные поля отводится 1024-(1000+12+4)=8 байт, то есть их длина должна быть сокращена до минимума, иначе мы просто не влезем в отведенные нам лимиты. Другими словами, чтобы найти строку, вызывающую переполнение, требуется перебрать просто гигантское количество вариантов. Неудивительно, что большинство подобных ошибок годами остаются необнаруженными! Полуслепой поискБолее продуктивным оказывается полуслепой поиск, опирающийся на спецификацию конкретного протокола. Сканер просто использует спецификацию, скрупулезно проверяя каждый пункт RFC на соответствие реализации. Вернемся к нашему примеру с полем FROM. Поставим себя на место программиста, которому поручили распарсить строку, то есть расчленить ее на составляющие. Встретив открывающуюся угловую скобку, программист, со всей очевидностью, будет искать закрывающую. А что если там ее не окажется?! Если программист - лось, то он забудет обработать такую ситуацию и будет шпарить по адресному пространству до самого конца, пока не вылетит за пределы выделенной памяти, и операционная система, офигев от такой наглости, просто замочит сервер. То есть завершит его выполнение в принудительном режиме. Количество перебираемых комбинаций при полуслепом тесте по-прежнему велико, но все-таки сокращается на несколько порядков и (в зависимости от навороченности протокола) колеблется от сотен тысяч до десятков миллионов запросов. Допустим, обработка каждого запроса занимает 0,01 сек, тогда на сканирование уйдет от 10 минут до суток. Вполне приемлемое время! Единственная проблема в том, что разработка полуслепого сканера чрезвычайно трудоемка. Вместо тупого перебора строк разной длины в цикле, необходимо тщательно проштудировать горы RFC и для каждого пункта спецификации написать отдельную процедуру тестирования, а это километры строк на Си. До сих пор не существует ни одного полуслепого сканера, проверяющего все пункты спецификации даже самых простейших протоколов (таких как, например, POP3 или SMTP). Реально проверяются лишь наиболее «перспективные» пункты спецификации, да и то не в полной мере. Тем не менее, осознавая преимущества полуслепых сканеров, разработчики постоянно добавляют все новые и новые методы сканирования, и потому разница между старой и новой версией полуслепого сканера практически всегда оказывается весьма существенной, чего нельзя сказать о слепых сканерах, которые от версии к версии только обрастают жиром и побочным функционалом (типа генерации отчетов). Стоит также упомянуть эвристические алгоритмы. Как они работают, скорее всего, не понимают даже их авторы… В общем случае они вообще никак не работают и не дают никакого выхлопа, но лейбл «эвристический сканер безопасности» достаточно эффектен и активно используется для продвижения продукта на рынок. Если принцип эвристического алгоритма не описан в документации, то с вероятностью, близкой к единице, можно утверждать, что это просто лажа. Особенно если разработчики ссылаются за «закрытые запатентованные технологии», забыв о том, что закрытых патентов не существует и не может существовать по определению и что текст любого патента можно бесплатно скачать из интернета на совершенно легальной основе. Еще существуют (и активно используются) стресс-тесты, демонстрирующие реакцию сервера на пиковую загрузку. К безопасности они имеют весьма косвенное отношение, ну разве что позволяют устраивают DoS-атаки, которыми развлекаются пионеры, но… В том-то и дело, что завалить рядовой сервер небольшой компании можно и без всякого теста. Обычно для этого достаточно запустить программу, создающую зеркало сайта и качающую сразу в несколько потоков (например, в десять или сто). Забавно, но многие домашние пользователи уже имеют более широкие каналы, чем некоторые организации. И если администратор не ограничит скорость отдачи для каждого соединения (с учетом максимально разрешенного количества соединений), то DoS можно организовать и легальными методами с помощью обычного браузера, заняв 100% пропускной способности канала и оттеснив других посетителей сайта в глухую очередь, в которой они застрянут надолго. Но это ладно. Серьезные серверы таким способом не обломать, особенно если администратор заранее позаботился о балансировании нагрузки и воздвиг распределенную систему, подключенную к нескольким сетевым каналам шириной в целую магистраль. Вот тут стресс-тесты и выручают. Самые примитивные из них просто забрасывают сервер ворохом бессмысленных запросов, надеясь, что от этого ему сильно поплохеет, однако вслепую подобрать правильные запросы практически нереально. А вот если заранее спланировать атаку… Возьмем, например, Java-апплеты. Известно, что перед запуском они в обязательном порядке проходят через верификатор, проверяющий все инструкции виртуальной машины одну за другой. Причем если очередная проверяемая инструкция воздействует на предшествующую, то верификатор выполняет повторный цикл проверки с учетом открывшихся обстоятельств. При желании можно написать такой Java-апплет из N команд, верификация которого потребует N^N итераций, то есть подвесит сервер на очень долгий срок. Причем это не баг, а фича. Обойти ее возможно только квотированием процессорного времени, но не каждый сервер это позволяет, а если даже позволяет, его еще требуется настроить. Другой пример целенаправленного стресс-теста: упаковываем несколько гигабайт нулей по gzip-алгоритму (который поддерживают практически все web-серверы) и смотрим, что из этого получится. С некоторой вероятностью сервер либо впадет в задумчивость, граничащую с нирваной, либо рухнет. Целенаправленные стресс-тесты действительно весьма эффективны, однако толку с них… DoS-атаки - это чистейшей воды вандализм, причем преследуемый и наказуемый. И самое главное, если владелец сервера не полный лох, то он просто заблокирует IP-злоумышленника или даже всю подсеть его провайдера. И хотя остается возможность работы через proxy (вот только далеко не все утилиты для стресс-тестирования поддерживают proxy), блокируются и они. Чтобы завалить сайт конкурентов на длительное время, необходим доступ ко множеству интернет-каналов, что требует нехилых вложений. Дешевле банду гопников послать. Автоматизированный поиск дыр с сорцамиНаличие исходных текстов существенно упрощает поиск дыр, поскольку из черного ящика программа превращается в белый. В большинство современных компиляторов уже встроены более или менее серьезные верификаторы, обнаруживающие значительную часть ошибок. Достаточно задействовать максимальный уровень предупреждений, задаваемый ключом командой строки, описанным в документации на компилятор. По умолчанию компилятор ругается только на откровенную лажу, за которую расстреливать надо, но… большинство программ (в том числе и коммерческих) вызывают предупреждения компилятора даже на самом «мягком» уровне предупреждений. А на максимальном уровне половина компиляторов ругается на свои же собственные библиотеки. В компилятор GCC встроен достаточно мощный верификатор, что позволяет использовать его в качестве бесплатного сканера безопасности. К сожалению, проверка программ, написанных на Microsoft Visual C++, существенно затруднена. Хорошо, если GCC их вообще откомпилирует — уж слишком много в них системно-зависимого кода и нестандартных языковых расширений, которые GCC в упор не переваривает. Но мы же ведь не компилировать собрались, а сканировать, верно? Вот и выкидываем весь левый код, прогоняя через GCC системно-независимые модули, ответственные за обработку запросов, получаемых сервером из сети. Компилятор легко обнаруживает отсутствие проверок на длину строки перед копированием ее в буфер, а также выявляет ряд потенциально небезопасных конструкций. Самое главное, что теперь возможно загнать все ветвления на графы и перебирать аргументы именно в тех диапазонах, в которых осуществляется их проверка. В грубом приближении это выглядит следующим образом. Сканер находит функцию, копирующую строку (или ее фрагмент) в буфер фиксированного размера без предварительной проверки ее длины, прослеживает траекторию передачи аргументов: от входных данных до уязвимой функции, и смотрит, возможно ли подобрать такую длину строки, которая вызывала бы переполнение в уязвимой функции и не отсекалась бы предшествующими ей проверками. Подобное сканирование требует совсем немного времени и дает надежный результат. Но еще круче сканирование с обратной связью, при котором проверяются все возможные состояния программы. Движок таких сканеров основан на инструментах, измеряющих покрытие кода (coverage). Задача сканера состоит в том, чтобы покрыть 100% всего кода, проверив его работоспособность. Для каждой строки кода выполняется так называемый обратный расчет аргументов: сканер анализирует код и пытается найти такие входные данные, обработка которых привела бы функцию в заданное состояние. С точки зрения математики эта задача не имеет решения, однако если к сканеру прикрутить трассировщик, то мы получим возможность выполнять обратную трассировку, то есть как бы пустить время вспять. На самом деле это невозможно, поскольку выполнение программы представляет собой однонаправленный процесс, связанный с необратимой потерей данный. В частности, инструкция XOR EAX,EAX обнуляет регистр EAX, и мы не можем установить его оригинальное содержимое. Поэтому обратная трассировка дает не один вариант выполнения, а целое множество. Грубо говоря, образуется система уравнений, которую сканер должен решить. Вот пускай и решает! Сканеры с обратной связью появились относительно недавно и в настоящее время существуют в виде лабораторных образцов, не доведенных до рыночных продуктов. Однако с их помощью уже найдено множество дыр (впрочем, большей частью некритических) и проведен аудит кода популярной операционной системы OpenBSD. Как же быть?Если все так хорошо, то почему тогда все так плохо? Почему подавляющее большинство юзабельных дыр (то есть дыр, пригодных для атаки) обнаруживается именно вручную, а сканеры (даже самые лучше) в основном выявляют мелкие баги? Ответ тривиален: серьезные продукты перед сдачей в эксплуатацию прогоняются через новейшие сканеры безопасности, и потому хакер имеет шанс обнаружить дыру только при тестировании древнего продукта новой версией сканера. Только шансы эти будут весьма невелики, особенно в случае черного ящика, все состояния которого проверить невозможно. Наличие исходных текстов, подкрепленных авторитетом сканеров с обратной связью, конечно, существенно увеличивает шансы на удачу, но не кардинальным образом. Самый главный минус в том, что автоматизированные сканеры действуют по заложенной в них шаблонной схеме. Они не способы мыслить, совершать открытия, рождать качественно новые решения. Все это — удел человека. Дыры неизвестного типа сканеры даже не пытаются искать, поскольку это не входит в сферу их компетенции. А если бы даже пытались, то все равно бы не нашли. Автоматический сканер — это помощник, вспомогательный инструмент хакера и только. Сага об XSpiderXSpider – популярный сканер безопасности от Positive Technologies (www.ptsecurity.ru/xs7.asp), разработчики которого утверждают, что за последний год они проигнорировали 40% вновь опубликованных уязвимостей, поскольку интеллектуальные алгоритмы сканера определяли их с самого начала. Но интеллектуальность XSpider'а очень сильно преувеличена. Это шаблонный сканер, действующий методом слепого и полуслепого перебора, что, естественно, ограничивает его возможности. Основное его достоинство — обширная и регулярно пополняемая база известных уязвимостей, отслеживающая множество программных продуктов. Весьма полезно просканировать свой компьютер, чтобы убедиться в отсутствии критических дыр. То же самое относится и к чужим компьютерам. Особенности
WWW
|