Дыры в скриптах на PERL

Автор: Topol Воскресенье, Апрель 15th, 2012 Нет комментариев

Рубрика: Программирование

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

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

Предлагаю рассмотреть тект скрипта, который находится ниже:

#!/usr/bin/perl
$file = $ENV{‘QUERY_STRING’};
open(FILE, «$file»);
my @indata = <FILE>;
close(FILE);
print «Content-type: text/html\n\n»;
foreach (@indata) { print $_; }

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

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

К примеру. Пусть на сервере лежит документ secret.txt. На него естественно нет ни одной ссылки со страниц сервера. Вызов Ваших страниц организован следующим образом:
www.mysite.ru/script.pl?page1.htm
Так как ссылки на secret.txt с ваших страниц нет, то порядочный пользователь его и не увидит. Но стоит «плохому юзеру» набрать вручную
www.mysite.ru/script.pl?secret.txt
Как он на экране увидит его содержимое…

Первое, что приходит в голову, это изменить строку

open(FILE, «$file»);
на
open(FILE, «$file.htm»);

Что казалось бы позволяет открывать только файлы с расширением «.htm«. Точнее это расширение добавляется к каждой ссылке, и в строке запроса расширение необходимо опустить. Выглядеть при этом они будут так:
www.mysite.ru/script.pl?page1

Параметр secret при этом превратится в secret.htm, а secret.txt в secret.txt.htm. И ни один из них не соответствует файлу secret.txt.

Но если «плохой юзер» наберет
www.mysite.ru/script.pl?secret.txt%00
То он опять увидит на экране содержимое файла secret.txt

Почему это происходит? Perl позволяет нулевые символы в качестве данных содержащихся в переменной. В отличии от C NUL не является конечным символом строки. Но лежащие ниже вызовы системы/ядра написаны на «С», который распознает NUL как разделитель строки. Что получается в результате? Скрипт получает secret.txt%00. Преобразует его в secret.txt%00.htm. Далее Perl передает secret.txt.htm, но лежащие ниже библиотеки останавливаются когда встречают первый NUL. То есть имя файла превратится в secret.txt

Решение. Нужно удалить нули в строке запроса. К примеру так:

#!/usr/bin/perl
$file = $ENV{‘QUERY_STRING’};
$file =~ s///g;
open(FILE, «$file.htm»);
my @indata = <FILE>;
close(FILE);
print «Content-type: text/html\n\n»;
foreach (@indata) { print $_; }

Теперь если «плохой юзер» наберет
www.mysite.ru/script.pl?secret.txt%00
То скрипт получив secret.txt%00. Преобразует его сначала в secret.txt, обрезав нуль. Далее добавляет расширение, и имя файла превратиться в secret.txt.htm, которое к нашей радости не соответствует secret.txt!

Ошибка вторая. Скрипт позволяет обращаться к файлам более высокого уровня. Не секрет, что абсолютное большинство «плохих юзеров» интересует содержимое /etc/passwd. Название говорит само за себя (для пользователей UNIX). А что бы туда попасть обычно вполне достаточно, применительно к нашему скрипту, набрать нижеследующее:
www.mysite.ru/script.pl?../../../../../etc/passwd

Дело в том, что каждая последовательность «../» выводит нас на один уровень выше. И после нескольких таких обращений мы попадаем в корень диска. А от туда прямая дорога в /etc/passwd.

Решение. Запретить обратный ход в директориях можно следующим образом:

#!/usr/bin/perl
$file = $ENV{‘QUERY_STRING’};
$file =~ s///g;
$file =~ s/\.\.\///g;
open(FILE, «$file.htm»);
my @indata = <FILE>;
close(FILE);
print «Content-type: text/html\n\n»;
foreach (@indata) { print $_; }

В этом случае запрос
www.mysite.ru/script.pl?../../../../../etc/passwd
превратится в
www.mysite.ru/script.pl?etc/passwd

Что, согласитесь, не одно и тоже. И «плохой юзер» ничего не увидит.

Ошибка третья. Если файл открывается на чтение, то лучше делать это принудительно, а именно:

open(FILE, «<$file.htm»);

Если не указать знак меньше «<», то по умолчанию файл так же откроется на чтение. Но, как вы наверное догадываетесь, это самое «по умолчанию» иногда можно обойти. Вставив всего один символ «меньше» вы защитите и себя и свой сервер от кучи неприятностей.

Рекомендую всем использующим PERL-скрипты проверить их на наличие вышеописанных «дыр». Даже если у Вас нет никакой секретной информации. Как минимум есть что скрывать вашему хостинг-провайдеру. Конкретно, имена пользователей и пароли.

P.S. Статья не описывает все «дыры» PERL-скриптов. А указывает на самые распространенные ошибки и дает общие рекомендации по их устранению.

Источник: webcorp.ru

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты