Сегодня скрипты на PERL можно встретить не
только на крупном портале, но и на домашней страничке. Однако мощь языка
столь велика, что часто позволяет злоумышленникам взломать Ваш сервер с
помощью Ваших же скриптов. Происходит это конечно не по вине самого языка,
а по причине незнания web-мастером всех особенностей PERL, и некорректным
его использованием.
Предлагаю рассмотреть тект
скрипта, который находится ниже:
Работает скрипт следующим образом, берет
имя файла из строки запроса и выводит его на экран.
В
чем ошибка? Все прекрасно пока пользователь пользуется ссылками с Вашего
сайта. Однако он может "ручками" изменить строку запроса и тогда увидит на
экране любой интересующий его документ с Вашего сайта. Конечно он должен
знать имя этого документа, но скрипт предоставляет саму возможность
просмотра документа.
К примеру. Пусть на сервере лежит
документ secret.txt. На него естественно нет ни одной ссылки со страниц
сервера. Вызов Ваших страниц организован следующим образом:
http://mysite.ru/script.pl?page1.htm Так как ссылки на secret.txt с ваших страниц нет, то порядочный
пользователь его и не увидит. Но стоит "плохому юзеру" набрать вручную
http://mysite.ru/script.pl?secret.txt Как он на экране увидит его содержимое...
Первое, что приходит в голову, это изменить строку
open(FILE, "$file"); на open(FILE,
"$file.htm");
Что казалось бы позволяет открывать
только файлы с расширением ".htm". Точнее это расширение добавляется к
каждой ссылке, и в строке запроса расширение необходимо опустить.
Выглядеть при этом они будут так: http://mysite.ru/script.pl?page1
Параметр secret при этом превратится в secret.htm, а
secret.txt в secret.txt.htm. И ни один из них не соответствует файлу
secret.txt.
Почему это происходит? Perl позволяет нулевые символы
в качестве данных содержащихся в переменной. В отличии от C NUL не
является конечным символом строки. Но лежащие ниже вызовы системы/ядра
написаны на "С", который распознает NUL как разделитель строки. Что
получается в результате? Скрипт получает secret.txt%00. Преобразует его в
secret.txt%00.htm. Далее Perl передает secret.txt .htm, но лежащие ниже
библиотеки останавливаются когда встречают первый NUL. То есть имя файла
превратится в secret.txt...
Решение. Нужно удалить
нули в строке запроса. К примеру так:
Теперь если
"плохой юзер" наберет http://mysite.ru/script.pl?secret.txt%00 То скрипт получив secret.txt%00. Преобразует его сначала в
secret.txt, обрезав нуль. Далее добавляет расширение, и имя файла
превратиться в secret.txt.htm, которое к нашей радости не соответствует
secret.txt!
Ошибка вторая. Скрипт позволяет обращаться
к файлам более высокого уровня. Не секрет, что абсолютное большинство
"плохих юзеров" интересует содержимое /etc/passwd. Название говорит само
за себя (для пользователей UNIX). А что бы туда попасть обычно вполне
достаточно, применительно к нашему скрипту, набрать нижеследующее:
http://mysite.ru/script.pl?../../../../../etc/passwd
Дело в том, что каждая последовательность "../"
выводит нас на один уровень выше. И после нескольких таких обращений мы
попадаем в корень диска. А от туда прямая дорога в /etc/passwd.
Решение. Запретить обратный ход в директориях можно
следующим образом:
Что, согласитесь, не одно и тоже. И "плохой юзер"
ничего не увидит.
Ошибка третья. Если файл открывается
на чтение, то лучше делать это принудительно, а именно:
open(FILE, "<$file.htm");
Если
не указать знак меньше "<", то по умолчанию файл так же откроется на
чтение. Но, как вы наверное догадываетесь, это самое "по умолчанию" иногда
можно обойти. Вставив всего один символ "меньше" вы защитите и себя и свой
сервер от кучи неприятностей.
Рекомендую всем
использующим PERL-скрипты проверить их на наличие вышеописанных "дыр".
Даже если у Вас нет никакой секретной информации. Как минимум есть что
скрывать вашему хостинг-провайдеру. Конкретно, имена пользователей и
пароли.
P.S. Статья не описывает все "дыры"
PERL-скриптов. А указывает на самые распространенные ошибки и дает общие
рекомендации по их устранению.