Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 116, АВГУСТ 2008 г.

Серые кардиналы магистральных каналов

Крис Касперски

Хакер, номер #116, стр. 116-058-1

Преодолеваем аппаратные антивирусы

Примем как факт: ни домашние, ни корпоративные пользователи не обновляются и обновляться не будут. Никто не хочет вкладывать деньги в системы защиты и держать целый штат специалистов по безопасности. Почему же тогда глобальные эпидемии больше не возникают? Что мешает червям свободно распространяться от машины к машине?

Мрак секретности

Оказывается, помимо KAV'а, DrWeb'а, NOD'а (техника обхода которых постоянно обсуждается на хакерских форумах) существуют еще и аппаратные антивирусы, встроенные в железки от CISCO, DLINK'а и прочих производителей. Особенности реализации сами по себе не делают аппаратный антивирус крутым и могущественным. В них нет ничего загадочного, таинственного или сверхъестественного — эвристика, сигнатурный поиск и прочие классические техники каменного века. Почему же тогда аппаратные антивирусы работают, а программные тормозят со страшной силой (попробовали бы они так тормозить на магистральных каналах!), но ничего не ловят?

А все потому, что сигнатуры аппаратных антивирусов описывают не конкретный экземпляр малвари, а сценарий атаки, эксплуатирующей ту или иную уязвимость. Сигнатуры берутся у независимых поставщиков (крупнейшим из которых является Endeavor Security Inc), а не собираются каждым производителем индивидуально. Распределенные сенсорные сети (они же «гриды» от английского «sensor grid») детектят всякую аномальную активность, фиксируют хакерские атаки, эксплуатирующие еще не известные дыры, которые тут же описываются разработчиками антивируса на языке регулярных выражений и отправляются в базу. Разумеется, на это требуется время. И довольно значительное, поскольку дизассемблирование малвари/шеллкода приходится выполнять вручную, а специалистов по реверсингу не хватает.

Почему же тогда при всех своих недостатках аппаратные антивирусы оказались настолько эффективны, что прищемили всех червей, хакеров и установили в Сети круглосуточный комендантский час? Причина в том, что большинство атакующих даже не подозревают о существовании «серых кардиналов» и потому никак от них не защищаются. Да и как защищаться, если принципы работы аппаратных антивирусов неизвестны, а сам антивирус доступен лишь сотрудникам крупных IT-компаний, среди которых хакеры встречаются намного реже, чем крокодилы в Сахаре. А тем, что встречаются, никто не позволит вскрывать коробку ценой в несколько тысяч долларов!

Аппаратные антивирусы окутаны плотным мраком секретности. Даже доступ к сигнатурным базам лицензируется на весьма жестких условиях. Подписка о неразглашении, работа только с юридическими лицами — вот и все хакерство! Информацию приходится собирать буквально по крупицам. Но все же, есть добрые люди, имеющие доступ к коробке и сотрудничающие с лидерами отрасли. Они очень хорошо знают все зубчатые шестеренки и рычаги управления, приводящие в движение грандиозный механизм быстрого реагирования, стоящий на страже интернета.

Внутри коробки

Аппаратный антивирус представляет собой гибрид системы обнаружения вторжений с пакетным сканером, работающим на определенном сетевом уровне и опирающимся на более или менее развитый сигнатурный «движок». Простейшие антивирусы, встраиваемые в дешевое оборудование, работают либо на Ethernet, либо на IP уровне.

Потоковый анализ TCP-пакетов — это уже совсем другой ценовой класс, поскольку парсинг TCP-пакетов весьма ресурсоемкое дело. Особенно, если атакующий умышленно посылает IP-пакеты в обратном порядке, то есть пакет, находящийся в конце TCP-сегмента, идет первым, и, чтобы применить сигнатуру, антивирус должен созвать полную ассамблею. Другими словами – собрать весь TCP-сегмент, откладывая пакеты в память, которая, между прочим, не резиновая. А злоумышленник (вот гад) шлет пакеты с предельно низкой скоростью, такой, чтобы его только не отрубило по тайм-ауту. Да и не он один. Лишь в исключительных случаях пакеты следуют в том порядке, в котором они отправлялись. На перекрестках интернета они многократно перемешиваются с другими, переупорядочиваются, кое-что теряется по дороге... А куда антивирусу деваться? Приходится складировать пакеты в память и ждать прихода всего сегмента целиком или же расширять базу сигнатур, доводя ее до состояния, при котором атака однозначно идентифицируется по любому фрагменту TCP-пакета, что опять-таки требует памяти — сигнатуры нужно где-то хранить.

Антивирусы первых поколений использовали фиксированные последовательности байт, иногда «привязанные» к определенной точке — смещению от начала пакета или другой структуры. Затем появились подстановочные символы «*» и «?» (известные еще со времен MS-DOS). За ними пришли регулярные выражения типа REGEX/PRCE (впрочем, продвинутые антивирусы поддерживают сразу оба стандарта). Разбор регулярных выражений требует значительных вычислительных мощностей, к тому же – регулярные выражения в общем случае невозможно откомпилировать (во всяком случае, эффективно). Хуже того, они обладают существенными ограничениями, не позволяющими распознавать полиморфный код. В обычных программных антивирусах для него пишутся специальные модули, использующие самые невероятные алгоритмы — от простого подсчета энтропии до натягивая ветвлений на графы с переименованием регистров и ячеек памяти в псевдопеременные.

Крутые полиморфные вирусы распознаются с большим трудом и огромным количеством ложных срабатываний (и это – с учетом специально заточенных под них модулей детекции). Регулярные выражения здесь вообще отдыхают. Все, что могут разработчики — это создать сигнатурную базу, перечисляющую все возможные варианты следования байт в мутированном вирусе. Несколько тысяч регулярных выражений на один полиморфный вирус — явление вполне нормальное, хотя хреново работающее. Вручную набить (и отладить) столько регулярных выражений — нереально, а потому процесс их создания полностью автоматизирован. Отсюда и качество детекции (вернее, его отсутствие). В среднем, таким путем распознается от 75% до 95% штаммов, когда KAV и Dr.Web ловят до 99,6% (уровень в 98% — для них уже катастрофа и явный лаг детектора, который устраняется, как только поднимается крик «Почему ваш антивирус ничего не ловит?»).

Ограничения регулярных выражений приходится компенсировать дополнительными средствами. В частности, пороговыми датчиками (threshold sensor/detector). Что это значит? Допустим, мы имеем сигнатуру, описывающую последовательность NOP'ов, за которой идет JMP ESP (классический сценарий передачи управления на shell-код при стековом переполнении). Может ли такая последовательность встретиться в «честном» потоке данных? Может, почему бы и нет. NOP'ы – очень распространенное явление, а JMP ESP представляет собой двухбайтовую команду и потому вероятность ложных позитивных срабатываний весьма велика. Чтобы интернет не погрузился в пучину репрессий, у антивируса имеется определенный порог, ниже которого атака не фиксируется. И хотя грамотно написанному shell-коду для захвата управления достаточно послать всего один пакет (в идеале), аппаратные антивирусы целенаправленными атаками не интересуются и просыпаются лишь тогда, когда в Сети появляется червь или злобный хакер, забрасывающий shell-код на все узлы без разбора.

Выходит, что аппаратные антивирусы годятся лишь для предотвращения глобальных эпидемий? Не совсем. Ряд атак однозначно описывается языком регулярных выражений. К примеру, если мы имеем ошибку переполнения в графической библиотеке IE, неправильно обрабатывающего теги gif-файлов, на прикладном уровне атака однозначно идентифицируется парсингом gif-заголовков. Но до прикладного уровня еще дотянуться надо! Хорошо, если gif лежит на WEB-сервере «как он есть». А что, если его послали мылом в одной из многочисленных кодировок, которую только поддерживают почтовые клиенты, да еще в упакованном виде? Ни один антивирус, работающий на сетевом уровне, его не распарсит (правда, почтовые антивирусы справляются с такой ситуацией без труда). Некоторые производители в борьбе за рейтинги пытаются парсить прикладные протоколы с сетевого уровня, формально поддерживая сигнатуры, описывающие заданный тип атак, однако, их очень легко обломать (конечно, если знать об их существовании и в идеале имея доступ к базе сигнатур).

Как это ломают

Рассмотрим основные (можно даже сказать, фундаментальные) механизмы обхода аппаратных антивирусов, широко обсуждаемые в закрытых кругах и уже вырвавшиеся на свободу в виде весьма агрессивных вторжений в чужие системы. Держать информацию под колпаком больше не имеет смысла. Если кто от этого и выиграет — так только вандалы, нападающие на ничего не ведающих пользователей. Пользователи должны быть предупреждены! Короче, покажем, как обхитрить threshold sensor на примере «отравления» DNS-сервера поддельными пакетами. Microsoft выпускает уже четвертую по счету заплатку, затрудняющую атаку, но отнюдь не делающую ее невозможной. До недавнего времени номер порта-отправителя UDP-пакета с DNS-запросом и 16-битный номер последовательности Transaction ID (TXID) были легко предсказуемыми. Хакеры без труда генерировали подложные DNS-ответы, воспринимаемые системой как правильные. В результате, жертву удавалось заманить на совершенно посторонний узел, которому она сообщала конфиденциальные данные (от номера кредитки, до пароля на почтовый ящик).

В начале июля 2008 года Microsoft выпустила патч MS08-037, радикально меняющий стратегию назначения локальных портов. Если раньше номер порта каждого отправляемого пакета тупо увеличивался на единицу, то теперь используется – даже не rand(), а довольно серьезная криптографическая функция, генерирующая «очень случайные» 16 бит. Настолько случайные и непредсказуемые, насколько это возможно! Хотя, вообще-то, на трезвую голову хватило бы и rand(), но Microsoft не ищет простых путей :). Предыдущий патч (MS08-020) исправлял вполне предсказуемый TXID, основанный на простой временной функции, которая, однако, была предсказуема только в лабораторных условиях. До промышленных хакерских стандартов она явно не дотягивала, но специалисты по безопасности написали кучу умных статей с серьезными математическими выкладками (надо же как-то отрабатывать гранты). Обиженная до глубины души Microsoft разозлилась настолько, что всобачила криптостойкую функцию CryptGenRandom() в dnsapi.dll, живописно описав все ее преимущества на своем же блоге blogs.technet.com/swi/archive/2008/04/09/ms08-020-how-predictable-is-the-dns-transaction-id.aspx. И кстати, дипломатично «забыв» упомянуть, что если вызов CryptGenRandom() провалится, то вызывается обычный rand().

Так что, теперь сплошной абзац («Последнее слово отредактировано», – Прим. Forb). Оба поля совершенно случайны и абсолютно непредсказуемы. Во всяком случае, на первый взгляд. А если копнуть вглубь? Не дизассемблером и не отладчиком, а просто – головой? По умолчанию, пропатченный TCPIP.SYS драйвер использует ограниченный набор портов (49152-65535), что в пересчете на хакерскую валюту дает нам 20 бит (точнее, 19 с хвостиком, но хвостик мы округляем в большую строну). Плюс 16-битное поле TXID. Итого мы имеем 20 бит. Следовательно, для успешной атаки хакеру необходимо, в среднем, послать 2^20/2 = 524.288 подложных пакетов. Да это же настоящий шторм, который распознает любая IDS! У нее все датчики зашкалят!

Стоп! А куда нам спешить? Сядем, покурим, а пока курим, будем посылать пакеты. По одному в минуту. Ведь как устроена IDS? Она садится на канал, ловя все пролетающие пакеты. Если с одной стороны появляется большое количество DNS-ответов, которые не запрашивались и которые имеют совершенно левый номер порта с не менее левым TXID, то выставляется флаг атаки. Естественно, поскольку левые пакеты сыплются и без всякой хакерской помощи (у какого провайдера маршрутизатор идеально настроен?), то IDS для предотвращения ложных позитивных срабатываний реагирует не на количество левых пакетов вообще, а именно на их интенсивность. Один пакет в минуту – это не шторм, а вполне нормальное явление даже в мелкой подсети. Конечно, такими темпами атака будет длиться в среднем 364 дня, что вполне сопоставимо с вечностью, однако, когда атакуется не какая-то конкретная машина, ситуация резко меняется. Допустим, у хакера имеется 100 потенциальных жертв, которым рассылаются пакеты. Как не трудно рассчитать, среднее время атаки сокращается до 3,6 дня. Причем, атакующий может свободно менять собственный IP, ведь UDP работает без установки соединения, а ловить ответ хакеру не нужно. В пересчете на каждый используемый IP интенсивность посылки пакетов находится ниже порога чувствительности сенсоров. Вывод: IDS вместе с аппаратными антивирусами сидят тихо и не возникают!

Хорошо, с сенсорами мы разобрались. Займемся сигнатурами. Их тоже несложно одолеть – даже без привлечения полиморфизма. Отбросим бесполезную мелочь и сосредоточимся на антивирусах, установленных на магистральных каналах, обладающих достаточной мощью для сбора всего TCP-пакета и несущих на своем борту обширные базы оперативно обновляемых сигнатур, бьющие массированную атаку буквально через считанные часы (а то и минуты) после ее начала. Существует ли универсальный способ обхода заранее неизвестного антивируса? Оказывается, да. И такой, которому никакой магистральный антивирус принципиально не может противостоять. Прежде чем придумывать убийственный контраргумент, вернемся к истокам и вспомним, с чего все начиналось.

Изначально задумывалось, что интернет — это сеть, которая продолжит функционировать даже после начала атомной войны, когда большинство узлов разрушено. Сеть, в которой пакеты самостоятельно (ну не совсем самостоятельно, конечно) прокладывают себе маршрут. Сеть, в которой два фрагмента одного TCP-пакета из пункта «А» в пункт «В» могут идти разными путями. Гм, а ведь на счет путей – это идея! IP-пакеты, пущенные разными маршрутами, окончательно собираются в TCP только на целевом узле. Никакой отдельно взятый магистральный антивирус не в состоянии собрать полный TCP-пакет, поскольку через него физически «прокачивается» только небольшая его часть!

Как реализовать такую систему на практике? Имея домашний компьютер с несколькими сетевыми интерфейсами (ADSL-модемом и сотовым телефоном с GPRS) нетрудно написать утилиту, разбивающую исходное послание на IP-пакеты, пускаемые через разные интерфейсы. Но это неинтересно, да и смысла нет. С целенаправленными атаками магистральные антивирусы не борются, а если у жертвы (или у ее провайдера) установлен хотя бы простенький программный антивирус или брандмауэр, то подобное дробление ничем не поможет атакующему. TCP-пакет будет собран на узле, где установлен программный антивирус/брандмауэр, – или же все IP-пакеты пройдут через него, и он сможет собрать полный TCP.

А вот для червей это очень хорошая стратегия. Допустим, червь уже заразил два узла, находящиеся в различных подсетях и теперь хочет кинуть свою тушку на третий. Посылая пакеты с двух узлов одновременно (не забывая, что при этом придется реализовать определенный протокол синхронизации, так как TCP работает с установкой соединения, маркируя пакеты номерами последовательности), червь пройдет сквозь аппаратный антивирус без всяких преград, даже не заметив, что тут кто-то был!

Главное — добиться того, чтобы червя нельзя было отождествить по одному отдельно взятому пакету. Для этого достаточно написать тривиальный криптор, «размазанный» по всем пакетам и шифрующий их содержимое произвольным ключом. Очевидно, что, не зная ключа (который можно получить, только собрав все пакеты воедино), антивирус не сможет расшифровать вирусное тело, а, значит, не сможет и отождествить его по сигнатурам. Естественно, XOR с константой палится еще на излете (если ключ представляет собой 1 байт, то 256 сигнатур детектят червя по любому произвольно взятому IP-пакету) – но уже RC4 (реализуемый ничуть не сложнее) таким способом не словить, и победа остается за хакером и его червями!

Интернет – forever!

Интернет не умрет никогда. Глобальные эпидемии в исторической перспективе — явление вполне закономерное, можно даже сказать неизбежное. Всех нас будет колбасить и плющить, так что не стоит сопротивляться, лучше расслабиться и спокойно наблюдать за гонкой вооружений двух противоборствующих сторон — хакеров и создателей защитных механизмов, дополняющих друг друга как инь и янь, как свет и тьма, как день и ночь, как добро и зло...

Cтандарты регулярных выражений

REGEX в широком смысле этого слова означает все регулярные выражения (Regular Expressions), но в определенном контексте ассоциируется с библиотекой "REGEX", написанной Генри Спенсером (Henry Spencer). Ее синтаксис перекочевал во многие скриптовые языки (Perl, Tcl и т.д.), подробнее о которых можно прочитать на Вике: en.wikipedia.org/wiki/Regular_expression.

Двигаясь ходом эволюционного развития, регулярные выражения образовали библиотеку PRCE, что расшифровывается как Perl Compatible Regular Expressions — Perl-совместимые регулярные выражения, постепенно ставшие стандартом де-факто. Практический пример применения приведен ниже:

/w+?sw+?(([ws=]+,*|[ws=]+|(?R))*);/.

Естественно, помимо REGEX/PRCE существуют и другие библиотеки. Ряд антивирусов использует свои собственные, ни с чем не совместимые «стандарты», и потому поставщикам сигнатур приходится не по-детски извращаться, чтобы удовлетворить изыски разработчиков защитных механизмов.

Содержание
ttfb: 9.329080581665 ms