Привет! В первой части мы поговорим о взломе
сервера. Не о всех ошибках, а только о тех, где входной параметр это имя файла. Это значит, что когда ты в строке
браузера видишь что-то вроде:
www.target.ru/cgi-bin/auth.pl?file=data.db?user=xakep
то это именно тот случай. Приступим к вскрытию 🙂
Я надеюсь тебе известно, что PERL был всегда
не обделен вниманием со стороны хакеров. А все потому, что если автор скрипта не полностью
(или вообще) не отфильтровал входные параметры, то с сайтом можно было творить удивительные вещи
🙂 Давайте рассмотрим простой пример:
$location = '/users/data/file.dat';
open(FILE, "$location");
эта конструкция открывает файл. Допустим что $location (имя файла) не указано в
самом коде, а выдирается с входной строки. Тогда этот код примет такой вид:
$location = $ENV{'QUERY_STRING'};
open(FILE, "$location");
Пусть потом этот файл выводится нам в браузер следующим образом:
@data = <FILE>;
close(FILE);
print @data;
В следствии чего мы можем в входном параметре указать например /etc/passwd и
наивный скрипт выведет его на экран. Неплохо... но теперь это почти не катит.
Ладно, пусть кодер защитил себя установив четко базовую директорию:
$location = '/users/data/';
(undef, $location) .= split(/?/, $ENV{'QUERY_STRING'});
open(File, "$location");
Но теперь если мы введем ../../etc/passwd, то получим
тот же результат 🙂 Берем такой вариант, что скрипт обрезает
последовательность "../" следующим образом:
$location = '/users/data/';
(undef, $location) .= split(/?/, $ENV{'QUERY_STRING'});
$location = s/\.\.\///g;
open(File, "$location");
Думаете этот код защищен? Неееа! В никсах можно использовать место конструкции
"../../etc/passwd" следующую ".\./.\./etc/passwd", и снова на экране нужный
файл :). Потому что "../" фильтр не обнаружит а мы используем
".\./", что имеет идентичные функции.
Хорошо, посмотрим дальше:
$location = '/users/data/';
(undef, $location) .= split(/?/, $ENV{'QUERY_STRING'});
$location =s~\\~~g;
$location=s~\.\./~~g;
open(File, "$location");
или
$location = '/users/data/';
(undef, $location) .= split(/?/, $ENV{'QUERY_STRING'});
$location =s/\\//g;
$location=s/\.\.\///g;
open(File, "$location");
Этот фильтр обрезает "../" и "\" со строки. Неплохо правда? Давайте посмотрим
на примере... Если передать строку "fi../le" или "fi\le" то получится "file".
Хммм.... А если ввести ".../...//" то что получится? Первую точку он пропустит,
удалит "../", точку пропустит, "../" удалит, "/" пропустит. Так что мы имеем? А
имеем мы строку "../" - то, что нам и надо. Значит теперь мы пропишем в строке
браузера место реального имени файла что-то вроде
".../...//.../...//etc/passwd". Результат тот же, что и в первых случаях.
Каждый профессионал иногда допускается ошибки при фильтрации метасимволов
(&;`'\"|*?~<>^()[]{}$\n\r). Вот еще один пример:
$location =~ s/([\&;\`'\|\"*\?\~\^\(\)\[\]\{\}\$\n\r])/\\$1/g;
$location =~ s/\0//g;
unless (open(FILE, $location))
Если вы заметили, то они не фильтруют "\". Теперь если мы введем такое имя файла
"cat file.dat\|" то после фильтрации получим "cat file.dat\\|". Символ "\"
используется для того, чтобы не сработал мета символ "|". Эта ошибка очень
распространенная.... Если вы не поняли вот еще один пример. Пусть мы ввели
"/bin/echo "all ok" > file.dat|" - после фильтрации мы получим "/bin/echo "all
ok" > file.dat\|", и это не сработает. А если ввести "/bin/echo "all ok" >
file.dat\|", то получим строку "/bin/echo "all ok" > file.dat\\|". А этот код
уже сработает!
Ну как еще не умер со скуки? А если тебе надо хороший фильтр то можешь вставить
перед открытием файла такую строчку:
if($location =~ /[\&;\`'\|\"*\?\~\^\(\)\[\]\{\}\$]/) {&ErrorPageAndLog('Урод,
даже не старайся сломать мой сервак');}
Ну вот на этом первая часть окончена... И помните ЭТО только
начало 8)