Илья Медведовский - Атака на Internet
В 1990 и 1995 годах Кристофером Клаусом (Christopher Klaus) [26] было протестировано около 80 программ на 9 различных платформах. Специальная программа подавала на вход строки длиной до 100 000 символов. В результате 25–33 % программ в 1990 году и 18–23 % в 1995 году работали некорректно – зависали, сбрасывали аварийный дамп и т. п. Интересно, что в коммерческих версиях UNIX этот процент доходил до 43, тогда как в свободно распространяемых он был меньше 10. Впрочем, справедливости ради надо отметить, что только две программы-демона вели себя таким образом в 1990 году, а через 5 лет эти ошибки были исправлены.
На практике, когда мы занимались анализом безопасности одного из шифраторов IP-трафика, построенного на базе OC FreeBSD 2.2, нам потребовалось совсем немного времени, чтобы найти типичную ошибку переполнения буфера в SUID root-программе suidperl. Получить полномочия суперпользователя удалось передачей в качестве параметра строки из 1 197 байт, содержащей стандартный код вызова оболочки.
Также важно отметить, что технология переполнения буфера, являясь самой распространенной и эффективной для удаленного исполнения кода, то есть для реализации опасных угроз раскрытия и целостности, но требующая значительных усилий по формированию соответствующей строки, может применяться очень эффективно и для атак «отказ в обслуживании». Здесь нет необходимости специально подбирать буфер с правильным адресом возврата, а подойдет любой, и возврат совершится на некий случайный адрес, вызвав тем самым аварийный останов программы или всей ОС в целом. Для реализации таких атак необходимо подобрать только длину буфера, но вполне естественно, что хорошими кандидатами будут строки длиной на 10–20 байт больше, чем 80, 100, 128, 256, 512, 1 000, 1 024, 2 048....Для гарантированного отказа в обслуживании недостаточно подать на вход очень длинную строку, тем самым переполнив любой из потенциальных буферов. Дело в том, что начиная с некоторой длины такие строки могут не вызывать необходимого переполнения буфера, а приводить к другим ошибкам и иногда вообще никак не проявляться в работе программы. Иначе говоря, хакер, готовя переполнение буфера, ограничен максимальным размером кода, который он сможет выполнить. Тем не менее разумно подбирать длину буфера, начиная с больших величин.
Осталось подытожить, какие операционные системы могут подвергаться технологии переполнения буфера. Явно или неявно, но мы предполагали, что:
• параметры функций передаются через стек;
• адрес возврата также помещается в стек;
• локальные переменные располагаются в стеке;
• стек «растет» вниз;
• данные в стеке могут интерпретироваться как команды;
• должны существовать процессы или программы, имеющие уязвимый код, подобный функции process_data();
• некоторые процессы или функции должны иметь высокие привилегии.
Очевидно, что этим условиям удовлетворяет большинство ОС, в том числе UNIX и Windows NT.
И напоследок – переполнение буфера в стеке является тривиально используемой уязвимостью. Однако, если пытаться избавиться от таких уязвимостей простым переписыванием строк кода типа
char buf[FIXED];
на
static char buf[FIXED];
или
buf = (char *) malloc (FIXED);
(то есть убирая буферы из стека, чтобы невозможно было перезаписать адрес возврата), это не приведет к желаемым результатам, так как буферы, находящиеся в динамических или статических областях памяти, будут подвержены переполнению. А рядом с ними вполне могут находиться указатели на функции, данные структур для функций longjmp(), перезаписывание которых также приводит к исполнению функций злоумышленника. Более того, часто в подобных случаях можно обойтись без необходимости передачи управления: достаточно изменить имена файлов, идентификаторы (UID, GID, pid), пароли и т. п., лежащие в тех же областях памяти по соседству, чтобы задача хакера была выполнена.
Червь
В этом разделе мы перейдем к подробному рассмотрению не только самого известного случая нарушения безопасности Сети, но и самого крупного инцидента в области компьютерной безопасности вообще – Internet worm (вирус Морриса). Более того, он представлял собой не просто единичное вторжение в некоторый компьютер, а дал ответ на давний вопрос: могут ли не в абстрактных условиях существовать саморепродуцирующиеся программы? То, что теоретически это возможно, признавалось почти всеми. А подтвердив возможность создания такой программы, инцидент дал толчок к появлению целой отрасли компьютерной безопасности – компьютерной вирусологии (к тому времени уже существовали единичные вирусы и на персональных компьютерах – саморепродуцирующиеся в пределах одного компьютера).
Остается открытым (как мы увидим далее, исходя из существования схожих проблем безопасности UNIX и в наши дни) вопрос, почему же по сей день известен только один пример сетевого червя. Видимо, дело в том, что в странах с развитой компьютерной и сетевой инфраструктурой на сегодняшний день действует (во многом, кстати, вследствие вируса Морриса) очень жесткое законодательство против компьютерных преступлений такого рода (тем более, что написание червя не приносит никакой материальной выгоды, только сомнительную известность), а в странах, где подобные законы отсутствуют, нет и доступа широких кракерских масс к глобальным компьютерным сетям. Отсюда можно сделать вывод, что в ближайшем будущем, когда распространенность сетей достигнет необходимого уровня, нас ждут примеры новых сетевых червей, сделанных хакерами этих стран, и Россия здесь может занять не последнее место.
К 1988 году глобальная сеть Internet уже почти сформировалась, и практически все услуги сегодняшнего дня (кроме WWW) использовались и тогда. С другой стороны, в хакерских и околохакерских кругах скопилось достаточно информации о брешах в системах безопасности и способах несанкционированного проникновения в удаленные компьютеры. Критическая масса была накоплена, и она не могла не взорваться.
Итак, в начале ноября 1988 года Сеть была атакована так называемым сетевым червем, впоследствии получившим название «вирус Морриса» – по имени его создателя, студента Корнельского университета Роберта Морриса-младшего. Сетевым червем называют разновидность компьютерных вирусов, имеющих способность к самораспространению в локальной или глобальной компьютерной сети. Для этого червь должен обладать специфическими функциями:
• находить новые цели для атаки;
• проникать в них;
• передавать свой код на удаленную машину;
• запускать ее (получать управление);
• проверять на зараженность локальную или удаленную машину для предотвращения повторного заражения.
В сетевом компьютерном мире имя Роберта Морриса было известно давно. Еще в 1985 году компания AT&T Bell Labs опубликовала технический отчет, посвященный предсказанию TCP-идентификатора в версии 4.2 BSD UNIX [30]. Этот отчет был написан… Робертом Моррисом-старшим – отцом автора червя. Моррис-старший в то время занимал должность научного руководителя NCSC (National Computer Security Center – Национальный центр компьютерной безопасности) – эксперта по компьютерной безопасности. Моррис-старший много лет проработал в лаборатории AT&T Bell, где в 60-х годах принимал участие в разработке программ Core Wars. К этому необходимо добавить, что лето 1988 года Моррис-младший провел в той же лаборатории, где был занят переписыванием программ системы безопасности для компьютеров, работающих под управлением ОС UNIX. Кстати, инцидент с программой-червем практически никак не сказался на карьере Морриса-старшего. В начале 1989 года он был избран в специальный консультативный совет при Национальном институте стандартов и министерстве торговли. В задачу этого совета входила выработка заключений и рекомендаций по вопросам безопасности вычислительных систем правительственных органов США, а также решение вопросов, возникающих при разработке и внедрении стандартов защиты информации.
Червь Морриса инфицировал 6 200 компьютеров. Подсчитанные потери, хотя формально червь не наносил какого-либо ущерба данным в инфицированных хостах, были разделены на прямые и косвенные. К прямым потерям относились:
• остановка, тестирование и перезагрузка 42 700 машин;
• идентификация червя, удаление, чистка памяти и восстановление работоспособности 6 200 машин;
• анализ кода червя, дизассемблирование и документирование;
• исправление UNIX-систем и тестирование.
Прямые потери были оценены более чем в 32 000 000 долларов США. К косвенным потерям были отнесены:
• потери машинного времени в результате отсутствия доступа к сети;
• потери доступа пользователей к сети.
Косвенные потери оценивались более чем в 66 000 000 долларов США. Общие затраты составили 98 253 260 долларов США.
Далее мы подробно опишем структуру, механизмы и алгоритмы, применяемые червем. Было решено свободно распространять их, в отличие от исходных текстов, полученных в результате дизассемблирования. Однако по истечении 10 лет такое ограничение потеряло свою актуальность (воспользоваться сегодня ими все равно не удастся), и необходимую информацию можно найти в Internet. Большая часть материала этого раздела взята из [21, 32].