Записки исследователя компьютерных вирусов
Шрифт:
Я не призываю вас писать червей. Напротив, я призываю одуматься и не делать этого. Но если уж вам действительно невтерпеж, пишите, по крайней мере, так, чтобы ваше творение не мешало жить и трудиться всем остальным.
Введение, или превратят ли черви сеть в компост?
– А-а, черви. Я должен как-нибудь увидеть одного из них.
– Может быть, вы и увидите его сегодня.
Френк Херберт. «Дюна»Если кто и разбирается в червях, так это Херберт. Ужасные создания, блестяще описанные в «Дюне» и вызывающие у читателей смесь страха с уважением, – они действительно во многом похожи на одноименных обитателей кибернетического мира. И пока специалисты по информационной безопасности ожесточенно спорят, являются ли черви одним из подклассов вирусных программ или же образуют вполне самостоятельную группу вредоносных «организмов», черви уже успели перепахать весь Интернет и продолжают зарываться в него с бешеной скоростью. Удалить же однажды зародившегося червя практически невозможно. Забудьте о черве Морриса! Сейчас не то время, не те пропускные способности каналов и не та квалификация обслуживающего
А что мы имеем сейчас? Количество узлов сети вплотную приближается к четырем миллиардам, причем подавляющим большинством узлов управляют совершенно безграмотные пользователи, и лишь незначительная часть сетевых ресурсов находится в руках администраторов, зачастую являющихся все теми же безграмотными пользователями, с трудом отличающими один протокол от другого и во всем полагающимися на Microsoft и NT, которые «все за них сделают». Что такое заплатки, некоторые из них, возможно, и знают, но до их установки дело сплошь и рядом так и не доходит.
Можно до потери пульса проклинать Святого Билла и его корявое программное обеспечение, но проблема вовсе не в дырах, а в халатном отношении к безопасности и откровенном разгильдяйстве администраторов. Что касается программистских ошибок, то в мире UNIX ситуация обстоит ничуть не лучше. Здесь тоже водятся черви, пускай не впечатляющие численностью своих штаммов, зато отличающиеся большой изощренностью и разнообразием. Здесь также случаются вспышки эпидемий, насчитывающие тысячи и даже десятки тысяч жертв (достаточно вспомнить червей Scalper'a и Slapper'a, поражающих Apache-серверы, вращающиеся под управлением FreeBSD и Linux соответственно). Конечно, по сравнению с миллионами упавших Windows-систем эти цифры выглядят более чем умеренными, однако легендарная защищенность (точнее, как раз-таки незащищенность) UNIX'a тут совсем не причем. Просто UNIX-системы управляются намного более грамотными операторами, чем Windows NT.
Никто не гарантирован от вторжения, и Всемирная сеть действительно находится в большой опасности. Просто, по счастливому стечению обстоятельств, все предыдущие черви были довольно беззлобными созданиями, и ущерб от их размножения носил скорее косвенный, чем прямой характер. Но и в этом случае он измерялся многими миллионами долларов и долгими часами полного или частичного «полегания» сети. У нас еще есть время на то, чтобы извлечь хороший урок из случившегося и кардинальным образом пересмотреть свое отношение к безопасности, поэтому не будем больше тратить время на бесполезные философствования и приступим к стержневой теме данной главы.
Структурная анатомия червя
Те экземпляры червей, которые мы изучали, заставили нас предполагать, что внутри них происходит сложный химический обмен.
Френк Херберт. «Дюна»Условимся называть червем компьютерную программу, обладающую репродуктивными навыками и способную к самостоятельному перемещению по сети. Попросту говоря, червь – это нечто такое, что приходит к вам само и захватывает управление машиной без каких-либо действий с вашей стороны. Для внедрения в заражаемую систему червь может использовать различные механизмы: дыры, слабые пароли, уязвимости базовых и прикладных протоколов, открытые системы и человеческий фактор (см. раздел «Механизмы распространения червей»).
Нора, прорытая вирусом в системе, обычно оказывается слишком узка, чтобы вместить всего червяка целиком. Ну разве что это будет совсем крохотный и примитивный вирус, поскольку ширина типичной норы измеряется сотнями, а то и десятками байт. Поэтому сначала на атакуемую машину проникает лишь небольшая часть вируса, называемая головой, или загрузчиком, которая и подтягивает за собой основное тело червя. Собственно говоря, голов у вируса может быть и несколько. Так, достопочтенный вирус Морриса имел две головы, одна из которых пролезала через отладочный люк в sendmail, a другая проедала дыру в finger'e, поэтому создавалось обманчивое впечатление, что сеть атакуют два различных червя. Естественно, чем больше голов имеет вирус, тем он жизнеспособнее. Современные черви в своем подавляющем большинстве обладают одной-единственной головой, однако из этого правила случаются и исключения. Так, при дизассемблерном вскрытии червя Nimda (слово «admin», читаемое задом наперед) на его теле было обнаружено пять голов, атакующих клиентов электронной почты, shared-ресурсы, web-браузеры, MS IIS-серверы и backdoor, оставленные вирусом Code Red. Такие многоголовые монстры скорее напоминают сказочных драконов или гидр, поскольку червь с несколькими головами смотрится, так скажем, жутковато, но… в кибернетическом мире свои законы.
Вирусный загрузчик (обычно отождествляемый с shell-кодом, хотя это не всегда так) решает по меньшей мере три основные задачи. Во-первых, он адаптирует свое тело (и при необходимости основное тело червя) к анатомическим особенностям организма жертвы, определяя адреса необходимых ему системных вызовов, свой собственный адрес размещения в памяти, текущий уровень привилегий и т. д. Во-вторых, загрузчик устанавливает один или несколько каналов связи с внешним миром, необходимых для транспортировки основного тела червя. Чаще всего для этого используется TCP/IP-соединение, однако червь может воспользоваться услугами FTP– и/или POPS/SMTP-протоколов, что особенно актуально для червей, пытающихся проникнуть в локальные сети, со всех сторон огороженные сплошной стеной Firewall'ов. В-третьих, загрузчик забрасывает хвост вируса на зараженный компьютер, передавая ему бразды правления. Для сокрытия факта своего присутствия загрузчик может восстановить разрушенные структуры данных, удерживая систему от падения, а может поручить это основному телу червя. Выполнив свою миссию, загрузчик обычно погибает, поскольку включить в тело вируса копию загрузчика с инженерной точки зрения намного проще, чем собирать вирус по частям.
Однажды получив управление, червь первым делом должен поглубже зарыться в «грунт» системы, втянув свой длинный хвост внутрь какого-нибудь неприметного процесса и/или файла. А зашифрованные (полиморфные) вирусы должны себя еще и расшифровать/распаковать (если только эту операцию не выполнил за них загрузчик).
Впрочем, червь может вести и кочевую жизнь, автоматически самоудаляясь из системы по прошествии некоторого времени – это добавляет ему скрытности и значительно уменьшает нагрузку на сеть. При условии, что поражаемый сервис обрабатывает каждое TCP/IP-соединение в отдельном потоке (а в большинстве случаев дело обстоит именно так), червю достаточно выделить блок памяти, присвоить ему атрибут исполняемого и скопировать туда свое тело. Напрямую перебросить хвост в адресное пространство потока жертвы нельзя, так как сегмент кода по умолчанию защищен от записи, а сегмент данных по умолчанию запрещает исполнение[2], остается стек и куча. Стек чаще всего исполняем по дефолту, а куча – нет, и для установки атрибута Executable червю приходится «химичить» с системными функциями менеджера виртуальной памяти. Если же голова червя получает управление до того, как уязвимый сервис создаст новый поток или успеет расщепить процесс вызовом fork, червь должен обязательно возвратить управление программе-носителю, в противном случае та немедленно ляжет и получится самый натуральный DoS. При этом полный возврат управления предполагает потерю власти над машиной, а значит, и смерть червя. Чтобы не уронить систему, но и не лишиться жизни самому, червь должен оставить свою резидентную копию или модифицировать систему так, чтобы хотя бы изредка получать управление. Это легко. Первое, не самое удачное, зато элементарно реализуемое решение заключается в создании нового файла с последующим добавлением его в список автоматически запускаемых программ. Более изощренные черви внедряют свое тело в подложную динамическую библиотеку и размещают ее в текущем каталоге уязвимого приложения (или просто в каталоге любого более или менее часто запускаемого приложения). Еще червь может изменить порядок загрузки динамических библиотек или даже назначить существующим динамическим библиотекам подложные псевдонимы (в ОС семейства Windows за это отвечает следующий раздел реестра: HKLM\SYSTEM\CurrentControlSet\Control\Session Maneger\KnownDLLs). Сильно извращенные черви могут регистрировать в системе свои ловушки (hocks), модифицировать таблицу импорта процесса-носителя, вставлять в кодовый сегмент команду перехода на свое тело (разумеется, предварительно присвоив ему атрибут Writable), сканировать память в поисках таблиц виртуальных функций и модифицировать их по своему усмотрению.
ВНИМАНИЕ
В мире UNIX большинство таблиц виртуальных функций располагаются в области памяти, доступной лишь для чтения, но не для записи.
Короче говоря, возможных путей здесь не по-детски много, и затеряться в гуще системных, исполняемых и конфигурационных файлов червю ничего не стоит. Попутно отметим, что только самые примитивные из червей могут позволить себе роскошь создания нового процесса, красноречиво свидетельствующего о наличии посторонних. Печально известный Love San, кстати, относится именно к этому классу. Между тем, используя межпроцессорные средства взаимодействия, внедриться в адресное пространство чужого процесса ничего не стоит, равно как ничего не стоит заразить любой исполняемый файл, в том числе и ядро системы. Кто там говорит, что операционные системы класса Windows NT блокируют доступ к запущенным исполняемым файлам? Выберите любой понравившийся вам файл (пусть для определенности это будет iexplore.exe) и переименуйте его в iexplore.dll. При наличии достаточного уровня привилегий (по умолчанию это привилегии администратора) операция переименования завершается успешно, и активные копии Internet Explorer автоматически перенаправляются системой к новому имени. Теперь создайте подложный iexplore.exe-файл, записывающий какое-нибудь приветствие в системный журнал и загружающий оригинальный Internet Explorer. Разумеется, это только демонстрационная схема. В реальности все намного сложнее, но вместе с тем и… интереснее! Впрочем, мы отвлеклись. Вернемся к нашему вирусу, в смысле – к червю.
Укрепившись в системе, червь переходит к самой главной фазе своей жизнедеятельности – фазе размножения. При наличии полиморфного генератора, вирус создает совершенно видоизмененную копию своего тела, ну или, на худой конец, просто зашифровывает критические сегменты своего тела. Отсутствие всех этих механизмов оставляет червя вполне боевым и жизнеспособным, однако существенно сужает ареал его распространения. Судите сами, незашифрованный вирус легко убивается любым сетевым фильтром, как-то брандмауэером или маршрутизатором. А вот против полиморфных червей адекватных средств борьбы до сих пор нет, и сомнительно, чтобы они появились в обозримом будущем. Распознание полиморфного кода – эта не та операция, которая может быть осуществлена в реальном времени на магистральных Интернет-каналах. Соотношение пропускной способности современных сетей и вычислительной мощности современных же процессоров явно не в пользу последних. И хотя ни один полиморфный червь до сих пор не замечен в «живой природе», нет никаких гарантий, что таких вирусов не появится впредь. Локальных полиморфных вирусов на платформе Intel IA-32 известен добрый десяток (речь идет о подлинном полиморфизме, а не тривиальном замусоривании кода незначащими машинными командами и иже с ними), как говорится – выбирай, не хочу.