· 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:\TPNA\src
·. «ПАПКА» 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