№10(11) октябрь 2003 подписной индекс 81655 журнал для cистемных администраторов, вебмастеров и программистов
Управление сетевыми принтерами домена Настраиваем ASPLinux 7.3 Server Edition Установка IMAP4-сервера на базе cyrus-imapd + sendmail Использование LVM Борьба с вирусами: опыт контртеррористических операций
№10(11) октябрь 2003
Система обнаружения атак IDS Snort Мечта сисадмина
оглавление АДМИНИСТРИРОВАНИЕ
БЕЗОПАСНОСТЬ
Использование LVM
Обнаружение телекоммуникационных атак: теория и практика, Snort
Сергей Яремчук grinder@ua.fm
4
Установка IMAP4-сервера на базе cyrus-imapd + sendmail
48
Борьба с вирусами: опыт контртеррористических операций
Денис Шергин diesel@diesel.tomsk.ru
10
Настраиваем ASPLinux 7.3 Server Edition Александр Шибенко pulse@hotmail.ru
Павел Закляков amdk7@mail.ru
16
Крис Касперски kk@sendmail.ru
68
Анализ защиты программ и рекомендации по ее усилению Станислав Гошко bigafroelephaut@mail.ru
78
Как бороться с баннерами в ICQ Дмитрий Репин cmapuk@comprice.ru
19
Полиномиальная арифметика и поля Галуа, или Информация, воскресшая из пепла II
Мечта сисадмина Сергей Яремчук grinder@ua.fm
ОБРАЗОВАНИЕ
20
Крис Касперски kk@sendmail.ru
84
SMTP AUTH in da Postfix + ... Андрей Мозговой brain@m9.ru
26 IMHO Вооруженное до зубов перемирие, или Я – то, чего не может быть!
Свой собственный модуль Денис Колисниченко dhsilabs@mail.ru
30
Управление сетевыми принтерами домена Иван Коробко ikorobko@prosv.ru
Татьяна Ильченко ti@sysadmins.ru
BUGTRAQ
92
2, 29, 77
38 Уважаемые читатели!
С 1 октября началась подписка на 1-ое полугодие 2004 года. Подписной индекс по каталогу «Роспечать» – 81655. Оформить подписку можно в любом почтовом отделении связи СНГ или через Интернет. Более подробная информация на нашем сайте www.samag.ru Желаем успехов!
№10(11), октябрь 2003
1
bugtraq Удаленное переполнение буфера в ProFTPD-сервере
Поднятие привилегий и слабые сессионные куки в KDE
Программа: ProFTPD 1.2.7, ProFTPD 1.2.8, ProFTPD 1.2.8rc1, ProFTPD 1.2.8rc2, ProFTPD 1.2.9rc1, ProFTPD 1.2.9rc2. Опасность: Критическая. Описание: Переполнение буфера обнаружено в ProFTPDсервере. Удаленный атакующий может загрузить специально обработанный файл на сервер, чтобы получить root shell. Переполнение буфера происходит, когда файл передается в ASCII-режиме. Как сообщается, удаленный пользователь может выполнить произвольный код с root-привилегиями, в обход существующих ограничений защиты. URL производителя: http://www.proftpd.org Решение: Немедленно установите соответствующие исправления:
Программа: KDE 2.x-3.x. Опасность: Низкая. Описание: Две уязвимости обнаружено в KDE. Злонамеренный пользователь может поднять свои привилегии и подобрать сессионные куки. KDM может представить пользователю root-привилегии, если его конфигурация позволяет использовать pam_krb5 модуль. Возможно, другие pam-модули тоже уязвимы. Проблема связана с тем, что KDM не проверяет успешное завершение функции «pam_setcred()». Слабость обнаружена в алгоритме, который генерирует 128-битные сессионные куки. В результате злонамеренный пользователь может подобрать сессионные куки в локальной сети, чтобы получить доступ к системе.
ftp.<two_letter_iso_country_code>.proftpd.org (example: ftp.nl.proftpd.org). Not all countries have mirrors; however you should select one that is geographically close to you. The MD5 sums for the source tarballs are:
Решение: Обновите KDE до версии 3.1.4: ftp://ftp.kde.org/ pub/kde/security_patches
ca6bbef30253a8af0661fdc618677e5c 677adebba98488fb6c232f7de898b58a 417e41092610816bd203c3766e96f23b abf8409bbd9150494bc1847ace06857a b89c44467f85eea41f8b1df17f8a0faa 14ab9868666d68101ed942717a1632d1 27e3f62a5615999adbbebcefa92b4510 9ce26b461b2fa3d986c9822b85c94e5f
Удаленное выполнение произвольного кода при некоторых конфигурациях в wu-ftpd FTP-сервере
proftpd-1.2.7p.tar.bz2 proftpd-1.2.7p.tar.gz proftpd-1.2.8p.tar.bz2 proftpd-1.2.8p.tar.gz proftpd-1.2.9rc1p.tar.bz2 proftpd-1.2.9rc1p.tar.gz proftpd-1.2.9rc2p.tar.bz2 proftpd-1.2.9rc2p.tar.gz
Раскрытие чувствительной информации и отказ в обслуживании в ядре NetBSD Программа: NetBSD-1.5-1.6.1. Опасность: Низкая. Описание: Уязвимость обнаружена в kernel sysctl-коде в NetBSD. Локальный пользователь может раскрыть чувствительную информацию и выполнить отказ в обслуживании. Пользователь может вызвать ссылку на NULL-указатель, потому что переменная указателя используется для пользовательского адреса и адреса ядра. В результате локальный пользователь может аварийно завершить работу ядра. Пользователь может использовать proc.* sysctl-дерево на зомбированном процессе. Это заставит ядро разыменовывать данные недопустимого процесса, что приведет к отказу в обслуживании в ядре. Sysctl helper выполняет недостаточную проверку границ для нескольких sysctl-узлов в proc.curproc.rlimit-поддерерве. Эта уязвимость может эксплуатироваться для чтения произвольных частей памяти ядра. URL производителя: http://www.netbsd.org Решение: Установите обновленную версию ядра: NetBSD-current: 25 àâãóñòà, 2003 NetBSD-1.6 branch: 28 àâãóñòà, 2003 NetBSD-1.5 branch: 28 àâãóñòà, 2003
Программа: wu-ftpd 2.6.2 и более ранние версии. Опасность: Предельно низкая. Описание: Уязвимость обнаружена в wu-ftpd в некоторых конфигурациях (MAIL_ADMIN). Удаленный авторизованный пользователь может выполнить произвольный код на уязвимой системе. Если код wu-ftpd, сконфигурированный так, чтобы посылать почтовые сообщения, содержащие загружаемые имена файлов (т.е. скомпилированный с опцией MAIL_ADMIN), тогда удаленный авторизованный пользователь может эксплуатировать переполнение буфера в функции SockPrintf() в «ftpd.c», загружая на сервер файл со специально обработанным именем. Согласно сообщению, функция store() в «ftpd.c» вызывает уязвимую SockPrintf()-функцию с именем файла, представленным пользователем, которое может быть до 32768 символов, тогда как переменная «pathname» может быть не больше MAXPATHLEN символов (4095 в большинстве Linux-систем). Т.е. обнаруженную уязвимость можно успешно эксплуатировать только на Linux-системах, в которых ядро откомпилировано с параметром MAXPATHLEN не менее 32768 символов (практически не встречается). URL производителя: http://www.wuftpd.org/ Решение: Не используйте MAIL_ADMIN. Не используйте чрезмерно большие значения для параметра MAXPATHLEN. Cоставил Александр Антипов
2
администрирование
ИСПОЛЬЗОВАНИЕ LVM
4
администрирование Рано или поздно, но это произойдёт. В один прекрасный солнечный день, когда хочется поваляться на пляже, введя команду df, обнаруживаешь, что места на сервере осталось всего ничего. Причём как ни стараешься правильно разбить диск при установке системы, но предугадать, какой из разделов потребует больше места, а какой меньше, удаётся очень редко. Если корневой раздел, /usr и /opt в большинстве своём сюрпризов не приносят, т.к. устанавливаемый софт контролируется самим сисадмином и обычно здесь применяется стандартный набор приложений. Каталог /tmp сейчас обычно отдают на откуп tmpfs – файловую систему в оперативной памяти. То с /var и /home обычно возни больше. Выходов в этой систуации может быть несколько.
Первый. Простой Плюнуть на всё требования и поступить ещё при установке просто: #
parted /dev/hda mkpartfs primary linux-swap 0 256 ↵ && parted /dev/hda mkpartfs primary ext2 256 ###
т.е. использовать всего два раздела swap и всё оставшееся место отвести под корневой. Что тут сказать, пока диск не заполнится полностью, можно будет совсем не думать о наличии свободного/занятого места в разделах. Но это положительная сторона. А с другой стороны – производительность диска в таком случае будет не на высоте, особенно при большом заполнении. Плюс обязательно найдется кто-то, у кого дома много фильмов на дисках, и в один прекрасный день он решит их все принести на работу для демонстрации. Или кто-то «добрый» запишет большой файл в /tmp. После этого остановится всё, что требует места, например, почтовый сервер или syslog, которым просто некуда будет писать на диске данные.
Второй. Фашистский Если места мало, его нужно расчистить: # find /home ( -atime +365 -o -name '*.avi') -exec rm {}\;
т.е. если пользователь не удосужился заглянуть в файл в течение года, то он явно лишний (а будет кричать, то файл всегда найдется в бэкапе), плюс туда улетают и фильмы, работать надо на работе (здесь начальство даже похвалить может). # find /home -size 200 > trash ; cat
trash | less
Или просто посмотреть на те файлы, которые занимают много места.
Третий. Радикальный Все данные резервируются, и диск переразбивается заново с учётом текущих обстоятельств, до возникновения новых. Должно помочь.
Четвертый. Софтварный
СЕРГЕЙ ЯРЕМЧУК №10(11), октябрь 2003
При помощи утилиты parted, гарантирующей сохранение данных, размеры разделов изменяются. Но, к великому
5
администрирование сожалению, parted не работает с современными журналируемыми файловыми системами RaiserFS и XFS.
Пятый. Естественно, хардварный Идём к шефу и говорим, что свободного места нет, и требуем новый жёсткий диск для сервера и повышения зарплаты для себя (чтобы два раза не бегать). Далее вставляем его в корпус, форматируем и монтируем, например, в /home/newhome и часть данных переносим на новый диск. Чтобы при этом некоторые старые файлы были доступны, из нового месторасположения необходимо воспользоваться символическими ссылками. К слову, в таком случае очень неплохо бы и на втором диске создать swap-раздел, а в файле /etc/fstab сделать запись о равенстве их приоритетов. /dev/hda1 swap swap defaults,pri=1 0 0 /dev/hdc1 swap swap defaults,pri=1 0 0
Теперь всё пользовательское пространство будет состоять из двух файловых систем и придётся всё время помнить о том, на каком диске находятся данные и следить за их наполнением, но дополнительно ко всему отпадает возможность создания жёстких ссылок на данные, расположенные в другой файловой системе. Согласитесь, это несколько неудобно, гораздо лучше, чтобы оно выглядело как единое целое, пусть даже и не является таковым. И поэтому...
дит как одно большое целое. В терминологии LVM это называется группой томов VG (volume group), это главная часть, представляющая собой логическую надстройку над физическими разделами, некий банк дисковых ресурсов. Операционная система видит VG как единое целое, хотя фактически она состоит из нескольких реальных разделов жёсткого диска. Это можно представить (но только представить) как создание расширенного раздела при обычном разбиении. И теперь кладём плитку, т.е. нарезаем в получившемся VG разделы требуемых размеров (или не нарезаем, если в этом нет необходимости, т.е. сплошная стена вас вполне устраивает). Эти разделы называются логическими томами LV (logical volume). Такой раздел форматируется затем обычным образом под выбранную файловую систему, и драйвер ФС работает именно на этом уровне. Также, именно эти разделы монтирует пользователь и прописывает данные в /etc/fstab. В LVM (HOWTO), которое находится по адресу http://tldp.org/HOWTO/LVM-HOWTO/, все это схематически отображено так:
Вариант шестой Предусмотреть возможное несоответствие размеров и возможное перепланирование рабочего пространства в будущем еще на стадии разбиения диска или, если уж произошло такое, то воспользоваться удобными современными технологиями. Для решения этой задачи в самый раз придется популярная технология LVM (Logical Volume Manager, или менеджер логических томов), которая полностью поддерживается Linux-ядром версии 2.4.
По понятиям Давайте сначала немного разберёмся в терминологии и в том, что собственно происходит. Недавний ремонт вызывает у меня только строительные ассоциации, поэтому давайте представим жесткий диск в виде стены. Но стена неоднородная, она состоит из отдельных кирпичиков, т.е. физических разделов жёткого диска (physical media), все равно каких, первичных или логических разделов на расширенном. В терминологии LVM каждый кирпичик будет называться физическим томом PV (Physical Volume). Этому разделу при образовании присваивается определенный идентификатор типа файловой системы – 8e (например, программой fdisk). Сам Physical Volume образуется из неких элементарных единиц, называемых PE (physical extents). Будем считать, это тот песок, из которого состоят кирпичи. Это минимальный размер, с которым умеет обращаться VG и по умолчанию равен 4 Мб. Далее, чтобы на голый кирпич прицепить что-то более привлекательное для глаза, его сначала заштукатуривают, и теперь наша стена выгля-
6
Сам логический том также состоит из песчинок, называемых LE (logical extent), которые сопоставляются реальным физическим physical extents. Если в дальнейшем понадобится изменить размер logical volume, то это можно будет проделать как раз на величину, кратную physical extents. Такая взаимосвязь физических и логических extent обозначается термином mapping. И ещё, так как фактически нет разницы, какому PE противопоставить LE, то это можно сделать двумя вариантами – линейным (linear mapping) и чередующимся (striped mapping). В первом случае всё просто: непрерывной последовательности физических extent ставится в соответствие столь же непрерывная последовательность логических extent. Во втором – непрерывная последовательность логических extent связывается с чередующимися между различными физическими носителями extent. Эта схема напоминает нулевой (полосатый) RAID-массив. При этом если разместить два диска на различных IDE-каналах, можно добиться некоторого повышения производительности дисковых операций. Но надёжность в таком случае ниже, т.к. в случае вылета одного диска можно потерять всё. Поэтому бэкап в последнем случае играет не последнюю роль. И ещё не
администрирование стоит смешивать в одной VG оба метода, если есть в этом необходимость, то для striped mapping создайте отдельную volume group. Как говорил один из моих преподавателей: «Природу не обманешь, за всё надо платить». Естественно, за удобства приходится расплачиваться, в нашем случае это 10-15% процессорной мощности. Причем перенос файловых систем с физического на логический уровень на скорости дисковых операций не отразился в linear случае.
От теории к практике Теперь попробуем создать logical volume и подключить его как обычную файловую систему. Для начала давайте определимся, что не надо класть в LV. Так, нет особого смысла помещать туда каталог /boot, в котором содержится ядро и Grub. Его стоит вынести в отдельный раздел размером 50 Мб (с запасом) и в файле /etc/fstab прописать такие строки, чтобы он не автоматически монтировался при загрузке. /dev/hda1 /boot ext2 noauto 1 2
Применять журналируемые файловые системы в этом случае смысла особого нет, а при смене ядра (довольно редкое занятие) данный каталог всегда можно примонтировать вручную. Также, наверное, не стоит помещать туда и следующие каталоги /etc, /proc, /lib, /mnt, /bin, /sbin, /dev, /root, swap и /tmp (хотя это всё относительно). Обычно состав их более-менее статичен и много места не занимает, так, корневой раздел в CRUX такого состава получился у меня всего навсего 300 Мб, остальное находится в /usr, /var и /home. При большом количестве внесистемного софта также следует вынести в отдельный каталог и /usr/local с /opt (я обычно делаю символическую ссылку ln -s /usr/local /opt, чтобы голову меньше ломать). Дополнительно ко всему у вас всегда будет возможность зайти в систему из-под root в случае аварийных обстоятельств. LVM можно использовать при наличии в системе и одного жёсткого диска, но наибольшую гибкость данная технология даёт при использовании двух и более дисков в системе. Для эксперимента возьмем два раздела /dev/hda4 и /dev/hdс2.
Общее распределение разделов на дисках будет таким:
/dev/hda1 – /boot /dev/hda2 – swap (содержит и /tmp) /dev/hda3 – корневой (/etc, /proc, /lib, /mnt, /bin, /sbin, /dev, /root)
/dev/hda4 – будет использован с LVM /dev/hdс1 – swap /dev/hdс2 – будет использован с LVM
Необходимый софт В большинстве современных дистрибутивов, за исключением разве ориентированных на power user, всё необходимое для работы уже имеется. Так, например, программа установки Red Hat 9 позволяет создать LVM (и софтRAID) в графическом режиме (рис.1), но, если честно, мне она не показалась интуитивно понятной. Для поддержки технологии ядром при компиляции должны быть включены следующие опции. В секции Multi-device support (RAID and LVM) нужно включить поддержку самих Multiple devices и далее собственно менеджера логических томов (Logical volume manager (LVM) support). Файл /usr/src/linux/.config должен содержать следующие строки: # # Multi-device support (RAID and LVM) # CONFIG_MD=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set # CONFIG_MD_MULTIPATH is not set CONFIG_BLK_DEV_LVM=y
Следующим шагом необходимо установить софт для работы с LVM (если его нет, конечно). В виде исходников его можно взять с сайта http://www.sistina.com/. Установка заключается в стандартной компиляции (./configure && make; su; make install) и обычно проходит без сюрпризов. В результате получите три группы утилит, предназначенные для работы на «своём» уровне: pv* работает с физическими томами, lg* – с логическими группами и lv* – с логическими томами. Все их можно найти при помощи табуляции. Так команды вида *create создают том или группу в зависимости от первых двух букв, *display выводит полную информацию и т. д. Для начала создаём физические разделы с идентификатором 8е. Для примера взят второй диск. # /sbin/fdisk /dev/hdñ Command (m for help): p Disk /dev/hdñ: 3243 MB, 3243663360 bytes 128 heads, 63 sectors/track, 785 cylinders Units = cylinders of 8064 * 512 = 4128768 bytes Device Boot /dev/hdb1 /dev/hdb2
Ðèñóíîê 1.
№10(11), октябрь 2003
Start 1 21
End 20 785
Blocks Id System 168682+ 82 Linux swap 3165088+ b Win95 FAT32
Command (m for help): t Selected partition 2 Hex code (type L to list codes): 8e Changed system type of partition 2 to 8e (Linux LVM)
7
администрирование Command (m for help): p Disk /dev/hdñ: 3243 MB, 3243663360 bytes 128 heads, 63 sectors/track, 785 cylinders Units = cylinders of 8064 * 512 = 4128768 bytes Device Boot /dev/hdb1 /dev/hdb2
Start 1 21
End 20 785
Blocks 168682+ 3165088+
Id 82 8e
System Linux swap Linux LVM
Command (m for help): w The partition table has been altered!
group, который в нашем случае равен 2 Тб, в варианте по умолчанию его значение равнялось бы 256 Гб. Теперь pvscan сообщит, что тома активированы. # /sbin/pvscan pvscan -- reading all physical volumes (this may take a while...) pvscan -- ACTIVE PV "/dev/hda4" of VG "test" ↵ [1.22 GB / 1.22 GB free] pvscan -- ACTIVE PV "/dev/hdb2" of VG "test" ↵ [2.97 GB / 2.97 GB free] pvscan -- total: 2 [4.29 GB] / in use: ↵ 2 [4.29 GB] / in no VG: 0 [0]
Calling ioctl() to re-read partition table. WARNING: If you have created or modified any DOS 6.x partitions, please see the fdisk manual page for additional information. Syncing disks.
Теперь дисковые разделы превращаем в физический том, это своего рода форматирование, чтобы программы высшего уровня могли работать с ними. Причем если используется файловая система устройств devfs, то необходимо задавать полное имя в соответствии с принятым обозначением, т.е. что-то типа /dev/ide/host0/bus0/ target0/lun0/part4, программы не распознают символических ссылок. # /sbin/pvcreate /dev/hda4 pvcreate -- physical volume "/dev/hda4" successfully created # /sbin/pvcreate /dev/hdb2 pvcreate -- physical volume "/dev/hdb2" successfully created
Теперь запускаем программу vgscan, которая отыщет всё разделы с идентификатором 8е и создаст конфигурационные файлы /etc/lvmtab и /etc/lvmtab.d.
И теперь нарезаем большую VG на логические тома требуемых размеров. При этом нужно учитывать, что урезание файловой системы и затем логического тома (вот именно в два этапа) – немного более трудоёмкий процесс, чем увеличение. Дополнительно файловая система XFS пока не урезается. Поэтому лучше создать минимально требуемый размер логического тома (с запасом), а затем при необходимости его просто увеличить до нужного. Создаем. При этом при помощи -L указывается нужный размер, а при помощи -n имя и в конце следует имя VG. Если значение в килобайтах после него ставится K, в мегабайтах M и в гигабайтах G. # /sbin/lvcreate -L 1G -n lvm_usr test && /sbin/lvcreate ↵ -L 1G -n lvm_home test lvcreate -- doing automatic backup of "test" lvcreate -- logical volume "/dev/test/lvm_usr" ↵ successfully created lvcreate -- doing automatic backup of "test" lvcreate -- logical volume "/dev/test/lvm_home" ↵ successfully created
Или для полосатости. # /sbin/vgscan vgscan -- reading all physical volumes (this may take a while...) vgscan -- "/etc/lvmtab" and "/etc/lvmtab.d" successfully created vgscan -- WARNING: This program does not do ↵ a VGDA backup of your volume group
Дополнительно можно проверить, что думает о созданных физических томах система. # /sbin/pvscan pvscan -- reading all physical volumes (this may take a while...) pvscan -- inactive PV "/dev/hda4" is in no VG [1.27 GB] pvscan -- inactive PV "/dev/hdb2" is in no VG [3.02 GB] pvscan -- total: 2 [4.29 GB] / in use: 0 [0] / in no VG: 2 ↵ [4.29 GB]
И теперь объединяем все в группу томов. Для этого вызывается команда vgcreate, в качестве аргументов принимающая условное имя будущей группы, которое может быть любым (кроме lvm), и разделы, которые будут включены в эту группу. Дополнительно при помощи опции -s ##m можно задать размер physical extent (в большинстве рекомендуют 32 Мб). По умолчанию создаётся линейный режим чередования. Если есть необходимость, в полосатом режиме используйте опцию -i, a -l # при этом задаст размер чередующихся блоков. # /sbin/vgcreate -s 32 test /dev/hda4 /dev/hdb2 vgcreate -- INFO: maximum logical volume size is 2 Terabyte vgcreate -- doing automatic backup of volume group "test" vgcreate -- volume group "my" successfully created and activated
Обратите внимание на максимальный размер volume
8
# lvcreate -n stripedlv -i 2 -I 64 mygroup -L 20M
Проверяем. # /sbin/lvscan lvscan -- ACTIVE "/dev/test/lvm_usr" [1 GB] lvscan -- ACTIVE "/dev/test/lvm_home" [1 GB] lvscan -- 2 logical volumes with 2 GB total in 1 volume group lvscan -- 2 active logical volumes
Команда lvdisplay выдаст более подробную информацию. Обратите внимание на новое месторасположение вроде /dev/test/lvm_usr, именно с ними придется работать в дальнейшем. Следующим шагом будет создание файловых систем на логических томах. Это делается обычным образом, как и для обычного дискового раздела, при этом может быть выбрана любая из поддерживаемых современным ядром файловых систем. Например, создадим ReiserFS: # È # #
/sbin/mkfs.reiserfs /dev/test/lvm_home ìîíòèðóåì â âûáðàííîå ìåñòî. mkdir /home/test mount -t reiserfs /dev/test/lvm_home /home/test
# df /dev/hda3 4032124 2789108 1038188 ... /dev/test/lvm_home 1048540 32840 1015700
73% / 4% /home/test
Для автоматического монтирования раздела при загрузке системы в /etc/fstab добавляем следующие строки:
администрирование /dev/test/lvm_home /home/test
reiserfs
defaults 0 0
Чтобы система при загрузке могла обнаружить LVM, необходимо, чтобы в стартовых скриптах присутствовали две команды (для различных дистрибутивов примеры смотрите в HOWTO). /sbin/vgscan /sbin/vgchange -ay
В RedHat 9 в /etc/rc.d/rc.sysinit все это прописано такими строками: # LVM initialization if [ -f /etc/lvmtab -a ! -e /proc/lvm ] ; then modprobe lvm-mod >/dev/null 2>&1 fi if [ -e /proc/lvm -a -x /sbin/vgchange -a -f /etc/lvmtab ]; then action $"Setting up Logical Volume Management:" ↵ /sbin/vgscan && /sbin/vgchange -ay fi
И для размонтирования при остановке системы должна выполниться команда (/etc/rc.d/init.d/halt):
В командах это выглядит так: # umount /dev/test/lvm_home # resize_reiserfs -s -1.5G /dev/test/lvm_home # lvreduce -L -1G /dev/test/lvm_home # resize_reiserfs -f /dev/test/lvm_home
При работе с ext2 используется – resize2fs, XFS – xfs_growfs (но пока она урезаться не может). И хотелось бы сказать ещё об одной возможности LVM, названной snapshots, которая позволяет администратору создавать новое блочное устройство, в которое копируется логический том в «замороженном» на этот момент состоянии. Этот режим позволяет производить резервное копирование без закрытия приложений. Фактически теперь можно производить резервное копирование при любой нагрузке. По окончании процесса копирования администратор должен удалить snapshots. Создается snapshots командой lvcreate с ключом -s и с указанием размера, имени и логического тома, состояние которого необходимо заморозить. # lvcreate -L592M -s -n home_backup /dev/test/lvm_home lvcreate -- WARNING: the snapshot must be disabled ↵ if it gets full
/sbin/vgchange -an
lvcreate -- INFO: using default snapshot chunk size of 64 KB ↵ for "/dev/test/home_backup "
Изменение размеров раздела
lvcreate -- doing automatic backup of "test "
Теперь давайте попробуем изменить размер раздела. ReiserFS можно при этом не размонтировать. Для изменения размера логического тома используется команда lvextend, в качестве параметров принимающая новый размер или число (положительное или отрицательное), на которое необходимо изменить раздел: # /sbin/lvextend -L +1G /dev/test/lvm_home lvextend -- extending logical volume ↵ "/dev/test/lvm_home" to 2 GB lvextend -- doing automatic backup of volume group "test" lvextend -- logical volume "/dev/test/lvm_home" ↵ successfully extended
lvcreate -- logical volume "/dev/test/home_backup" ↵ successfully created
В результате образуется ещё один логический том с именем /dev/test/home_backup. Его можно смонтировать и посмотреть, что там есть. # mkdir /mnt/snapshots # mount /dev/test/home_backup /mnt/snapshots mount: block device /dev/ops/dbbackup is write-protected, ↵ mounting read-only
Всё, теперь архивируем данные и удаляем snapshots. Теперь при помощи resize_reiserfs изменяем раздел самой файловой системы: # /sbin/resize_reiserfs -f /dev/test/lvm_home
Проверяем: # df dev/hda3
4032124 2789108 1038188
73% /
... /dev/test/lvm_home 2097084 32840
2064244
2% /home/test
Как видите, размер получился в два раза больший. Уменьшение раздела производится в таком порядке: размонтируем файловую систему; уменьшаем файловую систему с запасом; уменьшаем размер логического тома при помощи lvreduce; расширяем файловую систему до заполнения всего тома.
№10(11), октябрь 2003
# umount /dev/test/home_backup # lvremove /dev/test/home_backup
Теперь при подключении к системе новых дисков на них можно создавать свои логические тома или присоединять их к существующим, копировать, перемещать импортировать имеющиеся на другой диск, в общем, полная свобода действий. Вот такая технология LVM, удобная, простая и в то же время позволяющая гибко управлять своими файловыми системами. Дополнительную информацию, кроме вышеназванного HOWTO, можно получить в статьях Дэниеля Роббинсона (Daniel Robbins) – одного из создателей дистрибутива Gentoo Linux в Learning Linux LWM, Part 1 и Part 2: http://www-106.ibm.com/developerworks/linux/library/l-lvm/ Как разместить корневую файловую систему на LVM, можно узнать по адресу: http://www.the-infinite.org/archive/ docs/lvm/howto-boot-off-root-lv.txt И в man-страницах, конечно же.
9
администрирование
10
администрирование Преамбула Данный материал – не сравнительный обзор протоколов работы с почтой, а практические рекомендации по установке IMAP-сервера (Internet Message Access Protocol) для тех, кто уже определился, что именно это ему необходимо. Тем, кто еще не определился с выбором, рекомендую почитать http://www.imap.org/imap.vs.pop.brief.html. В результате описанных в этой статье действий мы должны получить работоспособный IMAP4-сервис, при работе с которым поддерживаются защищенные методы авторизации, почта хранится и сортируется на сервере, не нужно заводить реальных почтовых пользователей в системе. Дополнительно настроим веб-интерфейс к системе фильтрации почты на сервере. Использовавшаяся в процессе подготовки материала операционная система – Slackware Linux 9.0, MTA – sendmail 8.12.9, MUA – sylpheed 0.9.4. Везде, где в тексте встречается your.hostname.domain – заменять на реальное имя вашего сервера.
Подготовительные работы
Обновляем openssl и sendmail до актуального состояния. Скачиваем:
cyrus-imapd-2.1.15.tar.gz (http://asg.web.cmu.edu/ cyrus/) cyrus-sasl-2.1.15.tar.gz (http://asg.web.cmu.edu/sasl/) php-4.3.2.tar.gz (http://www.php.net/) apache-1.3.28.tar.gz (http://httpd.apache.org/) imap-2002d.tar.Z (http://www.washington.edu/imap/) libmcrypt-2.5.7.tar.gz (http://mcrypt.hellug.gr/) smartsieve-i18n-ru.tar.gz (http://diesel.tomsk.ru/linux/ files/smartsieve-i18n-ru.tar.gz) Заводим пользователя cyrus (группа mail, домашний каталог /var/imap)
Сборка cyrus-sasl SASL (Simple Authentication and Security Layer) – это набор утилит и библиотек, необходимых для авторизации пользователей. В документации по cyrus-sasl рекомендуется отключить все неиспользуемые механизмы авторизации, я решил оставить только digest-md5, cram-md5, plain, anonymous. # tar zxvf ./cyrus-sasl-2.1.15.tar.gz # cd cyrus-sasl-2.1.15 # ./configure --disable-otp --disable-krb4 --disable-gssapi ↵ --without-pam # make # make install # ln -s /usr/local/lib/sasl2 /usr/lib/sasl2 # ldconfig
Заводим базу пользователей. Добавляем пользователя (подобным образом нужно будет добавить всех почтовых пользователей):
# chown cyrus.mail /etc/sasldb2
Примечание: как уже говорилось ранее, почтовые пользователи не пересекаются с системными.
Сборка cyrus-imapd Теперь соберем непосредственно IMAP-сервер. Здесь все просто: # # # # #
tar zxvf ./cyrus-imapd-2.1.15.tar.gz cd cyrus-imapd-2.1.15 ./configure make make install
Примечание: по умолчанию при обработке писем, в заголовках которых содержатся 8-битные символы (это противоречит RFC), заменяет их символами «X». Если вы хотите, чтобы такие письма проходили без модификации – можете перед сборкой внести соответствующие изменения в файлах imap/message.c и imap/lmtpengine.c (закомментировав строки 270 и 860 соответственно). Но, вообще-то, это нужно только в специфических случаях и лучше оставить все как есть, чтобы не противоречить стандарту.
Настраиваем cyrus-imapd Для того чтобы в случае неполадок облегчить поиск проблемы, включаем журналирование посредством syslog. Добавляем в /etc/syslog.conf следующее: local6.debug auth.debug
/var/log/imapd.log /var/log/auth.log
Перезапускаем syslogd: # killall -1 syslogd
Создаем /etc/imapd.conf: # touch /etc/imapd.conf
Его содержимое: configdirectory: /var/imap partition-default: /var/spool/imap sievedir: /var/spool/sieve admins: cyradmin sasl_pwcheck_method: auxprop sasl_auxprop_plugin: sasldb sasl_mech_list: CRAM-MD5 PLAIN tls_cert_file: /var/imap/server.pem tls_key_file: /var/imap/server.pem
Подробнее о возможных используемых опциях можно посмотреть в соответствующей man-странице: # man imapd.conf
Создаем каталоги и выставляем на них права: # saslpasswd2 -c cyradmin
Указываем пароль, после этого у нас должен получиться файл /etc/sasldb2 (это и есть база паролей для авторизации):
№10(11), октябрь 2003
# # # # # #
mkdir chmod mkdir chmod mkdir chmod
/var/imap 750 /var/imap /var/spool/imap 750 /var/spool/imap /var/spool/sieve 750 /var/spool/sieve
11
администрирование Создаем структуру остальных каталогов (в документации к cyrus-imapd сказано, что надо сделать «su cyrus» и только потом выполнять следующие действия, но я устанавливал из-под рута и потом просто раздал права доступа):
M4=`sh $BUILDTOOLS/bin/find_m4.sh`
на M4=/usr/bin/m4
# # # # #
cd cyrus-imapd-2.1.15/tools ./mkimap chown -R cyrus.mail /var/imap chown -R cyrus.mail /var/spool/imap chown -R cyrus.mail /var/spool/sieve
Примечание: если у вас файловая система ext2 на том разделе, где будут размещаться базы, то почитайте оригинальную документацию к cyrus-imapd. Если у вас прописаны в (x)inetd.conf сервисы pop3, imap, pop3s, kpop, lmtp, sieve – закомментируйте их и перезапустите (x)inetd. В /etc/services прописываем (если там нет этих записей): pop3 imap imsp acap imaps pop3s kpop sieve lmtp fud
110/tcp 143/tcp 406/tcp 674/tcp 993/tcp 995/tcp 1109/tcp 2000/tcp 2003/tcp 4201/udp
Из каталога master/conf берем конфигурационный файл: # cp master/conf/normal.conf /etc/cyrus.conf
Пробуем вручную запустить процесс master:
Примечание: если вы устанавливаете imapd таким образом, что сокет для работы с почтой находится в отличном от /var/imap/socket/lmtp месте, то необходимо будет исправить путь в файлике cyrusv2.m4 (по умолчанию в slackware его можно найти в /usr/share/sendmail/ cf/mailer). Если у вас sendmail версии 8.12.8 и ниже – загляните в документацию к cyrus-imapd, но я бы посоветовал обновить sendmail. Собираем новый sendmail.cf: # ./Build current.cf # cp ./current.cf /etc/mail/sendmail.cf
Добавляем запуск /usr/cyrus/bin/master в стартовые скрипты (например, в /etc/rc.d/rc.init2) и перезагружаемся.
Проверяем работоспособность Воспользуемся утилитой imtest: # /usr/local/bin/imtest -m cram-md5 ↵ -a cyradmin your.hostname.domain
Вводим пароль, если нам отвечают A01 OK, то все нормально, если ругаются – идем в /var/log курить логи до просветления.
# /usr/cyrus/bin/master &
Создаем почтовые ящики Генерируем сертификаты (в процессе нужно будет заполнить несколько полей информацией об организации): # openssl req -new -x509 -nodes -out /var/imap/server.pem ↵ -keyout /var/imap/server.pem -days 365 # chown cyrus.mail /var/imap/server.pem
Вышеприведенной командой мы создали X.509 сертификат, действительный 1 год (эта строчка для генерации есть в документации к cyrus-imapd). За более подробной информацией по поводу сертификатов и openssl, в общем, можно сходить на http:// www.openssl.org/ в раздел документации, правда, там зачастую можно встретить надписи [STILL INCOMPLETE].
Настраиваем sendmail Нам понадобится пакет sendmail-cf, если вы ставили sendmail из пакета (package) в slackware. Создаем наш mc-файл конфигурации sendmail: # cd /usr/share/sendmail/cf/cf # cp ./linux.smtp.mc ./current.mc
Добавляем туда строчки: define(`confLOCAL_MAILER', `cyrusv2')dnl MAILER(`cyrusv2')dnl
Если вы ставили sendmail-cf из пакета, то в скрипте Build надо заменить строчку:
12
Для управления почтовыми ящиками в комплекте с cyrusimapd идет утилита cyradm. После инсталляции для запуска cyradm мне пришлось скопировать часть библиотек, которые поставились не совсем корректно (при сборке cyrus-imapd с --prefix=/usr такой проблемы не будет): # cp -R /usr/local/lib/perl5 /usr/lib/
Типовая процедура создания нового почтового аккаунта: # saslpasswd2 -c dummyuser # cyradm --user cyradmin --server your.hostname.domain
В cyradm создаем почтовый ящик для пользователя и устанавливаем квоту в 20 Мб: your.hostname> cm user.dummyuser your.hostname> sq user.dummyuser 20480
Все, теперь настраиваем клиентскую часть и проверяем, что у нас получилось. В качестве клиента я использовал sylpheed, собранный с поддержкой SSL (configure --enable-ssl).
Настраиваем sieve Sieve – язык, на котором пишутся почтовые фильтры в cyrus-imapd.
администрирование Проверяем работоспособность сервера sieve (timsieved):
Затем пробуем скомпилировать c-client с выбранной опцией:
# telnet your.hostname.domain sieve # make slx
Если отвечают «IMPLEMENTATION» «Cyrus timsieved v2.1.15» ... OK, то все в порядке. Пишем на sieve скрипт для разбора почты (приведу здесь несколько типовых действий, дальше должно быть понятно): require ["reject","fileinto"]; # íå ïðèíèìàåì ïî÷òó è âûñûëàåì ñîîáùåíèå îá îòêàçå: if address :is :all "From" "annoying@badnet.domain" { reject "Äîñòàëè"; } # ôèëüòðóåì ïî subject êîðïîðàòèâíûé ñïèñîê ðàññûëêè: if header :contains "Subject" "corporate mailing" { fileinto "INBOX.lists.corporate"; } # åùå îäèí ñïèñîê ðàññûëêè: if header :is "List-Id" ↵ "<bugtraq.list-id.securityfocus.com>;" { fileinto "INBOX.lists.bugtraq"; } # à ýòî âîîáùå ñòðàííûå ïèñüìà - àäðåñîâàíû íå íàì: if anyof ( not address :all :contains ["To", "Cc", "Bcc"] ↵ "myname@myaddress.domain" ) { fileinto "INBOX.bad"; }
Сохраняем этот скрипт в файлик test.script. Подключаемся к серверу sieve, загружаем и активируем скрипт: # > > >
sieveshell -u cyradmin your.hostname.domain put test.script activate test quit
Как показывает практика, обычно с разбега сборка не удастся из-за различий в расположении файлов – придется немного поработать вместо configure, подбирая эти опции вручную. Можно либо править Makefile, либо указывать опции при запуске make. Для моей системы команда сборки выглядела следующим образом: # make slx EXTRASPECIALS="SSLINCLUDE=/usr/include/openssl ↵ SSLLIB=/usr/lib"
При возникновении проблем помогает вдумчивое прочтение Makefile. Итак, компиляция успешно завершена, теперь следующий этап – инсталляция скомпилированного (да, не удивляйтесь, make install не сработает – авторы решили выдержать все в одном стиле и не написали такой цели в Makefile, так что опять будем делать все вручную). Создаем каталог /usr/local/imap-2002d и подкаталоги /usr/local/imap-2002d/include и /usr/local/imap-2002d/lib. Из подкаталога c-client копируем все *.h-файлы в include, все *.c в lib. В том же каталоге находим файл c-client.a и копируем его в lib, переименовывая в libc-client.a. На этом с установкой c-client покончено, лично я в процессе инсталляции не раз помянул недобрым словом разработчиков за такое жестокое отношение к пользователям.
Устанавливаем веб-сервер Если все сделано правильно, то на этом все, мы получили разбор почты по каталогам на сервере. Если такая система управления фильтрацией вас устраивает, дальше можно не читать. Далее рассматривается прикручивание веб-интерфейса к sieve для того, чтобы пользоваться возможностями sieve могли и простые пользователи.
Устанавливаем библиотеку c-client Для того чтобы впоследствии скомпилировать PHP с поддержкой imap, необходимо установить бибилиотеку c-client. Инструкции по сборке я нашел на www.php.net, поискав по сайту с ключевым словом «imap». Скачиваем тарбол, распаковываем его, смотрим внутрь – а там нас поджидает веселый сюрприз в качестве одного Makefile. Авторы сего пакета, по всей видимости, не подозревают о существовании таких благ цивилизации, как autoconf и иже с ним, поэтому configure скрипта внутри нет, вместо него эксплуатируются мозги администратора. Просматриваем содержимое Makefile, среди комментариев ищем наиболее подходящее вашей системе описание, например, это «slx» («Linux using -lcrypt to get the crypt() function»).
№10(11), октябрь 2003
Предварительно собираем libmcrypt (тут все тривиально): # # # # # #
tar zxvf ./libmcrypt-2.5.7.tar.gz cd libmcrypt-2.5.7 ./configure make make install ldconfig
Установка и настройка Apache+PHP – очень обширная тема, я ограничусь лишь минимальным количеством разъяснений, которого должно хватить для достижения наших целей. Распаковываем apache, запускаем скрипт configure без каких-либо параметров. Распаковываем php (в том же каталоге, где развернули apache), собираем: # ./configure --with-imap=/usr/local/imap-2002d ↵ --with-imap-ssl=/usr/include/openssl ↵ --with-apache=./../apache_1.3.28 ↵ --with-mcrypt=/usr/local --with-iconv # make # make install
Пути к файлам могут изменяться на разных машинах, поэтому, если сборка не удалась, – проверьте пути (в частности, каталог с исходниками apache может называться по-иному).
13
администрирование Копируем файлик php.ini-recommended в /usr/local/lib/ php.ini. Если php успешно собралось и заинсталлировалось, возвращаемся в каталог с apache: # ./configure --activate-module=src/modules/php4/libphp4.a # make # make install
Если все собралось, идем в каталог, куда заинсталлировался apache (по умолчанию – /usr/local/apache), в каталоге bin запускаем веб-сервер командой: # ./apachectl start
Проверяем работоспособность сервера: # lynx http://your.hostname.domain/
Либо просто любым браузером обращаемся по адресу нашего сервера. Если видим ободряющую надпись «If you can see this, it means that the installation of the Apache web server software on this system was successful», значит – все нормально, иначе перечитываем вышенаписанное и идем читать документацию по php и apache до тех пор, пока не наступит счастье.
Устанавливаем SmartSieve В принципе можно удовлетвориться взаимодействием с sieve-сервером посредством sieveshell, но с точки зрения рядового пользователя такой метод управления почтой вряд ли можно назвать удобным. Альтернативой может послужить использование SmartSieve (http://smartsieve.sourceforge.net/) – это написанный на PHP менеджер sieve-скриптов, позволяющий черз вебинтерфейс управлять правилами сортировки почты.
14
Изначально я скачал с официального сайта smartsievei18n версии 0.5.1, однако при его использовании столкнулся с проблемой работы с русскими именами каталогов в почтовом ящике. Решив, что транслит и другие компромиссы – это не наш метод, пропатчил это дело, заодно написав русскую версию. Русифицированную версию smartsieve можно скачать по адресу: http://diesel.tomsk.ru/linux/files/smartsieve-i18n-ru.tar.gz. Вся процедура установки сводится к распаковке тарбола и копированию содержимого в структуру каталогов, являющуюся структурой http-корня веб-сервера. По умолчанию опция DocumentRoot равна «/usr/local/ apache/htdocs». Уточнить ее значение можно в основном конфигурационном файле apache – httpd.conf (по умолчанию он находится в /usr/local/apache/conf). Допустим, мы скопировали файлы smartsieve в /usr/ local/apache/htdocs/smartsieve. Проверяем работоспособность, открывая в браузере страницу http://your.hostname.domain/smartsieve/ Логинимся под именем одного из заведенных пользователей, пробуем создавать правила (при входе в форме выбираем русский язык для корректной работы с русскоязычными каталогами). Небольшое примечание: smartsieve может не работать с sieve-скриптами, написанными вами вручную, а не с его помощью.
Заключение Если вы дошли до этого места и у вас все работает, значит, мы достигли поставленной вначале цели. При написании были активно использованы оригинальная документация к cyrus-imapd и поисковый сервер google. Отдельное спасибо Антону Жаровцеву (aka warm) за консультации.
Уважаемые господа! Компания «ITE LLC» (Москва), при содействии ITE Group Plc (Великобритания) предлагает Вашему вниманию
НЕДЕЛЮ ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ «IT-WEEK 2004» Москва, Экспоцентр на Красной Пресне 26 – 29 апреля 2004 года Неделя Информационных Технологий «IT-Week 2004» это: Крупнейший в России и странах СНГ форум в отрасли Информационных Технологий Пять международных IT-выставок, проводимых в одно время и в одном месте Две международные конференции Более 250 компаний-участников из 25 стран мира Свыше 75 000 посетителей из более чем 500 городов России и СНГ 35 000 специалистов IT-индустрии в деловой части выставки Официальная поддержка Министерства РФ по связи и информатизации, Министерства промышленности, науки и технологий РФ, Министерства экономического развития и торговли РФ, Министерства образования РФ, а также Правительства Москвы В рамках «IT-Week 2004» пройдут следующие выставки и конференции: 1. Personal Computing Expo – общая, неспециализированная выставка, ориентированная на конечных пользователей. В ней представлены производители и дистрибьюторы персональных компьютеров и периферии, компьютерных игр, дистрибьюторы сотовой техники и портативных компьютеров, интернет- и контентпровайдеры и многие другие. 2. Hardware & Peripherals Expo – специализированная выставка, на которой представлены: компьютеры, мониторы, периферийные устройства, комплектующие, накопители, коммуникационное оборудование и услуги, т.е. весь спектр hardware, ориентированного на ведение бизнеса. 3. Software Expo – специализированная выставка, ориентированная на программные продукты для систем бухгалтерского и складского учета, комплексного ПО управления предприятием, систем управления документооборотом, систем распознавания документов, разработку ПО, защиту информации. В рамках этой выставки будет подготовлен цикл тематических семинаров, посвященных актуальным вопросам в области разработки экономических программ и систем управления бизнесом.
№10(11), октябрь 2003
4. Специализированная выставка CAD/CAM/CAE представляет системы автоматизированного проектирования. Для большинства российских производителей необходимость использования САПР для оптимизации работы предприятия стала очевидной. Особенно ярко это проявляется в таких отраслях, как авиастроение, автомобилестроение, тяжелое машиностроение, архитектура, строительство, нефтегазовая промышленность. 5. eLearn Expo – специализированная выставка, на которой будут демонстрироваться новейшие продукты и технологии в сфере электронного обучения, предназначенные для коллективного и индивидуального пользования. Дистанционное обучение через сети Internet и Intranet, получившее широкое распространение в развитых странах, становится все более актуальным и для России. 6. eBusiness Russia (Электронный бизнес в России) – международная конференции, посвященная вопросам автоматизации бизнес-процессов, развития электронной коммерции, подбора ИТ-персонала. 7. Международная конференция eLearning Russia (Информационные технологии в образовании), на которой будут освещены последние достижения образовательных технологий в школах, вузах, а также рассмотрены вопросы дистанционного и бизнес-образования. Рекламная кампания по привлечению посетителей на IT-Week основана на многолетнем опыте проведения выставок, тщательном анализе данных маркетинговых исследований и четком выделении целевой аудитории. Посещение специализированных выставок Hardware & Peripherals Expo, Software Expo, CAD/CAM/CAE, eLearn Expo, составляющих деловую часть Недели Информационных Технологий, возможно только для корпоративных бизнес-посетителей, прошедших регистрацию. Это позволяет качественно изменить состав посетителей этой части и дает возможность участникам в деловой обстановке представить свою продукцию и услуги заинтересованным специалистам и партнерам по бизнесу. Практически полностью аудитория деловой части IT-Week представлена менеджерами высшего и среднего звена, техническими специалистами и системными администраторами. Тел.: +7 (095) 935 7350, 935 8120 eMail: it-week@ite-expo.ru
15
администрирование
НАСТРАИВАЕМ ASPLINUX 7.3 SERVER EDITION
АЛЕКСАНДР ШИБЕНКО 16
администрирование Желание познакомиться с каким-либо из отечественных дистрибутивов Linux зрело у меня уже довольно давно, а тут еще приятель похвастался, что раздобыл ASPLinux 7.3 Server Edition. Поэтому когда знакомые попросили помочь им с установкой и настройкой сервера для подключения локальной сети к Интернету и хранения общих файлов, особых сомнений не возникло. Нехорошо, конечно, ставить эксперименты на пользователях, но соблазн был велик. Поэтому первый из двух входящих в комплект CDдисков был помещен на подставку для кофе, и инсталляция началась. Размечать жесткий диск оказалось даже приятно. Графическая утилита позволяет легко и наглядно выбирать тип и размер файловой системы, а также задавать точку монтирования. Еще порадовало, что система без проблем распознала наличие на материнской плате 815-го чипсета и интегрированной видеокарты. Правда, установить для монитора режим 800х600 с частотой 85 Гц не удалось, пришлось ограничиться 60 Гц. Но на фоне воспоминаний о том, что выводилось на экран после установки RedHat 6.2 на компьютер с 810-м чипсетом, с этим легко можно было смириться. Также без проблем сами установились драйверы для сетевых карт Compex и Davicom, причем о существовании второй фирмы-изготовителя я до этого момента даже не слышал. Затем из предложенного списка, где среди прочих фигурировал пункт «сервер для работы с 1С» я выбрал «сервер для рабочей группы», потом наставил галочек против интересующих меня пакетов, согласился с предложением доставить неотмеченные, но необходимые для работы выделенных, компоненты, понаблюдал за их копированием и с удивлением понял, что процесс инсталляции в целом занял совсем немного времени. Единственное, что не удалось сделать – создать загрузочную дискету. После нескольких попыток, заканчивающихся сообщением об ошибке, было решено сделать это позднее. Пришло время для более интересного занятия – собственно настройки системы. Если помните, необходимо было обеспечить подключение локальной сети к Интернету. Причем дело не ограничивалось только доступом к ресурсам веб-серверов. Нужны были и ftp-клиент, и работа с почтой по протоколу POP3. Поэтому разумным показалось воспользоваться трансляцией адресов (Network address translation, NAT). ASPLinux 7.3 Server Edition базируется на ядре версии 2.4.18 и это значит, что соответствующие настройки нужно производить с помощью утилиты iptables, входящей в дистрибутив. В нашем случае выглядит это следующим образом: iptables -t nat –A POSTROUTING –s 192.168.100.0/24 ↵ –d 0/0 –j SNAT --to-source 207.46.249.27
Т.е. все адреса из частной сети 192.168.100.0 будут транслироваться в единственный реальный адрес 207.46.249.27. Но это не все. Созданные подобным образом правила сохраняются только в оперативной памяти и в случае перезагрузки сервера оказываются утерянными. Первое, что приходит в голову, – написать собственный сценарий и обеспечить его запуск во время старта системы, к примеру, поместив его (или ссылку на него) в
№10(11), октябрь 2003
каталог /etc/rc.d/rc3.d/. А заодно и в /etc/rc.d/rc5.d/. И в этом же сценарии разрешить, что тоже необходимо, перенаправление пакетов на другой сетевой интерфейс командой: echo 1 > /proc/sys/net/ipv4/ip_forward
Примерно так я и сделал. Все заработало, но не покидало ощущение неправильности или, точнее, неизящности такого подхода. Пришлось подробнее ознакомиться с описанием iptables, где, среди прочего, упоминались два сценария: iptables-save и iptables-restore. Причем последний вызывался в сценарии /etc/rc.d/init.d/iptables. Как говорится в детской игре, стало «теплее». Последовало прочтение еще пары-тройки руководств – и все встало на свои места. Действительно, при старте системы скрипт /etc/ rc.d/init.d/iptables пытается считать файл /etc/sysconfig/ iptables и применить сохраненные в нем правила. Ровно то, что и требовалось. Осталось только сформировать этот самый /etc/sysconfig/iptables. Но запущенный без параметров iptables-save почему-то этот файл не создал и пришлось сделать это принудительно: service iptables save
Осталось разрешить перенаправление пакетов. Здесь решение возникло в процессе просмотра log-файлов запуска и останова системы. Бросилось в глаза, что в них присутствует строка, содержащая примерно следующее: «sysctl: net.ipv4.ip_forward = 0». Т.е. при останове системы задача, обратная нашей, решается с помощью вызова команды sysctl, которая считывает предопределенные настройки из файла /etc/sysctl.conf. Исправляем в нем net.ipv4.ip_forward = 0 на net.ipv4.ip_forward = 1 и можно двигаться дальше. Задача номер два – организация доступа к совместно используемым файлам и подключенному к серверу принтеру решается без дополнительной установки каких-либо программ, необходимый пакет Samba версии 2.2.7 также входит в дистрибутив. Можно было бы, конечно, попробовать и 3-ю версию, но в мои планы на данном этапе это не входило. О том, как с помощью Samba реализовать доступ к файлам и эмуляцию контроллера домена, написано много. Да и проблем на этом этапе практически не возникло. А вот с чем реально пришлось побороться – так это с печатью. В «Руководстве пользователя» предлагается использовать для ее настройки графическую утилиту PrintTool. Однако если не устанавливать поддержку X Window System (а так ли нужны они на сервере?), воспользоваться ей, естественно, не удастся. Поэтому опишу, как выглядел процесс при использовании только текстовой консоли. Согласно большинству источников процедура настройки печати заключается в следующем. Сначала проверяется наличие в секции [printers] файла smb.conf параметра вида: path = /var/spool/samba
17
администрирование Если его нет, нужно добавить. Кроме того, необходимо вставить в файл /etc/printcap следующие строки:
командой chkconfig. Для этого останавливаем Samba: service smb restart
lp|hp:\ :sd=/var/spool/samba:\ :mx#0:\ :sh:\
затем выполняем: chkconfig --add smb
Проделав это и перезапустив с помощью расположенных в /etc/rc.d/init.d/ сценариев lpd и smb, я вместо распечатки тестовой страницы печати Windows c клиентского ПК получил следующее. Сценарий lpd выдал предупреждение о несоответствии прав на каталог /var/spool/samba и о том, что в системе отсутствуют принтеры. И действительно, файл /etc/printcap оказался пустым. А у каталога /var/spool/samba изменились владелец и права доступа. Пришлось смотреть, что же делает /etc/rc.d/init.d/lpd. Что происходит с файлом printcap, стало понятно достаточно быстро. Оказалось, что разработчики сценария теперь предложили хранить описания установленных принтеров в файле /etc/printcap.local, а в /etc/printcap просто переписывается его содержимое. А с правами все оказалось несколько сложнее. До конца разобраться в происходящем так и не удалось, но работоспособное решение появилось. Вот оно. В /etc/samba/smb.conf оставляем: path = /var/spool/samba
Создаем файл /etc/printcap.local следующего содержания: lp|hp:\ :sd=/var/spool/samba/hp:\ :mx#0:\ :sh:\
На каталог /var/spool/samba устанавливаем права 1777. Затем создаем каталог /var/spool/samba/hp с правами по умолчанию. После чего перезапускаем /etc/rc.d/init.d/lpd restart. Появится предупреждение о несоответствии прав на каталог /var/spool/samba/hp и они изменятся на 700, а владельцем каталога станет пользователь lp. Теперь печать должна заработать. Дело осталось за малым – обеспечить запуск и остановку Samba. Ранее уже упоминался выполняющий эту процедуру сценарий /etc/rc.d/ini.d/smb. Можно было бы, как и на начальном этапе настройки iptables, создать на него ссылки в соответствующих каталогах, но нашелся более простой, на мой взгляд, способ – воспользоваться
18
Но у меня так не получилось. Скорее всего дело в том, что для smb в chkconfig не прописаны уровни (run level) системы, для которых этот сервис должен выполняться. Поэтому пришлось сделать это следующим образом: chkconfig
--level 345 smb on
после чего выполнить проверку и снова запустить Samba: chkconfig --list smb service smb restart
Теперь осталось завести пользователей для Linux (а сделать это можно было еще на этапе инсталляции) и Samba, и сервер готов к работе. Правда, по-хорошему необходимо еще дополнительно позаниматься обеспечением его безопасности, да и ядро не мешает пересобрать, но это уже другие темы. В заключение хотелось бы поделиться еще одним соображением. При установке сервера я оставил на нем предлагаемую по умолчанию поддержку русского языка и столкнулся со следующим неудобством, характерным, пожалуй, практически для всех локализованных продуктов, но по-разному проявляющимся. Речь идет о диагностических сообщениях и предупреждениях об ошибках. Если при работе с русифицированной версией какой-либо ОС из семейства Windows весьма сложно бывает понять, о чем идет речь в выводимых системой сообщениях (и тем более невозможно в том же англоязычном TechNet провести контекстный поиск), то в моем случае выводимые по-русски, но в кодировке KOI-8R, сообщения на клиентских компьютерах оказались просто нечитабельными. В связи с этим есть предложение к разработчикам, занимающимся локализацией продуктов. Если это возможно, кроме перевода, оставляйте в системных сообщениях их оригинальное написание. Тем самым вы существенно облегчите жизнь многим системным администраторам. Автор выражает большую благодарность порталу SysAdmins.RU и лично Липовцеву Алексею за участие в написании этой статьи.
администрирование
КАК БОРОТЬСЯ С БАННЕРАМИ В ICQ? ДМИТРИЙ РЕПИН Патчи для ICQ, обрезающие баннеры – вещь полезная. Однако имея «на борту» сотню-другую пользователей, трудно заставить себя или эникейщика всем пропатчить ICQ. И эникейщика жалко, и себя жалко, и в то же время трафик жалко. Да и вообще, баннеры раздражают как явление. Требуется массовое решение проблемы одним ударом. И такое решение есть! Запускаем на шлюзе: tcpdump -li xl0 -w - src host ÍÀØ_IP |strings
и открываем аськино окошко ввода мессаджа (то, которое с баннером). И тут tcpdump вдруг показывает строчки вида: GET /client/ate/ad-handler/ad_468/0,,93169~
Теперь открываем конфиг сквида и добавляем следующие строчки: acl ICQban urlpath_regex /client/ate/ad-handler http_access deny ICQban
Реконфигурим сквид и... нет баннеров, но есть некрасивый html про ошибку в поле для баннера. Это не понашему! Убираем две вышеобозначенные строки из squid.conf и переходим к конфигурации SquidGuard (если кто не в курсе, то http://onix.opennet.ru ). В директории баз SquidGuard создадим директорию icq, а в ней – файл expressions, в котором напишем строчку: (/client/ate/ad-handler)
Теперь в конфиге SquidGuard добавим такое правило: dest icq { expressionlist icq/expressions redirect http://ÍÀØ ÑÅÐÂÅÐ/squidGuard/noicq.html }
А в блок ACL добавим: pass ... !icq ...
ну а на сервер повесим файл /squidGuard/noicq.html, содержащий примерно следующее: STOP DA BANNERS!
=)))
№10(11), октябрь 2003
Теперь выставим пользователя: chown -R nobody /usr/local/squid/db/squidGuard
Можно перезапускать сквид: killall -HUP squid
и радоваться жизни. При обращении к серверу ICQ получает html вот такого формата: <!-- Vignette StoryServer 5.0 Sun Jul 13 03:58:25 2003 --> <html> <head> <title>Welcome to ICQ 2000a </title> </head> <!-- "ICQWidth=234" "ICQHeight=65" --> <body bgcolor="white"> <!-- Ate Windows options --> <table width="100%" border="0"> <tr> <td align="CENTER" valign="MIDDLE"> <!-- Icons and Banner --> <a X-PASSCOOKIES href="http://ar.atwola.com/link/93169516/ ↵ %RAND%/aol/" target="_new"><img ↵ src="http://ar.atwola.com/image/93169516/%RAND%/aol/ ↵ " width="468" height="60" border="0"></a> <!-- /// Icons and Banner --> </table> </body> </html>
Теперь мы несколько изменим данный текст и запишем его в нашем файле noicq.html: <!-- Vignette StoryServer 5.0 Sun Jul 13 03:58:25 2003 --> <html> <head> <title>Welcome to ICQ 2000a </title> </head> <!-- "ICQWidth=234" "ICQHeight=65" --> <body bgcolor="white"> <!-- Ate Windows options --> <table width="100%" border="0"> <tr> <td align="CENTER" valign="MIDDLE"> <!-- Icons and Banner --> <a X-PASSCOOKIES href="http://192.168.0.251/squidGuard/ ↵ NOBANNERS.html?%RAND%" target="_new"><img ↵ src="http://192.168.0.251/squidGuard ↵ /noicq.gif?%RAND%" width="468" height="60" border="0"></a> <!-- /// Icons and Banner --> </table> </body> </html>
Таким образом можно заменить картинку баннера своей и даже вставить свой линк. Материал предоставлен порталом SysAdmins.RU. http://portal.sysadmins.ru/board/viewtopic.php?t=20783
19
администрирование
МЕЧТА СИСАДМИНА
СЕРГЕЙ ЯРЕМЧУК 20
администрирование Одна из задач, которую постоянно приходится решать системному администратору, – учет работы пользователей в Интернете, фильтрация ненужного трафика для повышения безопасности и отсеивания ненужного содержания, распределение полосы между пользователями и плюс сбор отчетных данных о том, кто, где и сколько. Для админа со стажем это обычно не является трудной задачей, уже в распоряжении имеются собственноручно написанные скрипты, автоматизирующие эту рутинную работу, правда, постоянно меняющиеся данные, конечно, вносят некоторый ажиотаж, да и возни, особенно поначалу, бывает предостаточно, в общем, результирующий КПД оставляет желать лучшего. А вот для новичка в мире Unix это может стать большой проблемой. OC Linux можно критиковать за недружелюбие к начинающему пользователю, за плохую поддержку оборудования, но практически всегда можно найти дистрибутив, если не полностью подходящий под определенную задачу, то хотя бы частично ее решающий. Итак, знакомтесь: СensorNet (http:// www.intrago.co.uk/products/censornet.php). Дистрибутив, базирующийся на Debian, предназначен для организации доступа в Интернет, для управления и мониторинга пользователей к Интернету. Представляет собой OpenSource-альтернативу коммерческим и далеко не бесплатным продуктам вроде WebSense, SurfControl, I-Gear, N2H2 и прочим подобным проектам. Возможности, предоставляемые CensorNet: Фильтрация контента по URL, ключевым словам и фразам, расширениям файлов, типам MIME, изображениям и пр. Управление доступом на уровне пользователя (не фильтруется, фильтруется, не разрешает, приостановка или только по «белому» списку). Управление доступом на уровне компьютеров (разрешен, запрещен, приостановка). Интернет-доступ по расписанию для пользователей, групп и компьютеров. Возможность создания своих «белого» и «черного» списков и возможность ограничить пользователя, например, только ресурсами из разрешенного списка. Ограничение предельной полосы для пользователей, групп и машин. Детальный отчет по каждому пользователю. Изменение (allow, deny) доступа к веб-сайтам на «лету». Подтверждение подлинности при помощи NT PDC, Active Directory и Samba. Автоматическое определение компьютеров в локальной сети. Поддержка UPS. Интегрированный firewall с NAT и кеширующий веб-сервер. Простая инсталляция и настройка посредством удобного веб-интерфейса. Никаких ограничений по числу пользователей, компьютеров. Хорошая документация, понятная и новичку. И все это совершенно бесплатно.
№10(11), октябрь 2003
Опционально также возможен удаленный контроль работоспособности и создание RAID-1 SCSI и автоматическое обновление списка запрещенных сайтов. Но это уже не за бесплатно. Так, возможность пользоваться Black List Software Update (BLUD) стоит уже 150 у.е. на 12 месяцев. Хотя при желании некоторые опциональные функции и многое другое можно установить и настроить уже вручную. Давайте познакомимся поближе.
Получение дистрибутива и его установка Получить СensorNet можно двумя способами: купить CD-ROM и самому скачать с сервера. Как вы понимаете, второй вариант наиболее подходящий в наших условиях. Но сразу скачать не получится. Сначала необходимо зайти в раздел GPL Downlod и заполнить форму, указав рабочий e-mail, на который должна прийти ссылка на Download Centre. После чего вы получите два письма: одно вышепомянутое с сcылкой, а второе с благодарностью за интерес к дистрибутиву и пожеланиями наладить обратную связь с разработчиками для уточнения вопросов, связанных с дальнейшим совершенствованием СensorNet, и, естественно, разрешения трудных моментов, связанных с эксплуатацией. В разделе Download можно найти как сам дистрибутив, на момент написания статьи это была версия 3.1r6 размером 160 Мб, а также патчи и некоторые дополнения к предыдущим версиям, плюс старые стабильные версии дистрибутива и документация по всем вопросам, даже таким, как настройка Symantec Live Update с CensorNet. После закачки записываем ISO-образ на болванку, и можно загружаться. Для установки потребуется отдельный компьютер с двумя сетевыми картами и с жестким диском, подключенным к первому IDE Master, причем все данные на диске будут уничтожены, о чем и предупреждает (два раза) соответствующая надпись при инсталяции. Сама установка заключается в автоматической разбивке диска, форматировании разделов под файловую систему ext3 (всего создается два раздела корневой в начале диска и в конце swap) и распаковке на них одного большого архива с CD-ROM, после чего устанавливается загрузчик LILO. Вот в принципе и все. При желании все эти операции можно провести и вручную без разрушения данных на жестком диске, если есть необходимость сначала изучить работу на своем компьютере или просто добавить еще утилит в архив. На этом установка собственно и заканчивается, далее вынимаем выехавший CD-ROM и перезагружаемся уже нормально с жесткого диска. В ходе загрузки системы обратите внимание на диагностические сообщения о найденном оборудовании. Теперь для настройки системы воспользуемся утилитой, названной CensorNet Configuration Tool (CCT). Ее можно вызвать несколькими cпособами, и все они, естественно, требуют прав суперпользователя. При первом входе в систему регистрируемся как root и пароль root, который тут же необходимо сменить при помощи passwd. И для запуска CCT вводим команду setup. Навигация в CCT осуществляется при помощи стрелок, перемещение между
21
администрирование пунктами выбора Tab (Alt+Tab), пробелом включается/выключается нужная опция, и Enter завершает процесс выбора данного пункта. Теперь можно, выбрав соответствующий пункт (рис. 1):
Вкладка System Maintenance предназначена для сис-
Ðèñóíîê 1.
В System Locale Setting изменить клавиатурную рас
22
складку и временной пояс, последний влияет на отчеты, поэтому не игнорируйте данную опцию. В Network Configuration сконфигурировать сетевые устройства (установить драйвера для карт в автоматическом или, если не получится, ручном режиме, список всех поддерживаемых можно найти на сайте; ввести IP-адреса для каждой; значения IP-адресов для двух DNS-серверов и gateway; изменить сетевое имя компьютера – по умолчанию sensornet). В DHCP Service Configuration при необходимости включить и отконфигурировать DHCP-сервис (диапазоны разрешенных IP-адресов и время использования IPадреса компьютером (по умолчанию и максимальное)). В User Authentication Configuration выбрать метод аутентификации пользователя (Windows NT PDC, Windows 2000 Active Directory и Internal Sensornet – Samba, последний по умолчанию, но при наличии первых двух рекомендуется использовать именно их, да и для больших сетей samba метод будет неудобным), при этом при выборе нужного пункта активируются дополнительные поля для заполнения (пароль и имя пользователя, домен, резервный и основной PDC и пр.) В Web Cache Configuration настроить параметры вебкеша, если вы уже используете данный сервис и не желаете его перенастраивать, то достаточно выбрать пункт «Use Parent Cache» и указать необходимые параметры (hostname и порты), при выборе пункта «Use for ALL request» SensorNet будет кешировать все запросы, а во вкладке Advanced можно установить размер кеша. Настроить firewall. По умолчанию все входящие подключения заблокированы, кроме порта 22, предназначенного для удаленного администрирования по SSH, если не знаете, как работать с настройками firewall, то во вкладке Advanced можно отключить SSH или, наоборот, разрешить доступ всем извне (хотя это и не лучшая идея), но этот пункт может понадобиться, если уже имеется установленный и настроенный firewall.
темного обслуживания и, наверное, наиболее часто используемый пункт при эксплуатации SensorNet. Здесь можно просканировать сеть на обнаружение работающих компьютеров и присоединение их к SensorNet (Probe LAN for Windows Workstation), перечитать список пользователей в PDC или Windows 2000 (Retrieve User-list from Windows Domain Controller), очистить вебкеш (Flush the Squid Web Disk-Cache), при этом Squid перезапускается, а вся информация удаляется, перестроить внутреннюю базу данных (Rebuild Internal SensorNet Database), отключение пользователя admin, который нужен для удаленного администрирования (первоначальный пароль admin также нужно сменить) Reset Web Admin Area Access, в System Tuning можно синхронизировать диск, установить кратный вход (Multiple Login Sensitivity) для «кочующих» пользователей, установить максимальное количество пользователей (Set user access level cache size) и последними двумя пунктами можно остановить или перезагрузить SensorNet и выйти в shell. Для изменения пароля пользователям root, admin и вебадмин можно воспользоваться пунктом Change Password (рис. 2).
Ðèñóíîê 2.
При оплате сервиса BLUD его нужно активировать
в пункте B.L.U.D Configuration, после этого SensorNet будет автоматически его загружать в установленное время. Последний пункт APC UPS Setting позволит настроить параметры источника бесперебойного питания (если его нет на последовательном порту, то SensorNet каждый раз будет ругаться при загрузке), установив тип, подключение к порту, параметры автоматической остановки системы при разрядке батарей.
Дальнейшая работа После настройки всех необходимых параметров можно, предварительно выключив компьютер, отсоединить клавиатуру и монитор. Компьютер с установленным CensorNet устанавливается вместо маршрутизатора, т.е. между локальной сетью и провайдером (рис. 3). Всю дальнейшую настройку параметров можно производить при помощи SSH (Secure Shell) или CensorNet Administration Area утилиты удаленного веб-администрирования. Доступ к последней возможен только из внутренней сети. Для этого необходимо настроить веб-браузер для работы с proxy, некоторые рекомендации для различных веб-браузеров рассмотрены в документе
администрирование
Ðèñóíîê 3.
«browser_config_guide», который имеется на сайте. Для IE, например, выбираем «Сервис» → «Свойства обозревателя» вкладка «Подключение», нажимаем кнопку «Установить», далее выбираем подключение через локальную сеть – «Ручная настройка proxy-сервера» и в окне HTTP вводим IP-адрес CensorNet-сервера, порт 8080 и для остальных сервисов ставим галочку в пункте «Один прокси-сервер для всех протоколов» (рис. 4) (Tools -Internet Option → Сonection → LAN Settings → Use a Proxy Server → Advanced).
Ðèñóíîê 4.
№10(11), октябрь 2003
Теперь, набрав в строке браузера IP-адрес или имя компьютера CensorNet, попадаем в утилиту конфигурирования. Первоначально запрашивается логин и пароль. В целях безопасности входите в систему как root только при первоначальной настройке, далее при подключении через SSH регистрируйтесь как admin, а при работе через веб-интерфейс только как web_admin. В случае перехвата пароля вред, причиненный системе, будет меньше. Я надеюсь, что в дальнейшем можно будет использовать защищенное подключение при помощи https. Пользоваться CensorNet Administration Area особого труда не составит. Рабочее пространство состоит из нескольких вкладок (Home, Reports, Users, Workstations, Content Filter, Site Filters, Filetype Filters, Image Filter рис. 5-5с), если подвести мышкой к соответствующему пункту, то появляется выпадающее меню с пунктами для настройки параметров, при помощи которых и можно провести основные настройки, в том числе и создать резервную копию CensorNet или восстановить все нажатием одной кнопки. Все вопросы освещены довольно подробно в документе CensorNetv3-UserGuide. При необходимости защищенного соединения можно прямо отсюда при помощи Java-апплета вызвать SSH. На этом, пожалуй, знакомство с этим замечательным дистрибутивом и закончим. Как видите, СensorNet позволяет более продуктивно использовать ресурсы Интернета, существенно сокращать время, связанное с администрацией сети, и тем самым освобождает администратора для решения других насущных задач.
23
администрирование
Ðèñóíîê 5-5a.
24
администрирование
Ðèñóíîê 5b-5c.
№10(11), октябрь 2003
25
администрирование
SMTP AUTH IN DA POSTFIX + ...
АНДРЕЙ МОЗГОВОЙ 26
администрирование SMTP AUTH in da Postfix + Cyrus-SASL + Mysql + CourierIMAP + DrWeb + SquirrelMail + SpamAssassin. Как собрать все это «хозяйство» с MTA Postfix, вы можете найти в следующих статьях: http://linuxnews.ru/docs/new/isp-mail/version1.2/isp-mailhowto.1.2.rus.txt http://www.onix.opennet.ru/mail/mail.html http://www.postfix.org/docs.html Как прикрутить SpamAssassin, можно почитать здесь:
А. Мозговой. Журнал «Системный администратор» №9(10), стр. 50 (http://brain.msk.ru/Postfix+SpamAssassin.txt)
http://useast.spamassassin.org/doc.html
Настоящая статья только вскользь опишет общую сборку большой связки. Главная цель – настроить авторизацию по SMTP (без SSL) и выдержать стиль Mini-HOWTO.
Большая связка Версии ПО, используемые мной на момент написания статьи: Linux Slackware-9.0 + Patches Postfix-2.0.13 Cyrus-sasl-2.1.15 Mysql-3.23.56 Courier-imap-1.7.1 Drweb-4.29.5 SpamAssassin-2.55 Squirrelmail-1.4.0 Честно говоря, у меня крутится MySQL, который поставляется вместе с дистрибутивом. MySQL, наверное, лучше установить/настроить первым. Качаем, распаковываем, конфигурим, собираем, устанавливаем. Заводим отдельного пользователя под Postfix, например, «postfix». Кстати, для повышения безопасности, почта все-таки, заставьте MySQL не слушать Сеть, общайтесь только через сокет-файл. Так оно и быстрее. --- /etc/my.cnf --... [mysqld] … skip-networking ... --- EOF /etc/my.cnf ---
Создаем базу данных (mail), в которой будут храниться таблицы, содержащие все записи о почтовых бюджетах (users), синонимах (aliases) и обслуживаемых доменах (transport).
Поля таблиц Можно обойтись несколькими полями в каждой таблице, но в Postfix-2.x.x появилась поддержка дополнительных полей/ условий. Это очень удобно, почему бы не воспользоваться ими? Придерживаясь главной цели сей статьи, буду краток. Некоторые поля действительно необязательны, но они пригодятся, когда будем прикручивать веб-интерфейс собственного производства (тема следующей статьи).
№10(11), октябрь 2003
CREATE TABLE users ( uid int(11) NOT NULL auto_increment, gid int(11) NOT NULL default '12', alias varchar(255) NOT NULL default '', domain varchar(255) NOT NULL default '', active enum('1','0') NOT NULL default '1', maildir varchar(255) NOT NULL default '', password varchar(255) NOT NULL default '', password-crypt varchar(255) default NULL, owner varchar(255) NOT NULL default '', create_date datetime NOT NULL default '0000-00-00 00:00:00', change_date datetime NOT NULL default '0000-00-00 00:00:00', quota varchar(255) NOT NULL default 'NOQUOTA', comment text, PRIMARY KEY (uid), UNIQUE KEY alias (alias), FULLTEXT KEY comment (comment) ) TYPE=MyISAM COMMENT='Çäåñü õðàíèòñÿ èíôîðìàöèÿ ↵ î ïî÷òîâûõ áþäæåòàõ'; CREATE TABLE aliases ( id int(11) NOT NULL auto_increment, alias varchar(200) NOT NULL default '', rcpt varchar(200) NOT NULL default '', create_date datetime NOT NULL default '0000-00-00 00:00:00', change_date datetime NOT NULL default '0000-00-00 00:00:00', active enum('1','0') NOT NULL default '1', PRIMARY KEY (id), UNIQUE KEY alias (alias,rcpt) ) TYPE=MyISAM COMMENT='Çäåñü õðàíèòñÿ èíôîðìàöèÿ î ñèíîíèìàõ'; CREATE TABLE transport ( id int(11) NOT NULL auto_increment, domain varchar(128) NOT NULL default '', transport varchar(128) NOT NULL default '', create_date datetime NOT NULL default '0000-00-00 00:00:00', change_date datetime NOT NULL default '0000-00-00 00:00:00', active tinyint(4) NOT NULL default '1', gid int(11) NOT NULL default '12', PRIMARY KEY (domain), KEY id (id) ) TYPE=MyISAM COMMENT='Çäåñü õðàíèòüñÿ èíôîðìàöèÿ ↵ îá îáñëóæèâàåìûõ äîìåíàõ';
Cyrus-SASL Немногим сложнее MySQL. Качаем, распаковываем, конфигурим, собираем, устанавливаем. --./configure --enable-login --with-mysql --with-openssl make make install --* ïðî÷òèòå ôàéë doc/install.html, ÷òîá ñäåëàòü * âñå íåîáõîäèìûå ëèíêè
Postfix Качаем, распаковываем. Учтите, что собирается postfix с учетом окружения и ОС, под которой в дальнейшем будет работать. Читайте INSTALL-файл. --make tidy make -f Makefile.init makefiles \ 'CCARGS=-DHAS_MYSQL -I/usr/include/mysql -DUSE_SASL_AUTH ↵ -I/usr/include/sasl' \ 'AUXLIBS=-L/usr/lib/mysql -lmysqlclient ↵ -lz -lm -L/usr/lib/sasl2 -lsasl2' make ... make install --*óòî÷íèòå ïóòè äî áèáëèîòåê â âàøåé ñèñòåìå
Настройка Postfix Если кратко, только то, что касается MySQL.
27
администрирование hosts = unix:/var/run/mysql/mysql.sock --- EOF /etc/postfix/transport.cf ----- /etc/postfix/uids.cf --user = postfix password = PASSWORD dbname = mail table = users select_field = uid where_field = alias additional_conditions = and active = '1' hosts = unix:/var/run/mysql/mysql.sock --- EOF /etc/postfix/uids.cf ---
--- /etc/postfix/main.cf --relay_domains = $transport_maps transport_maps = mysql:/etc/postfix/transport.cf virtual_alias_domains = $virtual_alias_maps virtual_alias_maps = mysql:/etc/postfix/aliases.cf virtual_gid_maps = mysql:/etc/postfix/gids.cf virtual_mailbox_base = / virtual_mailbox_domains = $virtual_mailbox_maps virtual_mailbox_maps = mysql:/etc/postfix/users.cf virtual_transport = virtual virtual_uid_maps = mysql:/etc/postfix/uids.cf --- EOF /etc/postfix/main.cf ----- /etc/postfix/users.cf --user = postfix password = PASSWORD dbname = mail table = users select_field = maildir where_field = alias additional_conditions = and active = '1' hosts = unix:/var/run/mysql/mysql.sock --- EOF /etc/postfix/users.cf ----- /etc/postfix/gids.cf --user = postfix password = PASSWORD dbname = mail table = users select_field = gid where_field = alias additional_conditions = and active = '1' hosts = unix:/var/run/mysql/mysql.sock --- EOF /etc/postfix/gids.cf ----- /etc/postfix/aliases.cf --user = postfix password = PASSWORD dbname = mail table = aliases select_field = rcpt where_field = alias additional_conditions = and active = '1' hosts = unix:/var/run/mysql/mysql.sock --- EOF /etc/postfix/aliases.cf ----- /etc/postfix/transport.cf --user = postfix password = PASSWORD dbname = mail table = transport select_field = transport where_field = domain additional_conditions = and active = '1'
28
Вся информация по настройке Postfix подробно расписана в man-страницах и на домашнем сайте Postfix. Расписывать установку и настройку Courier-imap, Drweb, SpamAssassin и Squirrelmail в этой статье нет смысла.
SMTP AUTH Создайте файл /usr/lib/sasl2/smtpd.conf следующего содержания: --- /usr/lib/sasl2/smtpd.conf --pwcheck_method: auxprop mysql_user: postfix mysql_passwd: PASSWORD mysql_hostnames: localhost mysql_database: mail mysql_statement: select password from users where alias = '%u@%r' --- EOF /usr/lib/sasl2/smtpd.conf ---
Это все. Небольшая выжимка из README-файла. %u имя пользователя до @, под которым логинятся. %p особенность запроса, механизм идентификации. %r все что за @, т.е. имя домена.
Я специально не расписывал возможные ошибки. Все они обязательно проявятся (если будут) и отобразятся в лог-файлах. Просто внимательно читайте, что вам пишут. С радостью отвечу на все вопросы по электронной почте, пишите.
bugtraq Удаленное переполнение буфера в OpenSSH #2 Программа: OpenSSH 3.7. Опасность: Критическая. Описание: Удаленное переполнение буфера обнаружено в OpenSSH. На этот раз, в отличие от предыдущего исправления, устраненная уязвимость позволяет выполнить произвольный код на уязвимом сервере. Вчера OpenSSH опубликовало информацию об уязвимости в OpenSSH, которая позволяла удаленному пользователю выполнить DoSнападение против SSH-сервера. Однако изначально говорилось о существовании уязвимости, которая могла использоваться для выполнения произвольного кода на уязвимом сервере. После детального изучения проблемы была обнаружена еще одна, более опасная уязвимость в OpenSSH, которая, возможно, позволяет удаленному пользователю выполнить произвольный код с root-привилегиями. URL производителя: http://www.openssh.com/ Решение: Обновите до OpenSSH 3.7.1 или примените следующий патч: Appendix A: patch for OpenSSH 3.6.1 and earlier Index: buffer.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/buffer.c,v retrieving revision 1.16 retrieving revision 1.18 diff -u -r1.16 -r1.18 --- buffer.c 26 Jun 2002 08:54:18 -0000 1.16 +++ buffer.c 16 Sep 2003 21:02:39 -0000 1.18 @@ -23,8 +23,11 @@ void buffer_init(Buffer *buffer) { - buffer->alloc = 4096; - buffer->buf = xmalloc(buffer->alloc); + const u_int len = 4096; + buffer->alloc = 0; + buffer->buf = xmalloc(len); + buffer->alloc = len; buffer->offset = 0; buffer->end = 0; } @@ -34,8 +37,10 @@ void buffer_free(Buffer *buffer) { - memset(buffer->buf, 0, buffer->alloc); - xfree(buffer->buf); + if (buffer->alloc > 0) { + memset(buffer->buf, 0, buffer->alloc); + xfree(buffer->buf); + } } /* @@ -69,6 +74,7 @@ void * buffer_append_space(Buffer *buffer, u_int len) { + u_int newlen; void *p; if (len > 0x100000) @@ -98,11 +104,13 @@ goto restart; } /* Increase the size of the buffer and retry. */ - buffer->alloc += len + 32768; - if (buffer->alloc > 0xa00000) + + newlen = buffer->alloc + len + 32768; + if (newlen > 0xa00000) fatal("buffer_append_space: alloc %u not supported", - buffer->alloc); - buffer->buf = xrealloc(buffer->buf, buffer->alloc); + newlen); + buffer->buf = xrealloc(buffer->buf, newlen); + buffer->alloc = newlen; goto restart;
№10(11), октябрь 2003
/* NOTREACHED */ } Index: channels.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/channels.c,v retrieving revision 1.194 retrieving revision 1.195 diff -u -r1.194 -r1.195 --- channels.c 29 Aug 2003 10:04:36 -0000 1.194 +++ channels.c 16 Sep 2003 21:02:40 -0000 1.195 @@ -228,12 +228,13 @@ if (found == -1) { /* There are no free slots. Take last+1 slot and expand the array. */ found = channels_alloc; - channels_alloc += 10; if (channels_alloc > 10000) fatal("channel_new: internal error: channels_alloc %d " "too big.", channels_alloc); + channels = xrealloc(channels, + (channels_alloc + 10) * sizeof(Channel *)); + channels_alloc += 10; debug2("channel: expanding %d", channels_alloc); - channels = xrealloc(channels, channels_alloc ↵ * sizeof(Channel *)); for (i = found; i < channels_alloc; i++) channels[i] = NULL; } =================================================================== Appendix B: patch for OpenSSH 3.7 Index: buffer.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/buffer.c,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- buffer.c 16 Sep 2003 03:03:47 -0000 1.17 +++ buffer.c 16 Sep 2003 21:02:39 -0000 1.18 @@ -23,8 +23,11 @@ void buffer_init(Buffer *buffer) { - buffer->alloc = 4096; - buffer->buf = xmalloc(buffer->alloc); + const u_int len = 4096; + buffer->alloc = 0; + buffer->buf = xmalloc(len); + buffer->alloc = len; buffer->offset = 0; buffer->end = 0; } @@ -34,8 +37,10 @@ void buffer_free(Buffer *buffer) { - memset(buffer->buf, 0, buffer->alloc); - xfree(buffer->buf); + if (buffer->alloc > 0) { + memset(buffer->buf, 0, buffer->alloc); + xfree(buffer->buf); + } } /* Index: channels.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/channels.c,v retrieving revision 1.194 retrieving revision 1.195 diff -u -r1.194 -r1.195 --- channels.c 29 Aug 2003 10:04:36 -0000 1.194 +++ channels.c 16 Sep 2003 21:02:40 -0000 1.195 @@ -228,12 +228,13 @@ if (found == -1) { /* There are no free slots. Take last+1 slot and expand the array. */ found = channels_alloc; - channels_alloc += 10; if (channels_alloc > 10000) fatal("channel_new: internal error: channels_alloc %d " "too big.", channels_alloc); + channels = xrealloc(channels, + (channels_alloc + 10) * sizeof(Channel *)); + channels_alloc += 10; debug2("channel: expanding %d", channels_alloc); - channels = xrealloc(channels, channels_alloc ↵ * sizeof(Channel *)); for (i = found; i < channels_alloc; i++) channels[i] = NULL; }
Cоставил Александр Антипов
29
администрирование
СВОЙ СОБСТВЕННЫЙ МОДУЛЬ
В этой статье мы рассмотрим основные операции с модулями ядра Linux, а также создание собственного модуля, позволяющего расширить возможности ядра операционной системы.
ДЕНИС КОЛИСНИЧЕНКО
30
администрирование Прежде чем сказать, что же такое модуль, поговорим о драйверах устройств. В Windows мы часто сталкиваемся с установкой, удалением и обновлением драйверов. Драйвером устройства называется определенная программа, позволяющая операционной системе (и пользовательским программам) работать с данным устройством. Операционная система Windows (имеется в виду ME/2000/XP) содержит драйверы для работы с наиболее распространенными устройствами, но если вы хотите установить какоенибудь экзотическое устройство (драйвера которого нет в базе драйверов операционной системы), вам нужен драйвер этого устройства – без него система не сможет работать с устройством. В Windows установка драйверов выполняется достаточно просто – запустил программу установки драйвера, подождал, пока драйверы будут установлены, и после перезапуска компьютера уже можно работать с новым устройством. Конечно, при условии, что вы выбрали подходящий драйвер. В Linux «драйверы»1 выполнены в виде модулей ядра. Ядро Linux содержит только самый необходимый код, чтобы только загрузиться. Поддержку остальных устройств обеспечивают модули, которые встраиваются в ядро при загрузке системы. В принципе можно вкомпилировать в ядро все необходимые модули, тогда у нас будет система, не использующая модули, но мы сейчас не будем говорить о таких системах. С помощью пакета modutils, который будет рассмотрен ниже, вы можете добавить нужный вам модуль в ядро во время работы системы. При этом перезагружать систему не нужно – устройство начнет работать сразу же после загрузки модуля. Раньше, в первых версиях ядра Linux, механизм работы с модулями не был предусмотрен, и ядра тех времен содержали в себе код драйверов для всех поддерживаемых устройств. Такое решение нельзя назвать рациональным. Мы не можем предусмотреть, какие устройства будут установлены у конечного пользователя, даже если включить в состав ядра драйверы всех возможных устройств. Предположим, что у нашего пользователя установлена звуковая плата Yamaha, а наше ядро «знает» еще с десяток звуковых плат. Получится, что один код будет работать всегда, а остальные десять драйверов будут просто использовать оперативную память. Кстати, об оперативной памяти: вы представляете размер ядра, если оно будет содержать драйверы всех устройств? Исходя из всего этого, разработчики ядра Linux «изобрели» механизм динамически загружаемых модулей. Модули хранятся на диске в виде объектных файлов (*.o). При необходимости ядро загружает необходимый ему модуль. Откуда ядро знает, какой модуль нужно загружать, а какой – нет? Список модулей, а также передаваемые им параметры хранятся в файле /etc/modules.conf (или /etc/conf.modules – в зависимости от дистрибутива и версии ядра). Вот пример этого файла: Ëèñòèíã 1. Ôàéë /etc/modules.conf (Linux Red Hat 7.3) alias sound-slot-0 i810_audio post-install sound-slot-0 /bin/aumix-minimal ↵ -f /etc/.aumixrc -L >/dev/null 2>&1 pre-remove sound-slot-0 /bin/aumix-minimal ↵ -f /etc/.aumixrc -S >/dev/null 2>&1
№10(11), октябрь 2003
Подробнее о формате файла /etc/modules.conf вы можете прочитать в справочной системе, введя команду man modules.conf. При загрузке система читает этот файл и загружает указанные в нем модули. В нашем случае загружается только модуль i810_audio. Примечание: загрузка модулей из файла modules.conf обеспечивается программой modprobe, которая вызывается из сценария инициализации системы /etc/rc.d/rc.sysinit. Во время работы системы мы сами можем загрузить нужный нам модуль. Для этого нужно использовать программу insmod, входящую в состав пакета modutils. Использовать программу очень просто: insmod <èìÿ_ôàéëà_ìîäóëÿ>
Чтобы использовать программу insmod, вы должны обладать привилегиями суперпользователя – пользователя root. Просмотреть список загруженных модулей можно с помощью команды lsmod. Вот вывод этой программы: Module autofs nls_koi8-r nls_cp866 vfat fat usb-uhci usbcore
Size 12164 4576 4576 12092 37400 24484 73152
Used by 0 2 2 2 0 0 1
Not tainted (autoclean) (unused) (autoclean) (autoclean) (autoclean) (autoclean) [vfat] (unused) [usb-uhci]
Некоторые модули загружаются не из файла /etc/ modules.conf. Например, модули файловых систем загружаются по мере необходимости – при монтировании определенной файловой системы загружается нужный модуль, если, конечно, он есть. Модули nls_koi8-r и nls_cp866 загружаются также при монтировании файловой системы, если указаны опции монтирования iocharset=koi8-r,codepage=866. Выгрузить модуль предельно просто: rmmod èìÿ_ìîäóëÿ
Программа modinfo позволяет просмотреть информацию о модуле: modinfo usbcore filename: /lib/modules/2.4.18-3/kernel/drivers/usb/usbcore.o description: <none> author: <none> license: "GPL"
Примечание: программы insmod, rmmod, lsmod и modinfo входят в состав modutils. Для использования любой этой программы необходимы права пользователя root. Теперь мы уже подошли к созданию своего собственного модуля. Что он будет делать, зависит от вас – это может быть драйвер устройства или просто небольшой модуль, дополняющий ядро нужной вам функцией. Для начала напишем каркас модуля на языке C – каркас можно будет откомпилировать, но в результате получится модуль, который ничего не делает. Данный каркас нам понадобится при написании более серьезных модулей.
31
администрирование Ëèñòèíã 2. Êàðêàñ ìîäóëÿ ÿäðà Linux (module.c)
Ëèñòèíã 4. Èíôîðìàöèÿ î ìîäóëå (module.c)
#define MODULE #define __KERNEL__ #include <linux/module.h>
#define MODULE #define __KERNEL__ #include <linux/module.h>
int init_module() { return 0; }
MODULE_AUTHOR("Denis Kolisnichenko dhsilabs@mail.ru"); MODULE_DESCRIPTION("Linux kernel module");
void cleanup_module() { return 0; }
void cleanup_module() { return 0; }
Теперь разберемся, что означает каждая строчка кода нашего будущего модуля. Первые две строчки делают обыкновенную программу модулем ядра Linux. Если вы не укажите их, компилятор сгенерирует совсем не тот код, которого мы от него ожидали. Попросту говоря, первые две строчки обязательны для каждого модуля. Примечание: первые две строчки листинга 2 – это не просто магические строчки, а директивы препроцессора, которые при обработке файла препроцессором cpp будут заменены нужным кодом. Третья строка подключает заголовочный файл module.h, в котором находятся все необходимые определения для создания модуля определения. Функция init_module() вызывается при загрузке модуля ядром. Если загрузка модуля прошла успешно, функция возвращает 0, в противном случае функция должна возвратить любое другое значение – код ошибки. Функция cleanup_module() вызывается при удалении модуля. Как и в прошлом случае, она возвращает 0, если удаление модуля прошло успешно. Названия функций init_module() и cleanup_module() необязательны – вы можете назвать их по-другому, но для этого вам нужно использовать функции module_init() и module_exit(), которые определены в заголовочном файле init.h. Переделаем наш шаблон так, чтобы не использовать стандартные имена функций init_module() и cleanup_module(): Ëèñòèíã 3. Øàáëîí ìîäóëÿ ñ ïåðåèìåíîâàíèåì ñòàíäàðòíûõ ôóíêöèé (module2.c) #define MODULE #define __KERNEL__ #include<linux/module.h> // äëÿ ìîäóëÿ #include<linux/init.h> // module_init() è module_exit() int start() {
return 0; }
void stop() {
return 0; }
module_init(start); module_exit(stop);
Функциям module_init() и module_exit() нужно передать имена функций, которые будут вызваны при инициализации и удалении модуля соответственно. Зачем это нужно? Для общего развития, чтобы вы знали, для чего используются эти функции. Ваш модуль не станет работать лучше, если вы переименуете стандартные функции инициализации и удаления. Помните, для чего используется программа modinfo? Да, для получения информации о модуле. Давайте добавим эту информацию в наш модуль.
32
int init_module()
{ return 0; }
Макросы MODULE_AUTHOR и MODULE_DESCRIPTION определены в заголовочном файле module.h, поэтому никаких дополнительных заголовочных файлов подключать не нужно. При необходимости модуль может выводить на консоль сообщения, например, о невозможности инициализации устройства. Выводимые модулем сообщения будут запротоколированы службой протоколирования ядра – демоном klogd. Выводить сообщения нужно не с помощью функции printf(), а функцией printk(). В этом случае сообщения не только окажутся на системной консоли, но и будут запротоколированы в файле /var/log/messages. Сейчас мы напишем модуль, который будет выводить сообщения при загрузке и при удалении: Ëèñòèíã 5. Èñïîëüçîâàíèå ôóíêöèè printk() #define MODULE #define __KERNEL__ #include <linux/module.h> #include <linux/kernel.h> // printk MODULE_AUTHOR("Denis Kolisnichenko dhsilabs@mail.ru"); MODULE_DESCRIPTION("Linux kernel module"); int init_module() { printk(“My module: Starting...\n”); return 0; } void cleanup_module() { printk(“My module: Stopping...\n”); return 0; }
Уже готово четыре различных листинга модуля, а мы еще не знаем, как его откомпилировать. Сделано это предумышленно: компилировать имеет смысл только последний листинг. Для компилирования модуля ядра вам понадобится установленный компилятор gcc, файлы заголовки и исходные тексты ядра – мы ведь занимаемся разработкой модуля ядра. Проще говоря, нужно установить следующие пакеты: cpp – препроцессор cpp; binutils – набор различных утилит (as, gprof, ld и др.); glibc-kerheaders – заголовочные файлы ядра; glibc-devel – вспомогательные файлы для разработки приложений с использованием стандартной библиотеки C; gcc – компилятор gcc; kernel-source – исходные тексты ядра Linux. Устанавливать пакеты нужно в указанной последовательности. Если компилятор gcc у вас установлен, то вам
администрирование нужно установить только последний пакет – исходные тексты ядра. Также нужно убедиться, что наше ядро поддерживает динамически загружаемые модули. Для этого перейдите в каталог /usr/src/linux-2.4 (или /usr/src/linux) и введите команду make menuconfig. Вы получили сообщение, что библиотека Ncurses не найдена? Установите пакеты ncurses (или ncurses4) и ncurses-devel и введите команду make menuconfig снова. Убедитесь, что в разделе Loadable module support включена опция Enable loadable module support (см. рис. 1).
Makefile поместите в один каталог с файлом module.c и выполните команду make. После ее выполнения вы получите файл module.o, который будет находиться в одном каталоге с файлом module.c. Если вы по каким-либо причинам не хотите использовать утилиту make, для компилирования модуля введите команду: gcc –O3 -DMODULE -D__KERNEL__ -I/usr/include -c module.c
После того, как наш модуль откомпилирован, его можно установить: insmod module.o
Ðèñóíîê
1. Êîíôèãóðèðîâàíèå ÿäðà
Если опция Enable loadable module support выключена, ее нужно включить, сохранить файл конфигурации ядра и перекомпилировать ядро. О компиляции ядра вы можете прочитать в моей книге «Linux-сервер своими руками» («Наука и техника», 2002 г.) или в статье «Компилирование ядра» http://dkws.narod.ru/linux/kernel/kern.html. Компилятору gcc нужно передать много параметров, поэтому мы напишем так называемый Makefile, облегчающий нам жизнь при компилировании/перекомпилировании модуля. Ëèñòèíã 6. Makefile íàøåãî ìîäóëÿ (Makefile) CC=gcc PATH=/usr/include /usr/src/linux-2.4/include MODFLAGS:= -O3 -Wall –DLINUX –D__KERNEL__ -I$(PATH) module.o: module.c $(CC) $(MODFLAGS) -c module.c
В качестве компилятора мы будем использовать компилятор gcc ($CC), ему будут переданы параметры $MODFLAGS и –c module.c. module.c – это имя файла нашего модуля. Опции компилятора означают следующее: O3: будет использован третий уровень оптимизации (что это такое, вы узнаете в справочной системе gcc: man gcc); Wall: включаем все предупреждения; DLINUX: генерируем код для Linux; I$(PATH): определяем путь поиска заголовочных файлов. По умолчанию компилятор ищет файлы заголовков в каталоге /usr/include, но там может и не быть нужных файлов, например, для дистрибутива ALT Linux (ядро 2.4.21) файлы заголовков находятся в каталоге /usr/include/linux-2.4.21rel-std-up/.
№10(11), октябрь 2003
Вы увидите сообщение My module: Starting... Это же сообщение будет записано в файл протокола /var/log/messages. Мы только что написали модуль ядра, который можно установить, удалить, который выводит сообщения, но он ничего полезного не делает. Усложним нашу задачу: напишем драйвер для некоторого устройства /dev/device. Данного устройства в нашей системе нет, поэтому нам его нужно создать, но этим мы займемся чуть позже. Перед тем как приступить к написанию драйвера устройства, нужно поговорить о самих устройствах. Устройства бывают трех типов: Символьные: чтение и запись устройства выполняются посимвольно. Примером такого устройства может послужить последовательный порт. Блочные: чтение и запись устройства выполняются блоками, как правило, по 512 или 1024 байта. Самый яркий пример блочного устройства – жесткий диск. Сетевые: файлов этих устройств вы не найдете в каталоге /dev, поскольку использование файловой системы, то есть работа с этими устройствами как с файлами, неэффективно. Пример – сетевая карта (ethX). Чтобы сделать устройство доступным для системы и пользовательских программ, нужно его зарегистрировать. В заголовочном файле fs.h определены функции для регистрации символьных и блочных устройств. Все они начинаются с префикса register. Наше устройство будет символьным, поэтому для его регистрации мы будем использовать функцию register_chrdev. Вот ее прототип: extern int register_chrdev(unsigned int, const char *, ↵ struct file_operations *);
Разберемся, что означает каждый параметр. Первый параметр – это старший номер (major number) устройства, определяющий его тип. Если старший номер равен 0, то функция возвратит свободный старший номер для устройства нашего вида (символьное устройство). Чтобы понять, для чего нужен старший номер, вспомним каталог /dev, содержащий файлы устройств. Возьмем файл /dev/tty1 – это терминал с номером 1. Старший номер определяет тип устройства – терминал (tty), а младший – его номер в системе (1). Человеку проще работать не с номерами, а с символьными именами устройств, по-
33
администрирование этому каждому старшему номеру соответствует символьное обозначение. При регистрации устройства нужно указать его тип – старший номер устройства. Но откуда мы знаем, какой номер занят, а какой – нет? Проще всего указать 0 в качестве первого параметра функции register_chrdev(). В этом случае функция возвратит свободный старший номер символьного устройства для нашей системы. Если же явно указать старший номер, может возникнуть конфликт номеров, и наше устройство не будет зарегистрировано. Второй параметр определяет имя устройства («device»). Последний параметр очень важен. Это структура указателей на функции для работы с нашим устройством. Наш драйвер (модуль) содержит таблицу доступных функций, а операционная система вызывает нужную функцию, когда пользовательской программе нужно выполнить операцию с файлом устройства (открытие/закрытие, чтение/запись). Таблица функций символьного устройства хранится в структуре file_operations, которая передается при регистрации устройства. После регистрации драйвера устройства происходит поиск устройств данного типа. Причем этот поиск должен произвести сам драйвер. Для простоты будем считать, что у нас всего два устройства. Нам нужно создать эти два устройства, но перед этим нам нужно вычислить старший номер устройства. Напишем драйвер, который помимо регистрации устройства выводил бы его старший номер – потом мы его будем использовать при создании устройства. Ëèñòèíã 7. Äðàéâåð óñòðîéñòâà /dev/device (áåç ñòðóêòóðû file_operations) #define MODULE #define __KERNEL__ #include<linux/module.h> #include<linux/init.h> #include<linux/kernel.h> #include<linux/fs.h> // ðåãèñòðàöèÿ óñòðîéñòâ #include<linux/ioport.h> // ðàáîòà ñ ïîðòàìè ââîäà/âûâîäà #include<linux/sched.h> // ðåçåðâèðîâàíèå ïðåðûâàíèÿ // Èìÿ íàøåãî óñòðîéñòâà #define DEV_NAME "device" // Ïîðòû ââîäà-âûâîäà íàøåãî óñòðîéñòâà #define PORT_START 0x2000 #define PORT_QTY 10 // Ïàìÿòü íàøåãî óñòðîéñòâà #define MEM_START 0x20000000 #define MEM_QTY 0x20 // Íîìåð ïðåðûâàíèÿ äëÿ íàøåãî óñòðîéñòâà #define IRQ_NUM 9 MODULE_AUTHOR("Denis Kolisnichenko dhsilabs@mail.ru"); MODULE_DESCRIPTION("Linux kernel module"); // Ñòàðøèé íîìåð ôàéëà óñòðîéñòâà static int Major; // Ñòðóêòóðà file_operations – ïîêà ïóñòàÿ, íî âñêîðå // ìû åå íàïèøåì struct file_operations FO; // Îáðàáîò÷èê ïðåðûâàíèÿ void irq_handler(int irq, void *dev_id, struct pt_regs *regs) { return; } int init_module() {
34
// Ðåãèñòðèðóåì óñòðîéñòâî printk("My module: starting…\n"); Major = register_chrdev(0, DEV_NAME, &FO); if (Major < 0) { // Óñòðîéñòâî íå çàðåãèñòðèðîâàíî printk("My module: registration failed\n"); return Major; } printk("My module: device registered, ↵ major number = %d\n",Major); // Ðåçåðâèðîâàíèå ïîðòîâ ââîäà-âûâîäà printk("My module: allocating io ports\n"); if (check_region(PORT_START, PORT_QTY)) { printk("My module: allocation io ports failed\n"); return -EBUSY; } request_region(PORT_START, PORT_QTY, DEV_NAME); printk ("My module: io ports allocated\n"); // Ðåçåðâèðîâàíèå ïàìÿòè if (check_mem_region(MEM_START, MEM_QTY)) { printk("My module: memory allocation failed\n"); release_region(PORT_START, PORT_QTY); return -EBUSY; } request_mem_region(MEM_START, MEM_QTY, DEV_NAME); printk ("My module: memory allocated\n"); // Ðåçåðâèðîâàíèå ïðåðûâàíèÿ if (request_irq(IRQ_NUM, irq_handler, 0, DEV_NAME, NULL)) { printk("My module: IRQ allocation failed\n"); release_mem_region(MEM_START, MEM_QTY); release_region(PORT_START, PORT_QTY); return -EBUSY; } printk ("My module: IRQ allocated\n"); return 0; } void cleanup_module() { // Îñâîáîæäàåì ïîðòû ââîäà-âûâîäà release_region(PORT_START, PORT_QTY); printk("My module: release io ports\n"); // Îñâîáîæäàåì ïàìÿòü release_mem_region(MEM_START, MEM_QTY); printk("My module: release memory\n"); // Îñâîáîæäàåì ïðåðûâàíèå free_irq(IRQ_NUM,NULL); printk("My module: release irq\n"); // Îòìåíÿåì ðåãèñòðàöèþ óñòðîéñòâà if (unregister_chrdev(Major, DEV_NAME) < 0){ printk("My module: cannot to unregister device\n"); } printk("My module: device unregistered\n"); return; }
При загрузке модуля вы увидите следующее сообщение: My module: device registered, major number = 255
Конечно, кроме этого сообщения будут другие сообщения, но нас они не интересуют. Почему именно это сообщение так важно для нас? В первой части сообщения говорится, что наше устройство успешно зарегистрировано, а во второй – сообщается старший номер устройства, который мы будем использовать для создания устройств /dev/device0 и /dev/device1.
администрирование Вы не забыли, что нам еще нужно создать два устройства типа device, чтобы программы могли бы работать с ними? Перейдите в каталог /dev и от имени пользователя root выполните команды: mknod device c 255 0 mknod device c 255 1
Здесь 255 – это старший номер устройства (у вас он будет другим), 0 и 1 – младшие номера устройств. После выполнения данных команд будут созданы два файла устройств – /dev/device0 и /dev/device1. После регистрации устройства функцией register_chrdev() мы пытаемся захватить диапазон портов. Для этого предназначена функция request_region(), но перед ее вызовом мы должны убедиться, что нужный нам диапазон не используется (функция check_region()). Затем, если нужно, мы резервируем память для нашего устройства. Для резервирования памяти используется функция request_mem_region(), а для проверки возможности захвата памяти предназначена функция check_mem_region(). После успешной регистрации памяти можно попытаться захватить IRQ – функция request_irq(). Предположим, что на каком-то этапе регистрации драйвера произошла ошибка. Если мы не смогли зарегистрировать порты ввода/вывода, вряд ли имеет смысл продолжать работу. Если же ошибка произошла при резервировании памяти, то перед завершением работы модуля нам нужно освободить порты ввода/вывода, которые мы зарегистрировали на предыдущем этапе. Аналогично поступаем при ошибке захвата IRQ – освобождаем порты и память. Функции release_mem_region(),release_region и free_irq() используются для освобождения памяти, портов и IRQ соответственно. Обратите внимание: мы написали драйвер так, что он захватывает порты и память от имени одного устройства – DEV_NAME. В реальности все гораздо сложнее: нужно захватывать ресурсы для каждого устройства данного типа. К тому же нужно предусмотреть поиск устройств драйвером: в нашем случае мы знаем, что устройств только два, но у конечного пользователя таких устройств может быть больше или меньше, поэтому наш драйвер будет не универсален, если он будет поддерживать только два устройства. О поиске устройств мы поговорим чуть позже. Наш драйвер пока еще не может называться драйвером в прямом смысле этого слова: устройство-то он регистрирует, но не позволяет выполнить ни одной операции с устройством – ведь структура file_operations пуста. Кроме структуры file_operations, нам еще понадобится структура для хранения информации о состоянии устройства, а так как устройств у нас два, то также нужен массив структур для хранения состояния каждого устройства. Индексами массива будут младшие номера устройств. // Ñòðóêòóðà äëÿ õðàíåíèÿ ñîñòîÿíèÿ óñòðîéñòâà struct device_state { // 1 – óñòðîéñòâî îòêðûòî, 0 - çàêðûòî int dev_open; // Êîëè÷åñòâî ïðî÷èòàííûõ áàéò èç óñòðîéñòâà
№10(11), октябрь 2003
ssize_t byte_read; // Êîëè÷åñòâî çàïèñàííûõ áàéò ssize_t byte_write; }; // Ìàññèâ äëÿ õðàíåíèÿ èíôîðìàöèè î ñîñòîÿíèè óñòðîéñòâ static struct device_state state[2];
В принципе можно обойтись и без кода поиска устройств – без него модуль будет проще, да и работать он будет быстрее. А мы знаем, чем проще программа, тем она надежнее. Обойти поиск устройств можно следующим образом. Мы не знаем, сколько устройств типа device будет у конечного пользователя – у него может быть только одно устройство – /dev/device0, а может быть целых 20 устройств – /dev/device0…/dev/device19. Поэтому вместо описанного выше массива state, нужно использовать динамический список, который будет содержать информацию о каждом устройстве типа device. При загрузке модуля он будет содержать всего один элемент – для устройства /dev/device0. Даже если этого устройства не будет в системе, будем считать, что оно просто закрыто, а при попытке обращения к нему будем сообщать, что оно занято. По мере поступления запросов программ на открытие других устройств /dev/deviceX будем добавлять новые элементы в наш список. Чтобы не усложнять код нашего модуля, в этой статье мы не будем использовать динамические структуры – для вас как начинающего разработчика модулей ядра Linux, главное – разобраться с написанием самого модуля, а добавить динамические списки вы можете в любой момент сами. Если же вам все-таки хочется узнать конкретное количество устройств /dev/deviceX, установленных у пользователя, можно просто просмотреть содержимое каталога /dev и посчитать количество файлов device*. Все готово для того, чтобы написать функцию открытия устройства. Ëèñòèíã 8. Ôóíêöèÿ îòêðûòèÿ óñòðîéñòâà static int device_open(struct inode *inode, struct file *fp) { struct device_state *dev_state; printk("My module: try to open device with minor number ↵ %d\n", MINOR(inode->i_rdev)); dev_state = &state[MINOR(inode->i_rdev)]; if(dev_state->dev_open) { printk("Devise is busy\n"); return -EBUSY; } dev_state->dev_open = 1; dev_state->byte_read = 0; dev_state->byte_write = 0; MOD_INC_USE_COUNT; return 0; }
Младший номер устройства мы получаем с помощью вызова MINOR(inode->i_rdev). Если устройство уже открыто, мы выводим сообщение: Devise is busy. В противном случае устанавливаем флаг открытия устройства, обнуляем byte_read и byte_write, а также увеличиваем счетчик использования данного модуля (MOD_INC_USE_COUNT).
35
администрирование Функция закрытия устройства: сбрасываем флаг dev_open и уменьшаем счетчик использования устройства. Ëèñòèíã 9. Ôóíêöèÿ çàêðûòèÿ óñòðîéñòâà static int device_close(struct inode *inode, struct file *fp) { struct device_state *dev_state; printk("My module: try to close device with minor number ↵ %d\n", MINOR(inode->i_rdev)); dev_state = &state[MINOR(inode->i_rdev)]; if(!dev_state->dev_open) { printk("Device is not open\n"); return 0; }
// Îáðàáîò÷èê ïðåðûâàíèÿ void irq_handler(int irq, void *dev_id, struct pt_regs *regs) { return; } int init_module() {
dev_state->dev_open=0;
// Ðåãèñòðèðóåì óñòðîéñòâî printk("My module: starting…\n");
MOD_DEC_USE_COUNT;
Major = register_chrdev(0, DEV_NAME, &FO);
return 0; }
if (Major < 0) { // Óñòðîéñòâî íå çàðåãèñòðèðîâàíî printk("My module: registration failed\n"); return Major; } printk("My module: device registered, ↵ major number = %d\n",Major);
Теперь нам нужно указать ядру, какие функции нужно использовать для открытия и закрытия устройства: struct file_operations FO = { open: device_open, release: device_close };
Полный код модуля устройства device вместе с функциями открытия и закрытия устройства, а также структурой file_operations приведен в следующем листинге: Ëèñòèíã 10. Ìîäóëü óñòðîéñòâà device (module.c) #define MODULE #define __KERNEL__ #include<linux/module.h> #include<linux/init.h> #include<linux/kernel.h> #include<linux/fs.h> // ðåãèñòðàöèÿ óñòðîéñòâ #include<linux/ioport.h> // ðàáîòà ñ ïîðòàìè ââîäà/âûâîäà #include<linux/sched.h> // ðåçåðâèðîâàíèå ïðåðûâàíèÿ // Èìÿ íàøåãî óñòðîéñòâà #define DEV_NAME "device" // Ïîðòû ââîäà-âûâîäà íàøåãî óñòðîéñòâà #define PORT_START 0x2000 #define PORT_QTY 10 // Ïàìÿòü íàøåãî óñòðîéñòâà #define MEM_START 0x20000000 #define MEM_QTY 0x20 // Íîìåð ïðåðûâàíèÿ äëÿ íàøåãî óñòðîéñòâà #define IRQ_NUM 9 MODULE_AUTHOR("Denis Kolisnichenko dhsilabs@mail.ru"); MODULE_DESCRIPTION("Linux kernel module"); // Ñòàðøèé íîìåð ôàéëà óñòðîéñòâà static int Major; // Ñòðóêòóðà file_operations – ïîêà ïóñòàÿ, íî âñêîðå // ìû åå íàïèøåì struct file_operations FO { open: device_open, release: device_close }; // Ñòðóêòóðà äëÿ õðàíåíèÿ ñîñòîÿíèÿ óñòðîéñòâà struct device_state {
36
// 1 – óñòðîéñòâî îòêðûòî, 0 - çàêðûòî int dev_open; // Êîëè÷åñòâî ïðî÷èòàííûõ áàéòîâ èç óñòðîéñòâà ssize_t byte_read; // Êîëè÷åñòâî çàïèñàííûõ áàéòîâ ssize_t byte_write; }; // Ìàññèâ äëÿ õðàíåíèÿ èíôîðìàöèè î ñîñòîÿíèè óñòðîéñòâ static struct device_state state[2];
// Ðåçåðâèðîâàíèå ïîðòîâ ââîäà-âûâîäà printk("My module: allocating io ports\n"); if (check_region(PORT_START, PORT_QTY)) { printk("My module: allocation io ports failed\n"); return -EBUSY; } request_region(PORT_START, PORT_QTY, DEV_NAME); printk ("My module: io ports allocated\n"); // Ðåçåðâèðîâàíèå ïàìÿòè if (check_mem_region(MEM_START, MEM_QTY)) { printk("My module: memory allocation failed\n"); release_region(PORT_START, PORT_QTY); return -EBUSY; } request_mem_region(MEM_START, MEM_QTY, DEV_NAME); printk ("My module: memory allocated\n"); // Ðåçåðâèðîâàíèå ïðåðûâàíèÿ if (request_irq(IRQ_NUM, irq_handler, 0, DEV_NAME, NULL)) { printk("My module: IRQ allocation failed\n"); release_mem_region(MEM_START, MEM_QTY); release_region(PORT_START, PORT_QTY); return -EBUSY; } printk ("My module: IRQ allocated\n"); return 0; } void cleanup_module() { // Îñâîáîæäàåì ïîðòû ââîäà-âûâîäà release_region(PORT_START, PORT_QTY); printk("My module: release io ports\n"); // Îñâîáîæäàåì ïàìÿòü release_mem_region(MEM_START, MEM_QTY); printk("My module: release memory\n"); // Îñâîáîæäàåì ïðåðûâàíèå free_irq(IRQ_NUM,NULL); printk("My module: release irq\n"); // Îòìåíÿåì ðåãèñòðàöèþ óñòðîéñòâà if (unregister_chrdev(Major, DEV_NAME) < 0){ printk("My module: cannot to unregister device\n"); } printk("My module: device unregistered\n"); return; }
администрирование ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, ↵ size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, ↵ struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, ↵ unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, ↵ int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, ↵ unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, ↵ unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, ↵ int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, ↵ unsigned long, unsigned long, unsigned long, ↵ unsigned long);
static int device_open(struct inode *inode, struct file *fp) { struct device_state *dev_state; printk("My module: try to open device with minor number ↵ %d\n", MINOR(inode->i_rdev)); dev_state = &state[MINOR(inode->i_rdev)]; if(dev_state->dev_open) { printk("Devise is busy\n"); return -EBUSY; } dev_state->dev_open = 1; dev_state->byte_read = 0; dev_state->byte_write = 0; MOD_INC_USE_COUNT; return 0; } static int device_close(struct inode *inode, struct file *fp) { struct device_state *dev_state; printk("My module: try to close device with minor number ↵ %d\n", MINOR(inode->i_rdev)); dev_state = &state[MINOR(inode->i_rdev)]; if(!dev_state->dev_open) { printk("Device is not open\n"); return 0; } dev_state->dev_open=0; MOD_DEC_USE_COUNT; return 0; }
Теперь драйвер для нашего абстрактного устройства device готов. Вы можете написать небольшую программку, которая бы пыталась выполнить операции с нашим устройством: открыть его и закрыть – других операций мы не определили. Для определения других действий используется та же структура file_operations. В файле /usr/ src/linux-2.4/include/linux/fs.h она объявлена так: Ëèñòèíã 11. Ôðàãìåíò ôàéëà /usr/src/linux-2.4/include/linux/ fs.h struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int);
№10(11), октябрь 2003
};
Как использовать структуру file_operations, думаю, ясно. Например, нам нужно описать обработчики записи и чтения устройства – функции device_write() и device_read(): struct file_operations FO = { open: device_open, release: device_close read: device_read, write: device_write };
Обработчики чтения и записи пишутся «по образу и подобию» обработчиков открытия и закрытия устройства, то есть сначала нам нужно определить младший номер с помощью вызова MINOR(), а затем произвести операцию с устройством. Все ваши вопросы и комментарии рад буду выслушать по адресу dhsilabs@mail.ru. 1
Слово «драйвер» заключено в кавычки потому, что в Linux нет такого понятия, как «драйвер». Вместо него есть модули, которые встраиваются в ядро и обеспечивают поддержку устройств. В этой статье для простоты мы иногда будем называть модуль устройства драйвером устройства.
37
администрирование
УПРАВЛЕНИЕ СЕТЕВЫМИ ПРИНТЕРАМИ ДОМЕНА
ИВАН КОРОБКО
38
администрирование Любой системный администратор хотел бы получить легкий, компактный и универсальный инструмент, с помощью которого можно одновременно контролировать состояние всех принтеров текущего домена Microsoft Windows; получать исчерпывающую статистику по настройкам принтера; управлять принтерами домена и их очередями; получать доступ к веб-интерфейсу принтеров, при его наличии; осуществлять поиск доступных принтеров по одному из критериев: по названию, по размещению, по месторасположению устройства. Предлагается решение, созданное на основе ASP, особенностью которого является динамичность. Выбор ASP обусловлен его возможностью работать с OLE-объектами и требованием динамичности. Для воплощения данного решения была использована библиотека интерфейса службы активного каталога (Active Directory Service Interface – ADSI), которая позволяет управлять пространством имен Microsoft Windows 2000. ADSI выпущен в 1997 году корпорацией Microsoft. ADSI поддерживает пространства имен LDAP, WinNT, IIS, NDS. В работе используются пространства имен LDAP и WinNT. Пространство имен LDAP используется для чтения текущего домена, соответственно списка опубликованных в них принтеров и поля AD. Протокол WinNT используется для работы управления принтерами и очередями печати.
Файловая структура проекта Инструмент представляет сайт, точкой входа в который является страница на языке HTML. Сайт создан на основе окон (Frameset): файл default.htm делит окно браузера на два столбца. Текст файла default.htm (HTML): <HTML> <HEAD> <!-- Ëåâûé ñòîëáåö ñîñòàâëÿåò 30% îò øèðèíû âñåãî îêíà. Ëåâîå îêíî èìååò èäåíòèôèêàòîð «main», âòîðîå «var». --> <TITLE>Ñïèñîê äîñòóïíûõ ñåòåâûõ ïðèíòåðîâ </TITLE> <META HTTP-EQUIV ="Content-Type" CONTENT="text/html; ↵ CHARSET=windows-1251"> </HEAD> <FRAMESET cols="30%,*" FRAMEBORDER="5" BORDER="yes" ↵ FRAMESPACING="5" > <FRMAE SRC="printer_adsi.asp?radGrp=1&Search_Text=" ↵ NAME="main" SCROLLING="yes" ÌÀRGINHEIGHT=1 > <FRAME SRC ="about:blank" NAME="var"> </FRAMESET > </HTML>
Остальные страницы взаимосвязаны друг с другом и являются рекурсивными. Обе страницы написаны на ASP. Для создания обеих страниц был выбран VBScript. VBScript выбран потому, что является языком, поставляемым с Microsoft Windows; обладает необходимыми возможностями для реализации данного проекта, имеет простой синтаксис. Каждый из ASP-файлов состоит из трех частей, которые взаимосвязаны друг с другом: WinNT, LDAP, HTML.
LDAP В разделе LDAP рассмотрены следующие вопросы: определение доступного домена; построение запроса SQL; поиск опубликованных принтеров в AD; чтение полей принтеров.
№10(11), октябрь 2003
Определение имени текущего домена Название текущего домена определяется с помощью функции GetObject. Используя функцию GetObject, можго прочитать корень пространства имен, т.е. текущий домен. Пример определения текущего домена (VBScript): SET rootDSE_ = GetObject("LDAP://RootDSE") domain_ = "LDAP://" + rootDSE_.Get("defaultNamingContext")
Переменная domain_ имеет вид «dc=microsoft,dc=com», если домен «microsoft.com». Имя текущего домена, полученного с помощью протокола WinNT, нельзя использовать, поскольку с помощью протокола WinNT, можно получить только сокращенное имя домена (в данном случае «Microsoft»). При указании сокращенного имени в строке с SQL-запросом произойдет ошибка. В сообщении, которое выведет браузер, будет указано, что путь к базе ошибочен, и базу невозможно открыть.
Построение запроса SQL Запрос SQL используется для осуществления процедуры поиска объектов при заданном типе объекта. В общем случае запрос SQL выглядит следующим образом: SELECT ïîëå_1, ïîëå_2, …, ïîëå_n FROM ↵ “LDAP://dc=äîìåí_1,dc=äîìåí_2…,domen_n” ↵ WHERE objectClass=’òèï_îáúåêòà’
В поле SELECT указываются поля, по которым идет выборка. Поля перечисляются через запятую, «пробелы» после запятой обязательны. Полный список полей объектов AD можно получить с помощью утилиты ADSI Edit, которая размещается в дистрибутиве Microsoft Windows 2000 в директории /Support/Tools. В поле FROM указывается путь к объекту. В данном случае известен только домен. Пробелы в данном поле недопустимы. В поле WHERE указывается тип объекта, к которому адресован запрос. Данное поле является фильтром. Протокол LDAP имеет несколько типов объектов, которые в запросе SQL определяются переменной objectClass: PrintQueue – массив принтеров, опубликованных в AD; Group – группы, созданные в AD; User – пользователи, созданные в AD; Computer – массив компьютеров, зарегистрированных в AD. Пример использования запроса SQL см. в разделе «Поиск опубликованных принтеров в AD».
«Поиск опубликованных принтеров в AD» Для поиска объектов в AD с помощью протокола LDAP используется ADODB-соединение. После создания соединения формируется SQL-запрос и осуществляется поиск в соответствии с запросом. Результатом поиска является массив, который содержит значения полей, указаных в параметре SELECT SQL-запроса. Затем происходит вывод данных на экран. В приведенном примере осуществляется поиск всех опубликованных принтеров в текущем домене и вывод на экран названия принтера и его сетевого имени (VBScript):
39
администрирование Set objConnection = CreateObject("ADODB.Connection") Set objCommand = CreateObject("ADODB.Command") objConnection.CommandTimeout = 120 objConnection.Provider = "ADsDSOObject" objConnection.Open "Active Directory Provider" Set objCommand.ActiveConnection = objConnection objCommand.CommandText = "SELECT printername, printsharename ↵ FROM '"&domain_&"' WHERE objectClass='printQueue'" objCommand.properties("Timeout")=30 objCommand.properties("Cache Results")=false Set st = objCommand.Execute st.Movefirst On Error Resume Next Do Until st.EOF printer_name=St.Fields("PrinterName").Value shares_enum="" shares=St.Fields("printsharename").Value for each share in shares shares_enum=shares_enum+share next Response.write printer_name & shares_enum & chr(13) st.MoveNext Loop
В Active Directory объектом класса printQueue является принтер. Данный объект имеет свойства, значение которых может быть двух типов: строкой и массивом. В приведенном примере значение, содержащее название принтера, является строкой, содержащее сетевые имена принтеров, является массивом. Ниже приведена таблица, с названиями часто используемых полей, соответствующий им тип данных, описание полей и общий формат данных, находящихся в этих полях:
WinNT С помощью протокола WinNT осуществляется подключение к локальному принтеру; чтение настроек и параметров принтера; управление принтером; чтение и управление очередью печати принтера.
Подключение к локальному принтеру Для подключения к принтеру в текущем домене необходимо знать два параметра – название компьютера, к которому подключен принтер, и название принтера. Поскольку принтеры сетевые, то имя компьютера, к которому подключены принтеры, является именем сервера печати (Print Server). Именем принтера является его сетевое имя (Share Name). Оба эти параметра определяются с помощью протокола LDAP. Синтаксис строки подключения в общем виде выглядит следующим образом: Set pq = GetObject("WinNT://" & server_name & "/" ↵ & shares_enum)
где serve_name – имя сервера печати, а shares_enum – сетевое имя принтера. Для получения доступа ко всем доступным принтерам и их очередям печати протокол WinNT совместно используется с протоколом LDAP (VBScript): Set st=objconnection.execute("SELECT shortservername, ↵ printsharename, FROM '" & Domain_ & " ' ↵ WHERE objectClass='printQueue'" ) Do Until st.EOF shares_enum="" shares=St.Fields("printsharename").Value for each share in shares shares_enum=shares_enum & share next server_name=St.Fields("ShortServerNAme").Value Set pq = GetObject("WinNT://" & server_name & "/" ↵ & shares_enum) st.MoveNext Loop
Чтение настроек и параметров принтера Чтение настроек с помощью протокола WinNT осуществляется с помощью элементов массива объекта, вызванного с помощью функции GetObject : Set pq = GetObject("WinNT://" & server_name & "/" ↵ & shares_enum) pq.name
40
администрирование В приведенном примере name является членом массива pq. По типу данных членом массива могут быть строки и массивы. Выше приведены часто используемые элементы массива, соответствующие элементам типы данных и описания элементов:
Управление очередью осуществляется тем же способом, что и управление принтером. Существует три команды, которые могут быть использованы для управления документом, находящимся в очереди печати:
Управление принтером Управление принтером также осуществляется с помощью элементов массива объекта, вызванного с помощью функции GetObject. Элементы массива содержат не только строки и массивы, но и команды:
Приведем пример использования одной из команд (VBScript): Set pq = GetObject("WinNT://" & server_name & "/" ↵ & shares_enum) pq.purge
Чтение и управление очередью печати принтера Очередь печати представляет собой массив, содержащий в себе задания, которые находятся в очереди печати на момент извлечения из нее данных с помощью протокола WinNT. Массив очереди печати является элементом массива, получаемого с помощью функции GetObject. Он содержит элементы, список которых приведен в таблице. Все элементы представляют собой строки:
Пример, в котором удаляется второе задание из очереди печати. Если такого нет, то ошибка обрабатывается с помощью выражения «On Error Resume Next» (VBScript): On Error Resume Next Set pq = GetObject("WinNT://" & server_name & "/" ↵ & shares_enum) For Each printJob In pq.PrintJobs If (number_docum=2) then printJob.remove end if number_docum=number_docum Next
HTML Раздел HTML обеспечивает применение таблицы стилей и установку необходимой таблицы кодировки шрифта для графического оформления проекта, автоматическое обновление страниц; взаимодействие страниц, основанное на передаче форм с помощью метода POST; поиск по заданным критериям.
Таблица стилей и выбор кодировки страницы Обе ASP-страницы используют таблицу стилей и работают в кодировке WIN-1251. Стили описываются в подключаемом файле style.css: H4 {font-size:11; font-family:Arial;} H5 {font-size:10; font-family:Arial;} H6 {font-size:9; font-family:Arial;}
Файл стилей указывается в разделе LINK, необходимая кодировка – в разделе META (HTML):
Пример, в котором читаются поля и выводятся на экран (ASP): Set pq = GetObject("WinNT://" & server_name & "/" ↵ & shares_enum) For Each printJob In pq.PrintJobs status_pre=printJob.status select case status_pre case "0" status_="Íîðìàëüíî" case "1" status_="Ïàóçà" case "18" status_="Îøèáêà" end select number_docum=number_docum summary = summary & ”Íîìåð äîêóìåòà: ” & number_docum ↵ & chr(13) & chr(13) & ”Ñòàòóñ: ” & status_pre & ↵ chr(13) & ”Ïðèîðèòåò: ” & printJob.Description & ↵ chr(13) & ”Ïîëüçîâàòåëü: ” & printJob.User & chr(13) & ↵ ”Âñåãî ñòð. ” & printJob.TotalPages & chr(13) & ↵ ”Ðàçìåð, (Mb) ” & round(printJob.Size/1000000,2) & ↵ chr(13) & ”Ñòàòóñ: ” & status_pre & chr(13) & chr(13) Next Wscript.Echo summary
№10(11), октябрь 2003
<HEAD> <LINK HREF="style.css" TYPE=text/css REL=stylesheet> <META HTTP-EQUIV ="Content-Type" ↵ CONTENT="text/html; CHARSET=windows-1251"> </HEAD>
Параметр CHARSET отвечает за выбор кодировки, в которой будет отображаться документ.
Автоматическое обновление страниц Особенностью проекта является его динамичность, которая достигается автоматическим обновлением страниц через определенный промежуток времени. Обновление обеих страниц происходит с частотой, которая указывается пользователем. Определение времени автоматического обновления является эвристической операцией. Рекомендуется использовать время автоматического обновления от 5 до 10 секунд. Время обновления указывается в разделе META (HTML): </HEAD> < META HTTP-EQUIV ="refresh" CONTENT=10 > </HEAD>
41
администрирование Параметр CONTENT отвечает за временной интервал обновления страниц. Время указывается в секундах.
Взаимодействие страниц Взаимодействие страниц основано на передаче форм, содержащих данные, методом GET. Передача данных осуществляется с помощью двух методов: прямого и косвенного. Прямой метод: В исходной странице создается форма, которая содержит поля для ввода информации и кнопку для отправки информации и загрузки страницы, принимающей данные (HTML): <FORM ACTION="printer_adsi.asp" TARGET="main" METHOD="get"> <INPUT TYPE="submit" VALUE="Ïîèñê"></INPUT> <INPUT NAME="Search_Text"></INPUT> </FORM>
В разделе FORM присутствуют следующие параметры: ACTION, TARGET, METHOD. В параметре ACTION указывается файл, в который будут передаваться данные после нажатия на кнопку. Подразделом, который обязательно присутствует в разделе FORM, является INPUT. INPUT имеет следующие параметры: TYPE, NAME, VALUE. Параметр TYPE определяет вид приемника информации: кнопка (TYPE=«submit» или «reset»); окно для ввода текста (TYPE=«text»), значение по умолчанию; кнопка выбора одного параметра из группы (TYPE=«radio»). VALUE – название поля, отображаемое в объекте. NAME – имя, которое участвует в формировании запроса. Запрос, который формируется с помощью метода GET, в общем виде выглядит следующим образом: http://èìÿ_ñòðàíèöà.asp(htm)?Ï1=Ç1&Ï2=Ç2&...Ïn=Çn
В приведенной строке присутствуют следующие обозначения: П – параметр, З – значение. В используемом примере данная стока будет выглядеть следующим образом: http://printer_adsi.asp?Search_Text=HP
если в стоке было введено «HP». Рассмотрим «страницу-приемник»: для получения переданных принимающей странице данных необходимо прочитать запрос и присвоить переданные значения переменным. Данная операция, опираясь на приведенный пример, осуществляется следующим образом: set s_p_r= Request.QueryString(«Search_Text»)
Таким образом, параметр s_p_r=«HP». Прямой метод используется для осуществления поиска. Косвенный метод: Косвенный метод используется для передачи данных из одной ASP-страницы в другую. Он основан на том, что
42
при нажатии пользователем на картинку или текст, являющийся ссылкой, сразу формируется запрос, который передает данные. Поскольку очередью принтера невозможно управлять, если принтер рассматривать как сетевое устройство, то использование протокола LDAP становится невозможным. Для доступа к очереди принтера, как ранее отмечалось, используется протокол WinNT. Для использования протокола необходимо передавать 2 параметра: сетевое имя принтера (Share Name) и название окна (Frame), в котором необходимо вывести данную страницу. Опираясь на приведенные ранее примеры, данные будут передаваться на страницу View_Printer.asp, запрос будет иметь следующий вид (ASP): <% <A HREF=" & chr(34) & "View_Printer.asp?Printer_to=" & ↵ printer_name & chr(34) & " target=" & chr(34) &"var"& ↵ chr(34) & " > <IMG SRC =images\pr1.jpg BORDER=0> </A> %>
Из-за особенностей ASP необходимо прибегать к обозначению кавычек функцией chr(34). Подробнее о передаче данных будет рассказано в разделе, посвященном WinNT.
Поиск по заданным критериям Поиск базируется на использовании фильтра. Перед осуществлением поиска пользователь выбирает критерий поиска, словосочетание для поиска и нажимает кнопку «Поиск», которая формирует запрос и загружает страницу. В качестве критерия может быть выбран один из параметров: «Название», «Описание», «Размещение». По умолчанию принято значение «Название». Выбор значения по умолчанию осуществляется меткой CHECKED в соответствующем разделе INPUT. Форма на странице-отправителе выглядит следующим образом (HTML): <FORM ACTION="printer_adsi.asp" TARGET="main" METHOD="get"> <INPUT TYPE="submit" VALUE="Ïîèñê"></INPUT> <INPUT NAME="Search_Text"></INPUT> <BR> <INPUT CHECKED TYPE="radio" VALUE="1" ↵ NAME="radGrp">Íàçâàíèå < INPUT TYPE="radio" VALUE="2" NAME="radGrp">Îïèñàíèå < INPUT TYPE ="radio" VALUE="3" NAME="radGrp">Ðàçìåùåíèå </FORM>
Если, например, осуществляется поиск всех устройств, которые встречают в названии словосочетание «hp», то формируется следующий запрос: http://printer_adsi.asp?Search_Text=hp&radGrp=1
В принимающем запрос файле printer_adsi.asp для расшифровки запроса используется следующая методика: данные, переданные форме, присваиваются переменным; происходит фильтрация данных в зависимости от параметра, отвечающего за критерий поиска; происходит поиск в соответствующих полях; вывод результатов поиска на экран.
администрирование
Установка сайта и особенности конфигурирования IIS Созданный сайт необходимо опубликовать с помощью IIS на любом компьютере домена, принтеры которого вы хотите инспектировать. Желательно, чтобы этим компьютером был компьютер, который функционирует круглосуточно. Таким компьютером является сервер. Данный сайт работает с Active Directory. Поскольку для чтения AD необходимы права администратора, то сайт будет работать только в случае его использования системным администратором. Необходимо иметь возможность просматривать сайт с любого компьютера в домене без перерегистрации пользователя. Для достижения желаемого результата необходимо назначить следующие права доступа на папку, в которой опубликован сайт: группе «Domain Admins» необходимо предоставить уровень доступа «Full Control» на папку с сайтом; остальные группы и пользователи должны быть удалены (см. рисунок 1). В настройке IIS для данного сайта в его свойствах необходимо, как показано на рисунке 3, войти во вкладку «Authentication Methods», нажав на кнопку «Edit». Затем выключить анонимный доступ (Anonnymos access), убрав галку напротив соответствующей записи. В разделе «Authenticated access» необходимо установить галку только напротив «Basic authentication».
Ðèñóíîê 1.
Ðèñóíîê 2. Èëëþñòðàöèÿ ñâîéñòâ ïðèíòåðà è î÷åðåäè ïå÷àòè
№10(11), октябрь 2003
43
администрирование невозможен по неизвестным причинам. Рекомендуется не ставить эту галку.
Приложение: default.htm <html> <head> <title>Ïðèíòåðû èçäàòåëüñòâà ÏÐÎÑÂÅÙÅÍÈß</title> <meta http-equiv="Content-Type" content="text/html; ↵ charset=windows-1251"> <FONT FACE="Arial" size="3"></FONT> </head> <frameset cols="30%,*" FRAMEBORDER="5" BORDER="yes" ↵ FRAMESPACING="5" > <frame src="printer_adsi.asp?radGrp=1&Search_Text=" ↵ name="main" scrolling="yes" ÌÀRGINHEIGHT=1 > <frame src="about:blank" name="var"> </frameset> </html>
style.css H4 {font-size:12; font-family:Arial;} H5 {font-size:11; font-family:Arial;} H6 {font-size:10; font-family:Arial;} Ðèñóíîê 3.
Желательно включить «Integrated Windows authentication» для того, чтобы системному администратору, который вошел в сеть под своей учетной записью, не предлагалось вводить пароль. Однако этот механизм доступа к сайту
Ðèñóíîê 4. Èëëþñòðàöèÿ âåá-èíòåðôåéñà ñåòåâîãî ïðèíòåðà
44
printer_adsi.asp <%@ Language=VBScript CODEPAGE=1251%> <HTML> <body link="red" VLINK=red> </body> <TITLE> Âûáîð ïîðÿäêà óïîðÿäî÷èâàíèÿ àäìèíñêîãî ñîôòà </TITLE>
администрирование <HEAD> <LINK href="style.css" type=text/css rel=stylesheet> <meta http-equiv="Content-Type" content="text/html" ↵ charset=windows-1251> <meta http-equiv="refresh" content=10 > </HEAD> <BODY> <FONT FACE="Arial"> <H4><b><center>"Ïðèíòåðû"</center></H4> <br> <h6> <FORM ACTION="printer_adsi.asp" target="main" METHOD="get"> <INPUT TYPE="submit" VALUE="Ïîèñê"></INPUT> <INPUT NAME="Search_Text"></INPUT> <br> <input checked type="radio" value="1" ↵ name="radGrp">Íàçâàíèå <input type="radio" value="2" name="radGrp">Îïèñàíèå <input type="radio" value="3" name="radGrp">Ðàçìåùåíèå </FORM> </h6> <center><table widht=90% cellpadding=10%> <td> <% set rootDSE_ = GetObject("LDAP://RootDSE") domain_ = "LDAP://" + rootDSE_.Get("defaultNamingContext") Set objNameSpace = GetObject("WinNT:") Set objConnection = CreateObject("ADODB.Connection") Set objCommand = CreateObject("ADODB.Command") objConnection.CommandTimeout = 120 objConnection.Provider = "ADsDSOObject" objConnection.Open "Active Directory Provider" Set objCommand.ActiveConnection = objConnection objCommand.CommandText = "SELECT servername, printername, ↵ printsharename, location, description FROM '"&domain_&"' ↵ WHERE objectClass='printQueue'" objCommand.properties("Page size")=1000 objCommand.properties("Timeout")=30 objCommand.properties("Cache Results")=false Set st = objCommand.Execute st.Movefirst set radio_=Request.QueryString("radGrp") '- what is search ↵ - can 1 - fullname ,2 - location ,3 - description set s_p_r= Request.QueryString("Search_Text") summary="<Table width"& chr(61) & "100% > <TR> ↵ <TD></TD><Center> <TD> <B> ↵ <H5>Íàçâàíèå ïðèíòåðà</H5></TD> <TD> </TD> <TD> ↵ </TD></tr></Center>" flag=0 i=0 on error resume next dim array_1(500) i=0 Do Until st.EOF
summary_where_search= descrits_enum case "3" summary_where_search= location_name end select if instr(Lcase(summary_where_search), Lcase(s_p_r)) then array_1(i)="<TR><td>" & status_P & " </td> <TD> <H6> ↵ " & printer_name & "</H6></TD> <TD><A href=" ↵ & chr(34) & "view_printer.asp?Printer_to=" ↵ & printer_name & chr(34) & " target=" & chr(34) ↵ &"var"& chr(34) & "title=" & chr(34) ↵ & printer_name & " - " & descrits_enum & chr(34) ↵ & " > <b> <img src=images\pr1.jpg border=0> ↵ </b></a> </td> <td> <A href=http:\\" ↵ & shares_enum & " target=" & chr(34) ↵ &"var"& chr(34) & "title=" & chr(34) ↵ & printer_name & " - " & descrits_enum ↵ & chr(34) & " > <b> ↵ <img src=images\pr2.jpg border=0> ↵ </b></a> </td></tr>" i=i+1 flag=1 end if st.MoveNext Loop up_array=ubound(array_1) for j=0 to up_array for i=0 to up_array if strcomp(array_1(i),array_1(i+1),0)=1 then temp=array_1(i) array_1(i)=array_1(i+1) array_1(i+1)=temp end if next next for i=0 to up_array summary=summary&array_1(i) next result_search=summary_header & " <table & summary & " </tr> </table></h6>"
> <tr> " ↵
if flag=0 then result_search="<center><FONT FACE=Arial size=3><B><I><H5> ↵ Ïî çàïðîñó íè÷åãî íå íàéäåíî!</H5></B></I></center>" end if Response.write result_search %> </BODY> </HTML>
view_printer.asp
printer_name=St.Fields("PrinterName").Value shares_enum="" shares=St.Fields("printsharename").Value for each share in shares shares_enum=shares_enum+share next server_name=St.Fields("servername").Value descrits_enum="" if vartype(St.Fields("description"))=8204 then descrits=St.Fields("description") for each des in descrits descrits_enum=descrits_enum+des next end if location_name=St.Fields("location").Value Set pq = GetObject("WinNT://" & server_name & "/" ↵ & shares_enum) status_printer=pq.status select case status_printer case "0" status_P="<img src=images\3normal.jpg border=0>" case "1" status_P="<img src=images\2pause.jpg border=0>" case "18" status_P="<img src=images\1error.jpg border=0>" end select select case radio_ case "1" summary_where_search= shares_enum & printer_name case "2"
№10(11), октябрь 2003
<%@language=VBScript %> <html><head> <meta http-equiv="Content-Type" content="text/html" ↵ charset=windows-1251> <meta http-equiv="refresh" content=10 > <LINK href="style.css" type=text/css rel=stylesheet> </head><body> <FONT FACE="Arial"> <% set printer_name_to=Request.QueryString("Printer_to") set rootDSE_ = GetObject("LDAP://RootDSE") domain_ = "LDAP://" + rootDSE_.Get("defaultNamingContext") Set objConnection = CreateObject("ADODB.Connection") objConnection.Provider = "ADsDSOObject" objConnection.Open "ADSI" set st=objconnection.execute("SELECT shortservername, ↵ printername, printsharename, location, ↵ description, driverversion, drivername, portname, ↵ printlanguage, printcolor, printmaxresolutionsupported, ↵ printmemory, whencreated, whenchanged, servername, ↵ printpagesperminute FROM '" & Domain_ & " ' ↵ WHERE objectClass='printQueue'" ) Do Until st.EOF printer_name=St.Fields("PrinterName").Value if printer_name_to=printer_name then shares_enum="" shares=St.Fields("printsharename").Value
45
администрирование for each share in shares shares_enum=shares_enum & share next descrits_enum="" if vartype(St.Fields("description"))=8204 then descrits=St.Fields("description") for each des in descrits descrits_enum=descrits_enum+des next end if location_name=St.Fields("location").Value driver_name=St.Fields("driverName").Value driver_version=St.Fields("driverVersion").Value if vartype(St.Fields("portName"))=8204 then ports=St.Fields("portName") for each port in ports port_name=port_name+port next end if support_color=St.Fields("printColor").Value Resolution=St.Fields("PrintMaxResolutionSupported").Value print_speed=St.Fields("PrintPagesPerMinute").Value server_name=St.Fields("ShortServerNAme").Value print_memory=St.Fields("PrintMemory").Value server_name=St.Fields("servername").Value when_created=St.Fields("WhenCreated").Value when_changed=St.Fields("WhenChanged").Value language_enum="" if vartype(St.Fields("printLanguage"))=8204 then formats=St.Fields("printLanguage") for each format in formats language_enum=language_enum+format next end if Set pq = GetObject("WinNT://" & server_name & "/" ↵ & shares_enum) set printer_change_status=Request.QueryString("change_status") select case printer_change_status case "1" pq.pause case "2" pq.resume case "3" pq.purge case "4" number_=1 number_to_="" For Each printJob In pq.PrintJobs set number_to_=Request.QueryString("number_doc") if cint(number_to_)=number_ then printJob.pause end if number_=number_+1 next case "5" number_=1 number_to_="" For Each printJob In pq.PrintJobs set number_to_=Request.QueryString("number_doc") if cint(number_to_)=number_ then printJob.resume end if number_=number_+1 next case "6" number_=1 number_to_="" For Each printJob In pq.PrintJobs set number_to_=Request.QueryString("number_doc") if cint(number_to_)=number_ then set del_docum=pq.printJobs del_docum.Remove cstr(printJob.name) end if number_=number_+1 next end select change_status=0 status_printer=pq.status select case status_printer case "0" status_P="<img src=images\3normal.jpg border=0>" case "1" status_P="<img src=images\2pause.jpg border=0>" case "18" status_P="<img src=images\1error.jpg border=0>" end select sum_jobs="<Table width=100% > <TR> <Center> ↵ <TD><h5>Îïåðàöèè</td><td><B><H5> Íàçâàíèå äîêóìåíòà ↵ </TD> <TD> <B> <H5> Ïîëüçîâàòåëü </TD> <TD> <H5> <B> ↵ Ïðèîðèòåò </TD> <TD> <H5> <B> Êîë-âî (ñòð) </TD> <TD> ↵ <B> <H5> Ðàçìåð (Ìá)</TD> <TD> <B> <H5> Ñîñòîÿíèå ↵ </TD></Center>"
46
number_docum=0 For Each printJob In pq.PrintJobs status_pre=printJob.status select case status_pre case "0" status_="<img src=images\3normal.jpg border=0>" case "1" status_="<img src=images\2pause.jpg border=0>" case "18" status_="<img src=images\1error.jpg border=0>" end select number_docum=number_docum+1 sum_jobs=sum_jobs & "<TR><TD width=60><h6> ↵ <a href="&chr(34)&" view_printer.asp?Printer_to=" ↵ & printer_name_to ↵ & "&change_status=4&Number_Doc="&number_docum ↵ & chr(34)& " > <img src=images\l2.jpg border=0></a> ↵ <a href="&chr(34)&" view_printer.asp?Printer_to=" ↵ & printer_name_to ↵ & "&change_status=5&Number_Doc="&number_docum ↵ & chr(34)& "><img src=images\l1.jpg border=0></a> ↵ <a href="&chr(34)&" view_printer.asp?Printer_to=" ↵ & printer_name_to ↵ & "&change_status=6&Number_Doc="&number_docum ↵ & chr(34)& "><img src=images\l3.jpg ↵ border=0></a></td></center> <td> <h6>" ↵ & printJob.Description & "</td><TD><h6>" ↵ & printJob.User & "</TD> <TD width=40> <h6>" ↵ & printJob.Priority &" </TD> <TD width=50><h6>" ↵ & printJob.TotalPages & " </TD><TD width=40><h6>" ↵ & round(printJob.Size/1000000,2) & " </TD> ↵ <TD width=50><h6>"& status_ & "</TD>" Next s1="<center><b> <H4>" & printer_name & "</b></center><Br> ↵ <Table width=100% > <tr> <td> <h5> Îïèñàíèå: <Br></td> ↵ <td colspan=3> <h6>"& descrits_enum & "<Br></td></tr> ↵ <tr><td><b><h5> Ðàñïîëîæåíèå:</b><Br></td> <td><h6>" ↵ & location_name & "<Br></td> <td><h5>" s2="<b> Äðàéâåð: </b><Br></td> <td><h6>" & driver_name ↵ & "<Br></td> </tr> <tr> <td> <h5> <b> Ñåðâåð: </b> ↵ <Br></td> <td> <h6>" & server_name & "<Br></td> ↵ <td><b><h5> Âåðñèÿ: </b><Br></td> <td> <h6>" ↵ & driver_version & "<Br></td></tr> <tr><td><h5><b> Ïîðò: ↵ </b><Br></td> <td> <h6>" & port_name & "<Br></td> <td> <h5>" s3="<b> Òèï äàííûõ: </b><Br></td> <td> <h6>"& pq.Datatype ↵ &"<Br></td></tr> <tr><td><b><h5> ßçûê: </b><Br></td> ↵ <td><h6>" & language_enum & "<Br></td> <td> <b><h5> ↵ Ïîääåðæêà öâåòà: </b><Br></td> <td> <h6>" & support_color ↵ & "<Br></td> </tr> <tr> <td> <b><h5> Ðàçðåøåíèå: ↵ </b><Br></td> <td><h6>" & resolution & " dpi <Br></td> ↵ <td><h5>" s4="<b> Ñêîðîñòü: </b><Br></td> <td> <h6>" & print_speed ↵ & " ñòð./ìèí.<Br></td> </tr> <tr> <td><b><h5> Ïàìÿòü: ↵ </b><Br></td> <td><h6>" & print_memory ↵ & " Ká <Br></td> <td><h5>" s5="<b> Ñîçäàí: <Br></td></b><td><h6>" & When_created ↵ & "<Br></td></tr><tr> <td><b><h5> ↵ Ñòàòóñ:</b><Br></td><td><center> <h6>"& status_P ↵ & "</center><Br></td> <td><b><h5> </b><Br></td> <td><h6>" ↵ & "<Br></td></tr> <td><h5>" b1="<b>Ïðèíòåð: </b></td><td><center> ↵ <a href="&chr(34)&" view_printer.asp?Printer_to=" ↵ & printer_name_to & "&change_status=1"&chr(34)& " > ↵ <img src=images\pause_pr.jpg border=0></a> &nbsp &nbsp &nbsp" b2="<a href="&chr(34)&" view_printer.asp?Printer_to=" ↵ & printer_name_to & "&change_status=2"&chr(34)& ↵ "><img src=images\resume_pr.jpg border=0></a> ↵ &nbsp &nbsp &nbsp" b3="<a href="&chr(34)&" view_printer.asp?Printer_to=" ↵ & printer_name_to & "&change_status=3"&chr(34)& ↵ "><img src=images\1error.jpg ↵ border=0></a></td></center></tr></table> " summary=s1 & s2 & s3 & s4 & s5 & b1 & b2 & b3 & "<br> <br>" end if st.MoveNext Loop Response.write summary Response.write num_docum Response.write sum_jobs %>
Отдельное спасибо Филиппу Зыкову, руководителю Центра ИТ Издательства «Просвещение», благодаря идее которого и возникла данная статья.
безопасность
ОБНАРУЖЕНИЕ ТЕЛЕКОММУНИКАЦИОННЫХ АТАК: ТЕОРИЯ И ПРАКТИКА, SNORT
ПАВЕЛ ЗАКЛЯКОВ
48
безопасность По данным CERT[1], число инцидентов в сети растёт не по дням, а по часам – если грубо поделить 100 тысяч на 365 дней и на 24 часа, то получится примерно около 11 регистрируемых инцидентов в час. Ситуацию, сложившуюся в последнее время с червём Blaster, следует убрать из рассмотрения как исключение.
Ãðàôèê 1. Ðîñò ÷èñëà èíöèäåíòîâ ïî ãîäàì (îñü èíöèäåíòîâ â ëîãàðèôìè÷åñêîì ìàñøòàáå, êðàñíàÿ ëèíèÿ ïîêàçûâàåò òåíäåíöèþ ðîñòà)
Мы видим, что число инцидентов растёт, а в то же время последние номера журнала не изобилуют статьями по вопросам сетевой безопасности, а тем более обнаружению телекоммуникационных атак. На мой взгляд, есть ряд удачных публикаций [2-4]; менее удачных в силу сложности непосредственной применимости [5-8] и неудачных, но все они далеки от обнаружения атак. Даже широко продаваемая литература [9-14] далека от жизни, и за красивыми названиями порой ничего не стоит, кроме полного отставания в вопросах практической реализации. Хотелось бы несколько заполнить этот вакуум полезной информацией, в частности информацией про систему обнаружения атак IDS Snort [15]. Так как теория не стоит на месте и все появляющиеся упоминания скорее неполные, чем неправильные, то хотелось бы закрыть этот вакуум, подведя читателя непосредственно подкованным к вопросу использования IDS Snort. Замечания, обсуждение и критика вопросов обнаружения телекоммуникационных атак приветствуются.
Способы классификации атак с позиции построения систем их обнаружения Существуют различные типы классификации атак. Например, деление на активные и пассивные, внешние и внутренние, умышленные и неумышленные и др. Классы, в свою очередь, могут делиться на подклассы, подвиды, часто пересекающиеся, в результате можно получить следующую классификацию:
Ðèñóíîê 1. Êëàññèôèêàöèÿ àòàê
№10(11), октябрь 2003
Вышеописанные типы классификации хороши с точки зрения детализации по тем или иным критериям, но часто они выделяют отдельные классы, имеющие минимальное значение с точки зрения систем обнаружения атак (СОА). Поэтому наиболее перспективной представляется уже описанная в литературе следующая классификация, разделяющая атаки на классы, в которых их будет легче обнаружить и классифицировать: 1. Удалённое проникновение (remote penetration). Атаки, которые позволяют реализовать удалённое управление компьютером через сеть. Примерами программ, реализующих такое управление, являются, NetBus или Back Orifice, реверсивный сеанс telnet [18, стр. 314]. 2. Локальное проникновение (local penetration). Атака, приводящая к получению несанкционированного доступа к узлу, на котором она запущена, либо повышению прав пользователя. Примером такой программы является GetAdmin или реализация эксплоита для уязвимости в ядрах Linux через ptrace. 3. Удалённый отказ в обслуживании (remote DoS (denial of service)). Атаки, которые позволяют нарушить функционирование системы или перезагрузить компьютер удалённо. Примерами такой атаки являются teardrop, trinoo, fapi. 4. Локальный отказ в обслуживании (local DoS). Атаки, позволяющие нарушить функционирование системы или перезагрузить компьютер, на котором они реализуются. В качестве примера такой атаки можно привести враждебный апплет, который загружает центральный процессор бесконечным циклом, что приводит к невозможности обработки запросов других приложений. Также, в случае неправильной настройки, это может быть ветвящееся приложение с кучей потомков, занимающих все свободные идентификаторы PID. 5. Сетевые сканеры (network scanners). Программы, которые анализируют топологию сети и обнаруживают сервисы, доступные для атаки. Примером такой программы может служить nmap. 6. Сканеры уязвимостей (vulnerability scanners). Программы, осуществляющие поиск уязвимостей на узлах сети и которые могут быть использованы для реализации атак. Примеры: система SATAN или Shadow Security Scanner, XSpider, LanGuard, XFocus-X-Scan и др. 7. Взломщики паролей (password crackers). Программы, которые подбирают пароли пользователей. Примером взломщика паролей может служить L0pht Crack для Windows или Crack для *nix. 8. Анализаторы протоколов и снифферы (sniffers). Программы, которые «прослушивают» сетевой трафик. При помощи этих программ можно автоматически искать такую информацию, как идентификаторы и пароли пользователей, информацию о кредитных картах и так далее. Фактически анализатор протокола – это сниффер плюс некоторая часть, осуществляющая фильтрацию и разбор перехваченных пакетов по некоторым правилам. Часто обе задачи выполняет один и тот же продукт. Примерами таких программ могут служить tcpdump, ethereal, Microsoft Network Monitor, NetXRay компании Network Associates, Lan Explorer.
49
безопасность Принадлежность реальных атак к тому или иному классу не всегда однозначна, так как не всегда можно чётко определить конечную цель атаки, которой можно добиться разными путями. Например, в случае невозможности осуществления напрямую DoS-атаки может быть выполнена атака на удалённое проникновение, после чего могут быть остановлены те или иные службы. С точки зрения СОА не имеет смысла классифицировать атаки по основным видам угроз [13, стр 77]: нарушение конфиденциальности, целостности, доступности, так как эти угрозы достаточно общие и реализуются по-разному, соответственно их обнаружение может быть осуществлено не единственным способом. Каждая фирма предпочитает классифицировать атаки по-своему, например, компания Internet Security Systems, Inc. [19] ещё больше сократила число возможных категорий, доведя их до пяти: сбор информации (Information gathering); попытки несанкционированного доступа (Unauthorized access attempts); отказ в обслуживании (Denial of service); подозрительная активность (Suspicious activity); системные атаки (System attack). Первые четыре категории относятся к удалённым атакам, а последняя – скорее к локальным, так как удалённое совершение системных атак затруднительно. Также в эту классификацию не попали некоторые атаки, например, «ложный DNS-сервер» [34, стр. 75-84], «подмена ARP-сервера» [34, стр. 84-99] и др. Современные атаки настолько разнообразны, что единой однозначно правильной классификации, учитывающей все нюансы, они не поддаются. Наиболее правильным подходом является классификация с точки зрения СОА, так как в этом случае более чётко можно отнести те или иные действия к тому или иному классу атак, указав реальные, а не гипотетические атаки, и определить способы противодействия и обнаружения. Давайте рассмотрим различные классы атак вместе со средствами противодействия. С позиции СОА изначально атаки следует разделить на два больших класса: активные и пассивные, как это показано на рис. 1. Пассивные атаки – это различный сбор информации о какой-либо службе, узле или сети узлов без какого-либо воздействия на их работу. Например, прослушивание и перехват трафика. Также пассивной атакой считается анализ открытых источников, однако данный подкласс мы рассматривать не будем, так как это не прямая, а косвенная атака. Более правильным было бы введение модели нарушителя, из которой сразу стало бы ясно, что в нашем случае считать атакой, а что нет, но чтобы не перегружать статью, опустим этот формальный момент. Пассивные атаки являются наиболее сложными с точки зрения их обнаружения, так как грамотно организованная атака никак себя не обнаруживает. Данным классом не стоит пренебрегать, так как основная часть трафика в сети передаётся в открытом виде и эта атака может служить составной частью более крупномасштабной атаки. Для её реализации чаще всего сетевой адаптер
50
ethernet переводится в режим promiscuous mode. Так как среда ethernet общая для всех, кроме случая точка-точка, сетевой адаптер начинает принимать (прослушивать) весь проходящий трафик. Поступающие так средства называются снифферами. Обычно снифферы запускаются на машинах, реально работающих в сети, то есть имеющих легитимные сетевые адреса. Если сниффер используется нарушителем, то это считается атакой. Если сниффер санкционированно используется администратором сети, то это мощное средство анализа работы сети. Также сниффер является составной частью любой сеть-ориентированной СОА (подробнее о сеть-ориентированных СОА см. далее). Обнаружение снифферов чаще всего основывается на ошибках их работы либо косвенными методами. При неправильной настройке хосты со снифферами могут выдавать ответы на пакеты, адресованные им, обнаруживая себя, в то время как при обычном режиме работы они на эти пакеты отвечать не стали бы. (Например, обнаружение большинства Linux-машин со снифферами несколько проще: в режиме прослушивания они отвечают на все пакеты, адресованные их IP-адресу, вне зависимости, их ли MAC-адрес в пакете или нет, из-за особенностей реализации и используемых настроек по умолчанию. В обычном же режиме работы все пакеты с чужими MAC-адресами отбрасываются не будучи обработанными.) Другой трудноскрываемой чертой снифферов, а следовательно, выдающей их, является статистическая зависимость. Любому снифферу необходимо обрабатывать трафик либо сохранять его куда-то на диск. В случае недостаточной производительности неизбежны задержки. При этом замедление реакции на обычные пакеты может коррелировать с повышением трафика в сети у узлов, находящихся в режиме прослушивания. Так как снифферы постоянно совершенствуются, то на подобных ошибках можно отловить только уязвимые снифферы или устанавливаемые удалённо (в процессе атак, когда многие мелочи невозможно не только предусмотреть, но и реализовать). Существует несколько способов борьбы со снифферами. Первым, не самым эффективным способом борьбы является их обнаружение с помощью антиснифферов. Среди таких программных средств, ловящих снифферы в сети, можно назвать следующие: AntiSniff, CPM (Check Promiscuous Mode), neped, sentinel. Со своей задачей данные программные продукты справляются очень неплохо. Однако хорошо настроенный сниффер обнаружить ими невозможно. Поиск необнаруживаемых средств возможен только косвенными способами, например, путём создания ловушек [6,20] и генерации ложного трафика к ним, содержащего ценную информацию, скажем, пароли в открытом виде при обращении к ложному почтовому POP3серверу. Хост, воспользовавшийся ложной информацией, будет значительным источником информации для успешного поиска сниффера. Однако и в этом случае атакующего могут и не поймать, если никто не воспользуется ловушкой. Ярким примером из жизни может служить история с городом Ковентри во время Второй мировой войны, когда был разбомблён целый город с людьми в цену сокрытия факта получения информации.
безопасность Несомненно, что бороться со снифферами лучше предупреждающими способами, сводя эффективность их использования до нуля. Например, с помощью сильных средств аутентификации. Под «сильными» мы понимаем такие методы аутентификации, которые трудно обойти. Например, использование одноразовых паролей (OTP – One-Time Passwords). Существует несколько способов реализации одноразовых паролей, в том числе и с использованием односторонних функций. Если нарушитель узнаёт одноразовый пароль с помощью сниффера, то эта информация будет бесполезной, потому что в этот момент пароль уже будет использован и выведен из употребления. Заметим, что этот способ борьбы со сниффингом эффективен только для борьбы с перехватом паролей. Снифферы, перехватывающие другую информацию (например, сообщения электронной почты), не теряют своей эффективности. Ещё одним способом борьбы со сниффингом пакетов в вашей сетевой среде является локализация трафика путём использования коммутирующей инфраструктуры. Если, к примеру, во всей организации используется коммутируемый ethernet, хакеры могут получить доступ только к трафику, поступающему на тот порт, к которому они подключены. Коммутируемая инфраструктура не ликвидирует угрозу сниффинга, но заметно снижает её остроту. На практике данный класс атак имеет очень узкое применение, ограничивающееся в случае локализации трафика одним сегментом. Сегодняшнее значительное падение цен на коммутаторы (switch-и,$25-55 за 5-16-портовые) позволяет полностью отказаться от концентраторов (hub), чем значительно снизить актуальность применения данной атаки на практике. В случае использования физической среды, отличной от ethernet, реализация программными средствами прослушивания сильно усложняется, вплоть до невозможности. Физическое снятие информации нами вообще не рассматривается. В случае прохождения трафика через ненадёжные узлы также возможна утечка информации, попадающая под данный класс атак. Реализация в этом случае не требует рассмотрения. Бороться следует либо шифрованием трафика, либо, если позволяет маршрутизация, заданием маршрута через надёжные узлы. Использование средств шифрования трафика (криптографии) не предотвращает возможности перехвата сообщений и не распознаёт работу снифферов, однако является самым действенным средством по борьбе со снифферами. Если канал связи является криптографически защищённым, то это значит, что нарушитель перехватывает зашифрованные сообщения. Использование стойких алгоритмов шифрования, например ГОСТ 28147-89, делает эту работу бесполезной. На сегодня существуют различные реализации данного способа с различной степенью надёжности. Например, криптография некоторых устройств фирмы Cisco на сетевом уровне базируется на протоколе IPSec, который представляет собой стандартный метод защищённой связи между устройствами с помощью протокола IP. К прочим криптографическим протоколам, которые можно использовать для борьбы со
№10(11), октябрь 2003
сниффингом, можно отнести SSH (Secure Shell) и SSL (Secure Socket Layer). Активные атаки – это взаимодействие со службой, узлом или сетью узлов с целью нарушения их функционирования либо получения несанкционированным образом какой-либо информации. (На сегодняшний день нет точного определения термина «атака» [9, стр. 38], как и точного определения «активная атака».) Исходя из этого определения можно заключить, что оно захватывает основные три типа угроз [13, стр. 77]: нарушение конфиденциальности, целостности, доступности, но, как было замечено выше, реально эти три типа сводятся к двум: активному сбору информации и нарушению работы. Для обоих типов имеются средства противодействия. Результатом нарушения работы может быть утечка информации, например, правила функционирования могут быть таковы, что информация недоступна. Также может быть отказ в обслуживании, замена одних параметров или данных другими. Формально в это определение попадёт и класс атак «без последствий», когда что-то было изменено, но ничего от этого не нарушилось, но от этого атаки не перестали быть атаками, как если бы вы перешли дорогу в отсутствие машин и свидетелей на красный свет, поэтому такие атаки надо также рассматривать. Многие определения упускают этот на первый взгляд безобидный класс атак. С точки зрения СОА этот класс атак практически ничем не будет отличаться от других. Под активным сбором информации следует понимать все способы, с помощью которых можно получить информацию: сканирование, работу со службами, получение информации в результате нарушения работы. (Существуют способы получения информации не техническими средствами или способами, которым нельзя противопоставить СОА. Такие способы не рассматриваются, так как с технической точки зрения ни атаками, ни телекоммуникационными атаками они не являются. Например, обзор печатных источников открытой информации.) Термин «телекоммуникационная атака» более правильный, но в силу его «громоздкости и длинности» в письменной и устной речи он практически всегда заменяется просто «атакой», все понимают смысл из контекста, хотя формально, например, удар топором по работающему серверу с последующим его выходом из строя будет являться атакой на отказ в обслуживании. Везде и ниже мы будем подразумевать телекоммуникационные атаки, если это не оговорено особо. Сканирование бывает двух видов: обычное (или открытое) и полуоткрытое (закрытое). Открытое сканирование – это когда производится попытка соединиться обычным образом с одной или несколькими службами. Так как службы привязаны к портам, то попытка соединения называется «опробованием порта» или просто опробованием. Чаще всего это делается с целью получения информации прямым или косвенным образом. При этом работа узлов, связанных каким-то образом с работой данной службы, не нарушается. Обычно сканирование/опробование идёт сериями, как вариант, растянутое по времени и случайным образом.
51
безопасность После соединения со службой и получения от неё приветственных заголовков соединение закрывается. Сканирование осуществляется программами, называемыми «сканерами». Обычно под сканером понимают средство защиты, выявляющее уязвимые места в системе, которое помимо различных сканирований может работать со службами. Если сканирование не санкционировано, то оно считается атакой. Сканеры могут запускаться как локально, так и удалённо на других узлах. Различные сканеры ищут разные слабые места, но все они могут быть разделены на две категории: сканеры системы и сканеры сети. Сканеры сети подобны человеку, проверяющему, закрыл он дверь или нет, дёргая при этом за ручку. Подёргивание ручки не у своей двери аналогично несанкционированному сканированию. С целью сбора информации открытому сканированию могут подвергаться не только отдельные службы и узлы, но и целые сети. Сканирование может проводиться как вручную, так и автоматическими средствами. С целью затруднения обнаружения в лог-файлах факта сканирования, оно может проводиться со случайным порядком сканирования портов и продолжительное время. Для борьбы со сканированием рекомендуется использовать программы, отслеживающие обращения с одного IP-адреса в короткое время к различным портам и блокирующие весь трафик для данного адреса. Также рекомендуется вместо сообщения об ошибке, в случае отсутствия сервиса/узла/ сети, во внешнюю сеть вообще не высылать никакой информации [21]. Среди программ-сканеров можно перечислить следующие программные продукты, имеющие те или иные дополнительные возможности: nmap, ISS, SATAN, Connect, exsscan, getethers, IdentTCPscan, jakal, portscan, QueSo, sl0scan, spoofscan, strobe, xscan и др. Для защиты от атак, выполняемых сканерами, существуют различные программы, например: courtney, IcmpInfo, scan-detector, klaxon, PortSentry и многие другие, включая большинство СОА. У обычного открытого сканирования есть один минус, а именно, оно может быть легко обнаружено без использования СОА путём ручного просмотра лог-файлов. На первых порах сканирования так и обнаруживали. В ответ на это был придуман способ закрытого или полуоткрытого сканирования, когда простым способом без использования дополнительных программ обнаружить факт сканирования невозможно. Полуоткрытое сканирование – это формально незавершённое обычное открытое сканирование. Если рассмотреть обычную процедуру трёхстороннего «рукопожатия» при установке TCP-соединения, то отличие от обычного сканирования будет заключаться в отсутствии третьей – завершающей стадии. Если коротко, то согласно рекомендациям [22, 23] при установке соединения с узла, осуществляющего сканирование, посылается пакет с установленным флагом SYN (первая стадия), в ответ высылается подтверждение установления соединения пакетом с установленными флагами SYN и ACK со сканируемого узла (вторая стадия). Далее требуется подтверждение установления соединения со сканирующего узла пакетом с установленным флагом SYN (третья стадия). При отсутствии последней стадии происходит разрыв формально не устано-
52
вившегося до конца соединения по тайм-ауту, как следствие, запись в лог-файлах об успешном соединении не делается. Отсутствие записи о попытке установления соединения свидетельствуют об отсутствии сканирования. Также в этот класс следует отнести сканирования пакетами без флагов, пакетами со всеми установленными флагами и различными их неправильными комбинациями, в литературе подобные сканирования носят свои названия, как NULL scan, FIN scan, X-MAS scan, «oddball packet» и др. Так как в RFC чётко не определено, как следует реагировать на неправильные пакеты, то различные операционные системы делают это по-разному, таким образом имеется возможность определить используемую операционную систему на хосте косвенным образом. Ситуация сравнима со следующей: вы подходите или подъезжаете к светофору, а там одновременно горят и красный и зелёный сигналы. Кто-то подождёт, кто-то пойдёт или поедет напролом, также по-разному реагируют и операционные системы на неправильные пакеты. Для борьбы с утечкой информации рекомендуется выбрасывать все неправильные пакеты, не отвечая на них сообщениями об ошибках. Так же можно использовать системы обнаружения сканирований или вторжений. С целью затруднения работы сканирующей стороне возможно использование липучих ловушек. Большинство сканирующих и обнаруживающих программных средств, перечисленных параграфом выше в разделе открытого сканирования, способны работать и с закрытыми сканированиями. Отделять эти программные средства в отдельную группу бессмысленно. Само по себе сканирование без последующего продолжения атак не несёт никакой угрозы, однако возникшая и существующая по сей день практика безнаказанности заставляет обратить на данный вид атак больше внимания. Безнаказанность приводит к регулярному, практически непрерывному и случайному сканированию всего блока IPадресов. Это отмечается и в различных последних отчётах по сетевой безопасности [24]. Факт сканирования уже не может, как ранее, использоваться в качестве высокодостоверного сигнала о начале какой-либо атаки. Случайные сканирования не столько представляют опасность для сканируемого узла, сколько «замусоривают» лог-файлы и затрудняют обнаружение атак, непосредственно направленных на данный узел. Для повышения значимости сканирования в качестве сигнального фактора обнаружения первой стадии атаки следует использовать обработку информации с нескольких распределённых узлов. Более подробно об этом будет рассказано в последующих разделах. Сейчас перейдём к следующей, логически вытекающей стадии перерастания сканирования в работу со службами. Работа со службами – это взаимодействие с одной или несколькими службами, когда целью ставится получение информации, не нарушая работы. Обычно в случае использования автоматических средств нападения и сканирования данный класс атак следует сразу же после сканирования. Нередко разделить стадию сканирования от стадии работы со службами бывает невозможно. Однако у этих двух классов атак есть различие – разная достоверность получаемых результатов. Работа со службами может более точно определять тип и диапазон версий
безопасность операционной системы и запущенных сервисов, тем самым подавать более достоверную информацию, что повышает вероятность осуществления успешной атаки на последующих стадиях. Классическим примером борьбы на первой стадии с данным и предыдущим классом атак является замена заголовков, выдаваемых теми или иными сервисами после установления соединения. Целью любой работы со службой обычно является получение информации для последующего нарушения работы служб. Нарушение работы может быть направлено на отдельные службы, группы служб, узлы и сети узлов с целью получения информации, изменения алгоритма функционирования атакуемого объекта, отказа в обслуживании. Более ясно представить классификацию атак можно, посмотрев на рисунок 1. Атака для получения информации. Данный класс является логическим продолжением предыдущих. После работы со службой следуют действия, вызывающие разовое изменение нормального алгоритма работы, в результате чего может произойти утечка информации. Цель атаки – только получение информации, при этом атакующий может восстановить работу узла и попытаться скрыть следы своего присутствия. Защита от данного класса атак ничем не отличается от мер, противодействующих сканированию и другим атакам. Дополнительно принятыми мерами может быть шифрование важной информации, начиная от swap-раздела и заканчивая шифрованием всего трафика. Не имеет смысла пытаться выделить средства, противодействующие только данному классу атак. Атака с целью изменения алгоритма функционирования является либо продолжением предыдущего класса, либо отдельным классом. Целью атак данного класса, как видно из названия, является явное изменение алгоритма функционирования. Часто атаки попадают сразу под несколько классов, так как имеют несколько целей. Два вышеописанных класса атак являются классическими, и чаще всего, когда употребляют слово «атака» без уточнений, то имеются в виду именно эти два класса. Системы обнаружения атак и/или вторжений изначально делают больший акцент на эти классы, так как ущерб от них, особенно от второй, сразу становится явным. Формально изменение алгоритма функционирования может быть произведено таким образом, что узел или служба «зависнет» либо просто не будет никак реагировать на обращения к нему. Однако данный вид атак обычно выделяют отдельным классом, так как привести систему к состоянию отказа в обслуживании бывает гораздо более простой задачей, чем что-то изменить в алгоритмах функционирования, не нарушив работоспособности. Отказ в обслуживании. (DoS, Denial of Service). Отдельный вид атак, когда целью ставится перевести узел, сеть или службу в такое состояние, когда она не могла бы обслуживать легальных пользователей, выдавая им сообщение о недоступности или вообще не отвечая. Добиться данного можно двумя путями. Первый – с помощью уязвимостей в атакуемом объекте. Несмотря на то, что цель атак подходит под определение данного класса, их принято классифицировать как «изменение алгоритма функционирова-
№10(11), октябрь 2003
ния», см. выше. Второй – с помощью большого числа запросов. Любой узел, даже без уязвимостей, с верифицированным алгоритмом работы, можно перевести в состояние отказа в обслуживании. Исторически изначально была попытка борьбы с данным классом атак путём увеличения производительности узлов и скорости пропускных каналов к ним, но тут же последовал ответ в виде распределённых атак на отказ в обслуживании (DDoS, Distributed Denial of Service). Распределённая атака на отказ в обслуживании – это когда атака ведётся не с одного узла в сети, а с нескольких. Логично заметить, что путём увеличения числа атакующих узлов, даже при маленькой пропускной способности и производительности, на них можно «забить» любой высокоскоростной узел/канал. Набор узлов для проведения подобных атак обычно является следствием других атак. В результате уязвимостей на узлах они атакуются и на них размещается некоторый код, который работает по продуманному алгоритму. С точки зрения выбираемой цели совершения той или иной атаки в данный класс возможно включение и некоторых видов вирусов-червей. Размещённый код может выжидать команды, а может и атаковать и «завербовывать» себе другие узлы, создавая распределённую сеть из заражённых узлов. Когда распределённая сеть из заражённых узлов начнёт атаку на отказ в обслуживании, то защищаться от данной атаки отдельно невозможно. Последствия можно как-то уменьшить, если у вышестоящего провайдера во время атаки ставить up-stream-фильтры. Борьба в данном случае ведётся уже вручную, а не автоматическими средствами, постепенным отключением каждого замусоривающего сеть узла через его провайдера. Наиболее эффективно данный класс атак предупреждать, так как заблокировать данные атаки за короткое время на сегодняшний день затруднительно. Если бы в узлах не существовали уязвимости, то данный класс атак было бы очень сложно реализовать по причине трудности создания объединённой атакующей сети. С нескомпрометированных узлов атаковать можно, но велик риск быть пойманным и наказанным. Атакующие предпочитают не рисковать таким образом. Сейчас этот класс в большинстве составляют именно распределённые атаки на отказ в обслуживании, так что слово «распределённые» часто опускается. После того как мы познакомились с классификацией атак с точки зрения систем их обнаружения, давайте рассмотрим более подробно используемые средства защиты и обнаружения на отдельных узлах.
Обнаружение атак и защита от них на отдельных узлах распределённой системы С существованием атак тесно связано их обнаружение. Если атаки нельзя было бы обнаруживать, то это было бы просто бедствием с точки зрения безопасности, наоборот, если бы все атаки обнаруживались, то нечего было бы исследовать и не от чего было бы защищаться. Для защиты от атак на практике используются не только программные продукты, описанные выше, но и специализи-
53
безопасность рованные программно-аппаратные средства. Использование аппаратной компоненты с точки зрения теории практически не вносит ничего нового, кроме особенностей функционирования, и призвано лишь удешевлять существующие решения при требованиях большей производительности и безопасности. Где есть необходимость в использовании аппаратных средств, будет оговорено отдельно. Многие классы атак являются включающими друг дуга, поэтому программные продукты, выполняющие различные функции предупреждения и защиты от атак, можно разделить на следующие категории, однозначно не совпадающие с приведённой выше классификацией атак. Эффективность обнаружения атак от этого не ухудшается: 1. Межсетевые экраны – средства, организующие фильтрацию пакетов на основе их заголовков и/или других критериев. Подробнее о межсетевых экранах можно прочитать в следующей литературе [21, 25, 26]. 2. Антивирусные программы, осуществляющие поиск вирусов и подозрений на вирусы в файлах или информационных потоках. Подробнее смотрите [27, 28]. 3. Снифферы – программы, осуществляющие перехват всего проходящего трафика в сегменте для дальнейшего его анализа вручную или автоматическими средствами [14, стр. 111-127]. 4. Средства обнаружения атак/вторжений – так же, как и снифферы, перехватывают весь или часть траффика и осуществляют поиск в нём подозрительных событий. Используются различные методы поиска, чаще всего сигнатурный метод. Иногда средства обнаружения вторжений дополнительно имеют свойства из других категорий [9]. 5. Средства контроля целостности файловых систем осуществляют периодическую проверку файловых систем, на которых установлены операционные системы, которые могут быть скомпрометированы на факт изменения или удаления «неизменяемых» файлов, появления новых. Проверка чаще всего осуществляется с использованием средств криптографии с целью повышения надёжности. По результатам проверки возможны различные заранее запрограммированные действия [14, стр 100-109], [4]. 6. Ловушки – осуществляющие имитацию работы той или иной службы/хоста/сети. Контролирующие и протоколирующие все обращения к ним. Являются развивающимся классом на сегодняшний день. Очень перспективны с точки зрения сбора доказательств злого умысла нападающего, не подвергая при этом реальные системы какой-либо опасности [6, 20]. Разберём все эти классы более подробно.
Межсетевые экраны «МЭ представляет собой локальное (однокомпонентное) или функционально-распределённое средство (комплекс), реализующее контроль за информацией, поступающей в АС и/или выходящей из АС, и обеспечивает защиту АС посредством фильтрации информации, т.е. её анализа по совокупности критериев и принятия решения о её распространении в (из) АС» [25].
54
В отечественной литературе в последнее время наблюдается разнобой в терминологии, в качестве синонима термина МЭ часто используются слова: «брандмауэр» и «firewall», заимствованные из немецкого и английского языков, соответственно дословно обозначающие «огненная стена». Работу МЭ можно разделить на несколько составляющих: Анализ и фильтрация пакетов. Пакеты могут быть различных протоколов. Блокирование пакетов протоколов или содержимого. Аутентификация пользователя (подключения) и шифрование сеанса. Одновременно в МЭ могут присутствовать любые составляющие из перечисленных в зависимости от требований, предъявляемых к МЭ. Если классифицировать МЭ по ЭМВОС (OSI/ISO) [29 стр. 19-25], [30 стр. 66-74] уровню, то имеется два основных типа МЭ: МЭ сетевого уровня или фильтры пакетов; шлюзы приложений. На канальном уровне тоже можно установить МЭ, относить данный МЭ следует к первому классу. Синонимом пакета в данном случае может служить и дейтаграмма, и ячейка, несмотря на то, что это несколько разные понятия. МЭ больше подходят для защиты, нежели для обнаружения атак, однако ведение логов и использование этих средств совместно с другими может расширять сферу их применения в области защиты. Под анализом и фильтрацией пакетов обычно понимается соответствие заголовков или поля данных какомулибо критерию. В процессе совершения атак или ведения подготовки к ним обмен с потенциально атакуемым объектом ведётся посредством обмена пакетами. МЭ является узким местом, где можно отсеять ненужные пакеты. Таким образом, если знать адреса нарушителей, то можно запретить обмен любым трафиком с нарушителями. Так, возможно разрешение или запрещение использования какихлибо служб какими-то отдельными узлами. Например, если имеется внутренняя БД, например, на порту 1433, то можно запретить все входящие пакеты, имеющие порт назначения 1433, тем самым исключив возможность атаки на этот порт. Также фильтрация может осуществляться на основе критерия «направления установки соединения» изнутри наружу или снаружи внутрь по флагам в пакетах. Можно запретить все входящие соединения. Фильтрация неправильных пакетов может предупредить различные атаки, направленные на переполнение буфера, определение операционной системы, сканирование портов. Фильтрация таких пакетов есть способ борьбы с полуоткрытым сканированием, описанным выше в разделе классификации атак. Многие операционные системы имеют мощные встроенные МЭ. Обычно это пакетные фильтры с расширяемыми возможностями. Так, операционная система Linux имеет пакет iptables (ipchains или ipfw), позволяющий производить фильтрацию [7, 8]. ОС OpenBSD, FreeBSD и другие также имеют МЭ. Различные версии Windows (на базе NT) имеют также встроенные, но с меньшим набором функциональных возможностей МЭ. Малый набор фильтрую-
безопасность щих возможностей штатными средствами, особенно у семейства операционных систем Windows, компенсируется наличием большого числа коммерческих продуктов от третьих производителей, например AtGuard, ZoneAlarm и др. Для ОС с открытым кодом такие продукты по большей части бесполезны, так как они не могут фильтровать лучше, чем сама ОС, средствами ядра. Имеется множество программно-аппаратных средств от различных производителей, реализующих функции фильтрации «в виде отдельного блока» независимо от ОС: Cisco Secure IDS, ISS RealSecure for Nokia, NFR Intrusion Detection Appliance, SecureCom, Citadel и многие другие. Некоторые из них даже сертифицированы бывшим ФАПСИ. С точки зрения размещения МЭ может располагаться как на защищаемом узле, так и отдельно. Первый вариант обходится дешевле, но с большим риском для безопасности. Существует конечная вероятность того, что атака может вывести МЭ из строя. Отдельные узлы, особенно не имеющие IP-адресов (например, различные МЭ-мосты [26]) и администрируемые исключительно с консоли или доверенного интерфейса, практически имеют очень большую надёжность, определяемую только используемым ПО внутри этих средств, которое может случайно содержать ошибки. Так как извне к таким устройствам обратиться невозможно, то невозможно и как-то повлиять на их работу. Даже атака на отказ в обслуживании экранируемой сети при правильном расчёте не приведёт к выводу из строя или изменению алгоритма работы таких устройств. Пакеты, предназначенные для фильтрования, будут отфильтрованы в любом случае. Ещё одним плюсом за использование отдельных МЭ можно назвать безразличность этих средств к вирусам, так как обработка пакетов напоминает чем-то гарвардскую архитектуру, где разделены потоки команд и данных. Единственным минусом таких средств является их взаимодействие с внешним миром. Чем больше возможностей для связи имеется, тем больше риск атаки на МЭ. Приходится выбирать между удобствами администрирования и безопасностью. Многие вещи довольно сложно или неэффективно реализовать с помощью фильтров пакетов, например, если надо разрешить посещать какой-то сайт, но в то же время запретить посещение его какой-то части, то для выполнения данной задачи потребуется разборщик и анализатор пакетов, и пр. В конечном счёте получится что-то вроде прозрачного шлюза приложений. Поэтому лучше сразу заметить, что с подобной задачей легко справляются шлюзы приложений. По сложившейся практике никто не называет шлюзы межсетевыми экранами, хотя они являются их подтипом. Шлюзов приложений также много, сколько и приложений, их использующих. Наибольшей популярностью пользуются http-прокси-сервера, насколько они популярны, настолько же часто они подвергаются различным атакам. Среди открытых программных продуктов, распространяемых по лицензии GNU Public License, наибольшей популярностью пользуется пакет squid. Среди программных продуктов с закрытым кодом сложно перечислить однозначно наиболее часто используемые продукты. Правильно настроенный прокси-сервер может защищать от многих атак. Во-первых, помимо защиты он может про-
№10(11), октябрь 2003
сто ускорять работу, кэшируя различные данные. Во-вторых, он может скрывать пользователя, будучи анонимизирующим прокси. Злоумышленнику придётся сначала сломать прокси-сервер, прежде чем он доберётся до того, что скрывается за ним. Довольно часто прокси-сервера устанавливаются на шлюзах. Также прокси-сервера могут бороться с неавторизованными пользователями, не пропуская пакеты от них. Так как прокси-сервер сам устанавливает соединение на уровне приложения, то появляются дополнительные возможности по изменению передаваемого содержимого. Перед передачей данных пользователю их можно проверять на вирус «на лету» и блокировать или изменять в зависимости от результатов проверок. В данном случае МЭ уже становится комбинированным средством, обладающим свойствами различных классов программ, начиная от фильтра пакетов и заканчивая антивирусными программами. Иногда прокси-сервера ставят прямо перед веб-серверами. Получается подключение в разрыв. В данном случае доверенный прокси-сервер будет защитой от передачи нестандартных запросов недоверенному веб-серверу. Не секрет, что есть случаи, когда производители оставляют специально или забывают убрать, по ошибке, различные недокументированные функции из своих программ. Злоумышленники, узнав про такие возможности, могут ими воспользоваться. Именно по этой причине на первый взгляд может показаться, что программные продукты с открытым кодом содержат большее число уязвимостей. На самом деле реальное число уязвимостей оценить сложно, а в закрытом программном коде такие уязвимости скрыты от простого просмотра, и для их выявления требуются гораздо большие усилия. Использование прокси-сервера с верифицированным алгоритмом работы исключит всякие отклонения от предусмотренного режима работы. Также из внешней сети будет виден прокси-сервер. Попытка определения операционной системы узла, скрывающегося за прокси, встретит на своём пути трудности. Фактически при правильной настройке возможно полностью исключить возможность определения ОС, функционирующих на узлах за прокси-сервером, а также топологию сети даже косвенными методами. К сожалению, данные способы использования прокси ввиду их небольшой популярности практически не описываются в литературе. В литературе большее внимание уделяется кэширующим способностям прокси-серверов. Подключение в разрыв может быть как прозрачным (без изменения сетевых настроек), так и нет (когда требуется изменение настроек). Возможно прозрачное установление прокси в «разрыв» так, что даже легитимные пользователи, общающиеся с внешней сетью, его не заметят. В то же время будет иметься возможность полного контроля их соединений. Многие операционные системы, в частности ОС Linux, позволяют делать данные вещи штатными средствами (bridge, divert, squid) [26]. Использование межсетевых экранов – это всё равно, что мощная бронированная железная дверь, а разрешающие и запрещающие правила – это замок. По-хорошему, такую дверь сломать нельзя, однако никто не мешает попасть внутрь через окно или через дырку в стене, которую могли случайно оставить по ошибке рабочие. Или вам про-
55
безопасность сто изнутри эту дверь кто-то откроет. Поэтому комплексная защита межсетевыми экранами не ограничивается. Следующим отдельным классом идут антивирусные средства.
Антивирусные программы История вирусов очень богатая, а классификация вирусов очень широкая. Мы будем рассматривать только те вирусы, которые имеют какие-то сетевые компоненты и могут оказывать какое-то влияние на другие сетевые устройства через сеть. Если какой-то компьютер заражён boot-вирусом, то он никоим образом не влияет на работу независимого сетевого окружения, поэтому и не стоит подобные классы очень подробно рассматривать в рамках обнаружения телекоммуникационных атак. Наибольший интерес представляют вирусы последнего поколения, сочетающие в себе много различных функций. Природа вирусов обычно такова, что они должны распространяться, заражая при этом максимально возможное число компьютеров. Если ранее обмен данными чаще происходил посредством обмена дискетами, то на сегодняшний день большую часть занимает обмен сетевым трафиком. Некоторые компьютеры и дисковода не имеют. Поэтому гораздо выгоднее стало писать вирусы, распространяющиеся через сетевые среды. Дополнительным фактором, стимулирующим написание сетевых вирусов, является относительно постоянное подключение заражаемых компьютеров к сети, даже пользователь, подключившийся по модему, в течение некоторого отрезка времени может быть рассмотрен как находящийся на постоянном подключении, и, следовательно, его ресурсы могут быть атакованы, заражены и послужить источником для дальнейшего цепного распространения. Первым сетевым вирусом, положившим название целому классу вирусов-червей, был червь Морриса. Алгоритм работы вирусов-червей не сильно изменился за последние годы. Поэтому для противодействия вирусам необходимо учитывать особенности их появления. Для написания вируса необходимо совершить следующие шаги: Найти какую-то уязвимость в программном обеспечении. Написать программу, автоматически заражающую удалённый компьютер через эту уязвимость. Написать программу, осуществляющую автоматический поиск компьютеров для их поражения программой из второго пункта. Разработать средство взаимодействия заражённых компьютеров. Противостоять данному виду вирусов можно либо путём блокирования уязвимостей, либо путём их устранения, либо путём их защиты дополнительными средствами. Можно попытаться противостоять взаимодействию частей вируса, однако существуют вирусы, в которых не осуществляется никакого взаимодействия и процесс заражения никем не координируется. Направить основные усилия на устранение недостатков в существующем ПО не представляется возможным по причине того, что объёмы программного кода постоянно растут, программные продукты очень быстро устарева-
56
ют, поэтому невыгодно производить дорогостоящие проверки и тестирования. Создание верифицированных продуктов выливается в круглую сумму. Работу продуктов с закрытым кодом проанализировать и проверить сложно, а зачастую это противоречит лицензии того или иного продукта, поэтому многие уязвимости так и не обнаруживаются. С открытым и бесплатным кодом дела обстоят проще, поиск уязвимостей ведётся по мере чьей-то заинтересованности в этом и большим числом народа. Поэтому уязвимости в ПО с открытым кодом обнаруживаются чаще. Можно смело утверждать, что в любом ПО средних и больших размеров существуют ошибки. Коренным образом решить проблему их появления невозможно. Таким образом, системам защиты приходится защищаться косвенными образом. Если у вас на двери сломан замок и его нельзя заменить, то можно около двери поставить сторожа. Обычно таким местом, где следует поставить антивирусного сторожа, являются почтовые сервера и межсетевые экраны. На первых осуществляется проверка всей электронной корреспонденции на наличие известных вирусов. На вторых может проверяться любой сетевой поток вне зависимости, куда он идёт или откуда поступает. Для поиска вирусов используется сигнатурный метод. Данный процесс фактически ничем не отличается от сигнатурного обнаружения атак, однако тут есть своя специфика существующей БД и проверяемого потока. Например, антивирусные программы могут исправлять поток данных, вылечивая заражённые объекты «на лету», не блокируя их, в то время как СОА в основной массе не имеют аналогичных возможностей. Для поиска вирусов на отдельных локальных компьютерах используются подобные средства мониторинга, осуществляющие проверку всех получаемых и открываемых файлов. Использование сигнатурных баз данных требует постоянного их обновления, поэтому для создания надёжной защиты следует использовать данные средства совместно с другими. Например, довольно часто антивирусные программы могут осуществлять контроль целостности файлов. Либо являться компонентой какого-то более общего средства. Среди программных продуктов можно назвать очень много антивирусных программ, но выделить наиболее эффективные среди них довольно сложно, а тем более попытаться как-то выбрать лучшее средство. Наличие большего числа сигнатур не является доминирующим аргументом в пользу того или иного антивирусного продукта, так как нужного вируса в БД сигнатур может не оказаться, несмотря на то, что там содержится наибольшее число сигнатур. Поэтому защита не может основываться на одних антивирусных средствах. Среди наиболее часто используемого антивирусного ПО следует назвать: AVP Касперского, Dr.Web, Norton Antivirus, OpenAV и др. Многие продукты имеют версии для различных операционных систем, начиная от Linux и заканчивая Novell Netware. Существуют антивирусы и с открытым программным кодом.
Снифферы Снифферы, как и оружие, могут применяться как с целью нападения (см. про пассивные атаки выше), так и с целью защиты. Для защиты они помещаются рядом с защищае-
безопасность мым местом для перехвата всего проходящего трафика в данном сегменте. Явным образом снифферы защищать не могут, они защищают «косвенным» образом и используются как составная часть других средств. При этом при необходимости физически специально создаются условия для перехвата всего трафика. Например, сниффер может быть подключён к дополнительному концентратору или к специальному порту коммутатора, на который передаются копии данных со всех портов. После получения данных сниффером производится их анализ. Анализ может быть как местным, так и внешним. Данные могут помещаться в БД, которая будет анализироваться уже другими средствами. Захватывать данные удобнее всего в сетях с общей средой передачи, как в Ethernet. Среди программных продуктов, осуществляющих перехват всего трафика в сетях Ethernet, можно назвать tcpdump, windump, ethereal и др. Вести перехват данных можно и в сетях, отличных от Ethernet, реализация в этом случае может немного усложниться, и потребуется наличие дополнительной аппаратной компоненты. Суть при этом не меняется. По данным перехвата, при умелом их прочтении можно очень многое сказать о сети, из которой они были перехвачены. По количеству передаваемых пакетов можно судить о загруженности. По адресам источников и назначения можно судить об используемых сервисах и серверах, если таковые имеются в сети. Также снифферы отслеживают попытки взлома тех или иных сервисов, а их БД являются доказательной базой совершения тех или иных действий. Эти БД также могут служить источником информации для пополнения сигнатурных БД, используемых другими средствами защиты. Часто снифферы используются совместно с ловушками. Порой количество проходящих данных настолько велико, что не имеется физической возможности производить постоянную запись всего трафика хотя бы за последние сутки. Даже при наличии всего перехваченного трафика существует проблема его анализа и поиска в нём нужной информации. Администратор-человек бессилен. Для автоматизации процесса поиска в своё время были написаны программы, которые в дальнейшем приобрели ряд дополнительных свойств и стали называться системами обнаружения атак/вторжений, о которых пойдёт речь в следующем параграфе.
Системы обнаружения атак (СОА) Данный класс средств защиты есть историческое развитие других классов. Поэтому СОА обладают различными характеристиками других классов, которые в совокупности могут предоставить дополнительную информацию. СОА собирают данные с различных источников. Основное – это перехват данных снифферами, однако, как было замечено выше, не всегда имеется возможность и требуется перехватывать все данные целиком. Поэтому СОА осуществляют анализ данных «на лету», не обращая внимания на менее значимые события. Обычно анализ проводится сигнатурным методом. В этот момент работа СОА практически ничем не отличается от работы антивирусных средств за исключением специфики БД. Большинство злоумышленников изначально пытаются атаковать узлы уже известными атаками, так как вероят-
№10(11), октябрь 2003
ность существования уязвимостей для этих атак больше, но и вероятность присутствия данной атаки в сигнатурной БД тоже велика, поэтому СОА обнаруживают такие атаки. Так, любое сканирование распознаётся практически безошибочно. В качестве реакции на какое-то событие СОА может передавать управление любому заранее написанному скрипту, который может инициировать закрытие соединения с атакующим узлом либо изменять политику фильтрации пакетов. Из последнего следует, что СОА очень тесно используются совместно с межсетевыми экранами. Отсутствие в трафике данных, коррелирующих с теми или иными сигнатурами, не говорит об отсутствии нарушителей, поэтому в данных средствах используется сбор информации с различных мест. Сбор данных в сети осуществляется посредством сенсоров – небольших программ или приспособлений, расположенных вблизи прослушиваемых мест и выдающих различную информацию о состоянии прослушиваемого объекта. Объектом может быть как соединение, так и лог-файл работы той или иной программы. Средства, анализирующие лог-файлы, исторически не принято называть сенсорами. Фактически, сенсор – это маленькая копия СОА, отправляющая данные в некий общий центр – ядро анализа СОА. Всё вышеописанное может располагаться как на одном узле, и тогда сложно отделить одни функции от других, так и в различных местах сети. СОА исторически делятся на два типа: cеть- и хост-ориентированные СОА. Хост-ориентированные СОА как раз и занимаются анализом различных файлов на хосте, в то время как сеть-ориентированные занимаются перехватом и анализом трафика в сети. Большее развитие в последнее время получило сеть-ориентированное направление. Отчасти это объясняется платформенной независимостью СОА от используемых ОС на компьютерах в сети. Правильно настроенная СОА обнаруживает большой процент атак, при маленьком проценте ложных срабатываний. Понятие «СОА» часто трактуется очень широко и включает в себя множество различных компонентов, в результате чего довольно сложно определить границы. Например, это может быть обычная БД. Те же антивирусные средства также могут являться одним из компонентов СОА. Не следует исключать ошибки первого рода, которые уходят из внимания СОА. Среди программных продуктов можно перечислить: NIDS, BRO, Snort и др., о последнем продукте как раз пойдёт речь дальше в статье.
Средства контроля целостности файловых систем СОА не могут гарантировать обнаружение всех атак, поэтому существует некоторый процент атак, не обнаруживаемый СОА. Пропущенную на первый взгляд атаку можно достоверно обнаружить другими средствами. Основывается данное утверждение на том, что цель практически любой атаки – реализоваться, поэтому любая атака будет себя как-то проявлять. Она или запустит/остановит какой-то процесс, или изменит какой-то файл или несколько файлов на диске. В любом случае, чтобы после перезагрузки компьютера его не пришлось повторно атаковать на его жёстком диске либо другом носителе, скорее всего будут сделаны изменения. В результате реализации атаки могут быть изменены загрузочные файлы либо
57
безопасность часто используемые утилиты, например команда ls в *nix. Для борьбы с подменой или искажением файлов можно выделить группы важных неизменяемых файлов или областей диска и периодически проверять их неизменность. Некоторый аналог вспаханной полосы на границе. Средства проверки могут быть от самых простых – проверка по размеру и времени файла – до сложных, когда используется хэш не только с содержимого файла, но и от его месторасположения на диске. Реагирование на изменение того или иного файла может быть различным от запуска заранее определённого сценария до замены файла «новым». Например, Windows XP, если обнаруживает замену некоторых своих файлов чужими, может восстановить их без ведома пользователя. Это не всегда удобно, например, если по ошибке поменять папку с пользовательскими документами как системную. Поэтому чаще всего такие средства не обходятся без контроля человеком – они высылают предупреждения администратору, а тот уже сам решает, как поступать. В качестве примера, демонстрирующего удобство и наглядность данных средств защиты, можно рассмотреть случай организации веб-сервера, защищаемого таким образом от взлома. Для этого устанавливаются два компьютера. Один с доступом во внешний мир, на котором запущен потенциально взламываемый http-сервер, а другой для обновления, на нём нет службы http-сервера, возможно, и доступа ко внешней сети у него тоже нет. Периодически второй компьютер по внутреннему каналу связи проверяет содержимое первого и загружает туда изменения. Таким образом, однажды заменённые файлы просуществует до первой проверки, после которой изменения будут восстановлены и будет выслано сообщение администратору о необходимости его дальнейшего вмешательства. Данная схема недостаточно надёжная по причине того, что уязвимость не закрывается и сервер могут сломать повторно, но всё же реализуемая в ряде случаев. Следует отметить, что большой процент инцидентов не регистрируется, поэтому многие атаки оказываются неучтёнными. Общее число атак день ото дня растёт с завидным постоянством. Подробнее см. ниже данные CERT. Появление нежелательного трафика к хосту является уже нормальным явлением, а различные сканирования уже не рассматриваются как инциденты, требующие немедленного вмешательства по причине того, что их очень большое число, а найти и доказать злой умысел того или иного нарушителя является непростой задачей. Возникает вопрос выбора средств по отсеву более опасных событий от менее опасных. Хост-ориентированные СОА путём исследования лог-файлов и средства контроля целостности файловых систем не всегда могут своевременно сделать выводы о начавшейся атаке до того, как станут ощутимыми её последствия. Чтобы не подвергать существующие системы большому риску, следует выбирать другие средства. Такими средствами могут быть виртуальные ловушки.
Ловушки Использоваться виртуальные ловушки стали только в последнее время. И их появление вызвано насущной необходимостью. В связи с увеличением числа атак стало очень
58
сложно классифицировать атаки между собой по степени их опасности. Например, какой-нибудь школьник, взламывая гипотетический НИИ, может не знать, чей узел он взламывает. Он может добраться до каких-то научных расчётов, которые он тут же сотрёт, так как более ценной информацией для него будут, например, пароли для Интернета. Поэтому утечки информации в данном случае не будет, как если бы эти расчёты попали в руки спецслужб других стран. СОА не в состоянии классифицировать случаи взлома по-разному. Создав ложные службы, узлы или сети, мы можем спровоцировать нападающего на их взлом, тем самым получить больше информации о взломах, методиках и пр., из которых соответственно можно будет принять правильное решение на основе собранных данных, которые могут служить доказательной базой наличия злого умысла у атакующего в суде. В случае использования ловушек также решается и другая проблема – опасность вывода из строя реальных служб. Если атаки производить на реальные службы и узлы, то последствия могут быть более значительными. На сегодняшний день существует огромное число виртуальных ловушек, большинство из которых могут не только собирать данные, но и предпринимать какие-то активные действия по отношению к нарушителю. В зависимости от способов установки и работы ловушки бывают следующих видов. См. рисунок 2.
Ðèñóíîê 2. Âèäû ëîâóøåê
Рассмотрим преимущества тех или иных видов ловушек с точки зрения поимки нарушителей. Ловушки, моделирующие отдельные службы, хороши тогда, когда имеется некоторый известный узел, выполняющий функции какого-либо сервера, например, вебсервера или шлюза. С большой вероятностью данный сервер будет атаковаться, и будут попытки взлома. Если нет уязвимостей или их наличие маловероятно, то все атаки и попытки взлома будут просто-напросто растрачивать ресурсы сервера. При этом разделение случаев атак от легального использования будет осложнено. Создание на этом же сервере (логически) других фиктивных сервисов заставит атакующих распараллелить свои действия. Так как потенциально возможных уязвимых сервисов будет больше, то и вероятность успешной атаки с точки зрения атакующих будет больше. Эту вероятность можно будет заведомо повысить, выдав ложные сведения о плохой защищённости подставных виртуальных ловушек. Между тем легальные пользователи не будут работать с ловушками или реальными службами нештатными способами, пытаясь вывести те из строя, основываясь на ложной информации, полученной прямым или косвенным способом от ловушек о наличии тех или иных уязвимостей. Таким образом, можно понизить вероятность ошибок первого и второго рода. Однако при данной реализации есть некоторая
безопасность опасность нарушения функционирования реальных служб. Также нарушитель не всегда может впоследствии воспользоваться ложной информацией об уязвимостях и атаковать предоставленные ему ловушки. Безопаснее ловушки, моделирующие узлы, ставить виртуально или использовать, ловушки, моделирующие работу отдельных узлов. Ловушки, моделирующие отдельные узлы, хороши с точки зрения безопасности, так как они ставятся отдельно. В случае их компрометации ущерб будет меньше, чем если бы они стояли на реальных узлах. Моделирование целых узлов даёт больше возможностей для реализации тех или иных моделируемых конфигураций. Для реализации одних и тех же служб могут использоваться различные платформы. При этом атакующий, если ничего не знает об уязвимостях какой-то платформы, может не воспользоваться предоставляемым ему «куском сыра в мышеловке» и тем самым не быть пойманным. Поэтому для увеличения вероятности поимки атакующего следует предоставить ему возможность выбора, тем более использование различных платформ в одной сети одновременно – не редкость. Попав в подобный клондайк, нарушитель, возможно, захочет пойти по наиболее лёгкому пути и атаковать более известную ему платформу. На данном этапе уже можно составлять некоторые «портреты», характеризующие нарушителей. Если нарушитель окажется в состоянии сломать все предоставленные ему ловушки, то опять же это охарактеризует его уникальным образом и позволит выделить среди других производимых атак. Нельзя не сказать, что подобные характеристики о взломщиках могут дать много полезной информации в дальнейшем, при доказательстве злого умысла нарушителей и при использовании обработки информации с распределённых телекоммуникационных систем. Создание отдельных виртуальных ловушек, объединённых в сеть, может обойтись довольно дорого, поэтому дешевле наряду с отдельно моделируемыми хостами моделировать целые сети с их замысловатой топологией. Ловушки, моделирующие целые сети, позволяют моделировать случайным образом задержки между узлами, потерю пакетов, создавая полную иллюзию реальности происходящего. Организациям обычно выдаются диапазоны адресов, но не все и не всегда используются, размещение ловушек на неиспользуемых адресах может дать необходимый результат. Любое обращение к неиспользуемому адресу есть вероятная атака. Сканирующий снаружи нарушитель не может знать, что к какому-то узлу или узлам не следует обращаться. Поэтому нарушитель может быть сразу же замечен и взят под контроль какой-либо из систем обнаружения атак. Ловушки-липучки призваны затруднять действия нарушителей, заставляя их большую часть времени проводить в бессмысленном ожидании. Несмотря на то, что взлом любой из ловушек есть бесполезная, с точки зрения нарушителя, трата времени, количество потраченного времени можно увеличить. Например, если поставить ловушку-липучку, проверяющую работающие узлы в сети и отвечающую вместо неработающих на попытки извне установить соединения, то снаружи при проведении сканирования может создаться иллюзия работы всех узлов, в данном случае вопрос взлома того или иного реального узла бу-
№10(11), октябрь 2003
дет осложнён, так как атакующему будет необходимо найти реально работающие узлы либо попытаться атаковать все подряд, на что, несомненно, уйдёт время. Также при потенциальном подозрении на атаку можно увеличивать фрагментацию и задержки для пакетов, которыми ведётся обмен с нарушителем, имитируя загруженность сети. При этом время нарушителя будет растрачиваться понапрасну в ожиданиях. Это время может быть использовано при проведении оперативных мероприятий, где каждая лишняя минута может быть решающей. В силу специфики, варианты размещение ловушек могут очень сильно отличаться друг от друга. См. рисунок 3.
Ðèñóíîê 3. Âàðèàíòû ðàçìåùåíèÿ ëîâóøåê: à) ëîâóøêà íà îòäåëüíîì õîñòå; á) ëîâóøêà-ñåòü
Важным моментом работы ловушек есть сбор логов их работы и, по возможности, всего трафика обмена с ними. Данная информация является очень важной с целью её анализа после совершения той или иной атаки или только попытки. В случае реализации новой атаки, для которой нет записи в сигнатурной БД, по этим данным можно будет составить сигнатуры, которые в дальнейшем можно включить в БД СОА реальных систем, повысив их эффективность. В случае использования нескольких ловушек или ловушек-сетей, информация об их работе может собираться в едином центре для анализа с целью обнаружения распределённых телекоммуникационных атак.
IDS Snort Введение После небольшого введения в теорию я расскажу о практике, а именно, с чего собственно и хотел начать статью – про систему обнаружения атак IDS Snort. Введение появилось не случайно. Связано это с тем, что очень мало людей занимается вплотную вопросами обнаружения атак, поэтому наблюдается информационный вакуум в этой области. Читателю должно стать чётко ясно, где именно используется Snort и каким маленьким винтиком он является в большой теме обнаружения телекоммуникационных атак. Несмотря на то, что IDS расшифровывается как Intrusion Detection System и дословно переводится как Система Обнаружения Вторжений (СОВ) использование этого термина не совсем правильно и в силу возможностей великого и могучего русского языка мы будем говорить о Системе Обнаружения Атак (СОА) Snort. Простой пример в правильности выбранного термина: атака может быть совершена, но
59
безопасность безуспешно, то есть вторжения не было. Система, отвечающая первому названию, не должна ничего обнаружить, в то время как вторая, и тот же Snort, обнаруживают именно атаки независимо от их последствий. Конечно, тут есть и доля философская, читатель может спросить, а какой мне смысл от того, что мы обнаружили атаку, которая уже сделала своё «чёрное дело»? И вопрос будет кстати, так как он подтвердит нужность всего вышенаписанного введения, что есть способы и программы защиты, а есть программы, обнаруживающие, например, атаки. Полная аналогия тому, если вы захотите поставить видеокамеру над входной дверью. От взломщиков она никак не спасёт, дверь будет взломана одинаково, вне зависимости от наличия или отсутствия видеокамеры, надо ставить хорошую дверь и хороший замок, но камера может дать сигнал хозяину о необходимости принятия дополнительных мер, записать действия взломщиков, что может служить доказательной базой в суде по факту взлома. Однако если хозяин не предпринимает никаких мер, то и польза от такой камеры минимальна. Всё это говорит о том, что обнаружением атак надо заниматься серьёзно и постоянно уделять этому внимание. Всё описанное будет реально полезно тем, кто будет целенаправленно и практически ежедневно уделять время и работать по вопросам обнаружения атак. Статья должна заложить базу для развития в этом направлении. Для всех же остальных, кто поленится или сочтёт тему скучной, статья может быть полезной только с точки зрения расширения кругозора.
История Данный продукт, а вместе с ним и выпускающий его одноимённый проект является уже немолодым, первые упоминания датируются январём 1999 года, собственно, когда его основателю (Martin Roesch) и пришла в голову мысль о создании некоторой логической структуры правил по выборочному перехвату трафика. С этого момента и начало зарождаться некоторое подобие простой системы обнаружения атак. Что можно отметить последующим появлением версии 1.0. Уже к концу января появляется законченный продукт, который в полной мере может «ловить» атаки и называться системой обнаружения атак. Система может на основании заданных правил ловить атаки и структурированно вести лог-файлы. Правила можно задавать в любом удобном для пользователя порядке, и система толерантно относится к этому. Однако созданный продукт не устраивает разработчика в полной мере, и есть ещё ряд вещей, которые хочет внедрить Мартин в свой продукт с целью его улучшения. А именно: ставятся задачи создания возможности задания правил и обработки TCP-пакетов на основании выставленных в них флагах. Обработка фрагментированных пакетов и др. В это время Мартин меняет работу и привыкает к своей новой эргономичной клавиатуре, что сказывается на замедлении темпов процесса разработки. Основные силы переключаются на исправление ошибок, и появляется идея улучшить читаемость правил, в ухудшение удобности их набирания пользователями. Правила должны стать более длинными, менее удобными, но зато более понятными. Переписывается заново ядро обработки пакетов, за счёт чего увеличивается скорость их обработки, по просьбам «трудящихся» вводится более точное определение времени при-
60
хода пакета в систему, с учётом миллисекунд. В конце марта – начале апреля добавляется ранее задуманная обработка фрагментированных пакетов и другие вещи. В конце апреля добавляется возможность разбора PPP- и SLIP-пакетов, что позволило модемным пользователям применять Snort в полной мере. К проекту постепенно начинают подключаться всё больше и больше людей: Chris Sylvain, Damien Daspit и другие. Благодаря им у Snort появляется ряд новых полезных свойств. Проект идёт по миру и развивается. К началу лета выходит уже версия 1.2 с частично переписанным кодом. Однако обнаруживаются ошибки в работе Snort на платформах, отличных от Linux, в результате чего в августе появляется версия 1.2.1 с исправлениями, которая без проблем может запускаться как на Sparc, так и на OpenBSD. Чуть позже, в конце сентября (1999), ставится точка на активном развитии версии серии 1.x, и выдвигается идея о создании улучшенной с радикально переписанными кусками кода второй серии версий с номером 2.0. Всё самое лучшее – во вторую версию. Работа над второй версией идёт медленно, в то же время и не прекращается улучшение первой. В конце декабря выходит версия 1.5. Новый год знаменуется выходом версии 1.6. К середине года выходит версия 1.6.1, и ставится задача по выпуску версии 1.7 к октябрьской конференции «SANS Network Security 2000» [31]. Поспешный выход 1.6.1 приводит к выходу 1.6.2.2, и далее 1.6.3. Версию 1.7 удаётся выпустить только в начале 2001 года. Возможно, это было сделано специально, с целью ознаменования больших трудов на протяжении полугода. Версия 1.7 уже без проблем компилируется и работает на таких платформах, как: Linux 2.0.X, Linux 2.1.X, Linux 2.2.X (i386) FreeBSD 3.x, 4.x (i386) SunOS/gcc 5.5, 5.5.1, 5.6, 5.7, 5.8 (sparc) OpenBSD 2.7, 2.8 Tru64/gcc HPUX 11.0/gcc Ещё через полгода выходит новая версия, идея по выходу второй версии вот-вот осуществится, на этот раз в разрабатываемую версию уже включено всё самое лучшее, чего удалось добиться в версии 1.7. Далее, во второй половине лета у Мартина рождается сын, и поэтому его усилия более переключаются на него. Несмотря на это актуальность выпуска второй версии не уменьшается. До конца года выходят версии 1.8.1 с множеством дополнений и новых функций и сразу же после выходят исправления к новым ошибкам в 1.8.2. В новом, 2002 году выходит версия 1.8.3, и продолжает улучшаться вторая версия. В 2003 году выходят завершающие версии 1.9.x и долгожданная вторая версия, туда уже включены следующие функции, многие из которых даже и не принадлежат руке Мартина: Улучшенная производительность (благодаря новым образцам для фильтров и переписанному блоку сравнения). Лучшее декодирование. Расширенные возможности дефрагментирования и повторной сборки пакетов. Исправлены тысячи ошибок. Обновлены правила для обнаружения атак. Обновлён файл конфигурации Snort.conf.
безопасность Введены новые ключевые слова и соответствие образцам.
Новый анализатор HTTP-потоков. Расширены возможности аномального детектирования (для HTTP, RPC, TCP, IP и др. протоколов).
Лучшая защищённость программы. Исправлена ошибка Xrefs. Flexresp работает быстрее и эффективнее. Лучшие возможности chroot(). Исправлено декодирование 802.1q. Количество постоянных разработчиков Snort уже превысило 13, а количество людей, как-то оказавших помощь проекту, уже исчисляется сотнями. И вот летом выходит улучшенная «вторая» версия – 2.0.1, а уже в начале осени, 17 сентября 2003 года, выходит версия 2.0.2, установкой и настройкой которой мы и займёмся чуть ниже. Что же касается разработчиков, то они ни на минуту не останавливаются и продолжают совершенствовать данный продукт. Одним из направлений развития предполагается создание систем из 5/10/20/100 машин с установленным Snort в виде сенсоров с целью централизованного обнаружения и мониторинга больших сетей, в том числе и с целью обнаружения распределённых телекоммуникационных атак. По крайней мере Мартин просит всех заинтересованных в данном проекте дать о себе знать [32]. Возможно, удастся обсудить тему нескольких сенсоров в будущих публикациях, а пока непосредственно перейдём к установке самой простой конфигурации Snort с введением логов в файл.
Начальная установка IDS Snort
Ðèñóíîê 4. Screenshot ñêîïèðîâàííîãî ñîäåðæèìîãî àðõèâà
В директории /progi/Snort-2.0.2/contrib мы можем найти множество полезных программ и утилит, которые не являются частью Snort, но значительно могут помочь в работе со Snort. Многие вещи нам в первый раз не понадобятся, они скорее нужны для продвинутых пользователей. Среди представленных программ вы найдёте готовые скрипты с командами по созданию таблиц в различных БД: MSSQL, MySQL, PostgreSQL, Oracle с целью ведения логов в БД. (Организация ведения логов в другие БД открыта и не представляет сложностей, разве что придётся написать скрипты самостоятельно.) Делать выборки и различные операции с БД более удобно, чем с обычными текстовыми логфайлами. Для более-менее простого просмотра БД с логами мы там же можем найти ACID – систему визуального отображения содержимого БД через php и веб-сервер.
Для начала нам необходимо зайти на сайт [15] и скачать оттуда последнюю версию. Сейчас это версия 2.0.2 http:// www.Snort.org/dl/Snort-2.0.2.tar.gz. Далее необходимо удостовериться в том, что мы скачали что надо, для этого мы скачиваем контрольную сумму http://www.Snort.org/dl/ Snort-2.0.2.tar.gz.md5. (Также можно проверить подлинность с помощью имеющейся PGP-подписи.) Подсчитываем контрольную сумму от скачанного файла: # md5sum snort-2.0.2.tar.gz
В результате запуска получим: 21b14d90e2a323831d85f3d845d64b23
snort-2.0.2.tar.gz
Сверив это значение с тем, что записано в файле Snort2.0.2.tar.gz.md5, и убедившись, что они идентичны, мы можем приступать к распаковке и установке пакета. Не следует пренебрегать этим, казалось бы, излишним шагом. В 2002 году уже имелись инциденты по взлому различных веб-сайтов, в том числе и различных официальных зеркал, с которых скачивались «модифицированные» программы [24]. Все возникающие вопросы мы будем решать по мере их появления. Содержимое полученного архива следует куда-либо записать, удобнее это сделать в mc. Мы создадим для этого директорию /progi, куда и запишем содержимое скачанного архива.
№10(11), октябрь 2003
Ðèñóíîê.5. Âèä ACID ÷åðåç âåá-áðàóçåð mozilla
Подробнее с ACID мы познакомимся в следующих статьях. Если вас чем-то не устраивает ведение логов в БД, а просматривать лог-файлы вручную всё же вам кажется не очень удобным, то для удобства просмотра имеется
61
безопасность модуль SnortLog.pm для Perl в Net-SnortLog-0.1.tar.gz. Помимо этого имеется: Guardian – скрипт на Perl, позволяющий изменять правила пакетного фильтра (пока для ipchains) с файлом конфигурации и небольшим README. PassiveOS – скрипт для Perl, пытающийся по имеющимся логам определить, какую операционную систему имел атаковавший вас хост. mysql.php3 – php-скрипт для просмотра статистики работы Snort в online (10 наиболее частых TCP-опробований, 10 наиболее частых UDP-опробований и пр. ), данные берутся из БД mysql. snort2html, cкрипт на Perl, создающий отчёты в html. S99snort – стартовый скрипт, чтобы запускать Snort при загрузке системы из /etc/rc.d/init.d – он вам понадобится, если вас не устроит изложенный вариант решения ниже. snortdb-extra.gz – файл с правилами, создающими дерево таблиц в любой SQL92-совместимой БД, с целью более удобного изучения данных Snort пользователями. snortlog – ещё один небольшой скрипт на Perl, ведущий анализ логов. snortnet.tar.gz – набор программ, используемых проектом по обнаружению распределённых телекоммуникационных атак, когда Snort используется в качестве сетевого сенсора. snortwatch – программка на python, позволяющая отслеживать предупреждения, генерируемые Snort. Даже имеется система обнаружения аномальных событий на основе их вероятности – SPADE (Statistical Packet Anomaly Detection Engine).
увидите сообщение о произошедшей ошибке и необходимости установки библиотеки.
Создаётся впечатление, что для Snort пишут свои добавления все, кому не лень это делать, что даже очень хорошо, так как это говорит о реальной популярности программы и гибкости её использования. Пробежавшись далее быстро по всем встречающимся директориям, мы можем встретить документацию в doc, файлы конфигурации в etc, правила в rules, исходники в src и образцы препроцессоров для обработки данных в templates. Для успешности последующих действий в вашем компьютере должны быть установлены средства разработки приложений, остальное всё, как обычно, перед компиляцией Snort необходимо запустить конфигурирование: # ./configure
Для самого простого случая, как у нас, не надо передавать никаких параметров. (Забегая вперёд, для продвинутых пользователей скажу, что для конфигурации Snort для работы с БД MySQL следует указывать параметр --with-mysql, со всеми остальными рассмотрим этот режим работы Snort позже, возможно, даже в следующей статье). В процессе конфигурации осуществляется проверка на наличие всех необходимых компонент. Так как Snort работает в режиме сниффера, когда перехватывает пакеты, то он использует библиотеку libpcap. Если вы никогда не ставили её и не пользовались пакетом tcpdump, то у вас её может не оказаться, и тогда вы через несколько строчек после запуска
62
Ðèñóíîê 6. Ñîîáùåíèå ñ îøèáêîé âî âðåìÿ çàïóñêà êîíôèãóðèðîâàíèÿ î íåîáõîäèìîñòè óñòàíîâêè áèáëèîòåêè libpcap
В RedHat 7.3 libpcap-0.6.2-12.i386.rpm находится на втором диске в директории /RedHat/RPMS. (В RedHat 9.0 файл уже называется libpcap-0.7.2-1.i386.rpm и находится тоже на втором диске в той же директории). Устанавливаем библиотеку (с поправкой на вашу версию): # rpm -i libpcap-0.6.2-12.i386.rpm
и запускаем конфигурирование повторно. В случае успешного завершения, то есть отсутствия сообщений об ошибках, можем запустить компиляцию командой:
безопасность # make
из директории /progi/snort-2.0.2, куда мы распаковали пакет. После завершения компиляции у нас в директории /progi/snort-2.0.2/src должен появиться запускаемый файл – snort. Это и есть готовая программа. (У меня её размер 1224986). Если её просто запустить, то она выдаст информацию о ключах и пожалуется на то, что мы, «глупые» пользователи, не сообщили, что ей после запуска нужно делать: «Uh, you need to tell me to do something...» Программа готова к работе, задавая нужные ключи, можно запустить её работать, однако более разумным будет предварительное копирование программы в систему, то есть «установка» на своё место. С помощью команды: # make install
программа копируется в директорию /usr/local/bin, устанавливается man. После того как программа установлена, наступает самый интересный, а может, и самый муторный момент – конфигурация и создание правил, от корректности задания которых будет зависеть – будут ли ловиться те или иные атаки или нет. Цитата из раздела про sendmail в [33, стр. 718] гласит: «Если вы увидите человека, который начинает создание конфигурационного файла с пустой страницы в текстовом редакторе, можете с чистой совестью звонить в 03... Не имеет никакого смысла создавать этот файл с нуля (особенно если учесть его сложность) – гораздо проще изменить существующий. Только не забудьте сделать перед этим его копию!» То же самое можно сказать и про конфигурационный файл Snort – snort.conf. Конечно, он несколько проще его вышеупомянутого собрата, но незначительно. Готовый файл имеется в директории etc (/progi/snort-2.0.2/etc/snort.conf). Имя и размещение для файла конфигурации нигде не определены, однако де-факто файл называется snort.conf и размещать мы его будем в директории /etc/snort, которую необходимо создать. Далее в директории /etc/snort создадим поддиректорию rules, позже мы туда поместим правила. Правила мы также возьмём готовые и рассмотрим парочку правил, чтобы было ясно, как они создаются, на случай, если нам придётся их править и писать свои правила. Готовые правила можно взять из дистрибутива, однако они могут несколько отставать от жизни. Поэтому лучше брать ежедневно обновляемые правила на сайте Snort в разделе download: http://www.snort.org/dl/rules/snortrules-stable.tar.gz. Они подходят как для версий 1.9.x, так и для всех версий 2.0.x на момент написания статьи. Вопросы автоматического скачивания и обновления правил в этой статье мы рассматривать не будем. Также во всех файлах с правилами имеется шаблон файла конфигурации. Из файла с последними правилами или из дистрибутива переписываем все файлы с расширением .rules в директорию /etc/snort/rules, а оставшиеся несколько файлов в /etc/snort: classification.config generators gen-msg.map Makefile.am reference.config
№10(11), октябрь 2003
sid sid-msg.map snort.conf Не все файлы нам нужны, и необязательно правила писать в отдельную директорию, просто мне кажется, что так будет удобнее, когда «мухи отдельно, котлеты отдельно». Язык написания правил довольно специфичный, но в то же время простой и понятный. Большинство правил настолько просты, что умещаются в одну строчку. В старых версиях до 1.8 это даже было необходимо. Сейчас же правила могут переноситься с помощью обратного слеша «\» в конце строки. Для удобства правила состоят из двух логических частей: заголовка и опций. Заголовок определяет, какие пакеты следует смотреть, опции определяют, на что следует смотреть в перехваченных пакетах. Так, правило по «обнаружению водителя с пассажиром на жёлтых «Жигулях» будет выглядеть так: «Сообщить в центр, если мимо поста будут проезжать жёлтые «Жигули», едущие из центра в область по Рублёвскому шоссе c номером «22-33» днём с включёнными фарами, если водитель негр, а пассажиры – стройная блондинка с собачкой, о том, что проехала машина А.». Если применять это всё сразу к правилам и проводить аналогию, то первая часть правила – это «сообщить в центр, если мимо поста будут проезжать жёлтые «Жигули», едущие из центра в область по Рублёвскому шоссе», а вторая – «c номером «22-33» днём с включёнными фарами, если водитель негр, а пассажиры – стройная блондинка с собачкой, о том, что проехала машина А.». «Сообщить в центр» – это будет действие. «Жёлтые «Жигули» – это протокол. «Едущие из центра в область» – это направление следования, порты и IP-адреса отправителя и получателя. «По Рублёвскому шоссе» – это будет интерфейс, который будет слушать Snort, к правилам это отношения не имеет. А всё остальное будет опцией с условием. Если выразить это коротко и без комментариев, то получится, что заголовок содержит информацию о принимаемом действии по данному правилу, протокол, порты и IP-адреса отправителя и получателя с сетевыми масками. Опции же определяют, какую часть пакета стоит просматривать на соответствие чему-то и какой текст выдавать. Часть пакета – это будет салон автомобиля – смотрим на пассажира и водителя, а какой текст выдавать – «проехала машина А.». Простой пример: alert tcp any any -> 192.168.1.0/24 111 ↵ (content:"|00 01 86 a5|"; msg:"mountd access";)
До скобок это заголовок правила, в скобках – опции. Пояснять правило, думаю, не имеет смысла, и так должно быть понятно. Теперь пример посложнее, давайте возьмём файл /etc/ snort/rules/ftp.rules и рассмотрим его первую непустую строчку с правилом: alert tcp $EXTERNAL_NET any -> $HOME_NET 21 ↵ (msg:"FTP CEL overflow attempt"; ↵ flow:to_seserver,established; ↵ content:"CEL "; ↵ nocase; ↵ content:!"|0a|"; ↵ within:100; ↵
63
безопасность reference: bugtraq,679; ↵ reference:cve,CVE-1999-0789; ↵ reference:arachnids,257; ↵ classtype: attempted-admin; ↵ sid:337; ↵ rev:5;)
Правило выглядит более «навороченным», но несмотря на это, его можно по кусочкам изучить, и думаю, что читатель, знающий английский язык, без труда поймёт содержание правила. Добавлены комментарии, чтобы было проще найти информацию об уязвимостях, на которые направлено это правило, чтобы точно знать, когда указанная атака действительно может повлиять на систему. Если для данной атаки ваша система неуязвима, тогда и беспокоиться не стоит. Внимательный читатель заметит, что вместо адресов в последнем правиле используются переменные $EXTERNAL_NET и $HOME_NET. Введение переменных очень удобно, и оно предусмотрено синтаксисом файла конфигурации, где могут писаться правила. Можно один раз задать постоянные и часто неменяемые параметры сети, и не придётся после менять их во многих местах. Настройка Snort по большей части как раз и сводится к заданию подобных уже выбранных переменных в файле конфигурации. Помимо этого к каждой такой переменной идут комментарии. Чтобы файл конфигурации не «распухал», используется опция include с именем включаемого файла, аналогичная языку C. Разве что задаётся она без знака решётки в начале строки. Знак решётки, как обычно, используется для комментирования ненужных строк. Думаю, что не имеет смысла расписывать все возможные опции для правил вроде TOS и TTL, так как это есть в обширной и очень понятной документации и любой читатель при необходимости в написании своих правил может заглянуть на страничку с документацией к Snort в разделе Documentation и выяснить для себя детали синтаксиса. А пока давайте рассмотрим основные шаги внесения изменений в конфигурационный файл snort.conf, чтобы в конечном итоге наша система обнаружения атак худобедно заработала. Первое, что мы видим в конфигурационном файле, – это инструкция о необходимости выполнения конфигурации в 4 этапа: 1. Установка сетевых переменных; 2. Конфигурирование препроцессоров; 3. Конфигурирование и определение, куда будет вестись вывод; 4. Выбор необходимых правил.
1-й этап Переменная $HOME_NET определяет IP-адреса, считаемые адресами нашей домашней сети. Это нужно, чтобы Snort знал, что считать своим, а что чужим. Например, если мы имеем одну машину с адресом 123.45.45.45, то следует написать: var HOME_NET 123.45.45.45
64
В случае маскируемых сетей и если их несколько, пишем без пробелов в скобках: var HOME_NET [10.1.1.0/24,192.168.1.0/24]
Можно использовать ключевое слово «any» – оно означает любой адрес. Далее следует определить адрес внешней сети. Обычно это все адреса: var EXTERNAL_NET any
Далее идёт секция с выбором серверов, используемых в сети. Нужно это для того, чтобы не распылять ресурсы напрасно и повысить эффективность работы. Вопрос, конечно, открытый: какой смысл ловить атаки на веб-сервера, если у вас в сети нет ни одного веб-сервера? Но большая часть ответит, что никакого, поэтому в этой секции следует убрать лишнее либо задать более конкретно. Спешу вас предупредить, что бездумное комментирование этих строчек может привести к не запуску Snort и сообщениям об ошибках, так как некоторые включаемые ниже файлы с правилами, возможно, будут иметь ссылки на несуществующие переменные. Далее определяются порты для некоторых служб и прочие переменные. Для первого запуска лучше бегло пробежать, пропустив некоторые сложные моменты, и запуститься, а после уже заниматься более детальным изучением тех или иных правил и строчек в конфигурационном файле с целью выбора оптимальных настроек. Переменную $RULE_PATH следует определить как rules: var RULE_PATH rules
а не: var RULE_PATH ../rules
что написано по умолчанию, либо необходимо переписать правила в другую директорию.
2-й этап Конфигурирование препроцессоров. На первый взгляд может показаться, что препроцессоры – это лишняя и ненужная вещь, и, наверное, это будет по большей части правдой, только если не одно «но», что в сети одно и то же сообщение может быть разбито на две части и на много маленьких пакетов вплоть до содержания в 1 байт. Такие пакеты, не обнаруживая себя, будут проходить через любую СОА без особых трудностей; в зарубежной литературе, в том числе и электронной, эта классическая ситуация очень хорошо и с рисунками расписана. Поэтому разумнее накапливать все маленькие пакеты в буфере и пересобирать до нужного размера, а после уже проверять на наличие признаков той или иной атаки. Пересобирать можно и обычные, среднестатистические пакеты при необходимости. Также, если необходимо, препроцессоры могут выполнять предварительные преобразования веб-адресов. Не секрет, что через процент и шестнадцатеричное число в строке адреса можно передавать лю-
безопасность бые символы. Так, в истории есть один интересный факт, ставший примером классической глупости компании Microsoft, связанной с этим преобразованием, когда оная, обнаружив одну ошибку, исправила её другой. Некоторое время назад в серверах IIS была найдена ошибка, которая заключалась в том, что если в конце URL-адреса какого-либо asp-сценария дописать точку, то вместо запуска сценария на выполнение выводился его исходный текст. (Подобная ситуация была и со знаком пробела). На сообщения об этом известная фирма выпустила тут же заплатку, заключавшуюся в установке простой проверки синтаксиса запроса на наличие в конце знака «.» и удалении его перед передачей запроса непосредственно обрабатывающему его серверу. На что специалисты только посмеялись, а взломы серверов продолжились как ни в чём не бывало, с тем лишь различием, что в конце запроса вместо точки стал использоваться её шестнадцатеричный код со знаком процента, который беспрепятственно пропускался всеми фильтрами. Этот обходной манёвр несколько позже тоже прикрыли, но факт остался фактом. Поэтому лучше 7 раз подумать и один раз сделать, чем один раз подумать и 7 раз переделывать. Если, прочитав комментарии к препроцессорам, вы поняли, что всё ещё не сильны в их настройке или даже не поняли, зачем они вообще нужны, то лучше оставьте пока эту секцию без изменений.
-d – выводить содержимое уровня приложения в паке-
тах, если стоит режим избыточности вывода или ведения учёта пакетов (дополнительная информация нам не помешает). -с /etc/snort/snort.conf – использовать указанный конфигурационный файл.
Имеется ещё одна полезная опция «-l имя_директории» – она позволяет задавать ведение логов в какую-либо конкретную директорию. По умолчанию это /var/log/snort, поэтому мы не стали задавать этот излишний параметр. После этого, если программу не прерывать, то она висит на консоли и ловит атаки – это не самый удобный способ запуска, но для понимания происходящего и отладки – самый лучший. При этом на каждый IP-адрес, с которого идут атаки, создаётся поддиректория в директории, куда ведутся логи, и там создаётся файл с коротким названием сокращённо от протокола и портов зарегистрированной атаки, например: TCP:3739-1080 или TCP:21-21, или ICMP_ECHO. В частности, пока я отлаживал запуск в процессе написания этой статьи, за несколько секунд успело зарегистрироваться несколько реальных атак.
3-й этап Конфигурирование параметров вывода. Здесь мы указываем, куда у нас будет осуществляться вывод, в БД или в обычный лог-файл. Если в БД, то можно задать различные параметры, если в файл, то можно задать имя файла. Подробнее о ведении логов в БД и настройках, я думаю, я напишу в следующих статьях, а пока мы попытаемся настроить вывод в обычный файл, как и планировалось. (Замечание: напоминаю, что для вывода в БД необходима компиляция с поддержкой той или иной БД). Для вывода в файл надо оставить всё как есть по умолчанию и создать директорию, куда будут вестись логи – это /var/ log/snort. Необходимо проследить, чтобы у Snort было достаточно прав на запись в неё.
Ðèñóíîê 7. Âèä äèðåêòîðèè, êóäà âåäóòñÿ ëîãè
Внутри файлы имеет более подробное содержание произошедшего, например, просмотрев файл ICMP_ECHO, мы получаем информацию, что были атаки на узлы xx.xx.xx.7, xx.xx.xx.15, xx.xx.xx.16, что показано на рис. 8.
4-й этап Выбор тех или иных уже готовых правил обычно происходит с появлением некоторого опыта, поэтому мы оставим всё как есть по умолчанию. После внесения изменений мы сохраняем конфигурационный файл и запускаем Snort от имени суперпользователя командой: # /usr/local/bin/snort -o -i eth0 -d -c /etc/snort/snort.conf
(вместо eth0 можно указать любой другой прослушиваемый интерфейс), использованные опции означают: -o – сменить порядок применения правил с Alert → Pass → Log order на Pass → Alert → Log order, это ускоряет несколько работу. -i eth0 – слушать указанный интерфейс. Можно опустить, если интерфейс один в системе.
№10(11), октябрь 2003
Ðèñóíîê 8. Ïðèìåð ñîäåðæèìîãî ôàéëà ñ èíôîðìàöèåé îá àòàêàõ
65
безопасность Замечание. Из-за нашествия червя Blaster в последнее время (начиная с августа), которое стало возможным благодаря ошибкам в Windows NT/2000/XP и Windows 2003 Server, «холостой» трафик на все узлы в сети увеличился практически в десять и более раз за счёт подобных пакетов. Поэтому не удивляет тот факт, что за малый промежуток времени были зарегистрированы атаки. Запускать Snort руками хорошо только в отладочных целях, когда же мы убедились, что он работает, необходимо подумать об автоматическом его запуске.
Автоматизация процесса запуска Snort Изначально вопрос автоматического запуска никак не был продуман, и каждый запускал его как хотел из стартовых скриптов. Потом кто-то выложил свои скрипты в сети, а потом стартовый скрипт для помещения в директорию /etc/rc.d/init.d стал поставляться среди дополнительных программ (см.выше). Объяснить сиё можно только тем, что Snort может запускаться на различных платформах, а поддерживается он многими (см. таблицу 1, в которой запуск реализуется по-разному). Один из возможных способов автоматического запуска представлен ниже. Для Linux следует создать файл /etc/rc.d/init.d/snortd следующего содержания: #!/bin/bash # # snortd Start/Stop the snort IDS daemon. # # chkconfig: 2345 79 11 # description: snort is a lightweight network intrusion # detection tool that currently detects more # than 1100 host and network vulnerabilities, # portscans, backdoors, and more. # # June 10, 2000 -- Dave Wreski <dave@linuxsecurity.com> # - initial version # # July 08, 2000 Dave Wreski <dave@guardiandigital.com> # - added snort user/group # - support for 1.6.2 # Source function library. . /etc/rc.d/init.d/functions # Specify your network interface here INTERFACE=eth0 # See how we were called. case "$1" in start) echo -n "Starting snort: " # ifconfig eth0 up daemon /usr/local/bin/snort -o -i $INTERFACE -d -D \ -c /etc/snort/snort.conf touch /var/lock/subsys/snort sleep 3 if [ -f /var/log/snort/alert ] then rm /var/log/snort/alert fi echo ;; stop) echo -n "Stopping snort: " killproc snort rm -f /var/lock/subsys/snort echo ;; restart) $0 stop $0 start ;; status) status snort ;; *)
66
echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0
Далее следует дать команду: # chkconfig snortd on
чтобы в директориях соответствующих уровней появились символические ссылки на этот файл. Закомментированная строчка «ifconfig eth0 up» имеет следующий смысл: если при каких-то условиях (смена номера, запуска или какой-то сбой при запуске network) у нас Snort будет запускаться до запуска сети и поднятия интерфейса, то при её наличии ошибки не будет. Повторное поднятие уже поднятого интерфейса ошибок давать не должно. Строчку «rm /var/log/snort/alert» и несколько соседних можно закомментировать, если вы не хотите, чтобы у вас при запуске этот файл начинался с нуля. В заключение хотел бы привести таблицу возможных платформ, на которых может работать Snort. Òàáëèöà 1. Ïëàòôîðìû, íà êîòîðûõ ðàáîòàåò Snort
Планы на будущее Если эта статья вам понравилась и вы заинтересовались СОА Snort, значит, статья удалась. В дальнейшем я планирую продолжить тему обнаружения атак и написать про введение логов в БД, просмотр БД с помощью ACID, возможно, рассказав ещё про Snortcenter и другие вещи. Далее я планирую переключить внимание на обнаружение распределённых телекоммуникационных атак с помощью нескольких сенсоров Snort. В эксперименте по установке и настройке IDS Snort разных версий принимал участие RedHat Linux v.7.3.
Литература: 1. Статистика CERT http://www.cert.org/stats/cert_stats.html 2. C.Яремчук. L.I.D.S. //Системный администратор, №4(5), 2003. 3. В.Мешков. Система крипрографической защиты информации //Системный администратор, №4(5), 2003. 4. С.Яремчук. Контрольная сумма на защите Linux/ FreeBSD //Системный администратор, №6(7), 2003. 5. С.Яремчук. SELinux //Системный администратор, №5(6), 2003. 6. А.Даниленко. Технологии протоколирования Honeypot в обеспечении безопасности сетевых Unix-систем //Системный администратор, №5(6), 2003.
безопасность 7. В.Мешков. Брандмауэр //Системный администратор, №1(2), 2003. 8. В.Мешков Брандмауэр ч.2. //Системный администратор, №2(3), 2003. 9. Лукацкий А.В., Обнаружение атак. – СПб: БХВ-Петербург, 2001. – 624 с. 10. Милославская Н.Г., Толстой А.И. Инстрасети: обнаружение вторжений: Учеб. пособие для вузов. – М: ЮНИТИ-ДАНА, 2001. 11. Н.Польман, Т.Кразерс. Архитектура брандмауэров для сетей предприятия.: Пер. с англ. – М.: Издательский дом «Вильямс», 2003. 12. С.Норткат, М.Купер и др. Анализ типовых нарушений безопасности в сетях.: Пер. с англ. – М.: Издательский дом «Вильямс», 2001. 13. П.Н.Девянин, О.О.Михальский, Д.И.Правиков, А.Ю.Щербаков. Теоретические основы компьютерной безопасности: Учеб. пособие для вузов. – М: Радио и связь, 2000. 14. Анонимный автор, Максимальная безопасность в Linux.: Пер. с англ./Автор анонимный – К.: Издательство «ДиаСофт», 2000. 15. Сайт системы обнаружения атак IDS «Snort» http:// www.snort.org/ 16. А.Потёмкин. Общий обзор наиболее часто применяемых техник компьютерных атак и защиты от них //Системный администратор, №1(2), 2003. 17. Форум журнала «Системный администратор» http:// www.samag.ru/cgi-bin/yabb/YaBB.pl 18. Мак-Клар, Стюарт, Скембрей, Джоел, Курц, Джордж. Секреты хакеров. Безопасность сетей – готовые решения, 2-е изд.: Пер. с англ. – М.: Издательский дом «Вильямс», 2001. 19. Сайт компании Internet Security Systems, Inc. http:// www.iss.net/
№10(11), октябрь 2003
20. Правиков Д.И. Закляков П.В. Использование виртуальных ловушек для обнаружения телекоммуникационных атак. //Проблемы управления безопасностью сложных систем: Труды международной конференции. Москва, декабрь 2002 г./ Под ред. Н.И.Архиповой и В.В.Кульбы. Часть 1. – М.: РГГУ – Издательский дом МПА-Пресс. 342 с., с 310-314; 21. Роберт Л. Зиглер., Брандмауэры в Linux. : Пер. с англ.: Уч.пос. – М.: Издательский дом «Вильямс», 2000. – 386 с. 22. Request For Comments ? 793 23. Request For Comments ? 3168 24. Отчёт фирмы Symantec по угрозам безопасности в Интернете. http://www.symantec.com/region/ru/ruresc/ download/SymantecInternetSecurityThreatReport2003.pdf 25. Руководящий документ Государственной Технической Комиссии России при Президенте РФ «Средства вычислительной техники. Межсетевые экраны» 26. П.Закляков «Разводной мост на Linux» //Системный администратор, №4(5), 2003. 27. Козлов Д.А. Энциклопедия компьютерных вирусов.- М.: «Солон», 2001. – 464 с. 28. Большая вирусная энциклопедия http:// www.viruslist.com/index.html 29. С.Манн, М.Крелл Linux. Администрирование сетей TCP/ IP. Пер. с англ. – М.:ООО «Бином-Пресс», 2003. 30. В.Г.Олифер, Н.А.Олифер. Компьютерные сети. Принципы, технологии, протоколы – СПб: Питер, 2001. 31. Сайт SANS Institute – Computer Security Education and Information Security Training http://www.sans.org/ 32. Файл NEWS из Snort-2.0.2.tar.gz 33. Дж.Такет, С. Барнет. Использование Linux. Специальное издание.: 5-e изд.:Пер с англ.: Уч. пос. – М.: Издательский дом «Вильямс», 2000. 34. Медведковский И.Д., Семьянов П.В., Платонов В.В. Атака через INTERNET. Под научной редакцией проф. Зегжды П.Д. - СПб: «Мир и семья-95», 1997.
67
безопасность
БОРЬБА С ВИРУСАМИ ОПЫТ КОНТРТЕРРОРИСТИЧЕСКИХ ОПЕРАЦИЙ Не рой яму другому, чтобы он не использовал ее как окоп! Солдатская мудрость Червю LoveSan, разрушительной силой своей эпидемии побудившего меня написать эту статью, посвящается… Автор
…знайте: когда вы читаете эти строки, какой-то парень на планете отлаживает очередной вирус, который не сегодня завтра нанесет удар и одной из жертв вирусного террора окажетесь вы. Не пытайтесь отмахнуться от проблемы и не надейтесь, что на этот раз вас «пронесет»! Вирусные атаки стали слишком интенсивными и никто не может чувствовать себя в безопасности. Использование антивирусов ничего не меняет: если вы администрируете локальную сеть крупной организации, персонально для вас может быть написан специальный вирус (троянская программа, шпион), проходящий сквозь антивирусные заслоны, как нож сквозь масло. Причем если до недавнего времени вирусы были нетехнической проблемой «грязных рук», которая решалась элементарным выламыванием дисководов и раздачей по ушам всем любителям левого «софта», то основная масса современных вирусов проникает в целевые компьютеры самостоятельно, не требует никаких действий со стороны пользователя. Всякий уважающий себя администратор должен уметь находить и нейтрализовать имеющие его вирусы самостоятельно. Тому, как именно это сделать, и посвящена настоящая статья. (P.S. речь идёт о ОС Windows NT/W2K/XP/9x/Me)
КРИС КАСПЕРСКИ 68
безопасность Расплата за бездумность Ущерб, приносимый вирусами, троянскими конями и прочими зловредными программами, трудно переоценить. И дело здесь не только в разрушенной информации (при своевременном резервировании данных их всегда можно восстановить). Гораздо большие убытки приносит панический страх перед самой возможностью заражения, выливающийся в настоящую вирусную истерию. А всякий страх зиждется на незнании. После изобретения громоотвода молнии по-прежнему продолжают убивать людей, однако сейчас их (молний) уже не так боятся и, оказавшись застигнутым молнией один на один, всякий грамотный человек знает, как свести риск поражения к минимуму. Напротив, поддавшись панике и действуя наобум, вы идете прямой тропой к своему кладбищу. И плачевные результаты попыток противостояния вирусным атакам – лучшее тому подтверждение. Лихорадочные переустановки операционной системы, чередующиеся с форматированием винчестера и отрубанием себя от Сети – ничуть не эффективнее омовения сервера святой водой или накачиванием его антибиотиками. Использование антивирусов также не решает проблемы. Чтобы там ни говорила реклама, а качество антивирусных программ все еще оставляет желать лучшего. Зачастую вирусы не распознаются совсем или распознаются, но не удаляются. Мягкая переустановка системы (т.е. переустановка «поверх» ранее установленной версии) не гарантирует удаления заразы, и многие зловредные программы ее вполне благополучно переживают! Форматирование диска – вообще безумный способ лечения, сродни сжиганию больных на костре – жестокий и крайне неэффективный. До тех пор, пока не будут перекрыты все каналы проникновения вируса в систему, повторные заражения будут происходить вновь и вновь! Основной недостаток подавляющего большинства антивирусов как раз и состоит в том, что удаляя вирус из системы, они даже и не пытаются заткнуть те дыры, которые вирус использует для своего распространения. Как следствие, «лечение» компьютера, подключенного к сети, превращается в перегон тараканов из одной казармы в другую, а потом обратно. Ладно, заражение локальной сети – это еще полбеды («останавливаем» сеть, лечим все машины, «запускаем» сеть), но вот проникновение вирусов в Интернет представляет собой весьма нетривиальную проблему. Вылечить все машины глобальной сети за раз просто нереально… Можно (и нужно!) установить очередное обновление от Microsoft, заткнув брешь в системе безопасности, но… кто даст голову на отсечение, что этот способ действительно сработает? Ряд обнаруженных дыр парням из Microsoft удалось заткнуть лишь со второго-третьего раза, а некоторые дыры остались не заткнутыми и до сих пор (или заплатки были выпущены не для всех ОС). Причем наблюдается ярко выраженная тенденция в ухудшении поддержки четвертой версии Windows NT. Хоть и древней, но до сих пор работающей. В идеале каждый администратор должен быть готов к самостоятельному отражению вирусной атаки, не надеясь на помощь извне. Существование подобных отрядов са-
№10(11), октябрь 2003
мообороны, рассредоточенных по всей Сети, сделало бы развитие глобальных эпидемий практически невозможным и снизило убытки от хакерских атак к разумному минимуму. В свое время существовала прекрасная книга «Компьютерные вирусы в MS-DOS» Евгения Касперского, доходчиво объясняющая методики рукопашной борьбы с вирусами, доступные для освоения всякому специалисту средней руки. Однако с появлением Windows и развитием глобальных сетей, стратегия заражения файлов существенно изменилась, и старые рецепты перестали работать, а новых книг по этой тематике с тех пор так и не выходило. Данная статья рассказывает о наиболее типичных способах инфицирования исполняемых файлов и методах их выявления. Материал ориентирован на системных администраторов и прикладных программистов с минимальным уровнем подготовки.
Что нам потребуется? Анализ вирусного кода требует обширных значений из различных областей программирования, а также специализированного инструментария, без которого исследовательская работа рискует превратиться в орудие средневековой пытки. Все это отпугивает новичков, которые порой даже и не пытаются взять в руки дизассемблерный меч, считая, что борьба с вирусами слишком сложна для них. Однако это предположение неверно. Бесспорно, наивно надеяться на то, что искусству дизассемблирования можно научиться за одну ночь, но вот пары недель упорного труда для достижения поставленной цели должно оказаться достаточно. Знание языка ассемблера – древнейшего языка программирования – обязательно. И одних лишь учебников в стиле «ASSEMBLER» Юрова и «Программируем на языке ассемблера IBM PC» Рудакова для его освоения катастрофически недостаточно, поскольку всякий язык познается лишь при общении «вживую». Сходите на любой системно-ориентированный сайт (например, www.wasm.ru) и попытайтесь ухватить суть ассемблера извне, а не изнутри. На форумах, где дикие люди произносят непонятные слова, ругаются матом и обсуждают репродуктивные рецепторы вирусов, витает особый системный дух, делающий все сложное таким простым и понятым. В конечном счете ассемблер – это всего лишь язык, причем очень и очень простой. Некоторые даже сравнивают его с эсперанто – десяток команд и вы уже можете сносно говорить. Единственная сложность состоит в том, что вирусы, в отличие от нормальных программ, содержат множество ассемблерных «извращений», смысл которых понятен только посвященным. Для непосвященных же это интеллектуальный вызов! Это увлекательные логические (и психологические!) головоломки; это бессонные ночи, горы распечаток, яркие озарения и ни с чем не сравнимые радости найденных вами решений! Хотя, если говорить честно… все уже украдено до нас, тьфу, все головоломки давным-давно разгаданы, а задачки решены. Ресурсы глобальной Сети к вашим услугам! Посетите сайт удивительного человека и исследователя программ Марка Русиновича – http://www.sysinternals.com, а также отыщите его книгу «Внутреннее устройство Windows 2000». Еще вам пригодится знаменитый Interrupt List Ральфа Брауна, – хорошо
69
безопасность структурированный справочник по портам, ячейкам памяти и прерываниям (включая недокументированные). Последние версии Platform SDK и DDK от Microsoft и Basic Architecture/Instruction Set Reference/System Programming Guide от Intel иметь обязательно. Русские переводы технической документации, которые заполонили книжные магазины, годятся разве что для студентов, работающих над очередным рефератом, который все равно не читают, а для реальной работы они не пригодны. Из инструментария вам в первую очередь понадобится хороший отладчик и дизассемблер. Конечно, свой выбор каждый волен делать сам, но ничего лучше soft-ice от NuMega (www.numega.com) и IDA PRO от Ильфака Гуильфанова (www.idapro.com) еще никто не видел. Оба этих продукта относятся к классу тяжелой артиллерии и по сложности своего управления ничуть не уступают таким софтверным монстрам, как, например, Photoshop или Corel DRAW. Равно как изучение интерфейса, Photoshop не заменяет собой освоение техники рисования, так и искусство владения отладчиком/дизассемблером не ограничивается чтением штатной документации. Ищите в магазинах «Отладка Windows-приложений» Джона Роббинса, «Отладчик soft-ice» Романа Айрапетяна, «Образ мышления – дизассемблер IDA» Криса Касперски и «Фундаментальные основы хакерства – искусство дизассемблирования» его же.
Места наиболее вероятного внедрения вирусов Объектом вирусного поражения могут выступать как исполняемые файлы (динамические библиотеки, компоненты ActiveX, плагины), драйвера, командные файлы операционной системы (bat, cmd), загрузочные сектора (MBR и BOOT), оперативная память, файлы сценариев (Visual
Источники угрозы По данным сайта VX.NETLUX.ORG на начало сентября 2003 года рейтинг «популярности» вирусов и троянских коней выглядел так:
I-Worm.Sobig.f Worm.Win32.Lovesan Worm.Win32.Welchia I-Worm.Sobig.a Worm.Win32.Ladex Win32.Parite I-Worm.FireBurn Trojan.Win32.Filecoder I-Worm.Mimail I-Worm.Klez.a-h 33.525 Worm.P2P.Harex.a I-Worm.Tanatos.a TrojanProxy.Win32.Webber MBA.First AJ family Worm.P2P.Tanked Andrey.932 Worm.Win32.Opasoft Worm.Win32.Autorooter
Ðèñóíîê 1. TOP-20 âèðóñíîé ãîíêè íà âûæèâàíèå
Все двадцать вирусов из двадцати «сильнейших» чрезвычайно примитивные и неспособные к качественной мимикрии твари и все они легко обнаруживаются даже при поверхностном анализе исследуемых файлов по методикам, описанным ниже.
70
Basic Script, Java Script), файлы документов (Microsoft Word, Microsoft Excel) и… это далеко не все! Фантазия создателей вирусов поистине безгранична, и потому угрозы следует ожидать со всех сторон. Поскольку, охватить все вышеперечисленные типы объектов в рамках одной-единственной статьи не представляется сколь-нибудь разрешимой задачей, автор остановил свой выбор на самых интересных вирусоносителях из всех – на исполняемых файлах. Во-первых, вирусы, поражающие исполняемые файлы (а также троянские программы, распространяющиеся через них же), лидируют по численности среди всех остальных типов вирусов вообще. Во-вторых, методология анализа new-EXE файлов на предмет их заражения не в пример скудно освещена. В-третьих, тема дизассемблирования достаточно интересна и сама по себе. Для многих она служит источником творческого вдохновения да и просто хорошим средством времяпрепровождения. Так что не будем мешкать и совершим наш решительный марш-бросок, снося всех вирусов, встретившихся на нашем пути!
Основные признаки вирусного внедрения Единственным гарантированным способом выяснения, является ли данный файл «плохим» файлом или нет, является его полное дизассемблирование. Не скрою, дизассемблирование – крайне кропотливая работа и на глубокую реконструкцию программы размером в пять – десять мегабайт могут уйти годы если не десятки человеко-лет! Чудовищные трудозатраты делают такой способ анализа чрезвычайно непривлекательным и бесперспективным. Давайте лучше отталкиваться от того, что подавляющее большинство вирусов и троянских коней имеют ряд характерных черт, своеобразных «родимых пятен», отличающих их от всякой «нормальной» программы. Надежность таких «индикаторов» зараженности существенно ниже и определенный процент зловредных программ при этом останется незамечен, но… как говорится, на безрыбье и слона из мухи сделаешь! Количество всевозможных «родимых пятен», прямо или косвенно указывающих на зараженность файла, весьма велико и ниже перечислены лишь наиболее характерные из них. Но даже они позволяют обнаружить до 4/5 всех существующих вирусов, а по некоторым оценкам и более того (по крайней мере все «лауреаты» вирусного TOP-20 обнаруживаются).
Текстовые строки Прежде чем приступать к тотальному дизассемблированию исследуемого файла, нелишне пролистать его дамп на предмет выявления потенциально небезопасных текстовых строк, к которым, в частности, относятся команды SMTP-сервера и командного интерпретатора операционной системы («HELO/MAIL FROM/MAIL TO/ RCPT TO, DEL/COPY/RD/RMDIR соответственно), ветвей автозапуска реестра (RunServices, Run, RunOnce), агрессивные лозунги и высказывания («легализуем марихуану», «сам дурак») и т. д.
безопасность подства MS-DOS и преследовала собой следующие цели: уменьшение размеров программы на диске; сокрытие текстовых строк от посторонних глаз; затруднение анализа программы; «ослепление» сигнатурного поиска.
Ðèñóíîê 2. Ôðàãìåíò âèðóñà I-Worm.Kilez.e, òåêñòîâûå ñòðîêè ñîäåðæàùèåñÿ â òåëå êîòîðîãî âûäàþò àãðåññèâíûå íàìåðåíèÿ ïîñëåäíåãî ñ ãîëîâîé
Конечно, все это еще не свидетельство наличия вируса (троянской программы), а отсутствие компрометирующих программу текстовых строк – не гарант ее лояльности, но… просто поразительно, какое количество современных вирусов ловится таким элементарным способом. Не иначе как снижение культуры программирования дает о себе знать? Действительно, подавляющее большинство программ (и зловредных программ в том числе) сегодня разрабатывается на языках высокого уровня, и программисты не дают себе труда хоть как-то скрыть «уши», торчащие из секции данных (не знают, как это сделать?). Откомпилированная программа просто шифруется статическими упаковщиками, которые легко поддаются автоматической/полуавтоматической распаковке, выдавая исследователю исходный дамп со всеми текстовыми строками на поверхности (см. раздел «Идентификация упаковщика и автоматическая распаковка»). Выше в качестве примера приведен фрагмент вируса I-Worm.Kiliez.e, на малоизвестность которого жаловаться не приходится (вах! как трудно взглянуть на дамп того, что вы запускаете!).
Идентификация упаковщика и автоматическая распаковка Упаковка исполняемых файлов «навесными» упаковщиками была широко распространена еще во времена гос-
Критическая ошибка в SVCHOST.EXE Если, работая под Windows 2000/Windows XP, вы поймаете сообщение о критической ошибке приложения в модуле SVCHOST.EXE и эта критическая ошибка с завидной регулярностью станет повторяться вновь и вновь, не торопитесь переустанавливать систему, не сносите ваш компьютер в ремонт! Источник ошибки сидит отнюдь не в нем, а приходит к вам по Сети своим шагом и имя ему – DCOM RPC bug. Небрежное тестирование операционной системы вкупе с использованием потенциально опасных языков программирования привело к тому, что всякий нехороший человек получил возможность выполнять на вашей машине свой зловредный машинный код, управление которым передается путем нехитрого переполнения буфера. Однако современные хакеры в своей массе настолько тупы, что даже переполнить буфер, не уронив при этом машину, оказываются не в состоянии!
№10(11), октябрь 2003
Два последних пункта стоит отметить особо. Напрямую дизассемблировать упакованную программу нельзя. Прежде исследователю предстоит разобраться с упаковщиком, зачастую построеном по весьма нетривиальным алгоритмам, а также содержащим большое количество разнообразных приемов против отладчиков и дизассемблеров. Также существуют и полиморфные упаковщики, генерирующие машинный род распаковщика на «лету» и делающий зашифрованные экземпляры одной и той же программы не похожими друг на друга. Для борьбы с упаковщиками было создано большое количество автоматических распаковщиков, работающих по принципу трассировки исполняемого кода и отслеживания момента передачи управления на оригинальный код. Для борьбы с антиотладочными приемами использовалась технология эмуляции процессора, обхитрить которую было не так-то просто, хотя и возможно, но на этот случай в некоторых из распаковщиков был предусмотрен режим ручной распаковки, в котором распаковывалось все, что только было можно распаковать. С переходом на Windows многое изменилось. Количество упаковщиков резко возросло, но ни одного универсального распаковщика до сих пор так и не появилось, а потому анализ упакованных файлов представляет собой одну из актуальнейших проблем современной антивирусной индустрии. Если при дизассемблировании исследуемого файла большую часть исполняемого кода дизассемблер представил в виде дампа или выдал на выходе бессмысленный мусор (неверные опкоды команд, обращения к портам ввода/вывода, привилегированные команды, несуществующие смещения и т. д.), то файл скорее всего Немедленно кликните мышом по Windows Update и скачайте все критические обновления, которые вы по своей лени не скачали до сих пор! Поймите же наконец, что антивирусы против этой беды вам все равно не помогут, поскольку осуществляют лечение пост-фактум, когда зачастую лечить уже нечего… На худой конец закройте 135 порт – тогда вирусы и троянские кони не смогут распространяться.
Ðèñóíîê 3. Ýòî íå ïðèçíàê íåñòàáèëüíîñòè ñèñòåìû. Ýòî – ïðèçíàê âèðóñíîé àòàêè! Åñëè íàæàòü íà «ÎÊ» – ïåðåñòàíåò ðàáîòàòü áóôåð îáìåíà è íåêîòîðûå äðóãèå ôóíêöèè ñèñòåìû, åñëè íàæàòü íà «Îòìåíó» – çàïóñòèòñÿ îòëàä÷èê (åñëè îí ó âàñ åñòü) è ñèñòåìà ïîëíîñòüþ âñòàíåò. Åñëè æå íå äåëàòü íè òîãî, íè äðóãîãî – ñèñòåìà óñïåøíî ïðîäîëæèò ñâîþ ðàáîòó…
71
безопасность упакован и/или зашифрован. Зачастую расшифровщик крайне примитивен и состоит из десятка-другого машинных команд, смысл которых понятен с первого взгляда. В таком случае распаковать файл можно и самостоятельно. Вам даже не придется выходить из дизассемблера, всю работу можно выполнить и на встроенном языке (если, конечно, ваш дизассемблер поддерживает такой язык). Для расшифровки простейших «ксорок» хорошо подходит HIEW, а задачи посложнее решаются с помощью IDA. Подробное изложение методики расшифровки исполняемых файлов вы найдете в книге «Образ мышления – дизассемблер IDA» Криса Касперски.
вателя вашего отладчика, в частности, в soft-ice установка аппаратной точки останова осуществляется командой BPM адрес X).
Ëèñòèíã 1. Ïðèìåð òèïè÷íîãî «êñîðíîãî» ðàñøèôðîâùèêà ñ êîììåíòàðèÿìè ; CODE XREF: sub_401090+58?j .text:004010DA loc_4010DA: ; çàãðóçèòü â DL ñëåäóþùèé áàéò .text:004010DA mov dl, [esp+ecx+0Ch] ; ðàñøèôðîâàòü ïî XOR 66h .text:004010DE xor dl, 66h ; ïîëîæèòü íà ìåñòî .text:004010E1 mov [esp+ecx+0Ch], dl ; óâåëè÷èòü ñ÷åò÷èê íà åäèíèöó .text:004010E5 inc ecx ; åùå åñòü ÷òî ðàñøèôðîâûâàòü? .text:004010E6 cmp ecx, eax ; …åñëè äà, òî ìîòàåì öèêë .text:004010E8 jl short loc_4010DA ; CODE XREF: sub_401090+48?j .text:004010EA loc_4010EA:
Если же код расшифровщика по своей дремучести напоминает непроходимый таежный лес, у исследования есть все основания считать, что исследуемая программа упакована одним из навесных упаковщиков, к которым, в частности, принадлежат ASPack, UPX, NeoLite и другие. Отождествить конкретный упаковщик при наличии достаточного опыта можно и самостоятельно (даже полиморфные упаковщики легко распознаются визуально, стоит только столкнуться с ними три-пять раз кряду), а во всех остальных случаях вам помогут специальные сканеры, самым известным (и мощным!) из которых является бесплатно распространяемый PESCAN (http://k-line.cjb.net/tools/pe-scan.zip). Давайте возьмем файл с вирусом Worm.Win32.Lovesan (также известный под именем MSblast) и натравим на него PE-SCAN. Сканер тут же сообщит, что вирус упакован упаковщиком UPX, который можно скачать с сервера upx.sourceforge.net, а при нажатии на кнопку «OEP» определит и адрес оригинальной точки в файл (в данном случае она равна 0x00011CB). Ну коль скоро мы знаем имя упаковщика, найти готовый распаковщик не составит больших проблем («UPX» + «unpack» в любом поисковике)1. С другой стороны, знание оригинальной точки входа в файл позволяет установить на этот адрес точку останова и тогда в момент передачи управления только что распакованному файлу, отладчик немедленно всплывет (внимание! установка программной точки останова с кодом CCh в подавляющем большинстве случаев приводит к краху распаковщика, для предотвращения которого следует воспользоваться аппаратными точками останова; за подробностями обращайтесь к руководству пользо-
72
Ðèñóíîê 4. PE-SCAN â äåéñòâèè
А как быть, если PE-SCAN не сможет определить оригинальную точку входа или ни один из найденных вами распаковщиков не справляется с данным файлом? Если исследуемый файл хотя бы однократно запускался (то есть ваша машина уже потенциально заражена), можно взять ProcDump (http://ProcDump32.cjb.net) и, запустив распаковываемый файл еще раз, снять с него полный дамп памяти (Task → имя процесса → Dump Fill). Конечно, чтобы полученный дамп превратился в полноценный PEфайл, над ним придется как следует поработать «руками», но для дизассемблирования сойдет и так. Шансы распаковать файл без его запуска средствами ProcDump относительно невелики, да и качество распаковки оставляет желать лучшего. Зачастую распакованный файл не пригоден даже для дизассемблирования, не то что запуска! На худой конец можно попробовать перехватить передачу управления распакованному коду, просто поставив на соответствующие API-функции точки останова. При определенных навыках работы с двоичным кодом мы имеем все шансы осуществить такой перехват еще до того, как вирус успеет внедриться в систему или что-то испортить в ней, однако никаких гарантий на этот счет у нас нет и вирус в любой момент может вырваться из-под контроля, поэтому исследования такого рода лучше всего проводить на отдельной машине. Итак, вызываем soft-ice и устанавливаем точки останова на все потенциально опасные функции, а также все те функции, которые обычно присутствуют в стартовом коде (см. раздел «Стартовый код»). Если вирус написан на языке высокого уровня, мы захватим выполнение еще до начала выполнения функции main. В противном случае отладчик всплывет при первой попытке выполнения потенциально опасной функции. Отладчики, устанавливающие глобальные точки останова (и soft-ice в их числе), всплывают независимо от того, какое приложение их вызывает, поэтому всегда обращайте внимание на правый нижний угол экрана, в котором soft-ice выводит имя процесса, «потревожившего» отладчик, и, если это не исследуемый вами процесс, а что-то еще, вы можете смело покинуть отладчик, дожидаясь его очередного всплытия.
безопасность Òàáëèöà 1. Ôóíêöèè, ïîìîãàþùèå ïåðåõâàòèòü óïðàâëåíèå ó ðàñïàêîâàííîãî âèðóñíîãî êîäà, ïîëó÷èâøåãî óïðàâëåíèå
Давайте продемонстрируем технику ручной распаковки на примере анализа вируса IWorm.Sobig.f. PE-SCAN показывает, что он упакован полиморфным упаковщиком TeLock 0.98 (http://egoiste.cjb.net/), однако найти готовый распаковщик в Интернете для этой версии не удается (те, что есть, не распаковывают файл совсем или распаковывают его неправильно). Пошаговая трассировка распаковщика (равно как и попытки анализа алгоритма распаковки) заводят нас в никуда, ибо код оказывается слишком сложен для начинающих (а вот опытные программисты получают от его реконструкции настоящее удовольствие, ибо упаковщик весьма неплох). Просмотр дампа в HEX-редакторе также не показывает ничего подозрительного. Тупик… А теперь на сцену выходит наш прием с контрольными точками, и исследуемая программа тотчас ловится на GetModuleHandleA и CreateFileA. На момент вызова последних весь код и все данные зараженного файла уже полностью распакованы и просмотр содержимого сегмента данных немедленно разоблачает вирус по агрессивным текстовым строкам:
«вглубь» файла , демаскируя тем самым факт своего заражения. Сегодня, когда ассемблерные вирусы становятся музейной редкостью, такой способ отождествления малопомалу перестает работать, однако до полного списывания в утиль дело не дошло. Строго говоря, никаких формальных признаков «нормального» start-up не существует и каждый разработчик волен реализовывать его по-своему. Однако редкий разработчик цепляет к программе свой собственный start-up и все чаще для этих целей используется библиотечный стартовый код, поставляемый вместе с компилятором. Несмотря на то что даже в рамках одного-единственного компилятора существует множество разновидностей стартового кода, все они легко узнаваемы, и факт отсутствия стартового кода надежно обнаруживается даже самыми начинающими из исследователей! Приблизительная структура типичного стартового кода такова: сначала идет пролог, затем настройка обработчика структурных исключений (для Си++ программ), обнаруживающая себя по обращению к сегментному регистру FS. Далее следует вызов функций GetVersion (GetVersionEx), GetModuleHandleA и GetStartupInfoA. Подробнее об идентификации стартового кода можно прочитать в книге «Фундаментальные основы хакерства» Криса Касперски или в «Hacker Disassembling Uncovered» его же. Здесь же мы не можем позволить себе подробно останавливаться на этом обширном вопросе и просто сравним start-up код нормальной программы с кодом вируса Win2K.Inta.1676: Ëèñòèíã 2. Òàê âûãëÿäèò íîðìàëüíûé start-up îò Microsoft Visual C++ 6.0…
Ðèñóíîê 5. Ðàñïàêîâàííûé âðó÷íóþ I-Worm.Sobig.f ñðàçó æå âûäàåò àãðåññèâíîñòü ñâîèõ íàìåðåíèé õàðàêòåðíûìè òåêñòîâûìè ñòðîêàìè
Стартовый код В девяностых годах двадцатого века, когда вирусы создавались преимущественно на ассемблере и писались преимущественно профессионалами, а коммерческие программисты в своем подавляющем большинстве полностью отказались от ассемблера и перешли на языки высокого уровня, для разработчиков антивирусов наступили золотые дни, ибо распознать зараженный файл зачастую удавалось с одного взгляда. Действительно, любая нормально откомпилированная программа начинается с так называемого стартового кода (StartUp code), который легко отождествить визуально (как правило, он начинается с вызова функций GetVersion, GetModuleHandleA и т. д.), а дизассемблер IDA и вовсе идентифицирует стартовый код по обширной библиотеке сигнатур, выдавая тип и версию компилятора. Ассемблерные же программы стартового кода лишены, и потому, когда ассемблерный вирус внедряется в программу, написанную на языке высокого уровня, стартовый код отодвигается как бы
№10(11), октябрь 2003
.text:00401670 start proc near .text:00401670 push ebp .text:00401671 mov ebp, esp .text:00401673 push 0FFFFFFFFh .text:00401675 push offset stru_420218 .text:0040167A push offset __except_handler3 .text:0040167F mov eax, large fs:0 .text:00401685 push eax .text:00401686 mov large fs:0, esp ; Get current version number of Windows .text:00401696 call ds:GetVersion .text:004016EC push 0 .text:004016EE call __heap_init .text:00401704 mov [ebp+var_4], 0 .text:0040170B call __ioinit .text:00401710 call ds:GetCommandLineA .text:00401716 mov dword_424F44, eax .text:0040171B call ___crtGetEnvironmentStringsA .text:00401720 mov dword_4235C0, eax .text:00401725 call __setargv .text:0040172A call __setenvp .text:0040172F call __cinit .text:00401754 call _main .text:00401763 call _exit Ëèñòèíã 3. …à òàê âûãëÿäÿò îêðåñòíîñòè òî÷êè âõîäà âèðóñà Win2K.Inta.1676 .text:00011000 start proc near .text:00011000 mov eax, [esp+arg_0] .text:00011004 lea edx, loc_11129 .text:0001100A mov [eax+34h], edx .text:0001100D lea edx, dword_117A0 .text:00011013 lea eax, aHh ; "HH" .text:00011019 mov [edx+8], eax .text:0001101C mov [eax+4], aSystemrootSyst .text:0001101C ; "\\SystemRoot\\system32\\drivers\\inf.sys"
73
безопасность .text:00011023 .text:00011028 .text:0001102D .text:00011032 .text:00011034 .text:00011036 .text:0001103B
push push call or jnz mov retn
1200h 0 ExAllocatePool eax, eax short loc_1103E eax, 0C0000001h 8
Смотрите! В то время как «хорошая» программа лениво опрашивает текущую версию операционной системы и иже с ней, зловредный вирус сломя голову несется в объятья драйвера inf.sys. Правильные программы так себя не ведут и коварность вирусных планов разоблачается с первого взгляда! Разумеется, отсутствие стартового кода еще не есть свидетельство вируса! Быть может, исследуемый файл был упакован или разработчик применил нестандартный компилятор или набор библиотек. Ну с упаковкой мы уже разобрались, а с идентификацией компилятора поможет справиться IDA и наш личный опыт (замечание: текущие версии IDA PRO определяют версию компилятора непосредственно по стартовому коду, и, если он отсутствует или был изменен, механизм распознавания дезактивируется и поиском подходящей библиотеки сигнатур нам приходится заниматься вручную, через меню File → Load file → FLIRT signature file). И, если обнаружится, что нормальный start-up у файла всетаки есть, но выполнение программы начинается не с него, шансы на присутствие вируса значительно возрастут! Троянские программы, в большинстве своем написанные на языках высокого уровня, имеют вполне стандартный Start-Up и потому на такую наживку не обнаруживаются. Взять, например, того же Kilez, стартовый код которого выглядит так: Ëèñòèíã 4. ×åðâü I-Worm.Kilez.h èìååò ñòàíäàðòíûé ñòàðòîâûé êîä .text:00408458 start proc near .text:00408458 push ebp ; sub_408458 .text:00408459 mov ebp, esp .text:0040845B push 0FFFFFFFFh .text:0040845D push offset stru_40D240 .text:00408462 push offset __except_handler3 .text:00408467 mov eax, large fs:0 .text:0040846D push eax .text:0040846E mov large fs:0, esp .text:0040847B mov [ebp+var_18], esp ; Get current version number of Windows .text:0040847E call ds:GetVersion .text:004084AF xor esi, esi .text:004084B1 push esi .text:004084B2 call __heap_init .text:004084C4 mov [ebp+var_4], esi .text:004084C7 call __ioinit .text:004084CC call ds:GetCommandLineA .text:004084D2 mov dword_494E68, eax .text:004084D7 call ___crtGetEnvironmentStringsA .text:004084DC mov dword_493920, eax .text:004084E1 call __setargv .text:004084E6 call __setenvp .text:004084EB call __cinit .text:004084F0 mov [ebp+StartupInfo.dwFlags], esi .text:004084F3 lea eax, [ebp+StartupInfo] .text:004084F6 push eax ; lpStartupInfo .text:004084F7 call ds:GetStartupInfoA .text:004084FD call __wincmdln
Даже «невооруженным» глазом видно, что стартовый код червя идентичен стартовому коду Microsoft Visual C++ 6.0, что и неудивительно, так именно на нем червь и написан.
74
Точка входа При внедрении вируса в файл точка входа в него неизбежно изменяется. Лишь немногие из вирусов ухитряются заразить файл, не прикасаясь к точке останова (вирус может вписать по адресу оригинальной точки останова JUMP на свое тело, слегка подправить таблицу перемещаемых элементов или вклиниться в массив RVA-адрес таблицы импорта, внедриться в незанятые области кодовой секции файла и т. д.), однако ареал обитания таких особей ограничен преимущественно стенами лабораторий, а в дикой природе они практически не встречаются. Не тот уровень подготовки у вирусописателей, не тот… И если «нормальные» точки входа практически всегда находятся в кодовой секции исполняемого файла («.text»), точнее, в гуще библиотечных функций (навигатор IDA PRO по умолчанию выделяет их голубым цветом), непосредственно предшествуя секции данных, то точка входа зараженного файла традиционно располагается между секцией инициализированных и неинициализированных данных, практически у самого конца исполняемого файла. Так происходит потому, что дописывая свое тело в конец файла, «вирусная» секция оказывается самой последней секцией инициализированных ячеек памяти, за которой простирается обширный регион неинициализированных данных, без которого не обходится ни одна программа. Это-то его (вирус) и демаскирует! Ни один из известных автору упаковщиков исполняемых файлов так себя не ведет, и потому ненормальное расположение точки входа с высокой степенью вероятности свидетельствует о заражении файла вирусом!
Нестандартные секции При заражении исполняемого файла методом дозаписи своего тела в его конец у вируса есть две альтернативы: либо увеличить размер последней секции файла (а это, как правило, секция .data), присвоив ей атрибут Executable2, либо создать свою собственную секцию. Оба этих способа легко распознаются визуально. Код, расположенный в конце секции данных, – весьма характерный признак вируса, равно как и секция .text, замыкающая собой файл и после недолгих мытарств передающая управление «вперед» – на нормальную точку входа. То же самое относится и к секциям с нестандартными именами, зачастую совпадающими с именем самого вируса или маскирующимися под секции, создаваемые упаковщиками исполняемых файлов (но сам файл при этом остается неупакован!). Достаточно часто вирусы внедряются в создаваемую ими секцию .reloc, штатно предназначенную для хранения перемещаемых элементов. Быть может, вирусописатели думают, что разработчики антивирусов все сплошь круглые идиоты и не знают, для чего эта секция предназначена? Но так или иначе, встретив в исследуемом файле секцию .reloc, содержащую исполняемый код, знайте: с вероятностью близкой к единице, вы имеете дело с вирусом.
безопасность
Ðèñóíîê 6. Òàê âûãëÿäèò äèçàññåìáëåðíûé ëèñòèíã íîðìàëüíîãî ôàéëà. Òî÷êà âõîäà ðàñïîëîæåíà âíóòðè ñåêöèè .text â ãóùå áèáëèîòå÷íûõ ôóíêöèé, ïðèõîäÿñü ïðèáëèçèòåëüíî íà ñåðåäèíó ôàéëà
Ðèñóíîê 7. Òàê âûãëÿäèò äèçàññåìáëåðíûé ëèñòèíã ôàéëà, çàðàæåííîãî âèðóñîì WinNT.Infis.4608: òî÷êà âõîäà ðàñïîëîæåíà â ñåêöèè .reloc, ïîìåùåííîé íåïîñðåäñòâåííî çà êîíöîì èíèöèàëèçèðîâàííûõ äàííûõ ó ñàìîé «êðîìêè» èñïîëíÿåìîãî ôàéëà
Таблица импорта Операционные системы семейства Windows поддерживают два основных способа компоновки: статический и динамический. При статической компоновке имена (ординалы) вызываемых API-функций выносятся в специальную таблицу – таблицу импорта, изучение которой дает более или менее полное представление о природе исследуемой программы и круге ее интересов. К потенциально опасным функциям в первую очередь относятся сетевые функции, функции поиска, вызова и удаления файлов, TOOLHELP-функции, используемые для просмотра списка активных процессов и внедрения в них… Конечно, зловредной программе ничего не стоит загрузить все эти функции и самостоятельно, путем динамической компоновки, в простейшем случае опирающей-
№10(11), октябрь 2003
Ëèñòèíã 5. Òàê âûãëÿäèò äèçàññåìáëåðíûé ëèñòèíã ôàéëà, çàðàæåííîãî âèðóñîì WinNT.Chatter: èñïîëíÿåìûé êîä, ðàñïîëîæåííûé â ñåêöèè .reloc, ïðåäíàçíà÷åííîé äëÿ õðàíåíèÿ ïåðåìåùàåìûõ äàííûõ, ñèãíàëèçèðóåò î íåíîðìàëüíîñòè ñèòóàöèè
ся на вызов LoadLibrary/GetProcAddress, а то и вовсе на «ручной» поиск API-функций в памяти (адрес системного обработчика структурных исключений дает нам адрес, принадлежащий модулю KERNEL32.DLL, базовый адрес которого определяется сканированием памяти на предмет выявления сигнатур «MZ» и «PE» с последующим разбором PE-заголовка), но в этом случае текстовые строки с именами соответствующих функций должны так или иначе присутствовать в теле программы (если только они не зашифрованы и не импортируются по ординалу). Однако статистика показывает, что таблица импорта троянских программ носит резко полярный характер. Либо она вообще практически пуста, что крайне нетипично для нормальных, неупакованных, программ, либо содержит обращения к потенциально опасным функциям в явном виде. Конечно, сам факт наличия потенциально опасных функций еще не свидетельствует о троянской природе программы, но без особой нужды ее все-таки лучше не запускать. Анализ таблицы импорта позволяет выявить также и ряд вирусных заражений. Собственно, у вируса есть два пути: использовать таблицу импорта файла-жертвы или создавать свою. Если необходимых вирусу API-функций у жертвы нет и она не импортирует функции LoadLibrary/GetProcAddress, вирус должен либо отказаться от ее заражения, либо тем или иным образом импортировать недостающие функции самостоятельно (некоторые вирусы используют вызов по фиксированным адресам, но это делает их крайне нежизнеспособными, ограничивая ареал обитания лишь теми версиями ОС, на которые явно закладывались вирусописатели; другие же определяют адреса функций самостоятельно: по сигнатурному поиску или ручным анализом таблицы импорта: первое – громоздко и ненадежно, второе – слишком сложно в реализации для начинающих). И вот тут-то и начинается самое интересное. Разберем два варианта: использование готовой таблицы импорта и внедрение своей. На первый взгляд кажется, что отследить «левые» обращения к импорту жертвы просто нереально,
75
безопасность так как они ничем не отличаются от «нормальных». Теоретически все так и есть. Практически же не все так безнадежно. Большинство сред разработки компилирует программы с инкрементной линковкой и вместо непосредственного вызова всякой импортируемой функции, вызывает «переходник» к ней. Таким образом, каждая импортируемая функция вызывается лишь однажды и IDA генерирует лишь одну перекрестную ссылку. При заражении файла картина меняется и к API-функциям, используемым вирусом, теперь ведут две и более перекрестных ссылок. Это вернейший признак вирусного заражения! Вернее и быть не может! Ëèñòèíã 6. «Çàãëóøêà», ïðåäñòàâëÿþùàÿ ñîáîé ïåðåõîäíèê ê èìïîðòèðóåìîé ôóíêöèè è îòòÿãèâàþùàÿ âñå ïåðåêðåñòíûå ññûëêè íà ñåáÿ ; CODE XREF: sub_432A58+C0?p BRAT0:00648310 CreateFileA ; sub_432BC0+C0?p ... BRAT0:00648310 BRAT0:00648310 FF 25 48 44+ BRAT0:00648310 CreateFileA
proc near jmp endp
ds:__imp_CreateFileA
Ëèñòèíã 7. Òàáëèöà èìïîðòà èññëåäóåìîãî ïðèëîæåíèÿ: íàëè÷èå «ïàðàçèòíîé» ññûëêè íà CreateFileA óêàçûâàåò íà ôàêò âèðóñíîãî çàðàæåíèÿ ; DATA XREF: CreateDirectoryA?r .idata:006A4440 extrn __imp_CreateDirectoryA:dword ; DATA XREF: CreateEventA?r .idata:006A4444 extrn __imp_CreateEventA:dword ; DATA XREF: CreateFileA?r .idata:006A4448 extrn __imp_CreateFileA:dword ; DATA XREF: sub_6A4140?r .idata:006A4448 ; DATA XREF: CreateProcessA?r .idata:006A444C extrn __imp_CreateProcessA:dword ; DATA XREF: CreateThread?r .idata:006A4450 extrn __imp_CreateThread:dword
А что, если вирус захочет создать собственную секцию импорта или как вариант попытается расширить уже существующую? Ну две секции импорта для операционных систем семейства Windows – это слишком! Хотя… Почему, собственно, нет? Вирус создает еще одну секцию импорта, дописывая ее в конец файла, копирует туда содержимое оригинальной таблицы импорта, добавляет недостающие API-функции и затем направляет поле Import Table на «свою» таблицу импорта. По факту загрузки файла операционной системой вирус проделывает обратную операцию, перетягивая таблицу импорта «назад» (необходимость последней операции объясняется тем, что система находит таблицу импорта по содержимому поля Import Table, а
76
непосредственно сам исполняемый файл работает с ней по фиксированным адресам). Наличие двух таблиц импорта в файле – верный признак его заражения! Как вариант вирус может добавить к файлу секцию BOUND IMPORT, что очень просто реализуется и, что самое интересное, обнаруживается далеко не всеми дизассемблерами! Откройте исследуемый файл в HIEW и посмотрите на 12-й элемент Header Data Directories. Если такой элемент действительно присутствует и хранит в себе нечто отличное от нуля, – вероятность присутствия вируса в файле становится весьма велика (хотя некоторые легальные программы, в частности, линкер ULINK Юрия Харона также содержат в себе секцию BOUND IMPORT, но вирусами, очевидно, не являются). Расширение уже существующей таблицы импорта менее наглядно, но при наличии опыта работы с PE-файлами его все-таки можно разоблачить. Так, большинство линкеров упорядочивают импортируемые функции по алфавиту и функции, дописанные вирусами в конец таблицы импорта, сразу же обращают на себя внимание. Даже если импорт и не отсортирован, повышенная концентрация характерных для вируса API-функций все равно не может не броситься в глаза. Действительно, перечисление имен всех импортируемых функций обычно идет сплошным потоком от первой до последней используемой DLL, причем библиотека KERNEL32.DLL (которая вирусу и нужна!) оказывается в конце списка достаточно редко и вирусу ничего не остается, как дописывать импорт из KERNEL32.DLL в хвост другой библиотеки, в результате чего ссылка на модуль KERNEL32.DLL в таблице импорта зараженного файла присутствует дважды!
Заключение Вот мы и рассмотрели основные способы выявления зараженных файлов и теперь смело можем приступать к расширению и углублению полученных знаний и навыков. Чем больше вирусов пройдет через ваши руки, тем легче будет справиться с каждым из них. В конце концов не так страшны вирусы, как люди… 1
Упаковщик UNPX также содержит в себе и распаковщик, хотя это скорее исключение, чем правило. 2 Впрочем, под Windows 9x/NT этого можно и не делать, так как она разрешает выполнение кода в секции данных.
bugtraq Множественные уязвимости в Portable OpenSSH в PAM-коде
Удаленное выполнение произвольного кода в MondoSearch
Программа: Portable OpenSSH 3.7p1, 3.7.1p1. Опасность: Высокая. Описание: Несколько уязвимостей обнаружено в Portable OpenSSH в PAM-коде. Удалённый атакующий в некоторых конфигурациях может выполнить произвольный код на системе. Сообщается, что как минимум одна из обнаруженных уязвимостей может эксплуатироваться удалённо в некоторых конфигурациях (в которых отключен privsep). Версия OpenSSH для OpenBSD не содержит уязвимый код, поэтому не уязвима. URL производителя: http://www.openssh.com/portable.html Решение: Обновите программу до Portable OpenSSH 3.7.1p2 или отключите поддержку PAM («UsePam no» в sshd_config).
Программа: MondoSearch 4.x-5.х. Опасность: Критическая. Описание: Уязвимость обнаружена в MondoSearch. Злонамеренный пользователь может получить доступ к уязвимой системе. Дополнительные подробности не сообщаются. Mondosoft оценила риск обнаруженной уязвимости как «критический» и советует немедленно установить заплату. URL производителя: http://www.mondosoft.com/security/ Решение: Установите заплату для версий 4.4, 5.0, и 5.1: http://www.mondosoft.com/security/msp0903a.zip
Множественные уязвимости в Apple Macintosh OS X Программа: Apple Macintosh OS X. Опасность: Высокая. Описание: Множественные уязвимости обнаружены в Apple Macintosh OS X. Удаленный пользователь может скомпрометировать удаленную систему или выполнить DoS-нападение. SA9743. Mac OS X уязвима к недавно обнаруженным уязвимостям в OpenSSH. Уязвимость может использоваться для DoS-нападения. SA9758. Переполнение буфера обнаружено в обработчике Sendmail адресов и в обработчике правил. Уязвимость может использоваться для выполнения произвольного кода. SA9535. «off-by-one» переполнение обнаружено в функции «fb_realpath()». Уязвимы приложения, использующие уязвимую функцию. Уязвимость обнаружена в функции «arplookup()». Злонамеренный пользователь в локальной сети может исчерпать память ядра, посылая поддельные ARP-запросы. URL производителя: http://docs.info.apple.com/article.html? artnum=61798 Решение: Обновите систему до OS X 10.2.8, вручную или используя Software Update в System Preferences: Mac OS X Client (updating from 10.2 - 10.2.5): ht tp://download.info.apple.com/Mac_OS_X/0610 6 7 7 . 2 0 0 3 0 9 2 2 . P k N 4 5 / 2 Z / MacOSXUpdateCombo10.2.8.dmg Mac OS X Client (updating from 10.2.6 - 10.2.7): ht tp://download.info.apple.com/Mac_OS_X/0610675.20030922.fvWWd/2Z/MacOSXUpdate10.2.8.dmg Mac OS X Server (updating from 10.2 - 10.2.5): ht tp://download.info.apple.com/Mac_OS_X/0610 6 8 1 . 2 0 0 3 0 9 2 2 . d Z w 2 3 / 0 Z / MacOSXSrvrUpdCombo10.2.8.dmg Mac OS X Server (updating from 10.2.6 - 10.2.7): ht tp://download.info.apple.com/Mac_OS_X/0610 6 7 9 . 2 0 0 3 0 9 2 2 . G h 6 7 8 / 0 Z / MacOSXServerUpdate10.2.8.dmg
№10(11), октябрь 2003
Удаленное выполнение произвольного кода в LSH (эксплоит) Программа: LSH 1.4.x - 1.5.x. Опасность: Критическая. Описание: Уязвимость обнаружена в LSH – бесплатной альтернативе OpenSSH. Удаленный пользователь может выполнить произвольный код на уязвимой системе. Переполнение обнаружено в «read_line.c». Ниже рабочий код, которых позволяет удаленному атакующему скомпрометировать уязвимый сервер. Пример/Эксплоит: http://www.securitylab.ru/_exploits/ lsh_exploit.c.txt URL производителя: http://www.net.lut.ac.uk/psst/ Решение: Разрешайте подключения только из доверенных IP-адресов. Дождитесь соответствующего исправления.
Уязвимость в обработке TCP-пакетов в Microsoft Windows 2000 и Windows XP Программа: Microsoft Windows 2000 Advanced Server Microsoft Windows 2000 Datacenter Server, Microsoft Windows 2000 Professional, Microsoft Windows 2000 Server, Microsoft Windows XP Home Edition, Microsoft Windows XP Professional. Опасность: Низкая. Описание: Уязвимость обнаружена в обработке TCP-пакетов в Microsoft Windows 2000 и Windows XP. Удаленный атакующий может раскрыть конфиденциальную информацию. Windows, при определенных обстоятельствах, не сбрасывает «URG» тэг TCP-пакетов. Когда это происходит, Windows не устанавливает корректное значение для 16-битового значения «URG», включая в тэг «URG» случайные данные других пакетов. URL производителя: http://www.microsoft.com Решение: Для передачи критически важных данных используйте шифрованный трафик. Составил Александр Антипов
77
безопасность
АНАЛИЗ ЗАЩИТЫ ПРОГРАММ И РЕКОМЕНДАЦИИ ПО ЕЁ УСИЛЕНИЮ
СТАНИСЛАВ ГОШКО 78
безопасность Для того чтобы защитить программы от взлома, необходимо знать, против чего мы боремся. Будем считать, что мы являемся разработчиком программного обеспечения и нам противостоит взломщик среднего уровня. Почему среднего? Да потому, что если взломщик выше среднего уровня, то будет очень сложно создать защиту для программы, которую он бы не взломал (если не невозможно). В большинстве своём крэкеры используют следующий инструментарий: отладчики (SoftICE, TRW, Turbo Debugger, ...) дизассемберы (IDA, W32 Dasm, Sourcer, ... ) шестнадцатиричные редакторы (Hiew, Hex Workshop, ...) мониторы (FileMon, RegMon, ...)
Устанавливаем точку прерывания в SoftICE на
Теперь рассмотрим, как в основном взламываются обычные программы на конкретных примерах.
P.S. Можно было в HIEW заменить этот переход на jz.
MessageBoxA: bpx MessageBoxA
Всплывя в Irfan, мы видим кучу разных сравнений и несколько переходов. Моё внимание привлекла функция Kernel32, заполнив форму, я нашёл на неё переход и увидел, что переход находится по адресу: 0167:00440347 jnz 00440375
Исправляем флаг нуля в окне регистров и жмём F5, вуаля – мы зарегистрированы.
mIRC v. 6.01 Winzip 8.0 Загрузить SoftICE, поставить точку прерывания на GetDlgitemTexta, затем заполнить поля формы Winzip (name, serial_number; заполнить чем угодно) и нажать OK. Появится окно SoftICE, там поставить точку прерывания на 0167:00407AAB и посмотреть данные. bpx GetDlgItemTextA bpx 0167:00407AAB d eax В окне данных будет серийный номер, сгенерированный по вашему имени.
Hexworkshop 2.54 Ставим точку прерывания на GetWindowTexta, затем ставим точку прерывания по адресу 0167:004262AF. Трассируем без вхождения (F10) до второго перехода jnz. Этот второй переход выполняться не хочет, изменяем флаг нуля (в окне регистров наводим на Z и нажимаем INS). Теперь убираем все точки прерывания: bc *
и закрываем SoftICE – F5. Вводим имя и фирму, на которую хотим зарегистрироваться. Вот и всё.
Winamp 2.xx bpx hmemcpy Вводим serial. Всплываем в SoftICE. Видим что-то вроде: cmp eax, esi
два раза клацаем на эту строку, жмём F5.
? eax (там и хранится регистрационный код). Убираем точки прерывания, выключаем SoftICE.
Загрузить SoftICE, поставить точку прерывания на MessageBoxA. bpx MessageBoxA
Затем заполнить поля формы и нажать «ОК». Появится окно SoftICE. Выйдем из User32.dll и затем проанализируем код, предшествующий сообщению об ошибке. Выше вызова MessageBoxA я натолкнулся на следующий вызов функции: ; Ïîìåùàåòñÿ â ñòåê ñìåùåíèå ñåðèéíîãî íîìåðà push 0056d737 ; Ïîìåùàåòñÿ â ñòåê ñìåùåíèå èìåíè push 0056d350 ; Âûçîâ ôóíêöèè, êîòîðàÿ ïðîâåðÿåò êîððåêòíîñòü call 004c37b1 ; Ïðîâåðêà ðåçóëüòàòà ôóíêöèè test eax,eax ; !!!!!!!!!!!!! jz 004c3ce1
Команду условного перехода необходимо либо обратить (jnz 004c3ce1), либо забить nop. Адрес инструкции условного перехода следующий: 004с3с24.
Customiser Данная программа работает определённое количество времени и потом сообщает о том, что время её использования кончилось. И больше работать не хочет – это выражается в том, что пропадает кнопка «Continue». Начнём наше исследование с того, что взглянём, какие функции данная программа импортирует. Нас особо будут интересовать функции из USER32.dll, так как диалог, на котором была кнопка «Continue», импортируется скорее всего оттуда. Мое внимание привлекла функция – DialogBoxParamA. Загружаем SoftICE и ставим брейкпоинт на эту функцию:
Irfanview 2.0
bpx DialogBoxParamA
Данная программа была препарирована за 5 минут, а делалось это так:
После этого запускаем программу и сразу же всплы-
№10(11), октябрь 2003
79
безопасность вёт SoftICE в недрах USER32.dll, и мы поднимемся из этой функции (нажатием F12). Протрассируем до адреса 41f8c4, и там мы заметим подозрительный условный переход, следом за которым идёт ещё один. Второй переход указывает на вызов функции EnableWindow. Становится ясно, что нам нужно перейти по этому переходу. Для этого мы инвертируем флаг нуля в SoftICE и нажимаем F5, что возвращает управление программе, и мы видим, что программа заработала. Теперь мы должны пропатчить её. Запускаем HIEW, переходим по адресу 41f8c4 и меняем байты «75 03» на «EB 18». После этого снимем брейкпоинт в SoftICE. bc *
Запустим программу, нажмём кнопку «Exit», и программа не завершится, а, наоборот, запустится. Но попрежнему будет постоянно появляться это мерзкое окно с сообщением, что время твое прошло. Поэтому мы попытаемся избавиться от него. Найдём вызов функции рисования данного окна. Получится адрес 41f89c, и там будет вызов подпрограммы из 3 байт, которые перезапишем 3 nop («90»). Перезаписывать будем при помощи HIEW. Вот полная информация о проведённых изменениях: 41f89c: 90 90 90 41f8c4: EB 18
После этого программа будет запускаться без всяких окон. Существует ещё один способ продления лицензии без изменения программы. Нужно перед её установкой установить дату в системе лет на 20 вперёд, а после установки вернуть старую дату.
Как мы можем видеть, взлом программы чаще всего отталкивается от перехвата WIN API-функций. Как можно этому противостоять? Существует несколько методов:
Написание и использование своих функций с переходом куда-нибудь в середину WIN API-функции Рассмотрим написание своих функций на примере функции GetWindowTextA. Как устанавливается прерывание отладчика на имя функции? Вставляется байт «CC» перед первой инструкцией функции. Но мы ведь можем сделать так, что на этот первый байт инструкции управление никогда и не будет передано. Вы спросите, как это сделать? Давайте рассмотрим, как начинается данная функция: 77d5c13a: push 77d5c13c: push 77d5c141: call
0c 77d6e498 77d439c0
Так начало функции выглядит у меня. Каждому необходимо посмотреть на её начало под отладчиком самому: Загрузить SoftICE Ctrl + D ( Всплываем в SoftICE) u GetWindowTextA Теперь давайте разберёмся, как выглядит вызов нашей функции в программе в общем виде: push xxxxxxxx ................ push xxxxxxxx call GetWindowTextA
Причём при вызове GetWindowTextA идёт переход по адресу 77d5c13a. Мы же можем сделать следующим образом:
Shadow Security Scanner 5.37 Эта программа – один из лучших сетевых сканеров безопасности. Она имеет ограничение по времени на использование (trial). Метод, который применялся при взломе Customiser, не работает потому, что окно создаётся функцией CretaeWindowExA, это всё несколько усложняет. Но можно пойти другим путём. Трассировать программу без вхождения в подпрограммы, пока не появится окно, уведомляющее, что время программы закончилось. Нужно запомнить адрес подпрограммы, в которой выводится данное сообщение, и заглянуть туда. Там мы можем заметить какое-то странное сравнение: cmp [ebx+14],0
После этого переход, если не равно нулю. Поиграем с флагом нуля, и что мы видим – программа заработала, осталось только её пропатчить: 593598: EB
Вот и всё, защита с программы снята.
80
push xxxxxxxx ................ push xxxxxxxx push return_address push 0c jmp (GetWindowTextA+2)
Данный метод позволяет защититься от точки прерывания в SoftICE такого вида: bpx GetWindowTextA
Так же можно сделать следующим образом: push xxxxxxxx ................ push xxxxxxxx push return_address push 0c push 77d6e498 jmp (GetWindowTextA+7)
И таких вариантов существует достаточно много. В оптимальном варианте применения данной техники нужно написать дизассемблер длин и подключить его к программе таким образом, чтобы он формировал вызо-
безопасность вы функций, копируя некоторые инструкции из них в тело программы. Это позволит ещё более обезопасить программу от перехвата WIN API-функций.
push
Теперь нам необходимо заменить оригинальный обработчик на свой:
Подсчёт контрольной суммы WIN API-функций Данный метод мне ещё нигде не встречался, и хочется верить, что его идея принадлежит мне. Он заключается в том, что перед вызовом необходимой WIN API-функции подсчитывается её контрольная сумма и сверяется с той суммой, которая хранится в программе. Как вы помните, при установленной точке прерывания на место первой инструкции записывается байт «СС» (int 3), который и изменяет контрольную сумму данной функции. При проверке контрольной суммы данной функции и определении отладки можно выйти из программы. Теперь хочется сказать об эффективном применении данного метода. Я думаю, что если сверять контрольные суммы, то это может быть замечено взломщиком и результат сравнений подменён. Я предлагаю при помощи оригинальных контрольных сумм шифровать какие-нибудь критические данные, так, чтобы программа после декриптования данных неверной контрольной суммой работала некорректно. Ну естественно, что это ограничит круг операционных систем и их версий, но между двух зол выбирают меньшую.
dword ptr fs:[0]
push mov
offset SEH_Handler fs:[0],esp
Восстановление оригинального обработчика в нашем случае будет производиться следующей инструкцией: pop
dword ptr fs:[0]
Данная инструкция восстанавливает из стэка оригинальный обработчик SEH. А теперь рассмотрим программу, которая обрушивает отладчик, а без отладчика работает: .386p .model
flat
extrn
ExitProcess:PROC
.data Hi dd 0 .code ;--------------------------------------------------------; start: pop ebx ; Àäðåñ äëÿ âûçîâà èñêëþ÷åíèÿ call setupSEH Ex_Handler: mov
esp,[esp+8]
; Îøèáêà äàåò íàì ñòàðûé ESP ; â [ESP+8]
0 ExitProcess
; Êëàä¸ì â ñòýê 0 ; È çàâåðøàåì ïðîãðàììó
exit:
Обнаружение отладчика и завершение программы Все отладчики подсистемы семейства Windows делятся по уровням: ring 3 (уровень приложения) ring 0 (уровень ядра) В основном все отладчики, кроме SoftICE, относятся к отладчикам уровня приложения и против них существует множество методов, которые мы сейчас и рассмотрим:
Использование WIN API-функции IsDebuggerPresent Использовать её довольно легко: if (!IsDebuggerPresent()) goto no_debugger //........................................ no_debugger:
Или вот её полный код: mov mov movzx ret
eax,fs:[018h] eax,[eax+30h] eax,byte ptr [eax+02]
Погибель отладчику несут операции с SEH Нужно установить свой обработчик ошибки, а после вызвать ошибку попыткой записи в ядро. Вначале нам необходимо сохранить оригинальный обработчик SEH:
№10(11), октябрь 2003
push call
;--------------------------------------------------------; setupSEH: push dword ptr fs:[0] ; Push îðèãèíàëüíûé ; îáðàáîò÷èê SEH mov fs:[0],esp ; È ïîìåùàåì íîâûé ; (êîòîðûé íàõîäèòñÿ ; ïîñëå ïåðâîãî call) mov
eax,012345678h
xchg
eax,[ebx]
; Ïûòàåìñÿ ïèñàòü ; â ÿäðî (÷òî âûçîâåò ; èñêëþ÷åíèå)
end start
После того, как мы научились противодействовать отладчикам уровня приложения, не мешало бы научиться бороться с SoftICE. Победить правильно настроенный SoftICE практически невозможно, но дело в том, что в 90% он не настроен должным образом. 1) Стандартным методом является использование следующего кода: push pop int
ss ss 3
При попадании на инструкцию int 3 взломщик попадёт внутрь обработчика и будет там вдали от защитного механизма программы. 2) Следующий код эффективно использовать для модификации ключа расшифровки: mov
ebp,"BCHK"
81
безопасность push pop int db
ss ss 3 blabla ; Îïêîä ìîäèôèöèðóþùèé êëþ÷ ; äåêðèïòîâàíèÿ
3) Разработчики SoftICE оставили возможности для определения его присутствия, которыми мы и воспользуемся для защиты своей программы от SoftICE. Необходимо всего лишь открыть следующие файлы, если они открываются, значит, SoftICE присутствует на данной машине. В обратном быть уверенным нельзя. Список файлов: «\\.\NTICE» «\\.\SIWVIDSTART» «\\.\SICE» «\\.\SIWVID» Ну вот с отладчиками и закончили.
Дизассемблеры Перейдём к дизассемблерам, которые позволяют анализировать код без его исполнения. Чтобы им противостоять, оптимальным вариантом считается шифрование критических участков программы. Также определённое распространение получила техника под названием «перекрывающийся код». Рассмотрим листинг: mov jmp
eax,04ebh $-4
next:
Что же делает выделенная восклицательными знаками часть кода? В eax помещается значение 04ebh(это опкод команды jmp $+4) jmp $-4, переходит на значение 04ebh jmp $+4, переходит на метку next
82
Таким образом, можно строить сколь угодно сложный перекрывающийся код. Ещё в перекрывающемся коде есть один большой плюс, с его помощью можно прятать неприятные для кодоанализаторов инструкции.
Защита от изменения кода Многие программисты видели так называемые патчи (заплатки) для программ, которые сводят суть защиты программы на нет. Как же с этим бороться? Существуют два метода защиты: Шифровать при помощи контрольной суммы критического места программы важные данные. При этом если даже защита будет снята, программа будет работать некорректно. И это сведёт попытки взломщика на нет. А для полноценного взлома такого вида защиты нужно будет полностью разобраться в алгоритме, что доступно далеко не каждому взломщику. Использование помехозащищённого программирования. Смысл данной техники заключается в том, что программа сама восстанавливает изменённые в своём коде байты. Существует множество методов реализации данной схемы.
Мониторы Мониторам противодействовать практически невозможно, поэтому при построении защиты для программы необходимо свести обращения к файлам и реестру либо к минимуму, либо к максимуму. Первый способ скрывает защитный механизм внутри программы. А второй запутывает своими обращениями к различным файлам. Надеюсь, данный материал поможет вам достойно ответить на вызов крэкеров.
образование
ПОЛИНОМИАЛЬНАЯ АРИФМЕТИКА И ПОЛЯ ГАЛУА Искусство рассуждать – это искусство обманывать самого себя Антуан де Сент-Экзюпери «Цитадель»
ИЛИ ИНФОРМАЦИЯ, ВОСКРЕСШАЯ ИЗ ПЕПЛА II В прошлой статье этого цикла мы говорили о том, что помехоустойчивые коды Рида-Соломона основаны на двух фундаментальных математических составляющих: полиномиальной арифметике и арифметике полей Галуа. До тех пор, пока эти вопросы не будут нами всесторонне рассмотрены, мы не сможем двигаться дальше и потому наберемся чуточку терпения, чтобы совершить решительный штурм математических вершин. После чего начнется чистое программирование, практически без примесей всяких инородных математик.
КРИС КАСПЕРСКИ 84
образование Полиномиальная арифметика Полиномиальной арифметике посвящен шестой раздел третьего тома «Искусства программирования» Дональда Кнута, где полиному дается следующее определение: «Формально говоря, полином над S представляет собой выражение вида: u(x) = unxn + … + u1x + u0, где коэффициенты un, … ,u1,u0 – элементы некоторой алгебраической системы S, а переменная x может рассматриваться как формальный символ без определяющего значения. Будем полагать, что алгебраическая система S представляет собой коммутативное кольцо с единицей. Это означает, что S допускает операции сложения, вычитания и умножения, удовлетворяющие обычным свойствам: сложение и умножение являются ассоциативными и коммутативными бинарными операциями, определенными на S, причем умножение дистрибьютивно по отношению к сложению. Существует также единичный элемент по сложению 0 и единичный элемент по умножению 1, такие, что a + 0 == a и a1 == a для всех a из S. Вычитание является обратной по отношению к сложению операцией, но о возможности деления как операции, обратной по отношению к умножению, ничего не предполагается. Полином 0∗xn + m + … + 0∗x n + 1 + unxn + … + u1x + u0 рассматривается как идентичный unxn + … + u1x + u0, хотя формально он отличается от него». Таким образом, вместо того, чтобы представлять информационное слово D, кодовое слово C и остаток от деления R в виде целых чисел (как это делалось нами ранее), мы можем связать их с соответствующими коэффициентами двоичного полинома, выполняя все последующие математические манипуляции по правилам полиномиальной арифметики. Выигрыш от такого преобразования на первый взгляд далеко не очевиден, но не будем спешить, а лучше преобразуем любое пришедшее нам в голову число (например, 69h) в двоичный полином. Запустив «Калькулятор» или любое другое подходящее приложение по вашему вкусу, переведем наше число в двоичный вид (при соответствующих навыках эту операцию можно выполнить и в уме, см. «Техника и философия хакерских атак» Криса Касперски): 69h → 1101001. Ага, крайний правый коэффициент равен единице, затем следуют два нулевых коэффициента, потом единичный коэффициент… Короче говоря, получается следующее: 1∗x6 + 1∗x5 + 0∗x4 + 1∗x3+ 0∗x2 + 0∗x + 1. По сути говоря, битовая строка «1101001» является одной из форм записи вышеуказанного полинома – ненаглядной с точки зрения неподготовленного человека, но удобной для машинной обработки. Постойте, но если 69h уже представляет собой полином, то в чем разница между сложением полиномов 69h и 27h и сложением целых чисел 69h и 27h?! Разница несомненно есть. Как еще показал Ницше: фактов нет, а есть одни лишь интерпретации. Интерпретация же чисел и полиномов различна, и математические операции над ними выполняются по совершенно независимым правилам. Коэффициенты в полиномиальной арифметике строго типизированы и коэффициент при xk имеет иной тип, нежели при xm (конечно, при том условии, что k ≠ m).
№10(11), октябрь 2003
А операции над числами различных типов категорически не допустимы! Все коэффициенты обрабатываются независимо, а возникающий при этом перенос в старший разряд (заем из старшего разряда) попросту не учитывается. Покажем это на примере сложения чисел 69h и 27h: Ëèñòèíã 1. Ñëîæåíèå, âûïîëíåííîå ïî ïðàâèëàì ïîëèíîìèàëüíîé äâîè÷íîé àðèôìåòèêè (ñëåâà) è ñëîæåíèå, âûïîëíåííîå ïî ïðàâèëàì îáû÷íîé àðèôìåòèêè (ñïðàâà). 1101001 (69h) +0100111 (27h) ––––––– 1001110 (4Eh)
1101001 (69h) +0100111 (27h) ––––––– 10010000 (90h)
Простейшие расчеты показывают, что сложение полиномов по модулю два дает тот же самый результат, что их вычитание, и «волшебным» образом совпадает с битовой операцией XOR. Впрочем, совпадение с XOR – чистая случайность, но вот эквивалентность сложения и вычитания заставляет заново пересматривать привычную природу вещей, вспоминая задачки из серии «у Маши было одно яблоко, Петя отнял у нее его, затем ей подарили еще одно, спрашивается: сколько всего яблок у Маши осталось? А сколько у нее было бы, если бы первое яблоко осталось не отнятым?». С точки зрения арифметики по модулю два ответ: один и ноль соответственно. Да! Не отними бы Петя у Маши яблоко, 1 + 1 == 0 и бедная Маша вообще осталась бы ни с чем. Так что, мальчики, почаще отнимайте яблоки у девушек – учите их компьютерной грамотности! Впрочем, мы отвлеклись. Вернемся к фиктивному члену x нашего полинома и его коэффициентам. Благодаря их типизации и отсутствию взаимных связей, мы можем осуществлять обработку сколь угодно длинных чисел, просто XOR составляющие их биты на потоке. Это и есть одно из тех достоинств полиномиальной арифметики, которые не видны с первого взгляда, но благодаря которым полиномиальная арифметика стала так широко распространена. Однако в нашем случае одной лишь полиномиальной арифметикой дело не обходится и для реализации кодера/декодера Рида-Соломона нам потребуется активная помощь со стороны полей Галуа. Что же это за поля такие, спросите вы?
Поля Галуа В далеких шестидесятых, когда компьютеры были большими, а 20 Мб винчестеры напоминали собой стиральные машины, родилась одна из красивейших легенд о зеленом инопланетном существе, прилетевшем со звёзд и записавшем всю Британскую энциклопедию на тонкий металлический стержень нежно-серебристого цвета, который существо и увезло с собой. Сегодня, когда габариты 100 Гб жестких дисков сократились до размеров сигаретной пачки, такая плотность записи информации уже не кажется удивительной и даже вызывает улыбку. Но! Все дело в том, что инопланетное существо обладало технологией записи бесконечного количества информации на бесконечно крошечном отрезке и Британская энциклопедия была выбрана лишь
85
образование для примера. С тем же успехом инопланетянин мог скопировать содержимое всех серверов Интернета, нанеся на свой металлический стержень всего одну-единственную риску. Не верите? А зря! Переводим Британскую энциклопедию в цифровую форму, получая огромное-преогромное число. Затем – ставим впереди него запятую, преобразуя записываемую информацию в длиннющую десятичную дробь. Теперь только остается найти два числа A и B, таких, что результат деления A и B как раз и будет равен данному числу с точностью до последнего знака. Запись этих чисел на металлический стержень осуществляется нанесением риски, делящей последний на два отрезка с длинами, кратными величинам А и B соответственно. Для считывания информации достаточно всего лишь измерить длины отрезков А и B, а затем – поделить один на другой. Первый десяток чисел после запятой будет более или менее точен, ну а потом… Потом жестокая практика опустит абстрактную теорию по самые помидоры, окончательно похоронив последнюю под толстым слоем информационного мусора, возникающего из невозможности точного определения геометрических размеров объектов реального мира. В цифровом мире дела обстоят еще хуже. Каждый программист знает, что на деление целых и вещественных чисел наложены достаточно жесткие ограничения. Помимо того, что деление весьма прожорливая в плане процессорных ресурсов операция, так она еще и математически неточная! То есть, если c = a ∗ b, то еще не факт, что a == c/b! Таким образом, для практической реализации кодов РидаСоломона обычная арифметика непригодна и приходится прибегать к помощи особой математики – математики конечных групп Галуа. Под группой здесь понимается совокупность целых чисел, последовательно пронумерованных от 0 до 2n – 1, например: {0, 1, 2, 3} или {00h 01h, 02h, 03h, 04h, 05h, 06h, 07h, 08h, 09h, 0Ah, 0Bh, 0Ch, 0Dh, 0Eh, 0Fh}. Группы, содержащие 2 n элементов, называются полями Галуа (Galois Field) и обозначаются так: GF(2n)1. Члены групп в обязательном порядке подчиняются ассоциативному, коммутативному и дистрибьютивному законам, но обрабатываются довольно противоестественным на первый взгляд образом: 1) сумма двух любых членов группы всегда присутствует в данной группе; 2) для каждого члена «а» группы существует тождественный (identity) ему член, обычно записываемый как «e», удовлетворяющий следующему условию: a + e = e + a = a; 3) для каждого члена «a» группы, существует обратный (inverse) ему член «–a», такой, что: a + (–a) == 0.
пы равна: c = (a + b) % 2n, где операция «%» обозначает взятие остатка. Применительно к нашему случаю: (2 + 3) % 4 == 1. У математиков это называется «сложением по модулю 4». Естественно, вас интересует: а применяется ли сложение по модулю на практике или используется лишь в абстрактных конструкциях теоретиков? Хороший вопрос! Сложение по модулю мы машинально выполняем десятки раз на дню, даже не задумываясь о том, что это и есть сложение без учета переноса. Вот, например, проснувшись в шесть вечера по утру, вы просидели за компьютером девять часов кряду, а потом неожиданно бросили взгляд на свои наручные часы. Какое положение занимала часовая стрелка в это время, при условии, что часы идут точно? Искомое значение со всей очевидностью представляет собой сумму 6 и 9 по модулю 12 и равно оно: (6 + 9) % 12 == 3. Вот вам наглядный пример практического использования арифметики Галуа. А теперь давайте в порядке эксперимента вычтем из числа 3 число 6… (если не догадываетесь, как это правильно сделать, – возьмите в руки часы). Теперь самое главное: раз результат деления одного члена группы на другой, естественно, не равный нулю, член в обязательном порядке должен присутствовать в данной группе, то несмотря на то, что деление осуществляется в целых числах, оно будет точным. Точным, а не округленным! Следовательно, если c = a ∗ b, то a == c/b. Другими словами, умножение и деление непротиворечивым образом определено для всех членов группы, конечно, за исключением невозможности деления на нуль, причем расширения разрядной сетки при умножении не происходит! Конечно, это не совсем обычное умножение (и далеко не во всяком поле Галуа дважды два будет рано четырем), однако никто и не требует от арифметики Галуа ее соответствия «здравому смыслу» и «житейскому опыту». Главное – что она работает, причем работает хорошо. И существование жестких дисков, CDROM/DVD приводов – лучшее тому подтверждение, ибо все они так или иначе используют эту арифметику в своих целях. Как уже говорилось, в вычислительной технике наибольшее распространение получили поля Галуа с основанием 2, что объясняется естественностью этих полей с точки зрения машинной обработки, двоичной по своей природе. Для реализации кодера/декодера Рида-Соломона нам потребуются четыре базовых арифметических операции: сложение, вычитание, умножение и деление. Ниже они будут рассмотрены во всех подробностях.
Начнем с первого тезиса. Не кажется ли он вам бредом? Допустим, у нас есть группа {0, 1, 2, 3}. Это каким же в дупель пьяным нужно быть, чтобы при вычислении значения 2 + 3 получить число меньшее или равное 3?! Оказывается, сложение в полях Галуа осуществляется без учета переноса и сумма двух членов груп-
Сложение по модулю два в полях Галуа тождественно вычитанию и реализуется битовой операцией XOR. Этот вопрос мы уже обсуждали при изучении полиномиальной арифметики, поэтому не будем лишний раз повторяться, а просто приведем законченный пример программной реализации функции сложения/вычитания:
86
Сложение и вычитание в полях Галуа
образование Ëèñòèíã 2. Ôóíêöèÿ, ðåàëèçóþùàÿ ñëîæåíèå/âû÷èòàíèå â ïîëÿõ Ãàëóà. // ôóíêöèÿ âîçâðàùàåò ðåçóëüòàò ñëîæåíèÿ (âû÷èòàíèÿ) // äâóõ ïîëèíîìîâ a è b ïî ìîäóëþ 2 int gf_sum(int a, int b) { return a ^ b; }
Умножение в полях Галуа Открыв учебник математики за третий класс (если мне не изменяет память), мы найдем, что умножение представляет собой многократное сложение и, коль скоро сложение в полях Галуа мы выполнять уже научились, мы имеем все основания считать, что реализация функции умножения не создаст особого труда. Так? А вот и нет! Я всегда знал, что дважды два равно четырем, до конца никогда не верил в это и, впервые столкнувшись с полями Галуа, понял, насколько был прав2. Выяснилось, что существуют и такие математики, где дважды два не равно четырем, а операция умножения определяется не через сложение, а совсем по-другому. Действительно, если попытаться «обернуть» функцию gf_sum в цикл, мы получим то же самое сложение только в профиль. a ∗ b будет равно а, если b четно, и нулю, если b нечетно. Ну и кому такое умножение нужно? Собственно, функция «настоящего» умножения Галуа настолько сложна и ресурсоемка, что для упрощения ее реализации приходится прибегнуть к временному преобразованию полиномов в индексную форму, последующему сложению индексов, выполняемому по модулю GF, и обратному преобразованию суммы индексов в полиномиальную форму. Что такое индекс? Это – показатель степени при основании два, дающий искомый полином. Например, индекс полинома 8 равен 3 (23 = 8), а индекс полинома 2 равен 1 (21 = 2). Легко показать, что a ∗ b = 2i ∗ 2j = 2(i+j). В частности, 2 ∗ 8 = 2 3 ∗ 2 1 = 2( 3+1) = 2 4 = 16. Составим следующую табличку и немного поэкспериментируем с ней:
то есть удовлетворяла всем правилам групп, перечисленным выше (см. «Поля Галуа»). Естественно, поскольку от выбранной схемы сопоставления напрямую зависит и конечный результат, обе стороны (кодер и декодер Рида-Соломона) должны соблюдать определенные договоренности. Однако различные кодеры/декодеры Рида-Соломона могут использовать различные схемы сопоставления, несовместимые друг с другом. В частности, декодер Рида-Соломона, встроенный в CD-ROM привод, выполняет умножение по следующей таблице. Встретив такую таблицу в дизассемблерном листинге исследуемой вами программы, вы сможете быстро и надежно отождествить использующие ее функции: Òàáëèöà 2. Lock-up-òàáëèöà äëÿ GF(256). Ïåðâàÿ ñëåâà êîëîíêà – ïîëèíîìû/èíäåêñû (îáû÷íî îáîçíà÷àåòñÿ, êàê i), âòîðàÿ – òàáëèöà ñòåïåíåé ïðèìèòèâíîãî ïîëèíîìà 2 (îáû÷íî îáîçíà÷àåòñÿ êàê alpha_of), òðåòüÿ – èíäåêñû, ñîîòâåòñòâóþùèå äàííîìó ïîëèíîìó (îáû÷íî îáîçíà÷àåòñÿ êàê index_of).
Òàáëèöà 1. Òàáëèöà ïîëèíîìîâ (ëåâàÿ êîëîíêà) è ñîîòâåòñòâóþùèõ èì ñòåïåíåé äâîéêè (ïðàâàÿ êîëîíêà).
До сих пор мы оперировали понятиями привычной нам арифметики, и потому добрые две трети полей таблицы остались незаполненными. В самом деле, уравнения типа 2x = 3 в целых числах не разрешимы и ряд индексов не соответствует никаким полиномам! Так-то оно так, но в силу того, что количество полиномов всякого поля Галуа равно количеству всевозможных индексов, мы можем определенным образом сопоставить их друг другу, закрыв глаза на то, что с точки зрения обычной математики такое действие не имеет никакого смысла. Конкретная схема сопоставления может быть любой, главное – чтобы она была внутренне непротиворечивой,
№10(11), октябрь 2003
С помощью данной таблицы вы легко сможете осуществлять преобразование из полиномиальной формы в индексную и наоборот. Как пользоваться этой таблицей? Допустим, мы хотим умножить полиномы 69 и 96. Находим в первой колонке число 69. Ему соответствует alpha 47, запоминаем (записываем его на бумажке) и переходим к числу 96, alpha которого равен 217. Складываем 47 и 217 по модулю 256, получая в результате: (217 + 47) % 256 = 8. Теперь переводим результат произведения из индексной формы в полиномиальную: находим в первой колонке число 8 и в третьей колонке видим соответствующий ему полином: 3. (Если же мы вы-
87
образование полним обратную операцию, разделив 3 на 69 – мы получим 96, что доказывает непротиворечивость операций деления и умножения, а также всей арифметики Галуа в целом). Быстро, не правда ли, хотя местами и не совсем понятно, почему таблица составлена именно так, а не иначе? Хуже всего, что достоверность результата нельзя почувствовать «вживую», поскольку все это – абстракции чистейшей воды, что серьезно осложняет отладку программы (сложно отлаживать то, чей принцип работы до конца не понимаешь). Впрочем, таблицу умножения не обязательно набивать с клавиатуры вручную и ее вполне можно генерировать и на лету, по ходу исполнения программы. Один из примеров реализации генератора выглядит так: Ëèñòèíã 3. Ïðîöåäóðà ãåíåðàöèè look-up òàáëèöû áûñòðîãî óìíîæåíèÿ ïîëèíîìîâ. // ñòåïåíü RS-ïîëèíîìà (ñîãëàñíî Ñòàíäàðòà ECMA-130 – âîñåìü) #define m 8 // n=2∗m-1 (äëèíà êîäîâîãî ñëîâà) #define n 255 // êîëè÷åñòâî îøèáîê, êîòîðûå ìû õîòèì ñêîððåêòèðîâàòü #define t 1 // k = n-2∗t (äëèíà èíôîðìàöèîííîãî ñëîâà) #define k 253 // íåñîêðàòèìûé ïîðîæäàþùèé ïîëèíîì // ñîãëàñíî Ñòàíäàðòó ECMA-130: P(x) = x8 + x4 + x3 + x2 + 1 int p[m+1]={1, 0, 1, 1, 1, 0, 0, 0, 1 }; // òàáëèöà ñòåïåíåé ïðèìèòèâíîãî ÷ëåíà int alpha_to[n+1]; // èíäåêñíàÿ òàáëèöà äëÿ áûñòðîãî óìíîæåíèÿ int index_of[n+1]; //-------------------------------------------------------// ãåíåðèðóåì look-up òàáëèöó äëÿ áûñòðîãî óìíîæåíèÿ äëÿ GF(2m) // íà îñíîâå íåñîêðàòèìîãî ïîðîæäàþùåãî ïîëèíîìà P© // îò p[0] äî p[m]. // // look-up òàáëèöà: // index -> polynomial èç alpha_to[] ñîäåðæèò j=alpha^i, // ãäå alpha åñòü ïðèìèòèâíûé ÷ëåí, îáû÷íî ðàâíûé 2 // à ^ - îïåðàöèÿ âîçâåäåíèÿ â ñòåïåíü (íå XOR!); // // polynomial form -> index èç index_of[j=alpha^i] = i; // // © Simon Rockliff //-------------------------------------------------------generate_gf() { int i, mask; mask = 1; alpha_to[m] = 0; for (i = 0; i < m; i++) { alpha_to[i] = mask; index_of[alpha_to[i]] = i; if (p[i] != 0) alpha_to[m] ^= mask; mask <<= 1; } index_of[alpha_to[m]] = m; mask >>= 1; for (i = m+1; i < n; i++) { if (alpha_to[i-1] >= mask) alpha_to[i] = alpha_to[m] ^ ((alpha_to[i-1]^mask)<<1); else alpha_to[i] = alpha_to[i-1]<<1; index_of[alpha_to[i]] = i; } index_of[0] = -1; }
Сама же функция умножения выглядит тривиально, укладываясь всего в пяток строк. В большинстве про-
88
граммных реализаций кодера/декодера Рида-Соломона, которые мне только доводилось видеть, операция умножения даже не выносится в отдельную процедуру, а реализуется непосредственно по месту вызова. Ëèñòèíã 4. Ôóíêöèÿ áûñòðîãî òàáëè÷íîãî óìíîæåíèÿ ïîëèíîìîâ â ïîëÿõ Ãàëóà. // ôóíêöèÿ âîçâðàùàåò ðåçóëüòàò óìíîæåíèÿ äâóõ ïîëèíîìîâ // a íà b â ïîëÿõ Ãàëóà int gf_mul(int a, int b) { int sum; // íåìíîãî îïòèìèçàöèè íå ïîâðåäèò if (a == 0 || b == 0) return 0; // âû÷èñëÿåì ñóììó èíäåêñîâ ïîëèíîìîâ sum = alpha_of[a] + alpha_of[b]; // ïðèâîäèì ñóììó ê ìîäóëþ GF if (sum >= GF-1) sum -= GF-1; // ïåðåâîäèì ðåçóëüòàò â ïîëèíîìèàëüíóþ ôîðìó // è âîçâðàùàåì ðåçóëüòàò return index_of[sum]; }
Деление в полях Галуа Деление в полях Галуа осуществляется практически точно так, как и умножение, с той лишь разницей, что индексы не прибавляются, а вычитаются друг из друга. В самом деле: a/b == 2i/2j == 2(i-j). Для перевода из полиномиальной в индексную форму и наоборот может использоваться уже приводимая выше look-up таблица. Естественно, не забывайте о том, что какими бы извращенными поля Галуа ни были, а на нуль даже в абстрактной арифметике делить нельзя и функция деления должна быть снабжена соответствующей проверкой. Ëèñòèíã 5. Ôóíêöèÿ áûñòðîãî òàáëè÷íîãî äåëåíèÿ â ïîëèíîìîâ â ïîëÿõ Ãàëóà. // ôóíêöèÿ âîçâðàùàåò ðåçóëüòàò äåëåíèÿ äâóõ ïîëèíîìîâ // a íà b â ïîëÿõ Ãàëóà, ïðè ïîïûòêå äåëåíèÿ íà íîëü ôóíêöèÿ // âîçâðàùàåò -1 int gf_div(int a, int b) { int diff; // íåìíîãî îïòèìèçàöèè íå ïîâðåäèò if (a == 0) return 0; // íà íîëü äåëèòü íåëüçÿ! if (b == 0) return -1; // âû÷èñëÿåì ðàçíîñòü èíäåêñîâ diff = alpha_of[a] – alpha_of[b]; // ïðèâîäèì ðàçíîñòü ê ìîäóëþ GF if (diff < 0) diff += GF-1; // ïåðåâîäèì ðåçóëüòàò â ïîëèíîìèàëüíóþ ôîðìó // è âîçâðàùàåì ðåçóëüòàò return index_of[diff]; }
Простейшие практические реализации Хорошим примером воплощения кодера/декодера РидаСоломона являются древние модели жестких дисков, разработанных в недрах фирмы IBM. Модель IBM 3370 имела простой и наглядный кодер/декодер Рида-Соломона типа (174,171) в поле Галуа GF(256). Другими словами, он оперировал 8-битными ячейками (28 = 256), и на 171 информационный байт приходилось 3 байта суммы четности, что в результате давало кодовое слово с размером 174 байт, причем, как мы увидим далее, все три байта контрольной суммы рассчитывались совершенно независимо друг от друга, поэтому фактически ко-
образование дер/декодер Рида-Соломона оперировал одним байтом, что значительно упрощало его архитектуру. В современных же винчестерах кодер/декодер РидаСоломона стал слишком навороченным, а количество контрольных байтов многократно возросло, в результате чего пришлось работать с числами противоестественных разрядностей (порядка 1408 бит и более). Как следствие – программный код ощетинился толстым слоем дополнительных проверок, циклов и функций, чрезвычайно затрудняющих его понимание (к тому же большинство производителей железа в последнее время перешли на аппаратные кодеры/декодеры РидаСоломона, целиком реализованные в одной микросхеме). В общем, прогресс прогрессом, а для изучения базовых принципов работы лучше использовать древние модели. Ниже приведен фрагмент оригинальной прошивки жесткого диска IBM 3370 (только не спрашивайте: откуда он у меня взялся): Ëèñòèíã 6. Êëþ÷åâîé ôðàãìåíò êîäåðà Ðèäà-Ñîëîìîíà, âûðâàííûé èç ïðîøèâêè IBM 3370. for (s0 { s0 s1 sm1 };
= s1 = sm1 = i = 0; i < BLOCK_SIZE; ++i) = = =
s0 ^ input[i]; GF_mult_by_alpha[ s1 ^ input[i] ]; GF_mult_by_alpha_inverse[sm1 ^ input[i] ];
Ëèñòèíã 7. Êëþ÷åâîé ôðàãìåíò äåêîäåðà Ðèäà-Ñîëîìîíà, âûðâàííûé èç IBM 3370. // âû÷èñëÿåì ñèíäðîì îøèáêè err_i = GF_log_base_alpha[ GF_divide[s1][s0] ]; // èñïðàâëÿåì ñáîéíûé áàéò input[err_i] ^= s0;
Ну что, слабо нам разобраться: как он работает? Что касательно переменной s0 – с ней все предельно ясно: она хранит контрольную сумму, рассчитанную по тривиальному алгоритму. Как вы, наверное, помните, сложение в полях Галуа осуществляется логической операцией XOR, и потому: s0 += input[i]. Назначение переменной s1 выяснить сложнее, и чтобы понять суть разворачивающегося вокруг нее метаболизма, мы должны знать содержимое таблицы GF_mult_by_alpha. Несмотря на то, что по соображениям экономии бумажного пространства она здесь не приводится, ее имя говорит само за себя: содержимое s1 суммируется с очередным байтом контролируемого потока данных и умножается на так называемый примитивный член, обозначаемый как alpha, и равный двум. Другими словами: s1 = 2 ∗ (s1 + input[i]). Допустим, один из байтов потока данных впоследствии будет искажен (обозначим его позицию как err_i), тогда индекс искаженного байта можно определить тривиальным делением s1 на s0. Почему? Так ведь выражение s1 = 2 ∗ (s1 + input[i]) по своей сути есть не что иное, как завуалированное умножение информационного слова на порожденный полином, динамически генерируемый на основе своего примитивного члена alpha. А контрольная сумма информационного слова, хранящаяся в переменной s0, фактически представляет собой то же самое информационное слово, только
№10(11), октябрь 2003
представленное в более «компактной» форме. И, как уже говорилось в предыдущей статье: если ошибка произошла в позиции x, то остаток от деления кодового слова на порожденный полином будет равен k = 2x. Остается лишь по известному k вычислить x, что в данном случае осуществляется путем обращения к таблице GF_log_base_alpha, хранящей пары соответствий между k и 2x. Коль скоро позиция сбойного байта найдена, его можно исправить путем XOR с рассчитанной контрольной суммой s0 (input[err_i] ^= s0). Конечно, сказанное справедливо только для одиночных ошибок, а искажения двух и более байт на блок данный алгоритм исправить не в силах. Собственно, для этого и присутствует третий байт контрольной суммы – sm1, защищающий декодер от «политнекорректных» попыток исправления ошибок, когда их больше одной. Если выражение s1/s0 == sm1 ∗ s0 становится ложным, контроллер винчестера может засвидетельствовать факт наличия множественных ошибок, констатируя невозможность их исправления. Однако, как хорошо известно, дефекты магнитной поверхности имеют тенденцию образовывать не одиночные, а групповые ошибки. И, чтобы хоть как-то компенсировать слабость корректирующего алгоритма, парни из IBM прибегли к чередованию байт. Винчестер IBM 3370 имел чередование 3:1, то есть сначала шел первый байт первого блока, за ним первый байт второго блока, за ним – первый байт третьего и только потом – второй байт первого блока. Такой трюк усиливал корректирующую способность винчестера с одной одиночной ошибки, до трех последовательно искаженных байт... Однако, если разрушению подвергались не соседние байты, то корректирующая способность вновь опускалась до значений в один искаженный байт на блок, но вероятность такого события была несравненно меньше. Естественно, что данный алгоритм может быть реализован не только в самом жестком диске, но и вне его. Варьируя размер блоков и степень чередования, вы обеспечите себе лучшую или худшую защищенность при большей или меньшей избыточности информации. Действительно, пусть у нас есть N секторов на диске. Тогда, разбив их на блоки по 174 сектора в каждом и выделив 3 сектора для хранения контрольной суммы, мы сможем восстановить по меньшей мере N/174 секторов диска. Исходя из средней емкости диска в 100 Гб (что соответствует 209 715 200 секторам), мы сможем восстановить до 1 205 259 секторов даже при их полном физическом разрушении, затратив всего лишь 2% дискового пространства для хранения контрольных сумм. Согласитесь, что редкая «сыпка» винчестера проходит столь стремительно, чтобы корректирующих способностей кода РидаСоломона оказалось недостаточно для ее воскрешения (конечно, если эту сыпку вовремя заметить и если коэффициент чередования выбран правильно: так, что сектора, принадлежащие одному дисковому блину, обслуживались бы разными корректирующими блоками, в противном случае при повреждении поверхности одного из блинов возникнет групповая ошибка, уже неисправимая данной программой).
89
образование А как быть, если «навернется» весь жесткий диск целиком? Наиболее разумный выход – создать массив из нескольких дисков, хранящих полезную информацию вперемешку с корректирующими кодами. Главный минус такого подхода – его неэффективность на массивах, состоящих из небольшого количества жестких дисков. Разумный минимум: четыре информационных диска и один контрольный, тогда потеря любого из информационных дисков компенсируется оставшимся в живых контрольным. Ну а потерянный контрольный диск элементарным образом заменяется на новый, с последующим пересчетом всех контрольных кодов. Правда, одновременный выход двух дисков из строя – это кранты. Массив из пятнадцати дисков, двенадцать из которых – информационные, а оставшиеся три – контрольные, намного более отказоустойчив и допускает одновременный крах двух любых дисков, а при благоприятном стечении обстоятельств – и трех. Собственно, во всем этом ничего нового нет, и соответствующие RAID-контроллеры можно купить буквально в любом магазине. Однако… мне трудно представить себе, сколько будет стоит RAID-контроллер уровня 15 и удастся ли его вообще заставить работать (по личному опыту могу сказать, что RAID-контроллеры даже начальных уровней – вещь крайне глючная, капризная и требовательная как к железу, так и к операционному окружению). Наконец, практически все RAID-контроллеры требуют наличия абсолютно идентичных, ну или близких по своим характеристикам и/или интерфейсам дисков. А коли таковых нет? Программный RAID, активно пропагандируемый настоящим автором, всех этих недостатков лишен. Вы можете использовать диски различной геометрии и даже различной емкости, причем никто не обязывает вас сосредоточивать их в одном месте – доступ к дискам может осуществляться и по сети, причем совершенно необязательно отводить под RAID-хранилище весь диск целиком! Вы вольны произвольным образом выделять ту или иную часть дискового пространства. Как это можно реально использовать на практике? Первое, что приходит на ум, использовать часть емкости жестких дисков под хранение избыточной информации, помогающей восстановить их в случае аварии. Если несколько компьютеров объединить в сеть (что уже давным-давно сделано и без нас), то при относительно небольших накладных расходах мы сможем восстановить любой из жестких дисков членов сети даже при полном его разрушении лишь за счет одной избыточной информации, распределенной между остальными компьютерами. Более надежного хранилища для ваших данных нельзя и придумать! Подобная схема была реализована автором этой статьи в локальных сетях нескольких фирм и доказала свою высокую живучесть, гибкость и функциональность. Необходимость в постоянном резервировании содержимого жестких дисков автоматически отпала, что в условиях одноранговой сети с отсутствующим выделенным сервером более чем актуально! А ведь такие локальные сети – не редкость (нет, я не утверждаю, что такие сети хороши, просто я констатирую факт, что они существуют в природе и в обозримом будущем вымирать не собираются).
90
Единственный минус программного RAID – его невысокая производительность. В частности, поставив программный RAID на сервер, обрабатывающий тысячи запросов ежесекундно и интенсивно модифицирующий большое количество файлов, вы не выиграете ничего, но… ведь само понятие «производительность» очень относительно и при достаточно быстром процессоре кодирование/декодирование информации вполне реально осуществлять и на лету безо всяких потерь в пропускной способности! С другой стороны, если операции чтения доминируют над операциями записи, то ставить программный RAID сам Крестный Отец велел, поскольку контроль целостности считываемой информации осуществляется на «железном» уровне самим приводом и при использовании систематического кодирования (т.е. информационные слова – отдельно, байты четности – отдельно), декодеру Рида-Соломона нет никакой нужды как-то вмешиваться в этот процесс и его помощь требуется лишь тогда, когда часть информации оказывается безнадежно разрушена, что случается прямо-таки скажем не часто. Так что, право же, не стоит перекармливать фирмы, специализирующиеся на выпуске RAID, тем более что на домашний и мелкоофисный рынок они все равно не обращают внимания.
Заключение Вот мы и разобрались с нашим первым полноценным кодером/декодером Рида-Соломона, выполненным на базе арифметики Галуа. Мы также обсудили основные моменты организации дисковых массивов и даже соблазнились написанием соответствующего драйвера для реализации программного RAID. Все, что нам требуется – это научиться обрабатывать корректирующие коды большой разрядности, корректирующая способность которых не ограничивается одними лишь одиночными ошибками, а позволяет исправлять любое наперед выбранное количество искаженных байт. Вот об этом мы и поговорим в следующей статье этого цикла, где будет дан законченный алгоритм работы современных кодеров/декодеров Рида-Соломона и полезные советы по их самостоятельной реализации. 1
На самом деле, полями Галуа называют любые конечные поля, но в данном контексте мы будем говорить лишь о тех полях, количество членов которых равно 2n. 2 Другими словами говоря, щелкая выключателем, я знаю, что сейчас загорится свет. Но я не уверен в этом (монтер перерезал провода, лампочка перегорела и т. д.) Вот так и с математикой. Та жвачка, которой пичкают нас в школе и позже в институте, – это не математика. Это набор шаманских обрядов, который нас заставляют совершать, но который не позволяет проникнуть в самую суть – в дао математики. Может, оно и к лучшему, не знаю, но во всяком случае считаю долгом сказать, что «математика» преподаваемая в средних и высших учебных заведениях, имеет к математике не больше отношения, чем программирование к терзанию мыши в Word и установке системы Windows.
подписка
Началась подписка на I полугодие 2004 г. Более подробная информация на сайте www.samag.ru в разделе «Подписка»
Единый подписной индекс:
81655 по каталогу агентства «Роспечать»
Рады видеть Вас нашими читателями!
№10(11), октябрь 2003
91
IMHO
92
IMHO
ВООРУЖЕННОЕ ДО ЗУБОВ ПЕРЕМИРИЕ, ИЛИ Я – ТО, ЧЕГО НЕ МОЖЕТ БЫТЬ!
ТАТЬЯНА ИЛЬЧЕНКО №10(11), октябрь 2003
Разговоры о том, что информационные технологии и связанная с ними профессиональная деятельность – ни много, ни мало, а исключительно мужская епархия, понемногу стихают. И вот уже немногие представительницы прекрасного пола занимают свое место в среде программистов, веб-дизайнеров, администраторов баз данных и пр., ранее традиционно считавшихся этаким «мужским клубом». И если раньше многие работодатели уже по телефону категорично сообщали: «Девушку программистом на работу не возьму!» – не глянув в резюме, то теперь шансы попасть на собеседование и получить работу в большей степени стали зависеть от уровня компетентности и квалификации, чем от половой принадлежности. Но при этом прослеживается влияние этой самой принадлежности на размер оклада, и влияние, надо сказать, удручающее – в некоторых фирмах планка оклада запросто может опуститься на весьма значительную сумму, если должность в ITподразделении предлагается женщине. Например, один из услышанных мной мотивов занижения оклада: «Зачем ей такой оклад, вот выйдет замуж, и пусть у нее муж зарабатывает!» – безапелляционно заявил один из руководителей компании, крупнейшей в своем секторе рынка на юге России. Если посмотреть на количественное соотношение, то женщин в IT очень и очень мало (по некоторым оценкам, не больше 8% от общего количества специалистов, занятых в IT). На мой взгляд, это может быть связано с тем, что женщине, выбирающей профессию в сфере IT, предстоит преодолевать устоявшиеся стереотипы и ограничения, накладываемые обществом. Вот и получается, что мало кто из девушек, даже обладающих и склонностью, и способностями, может решиться стать системным, сетевым администратором (администратором БД) или программистом. Считается же, что компьютерным гением может быть только мужчина, и это при том, что первым программистом принято считать леди Аду Августу Лавлейс (Lady Ada Augusta Lovelace) – дочь известного английского поэта и ассистентку знаменитого математика и изобретателя Аналитической Машины Чарльза Бэббиджа (Charles Babbage). Вот и получается, что стереотипы, складывавшиеся десятилетиями, не получается просто отбросить – приходится с ними воевать и их преодолевать, если уж решила по зову сердца стать программистом или системным администратором. Тенденция же, несмотря на все это, как говорится, налицо, и программисты-женщины уже давно не редкость. Иначе дело обстоит в сфере системного администрирования: вот уж где мужчины считают себя непревзойденными и куда очень неохотно допускают противоположный пол. Это понастоящему закрытый клуб профессионалов. Мужской клуб. Точнее, был таковым до совсем недавнего времени – теперь и тут можно встретить, хоть и редко, девушку с LANтестером в руках, отверткой в кармане или за консолью «самого-главного-сервера-компании»1. При этом я хочу отметить, что в моем понимании системный администратор – это настоящий профессионал, который одновременно должен быть программистом (в той мере, которая позволяет писать утилиты, сценарии, автоматизирующие рутинные операции и т. п.), аналитиком, постановщиком задач и не только. В нашей стране системный администратор в зависимости от
93
IMHO масштабов компании, помимо исполнения своих прямых должностных обязанностей часто осуществляет также техническую поддержку пользователей, обслуживает оргтехнику и офисные АТС, монтирует кабельные системы и системы сигнализации, пишет технические задания на различные проекты автоматизации, обеспечивает информационную защиту предприятия и многое другое – «и швец, и жнец, и на дуде игрец». Последние семь лет моя работа непосредственно связана с информационными технологиями. От эникейства, написания программ на заказ, консультаций пользователей я «доросла» до должности системного администратора в составе регионального центра поддержки информационных систем и автоматизации крупной нефтяной компании. Сейчас у меня «под началом» больше десятка серверов-шлюзов, файл-серверов, серверов баз данных, почтовых и вебсерверов, функционирующих под управлением как ОС семейства MS Windows, так и различных клонов UNIX – BSDlike и Linux – в управлении одного из дочерних обществ компании и в восьми его филиалах, разбросанных по области, территория по площади которой равна двум Франциям. Кроме меня, в нашей группе работают: программист, связист, начальник группы и девять специалистов по ИТ-поддержке в филиалах. Обстановка у нас в коллективе достаточно комфортная и даже дружеская, несмотря на во многом пересекающиеся сферы ответственности. Первое время, правда, приходилось преодолевать отношение к себе как к диковинке, но в первую же неделю мне довелось разрешить некоторые проблемы в локальной сети и с доступом в Интернет по радиоканалу, сложившиеся якобы исторически, после чего коллеги безоговорочно признали меня «своим братом-сисадмином». Правда, дозваться теперь иногда кого-то из коллег, чтобы помогли что-то тяжелое перенести, бывает проблематично – легче самой все сделать. Поскольку по большей части работа системного администратора связана с постоянно изменяющейся предметной областью, приходится следить за новинками, успевать отслеживать и латать вновь появляющиеся уязвимости и ошибки, модернизировать парк техники, удерживать в зоне ответственности сервера филиалов и осуществлять методическое руководство в области сетевого администрирования для специалистов в филиалах. И мне эта работа нравится, ибо её характер заставляет постоянно держать себя в форме, успевать перерабатывать большие объемы информации в ограниченные отрезки времени. При этом учишься одновременно контролировать сразу нескольку дел: срочные (патчи, сервиспаки, срочная замена рабочих станций и пр.), текущие (регламентные работы – логи, состояние сети и пр.), поддержка пользователей (самое сложное, ибо «зная, что 2∗2=4, трудно понять, как кто-то может этого не понимать»). И при этом надо рабочий день построить так, чтобы осталось время на чтение новостей, поддержку собственного сайта, написание облегчающих жизнь программ/скриптов/утилит, систематизацию собственных архивов, заметок (miniHOWTO) и участие в различных конференциях-форумах. Но, как я уже сказала выше, мне это нравится, и я постараюсь убедить читателя в том, что женщина-сисадмин не морская свинка, которая не имеет отношения ни к морю, ни к повзрослевшим поросятам.
94
Вообще девушке, претендующей на должность системного администратора в сколько-нибудь серьезной организации (замечу, что я имею в виду наличие достаточной квалификации) туго приходится уже на первом собеседовании в кадровом агентстве – в головах рекрутеров, так же, как и большинства работодателей, прочно укрепился вышеупомянутый стереотип «компьютерщика» – в большинстве случаев это «слегка выбритый» длинноволосый тип с лихорадочным блеском в глазах, в вытянувшемся свитере и вытертых джинсах, изъясняющийся вроде и на русском, но совершенно непонятном языке. Он же обладает заведомым преимуществом, закрывающим передо мной перспективы трудоустройства на конкретную должность – он мужчина! Всё, пока есть претенденты равной или превосходящей квалификации мужского пола, женщинам доступ сюда закрыт. Хорошо, если пригласят на собеседование, и то больше из любопытства, чем планируя предложить вам вакантную должность. Даже если кандидат, претендующий на одну со мной позицию, обладает квалификацией, уступающей моим знаниям и умениям, у него все равно преимущество – ему простят куда более значительные огрехи и пробелы в знаниях, предложив восполнить их до второго тура собеседований, тогда как мне просто пообещают позвонить и забудут об этом. Или что, на мой взгляд, еще хуже – примут на работу в качестве экзотической игрушки на испытательный срок. Еще одно немаловажное обстоятельство, подчас мешающее в поисках работы, – это стереотип «Вот сейчас я ее возьму, а она раз – замуж и/или в декрет». И с этим стереотипом бороться сложнее всего. Я теперь пишу в резюме «замужем, детей нет», а в сопроводительном письме добавляю, что в ближайшее время (года три-четыре) мы и не планируем рождение ребенка. Иногда и это обстоятельство оказывается чуть ли не решающим. В общем, поиски работы для женщины в сфере информационных технологий напоминают хитроумную игру-квест: нужно найти и обрести артефакт, который позволит выполнить миссию. Это теперь по собственному опыту знаю, что такой артефакт – не что иное, как квалификация. И она должна быть не просто высокой, а предполагает чуть ли не исчерпывающие знания предметной области системного администрирования в пределах специализации – только тогда можно рассчитывать на равные условия при проведении конкурсного отбора на вакантные должности и на соответствующее отношение сотрудников компании, где доведется работать. После прохождения всех хитросплетений квеста «Найти для женщины работу в должности системного администратора» важно, получив все же вожделенную должность в компании, правильно выстроить отношения в коллективе. Многое зависит от того, являетесь ли вы сотрудником IT-подразделения, в большинстве состоящего из «лиц противоположного пола» (довольно часто встречается в силу уже описанных причин), или вы сами олицетворяете IT-подразделение в компании. Но при любой расстановке сил стоит руководствоваться правилом «золотой середины»: не нужно строить из себя этакого «своего парня», но и лишний раз подчеркивать какие-то присущие только женскому полу слабости тоже не стоит. Изначально нужно выстраивать отношения в коллективе, полагаясь, с одной стороны, на уже существующую схему таких отношений, но и при необходимости внося какие-то свои
IMHO правила игры. Мне в этом отношении, можно сказать, повезло: кроме того, что я не против в свободное время в компании единомышленников-коллег выпить немного хорошего чешского или немецкого пива, я могу на равных участвовать в дискуссиях о футбольных командах и матчах и даже частенько вместе с мужем выбираюсь на стадион посмотреть на домашние игры ростовского клуба. Это здорово помогает в неформальных контактах с коллегами-мужчинами. Однако это не панацея – тут тоже важно помнить о той самой «золотой середине». И потом на новой работе, возможно, придется столкнуться с непониманием и теми же стереотипами со стороны сотрудников других подразделений. Это может стать критичным, если в ваши обязанности входит и поддержка пользователей, что не редкость в наше время. Приветливое обращение и дружелюбие к пользователям могут стать неплохим фундаментом для определения вашего статуса как специалиста в компании. Впрочем, приведенные выше рекомендации не относятся только к женщинам-«сисадминам». Согласитесь, все описанное в двух предыдущих абзацах, чуть ли не прописные истины, но в то же время многие об этом забывают... И потенциальный работодатель найдет в ваших ошибках в тестовом задании поверхностность мышления, а в ответах на «пристрелочные» вопросы собеседования – дилетантство и непрофессионализм, если неправильно выбрать манеру поведения на переговорах. А новый коллектив может и не простить даже незначительных огрехов в выполнении вами повседневных обязанностей только потому, что вы изначально неправильно выстроили свои отношения этом коллективе. И останется только сетовать на то, что к нам, женщинам, в IT уж больно отношение пренебрежительное: дескать, не бывает женщин-программистов или системных администраторов, не бывает и точка! А ведь во многом
№10(11), октябрь 2003
мы виноваты сами. Раз уж приходится конкурировать с мужчинами в этой области профессиональной деятельности, так давайте и тут применять женскую мудрость и некоторые уловки, которые так помогают в обычной жизни. И в заключение хочется добавить несколько пожеланий всем сторонам этого «вооруженного до зубов перемирия» – так можно охарактеризовать сложившееся исторически положение в сфере информационных технологий. Женщинам – терпения и настойчивости в достижении желаемого на профессиональном поприще. Работодателям – внимания к резюме претенденток на объявленные вами вакансии в ITподразделении: нас еще не легион, но уже и не так мало, чтобы пренебрегать возможностью найти среди нас именно такого специалиста, который вам нужен. Сотрудникам-соратникам – коллегам по IT хорошо бы пожелать более терпимого отношения к коллегам-женщинам. Все мы учимся, а наши ошибки – почва для обретения опыта. И поверьте, женщины, ставшие системными администраторами по призванию, так же, как и вы, способны дневать и ночевать в серверной, когда этого требуют обстоятельства, протягивать и обжимать кабель, знают «как называется вон та штучка в PCI-слоте» и уверенно держат в руках не только отвертку и LAN-тестер, но и паяльник, если потребуется. И также способны одновременно контролировать несколько проблемных мест и попутно решать масштабные задачи. А «lamers» присутствуют в обоих конкурирующих лагерях. За сим позвольте откланяться, искренне ваша. 1
Конечно, я понимаю, что перечисленное не в полной мере отражает характер занятий системного администратора, но надеюсь на понимание читателей и на то, что смогла верно передать суть.
95
СИСТЕМНЫЙ АДМИНИСТРАТОР №10(11), Октябрь, 2003 год РЕДАКЦИЯ Исполнительный директор Владимир Положевец Ответственный секретарь Наталья Хвостова sekretar@samag.ru Технический редактор Владимир Лукин Научно-технические консультанты Павел Гашев Павел Закляков Руслан Иванов Андрей Бешков РЕКЛАМНАЯ СЛУЖБА тел.: (095) 928-8253 (доб. 112) факс: (095) 928-8253 Константин Меделян reсlama@samag.ru Верстка и оформление imposer@samag.ru maker_up@samag.ru Дизайн обложки Николай Петрочук 103012, г. Москва, Ветошный переулок, дом 13/15 тел.: (095) 928-8253 (доб. 112) факс: (095) 928-8253 Е-mail: info@samag.ru Internet: www.samag.ru РУКОВОДИТЕЛЬ ПРОЕКТА Петр Положевец УЧРЕДИТЕЛИ Владимир Положевец Александр Михалев ИЗДАТЕЛЬ ЗАО «Издательский дом «Учительская газета» Отпечатано типографией ООО «Мастер Печати» Тираж 5500 экз. Журнал зарегистрирован в Министерстве РФ по делам печати, телерадиовещания и средств массовых коммуникаций (свидетельство ПИ № 77-12542 от 24 апреля 2002г.) За содержание статьи ответственность несет автор. За содержание рекламного обьявления ответственность несет рекламодатель. Все права на опубликованные материалы защищены. Редакция оставляет за собой право изменять содержание следующих номеров.
96
ЧИТАЙТЕ В СЛЕДУЮЩЕМ НОМЕРЕ: Файловые системы Linux Что мне нравится в OС GNU/Linux – так это гибкость во всем: можно собрать систему под определенные задачи, выбрав необходимое из множества компонентов. Кроме патчей к ядру, различных версий библиотек и компиляторов есть возможность выбора и файловой системы, на которой будет работать Ось. В данной статье я предлагаю пробежаться по тому многообразию и определиться с выбором, узнать о достоинтсвах и недостатках предлагаемых файловых систем.
Интеграция SQUID + LDAP О настройках самого сервера LDAP написано достаточно много, поэтому останавливаться на этом не буду. Интеграция службы каталогов с разными службами освещена тоже достаточно подробно, например: http:// www.linuxrsp.ru/artic/LDAP-HOWTO.html Поскольку решения, как подружить proxy-сервер SQUID с вышеозначенной службой, я в этой статье не нашел, это и сподвигло меня на сей труд. Задача достаточно проста, заставить SQUID не только авторизовать пользователей, но и забыть, наконец, об acl-листах, в которых описаны группы.
Fusebox в помощь веб-программисту Осталось немного людей, использующих только средства HTML при создании веб-сайтов. Большинство веб-программистов используют PHP, MS ASP и т. п., но мало кто знает, как можно облегчить свой труд. Одним из решений этой проблемы является Fusebox. Fusebox – технология, позволяющая создавать веб-приложения. Изначально Fusebox – система, разработанная для Coldfusion-разработчиков. Fusebox является абсолютно бесплатным продуктом, что является плюсом в сторону его использования.
Аудит учетных записей пользователей в Active Directory В определенный момент времени наступает то критическое состояние для списка пользователей локальной сети предприятия, когда нежелание остановиться и провести анализ его содержимого может повлечь большие затраты и проблемы, нежели своевременное проведение работ по аудиту и устранению выявленных недостатков. О чем идет речь? В организациях, где число сотрудников, работающих с компьютерной техникой, превышает 100 человек, администрированием занимается, как правило, два-три сотрудника. Не все они, в силу различных обстоятельств, с достаточным педантизмом относятся к работе по внесению во вновь создаваемые учетные записи информации о владельцах. Кроме того, администраторы обычно не включены в список тех сотрудников, которым обязаны сообщать об увольнениях. Два этих обстоятельства являются основными причинами, из-за которых и происходит накопление учетных записей «мертвых душ».
Серверные адаптеры INTEL Данная статья написана в обзорном стиле, с учетом темпов современной жизни, когда многим профессионалам сложно выкроить время для глубоких системных подходов в изучении отдельных тем, порой граничащих с их основной деятельностью, но, тем не менее, достаточно важных. В таком случае обзор тенденций, систематизация информации и источников, готовые ответы являются хорошим средством экономии времени и сил. Подготовленный материал отвечает на наиболее часто задаваемые вопросы и снабжен различными ссылками, помогающими получить более детальную информацию по тем или иным аспектам, касающимся серверных сетевых адаптеров INTEL.