Крис Касперский - ТЕХНИКА СЕТЕВЫХ АТАК
Для создания конвейера необходимо использовать символ “|”, разделяющий запускаемые программы следующим образом: “программа 1 параметры | программа 2 параметры | программа 3 параметры”. Разумеется, стандартный ввод первой программы в цепочке и стандартный вывод последней могут быть перенаправлены с помощью символов “«” и “»” соответственно (результат попытки перенаправления остальных непредсказуем, и обычно разрывает цепочку конвейера).
Интереснее проследить, как происходит взаимодействие процессов и передача данных по конвейеру. Конвейер - сути дела тот же файл, но скрытый от пользователя, построенный по принципу FIFO (от английского First Input First Output - первый пришел - первым и уйдешь). Так, запись в конвейер, из которого никто не читает, рано или поздно вызывает его переполнение (а размер буфера обычно порядка четырех килобайт) и приводит к блокировке процесса-писателя, до тех пор, пока хотя бы один байт из конвейера не будет прочитан. Точно так, попытка чтения из пустого конвейера приводит к остановке процесса-читателя до тех пор, пока в нем не окажется хотя бы один байт.
Схематическое изображения конвейераНо в любом случае, при обработке конвейера программы поочередно запускаются слева направо, и приведенный выше пример, переписанный с учетом конвейера, может выглядеть так:
· $ ls | sort -r
· sioux.pl
· passwd
· iohack.o
· iohack.c
· index_hack.htm
· demos.txt
· bomb.pl
· attack2.htm
Не правда ли намного проще и элегантнее? Между прочим, конвейеры поддерживаются не исключительно одной UNIX, - не хуже с ними справляется и старушка MS-DOS. Доказывает это эксперимент, приведенный ниже:
· dir /b | sort /r
· sioux.pl
· passwd
· iohack.o
· iohack.c
· index_hack.htm
· demos.txt
· bomb.pl
· attack2.htm
Кажется, в этом нет ничего удивительного, но зададим простой вопрос, - как однозадачная операционная система MS-DOS может одновременно запустить два процесса? Оказывается, в ней реализован несколько другой механизм поддержки конвейера, - сначала запускается первая слева программа, записывает все результаты своей работы в некоторый промежуточный буфер, затем запускается вторая программа и получает из буфера входные данные. Это уже не труба получается, а настоящий бассейн!
С первого взгляда в таком подходе ничего дурного нет, но некоторые примеры могут работать некорректно или и вовсе не работать. К таким относится, например, UNIX-утилита “yes”, посылающая на стандартный вывод бесконечный поток символов ‘y’. За кажущейся бесполезностью она часто требуется для пакетного выполнения программ, периодически отвлекающих пользователя запросами на подтверждение выполнения какой-нибудь операции.
В UNIX конвейер полностью заполняется символами ‘y’, и выполнение утилиты “yes” приостанавливается, до тех пор, пока другой процесс не возьмет из конвейера один или несколько символов. Но в MS-DOS два процесса не могут исполняться параллельно, и пока процесс “yes” не закончит выполнение, никакое другое приложение не сможет получить управление, а поскольку выполнение ”yes” не завершиться никогда (программа-то умышленно зациклена) система скинет ласты и впадет в дурной цикл.
Сравнение конвейеров в UNIX и MS-DOS. В MS-DOS конвейер больше похож на «бассейн», чем на «трубопровод»Поддержка конвейеров - штука замечательная, но только не с точки зрения безопасности. Следующий код доказывает это утверждение (на диске он находится под именем “/SRC/pipe.hack.pl”).
· open(FH,«»);· if (FH)· {· while(«FH»)· {· print;·}·}
На первый взгляд, программа предназначена для вывода содержимого файла на экран, но ниже показано, что произойдет, если воспользоваться символом конвейера:
· ls|
· sioux.pl
· passwd
· iohack.o
· iohack.c
· index_hack.htm
· demos.txt
· bomb.pl
Опаньки! Да ведь функция open языка Perl негласно поддерживает конвейер! Вместо открытия файла происходит его запуск! Вряд ли стоит объяснять, какие последствия вытекают из этого! Так, одна из версий SendMail позволяла в качестве обратного адреса отправителя письма подставить строчку “|/usr/bin/sh” и оболочка действительно запускалась, предоставив атакующему привилегированный доступ в систему (от имени демона).
Огромное количество защит оказалось взломано именно «благодаря» поддержке конвейера, позволяющего выполнять на удаленной машине любой код [95]. Аналогично перенаправлению ввода-вывода, конвейерные дырки могут быть обнаружены не только тщательным изучением исходных тестов приложений, но и простой подстановкой знака “|” во все доступные строки ввода и поля заголовков. Не так уж и редко это срабатывает.
Важно отметить, подобной «вкусности» подвержена не только операционная система UNIX, но и множество других, в частности Windows 9x/Windows NT. Убедиться в этом поможет приведенный выше код “pipe.hack.pl”. Достаточно запустить его на платформе Windows и ввести следующую команду:
· dir |· Том в устройстве F не имеет метки· Серийный номер тома: 2F42-0AE8· Содержимое папки F:TPNAsrc·. «ПАПКА» 28.06.00 23:14.·… «ПАПКА» 28.06.00 23:14…· IO C 294 06.07.00 10:29 io.c· IO OBJ 775 06.07.00 10:18 io.obj· IO EXE 32 768 06.07.00 10:18 io.exe· IOSTD C 228 06.07.00 10:30 iostd.c· IOSTD OBJ 627 06.07.00 10:26 iostd.obj· IOSTD EXE 32 768 06.07.00 10:26 iostd.exe· MYFILE 16 06.07.00 10:53 myfile· OUT TXT 89 06.07.00 10:53 out.txt· IOHACK C 295 06.07.00 15:18 iohack.c· IOHACK OBJ 827 06.07.00 14:58 iohack.obj· IOHACK EXE 32 768 06.07.00 14:58 iohack.exe· PIPEHA~1 PL 65 06.07.00 22:29 pipe.hack.pl· 12 файлов 101 520 байт· 2 папок 1 710 641 152 байт свободно
Методы противодействия и защиты от подобных ошибок будут описаны в главе «Атака на WEB-сервер», а ниже будет объяснено почему символ конвейера появляется то слева от команды (как в примере с “|/usr/bin/sh”), то справа (“dir |”). Вообще-то «классический» конвейер состоит минимум из двух программ, и вывод первой из них попадает на ввод второй. То есть конструкцию “program 1 | program 2” можно изобразить как “stdin ® program 1 ® program 2® stdout”. А в случае, когда используется всего лишь одна программа, вывод программы, стоящей до символа конвейера, перенаправляется в открываемый функцией “open” манипулятор, а вывод программы, стоящей за символом конвейера, никуда не перенаправляется и идет прямиком на терминал.
Сказанное позволяет продемонстрировать приведенный ниже код (на диске, прилагаемом к книге, он находится в файле “/SRC/pipe.test.pl”):
· open(FH,«»);· if (FH)· {· while( $x=«FH» )· {· print “Этот текст прочитан из файла:$x” ;·}·}
Строка «Этот текст прочитан из файла», предваряющая переменную $x, позволит отличить символы, получаемые чтением из файла, от текста непосредственно выводимого программой на экран.
· echo Hello, Sailor |
· Этот текст прочитан из файла:Hello, Sailor
· |echo Hello, Sailor!
· Hello, Sailor!
В первом случае, когда команда “echo” стоит до символа конвейера, результат ее работы направляется в открываемый функцией open манипулятор, откуда он может читается оператором “«»” и выводится на экран вызовом “printf”.
В другом случае, когда команда “echo” стоит после символа конвейера, результат ее работы направляется в стандартное устройство вывода, и минует оператор “print”.
И так-то славно дело пошло! Я сижу на мачте верхом, кручу бочку одной рукой, другой снимаю с конвейера готовую продукцию, передаю Фуксу, тот Лому, а Лом считает, записывает и выпускает на берег. Часа за три весь остров заселили.
Александр НекрасовУдаленное выполнение программ (глава для начинающих)O В этой главе:
O История возникновения telnet
O Устройство telnet-сервера
O Настойка telnet-клиента
O Вход в удаленную систему
Пару десятков лет назад о персональных компьютерах никто и мечтать не смел. В то время электронно-вычислительные машины занимали целые помещения (ну если не помещения, то шкафы - точно) и стоили жутко дорого. Как правило, один компьютер покупался целиком на всю фирму (или университет) и обслуживал десятки терминалов.
Протокол telnet был разработан в начале 80-х годов в качестве типового метода 8-битной двунаправленной связи между виртуальным терминальным устройством и компьютером. Виртуальным терминал назван для того, чтобы отличать его от обычного (неинтеллектуального, dumb). По мере снижения цен на персональные компьютеры найти неинтеллектуальные терминалы становится все труднее. Многие из них представляют собой просто экран и клавиатуру, соединенные с компьютером через последовательный интерфейс. Персональные компьютеры, оснащенные собственными процессорами, ОЗУ и дисковой памятью, гораздо универсальнее и быстро вытесняют неинтеллектуальные терминалы. Около десяти лет назад, когда я работал в фирме, производящей UNIX-компьютеры, только высшее руководство имело свои собственные ПК, у простых смертных были установлены терминалы, подключенные по каналам со скоростью передачи 9600 бит/с. А счастливые пользователи ПК связывались с центральными UNIX-компьютерами с помощью DOS-версии telnet.