В этом параграфе мы рассмотрим дыры в безопасности, относящиеся к CGI скриптам, написанным на Perl. Для простоты мы не будем давать полный код примеров, а только части, которые необходимы для понимания, где находится проблема.
Каждый из наших скриптов построен по следующему шаблону:
#!/usr/bin/perl -wT
BEGIN { $ENV{PATH} = '/usr/bin:/bin' }
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Сделаем %ENV безопаснее =:-)
print "Content-type: text/html\n\n";
print "<HTML>\n<HEAD>";
print "<TITLE>Удаленная команда</TITLE></HEAD>\n";
&ReadParse(\%input);
# теперь можно использовать $input, например, так:
# print "<p>$input{filename}</p>\n";
# #################################### #
# Начало описания проблемы #
# #################################### #
# ################################## #
# Конец описания проблемы #
# ################################## #
form:
print "<form action=\"$ENV{'SCRIPT_NAME'}\">\n";
print "<input type=text name=filename>\n </form>\n";
print "</BODY>\n";
print "</HTML>\n";
exit(0);
# Первый аргумент должен быть ссылкой на хэш.
# Хэш будет заполнен данными.
sub ReadParse($) {
my $in=shift;
my ($i, $key, $val);
my $in_first;
my @in_second;
# Считывание данных
if ($ENV{'REQUEST_METHOD'} eq "GET") {
$in_first = $ENV{'QUERY_STRING'};
} elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN,$in_first,$ENV{'CONTENT_LENGTH'});
}else{
die "ОШИБКА: неизвестный метод запроса\n";
}
@in_second = split(/&/,$in_first);
foreach $i (0 .. $#in_second) {
# Замена плюсов пробелами
$in_second[$i] =~ s/\+/ /g;
# Разбиение на ключ и значение
($key, $val) = split(/=/,$in_second[$i],2);
# Перевод %XX из шеснадцетиричных чисел в символы
$key =~ s/%(..)/pack("c",hex($1))/ge;
$val =~ s/%(..)/pack("c",hex($1))/ge;
# Сопоставление ключа и значения
# \0 - разделитель нескольких значений
$$in{$key} .= "\0" if (defined($$in{$key}));
$$in{$key} .= $val;
}
return length($#in_second);
}
Подробнее об аргументах, переданных Perl (-wT), поговорим попозже. Мы начинаем с очистки переменных окружения $ENV и $PATH и посылаем HTML заголовок (это часть html протокола между браузером и сервером. Вы не можете ее видеть на странице, отображенной в браузере). Функция ReadParse() читает аргументы, переданные скрипту. Это можно было бы проще сделать при помощи модуля, однако так вы не увидели бы весь код. Затем, мы вставляем код примера. И в конце завершаем HTML файл.