Крис Касперский - ТЕХНИКА СЕТЕВЫХ АТАК
$file=$ARGV[0];
if ($file =~ /passwd/) {die "Goodby, Hacker!n";}
#…
open(BH,"«$file");
#…
open(AH,"«passwd");
#…
while («BH»)
{
print;
}
Поскольку сокеты с точки зрения подсистемы ввода-вывода - обычные файлы, корректно работающие с операторами ‘print’ и ‘«»’, возможна подмена файлового манипулятора открытым сокетом и, соответственно, наоборот.
Если скрипт устанавливает соединение с некоторым сервером (совершенно неважно, с каким именно, и по какому протоколу) и позволяет пользователю вместо имени файла задать манипулятор [301], у злоумышленника появляется возможность взаимодействия с этим сервером!
Пример, приведенный ниже (на диске, прилагаемом к книге, он находится в файле “/SRC/exchsc.pl”), демонстрирует ошибку, приводящую к перехвату трафика:
· socket(POP3, PF_INET(), SOCK_STREAM(), getprotobyname("tcp"));
· connect(POP3, sockaddr_in(110,inet_aton('zmail.ru')))
· $file=$ARGV[0];
· $x=«$file»;
· print $x;
· close(POP3);
· GET /cgi-bin/exchsc.pl?POP3
· +OK CommuniGate Pro POP3 Server 3.2.4 ready « [email protected]»
Приложения, имеющие такую уязвимость, способны выполнять запросы злоумышленника от имени сервера, на котором они расположены. Это может использоваться, например, для массовой почтовой рассылки.
Конечно, атакующий будет очень ограничен в своих возможностях. Стесненный уже существующим соединением с конкретным сервером по заданному протоколу он, скорее всего, не сможет причинить значительного ущерба. Наибольшая опасность заключается в том, что постороннее лицо способно получить доступ к секретным каналам связи, доступ к которым при нормальном ходе вещей был бы невозможен. Особенно это актуально для систем электронной коммерции, - если злоумышленнику удастся перехватить соединение с клиентом, он сможет «подсмотреть» номер кредитной карточки вместе с другими конфиденциальными данными, передаваемыми клиентом на сервер и даже исказить их!
Конечно, крупные on-line магазины, как правило, не содержат грубых ошибок. Но в сети огромное количество мелких поставщиков различного рода услуг, зачастую снабженных программным обеспечением, созданным «на коленках» Дядей Васей! Ошибки, описанные выше, очень характерны для кустарных разработок.
Врезка «информация»
Огромную опасность представляют недокументированные (или плохо документированные и малоизвестные) особенности интерпретаторов. И Perl в этом смысле не является исключением.
С его реализацией на платформе PC связан один громкий скандал. Фирма “Netscape” по некоторым причинам не поддержала в своем сервере ассоциации файловых расширений с исполняемыми приложениями. Вместо этого она предложила «волшебное» решение: вручную указывать требуемое приложение в самом URL. Так, например, вызвать “hello.pl” приходилось так: http://NetscapeServer/cgi-bin/perl.exe?hello.pl.
С первого взгляда ничем, кроме недовольного ворчания WEB-мастеров, это не чревато. Но уже беглое изучение документации по PC-версии Perl доказывает обратное. Особенность обработки командой строки приводит к тому, что на сервере может быть исполнена любая команда от имени интерпретатора. Достаточно воспользоваться конвейером, то есть конструкцией вида “| команда”.
Например, если набрать в командой строке “perl xxx|dir”, где ‘xxx’ имя любого, даже не обязательно существующего, скрипта, произойдет следующее: сперва, интерпретатором будет предпринята попытка запустить файл ‘xxx’, затем, независимо от успешности предыдущей операции, будет выполнена команда ‘dir’.
Врезка «замечание»
Выполнить любую команду Perl, например, ‘exec’ можно с помощью ключа командной строки, ‘-e’, о чем сообщается даже в короткой справке, выдаваемой при указании ключа ‘-h’ в командной строке.
Ниже приведен пример (на диске, прилагаемом к книге, он находится в файлах “/SRC/form.htm” и “/SRC/form.pl”) импровизированного виртуального магазина, занимающегося продажей товара через Internet c оплатой по кредитным карточкам. Перед первой покупкой посетителю (как это заведено в большинстве систем электронной торговли) необходимо зарегистрироваться - ввести свое имя и номер кредитной карты. Здесь не будет обсуждаться вопрос контроля достоверности представленной информации (это тема для отдельного разговора). Скрипт просто запоминает введенные сведения, и сверят всякий раз при загрузке.
· «HTML»
· «HEAD»
· «TITLE»VIRTUAL SHOP's "Hamburg"«/title»
· «META charset=windows-1251»
· «/HEAD»
·
· «BODY»
· «H1»«CENTER»VIRTUAL SHOP's "«U»Hamburg«/U»"«/CENTER»
· «HR»
· «/H1»
· «CENTER»
· «form method="POST" action="form.pl"»
· «br»Name:
· «BR»
· «input type="text" size="30" maxlength="300" name="name" value="Vasia"»
· «BR»
· «br»Credit card number:
· «BR»
· «input type="text" size="30" maxlength="30" name="card" value="OC271191"»
· «BR»
· «BR»
· «input type="submit" value="Welcome"»
· «/form»
· «/div»
· «HR»
· «/body»
·
· «/html»
·
· #!/usr/local/bin/perl
· print "Content-type: text/htmlnn";
· print "«HEAD» «title»VIRTUAL SHOPs 'Hamburg'«/title»«/head»n";
· print "«BODY» «H1»«CENTER»VIRTUAL SHOPs '«U»Hamburg«/U»'«/H1»«/CENTER»«HR»«BR»n";
·
· parseparameters();
· $Name=$parameters{'name'};
· $Card=$parameters{'card'};
· $Passwd="None";
· $file="users.dat";
·
· open(F,"«$file") || die "File $file not exist!n";
·
· while($f=«F»)
· {
· $tmp=«F»;
· if ("$Namen"=~$f)
· {
· if ($tmp!~$Card)
· {
· print "«CENTER»«H1»Wrong Card Number«/H1»«HR»";
· die;
·}
·
· $Passwd=$tmp;
·}
·}
·
· if ($Passwd=~/None/)
· {
· open(F,"»$file");
· print F "$Namen";
· print F "$Cardn";
· close(F);
· print "«B»New Buyer!«/B»«BR»n";
·}
·
· print «EOF;
· Buyer:$Name
· «BR»
· Card:$Card
· «TABLE width=100% border=1»
· «TR»
· «TH»Product ID
· «TH»Product Name
· «TH»Purchase
· «TR»
· «TD»Y2ZA
· «TD»Mice
· «TD»1 dollar
· «TR»
· «TD»ZG6T
· «TD»Mice Pad
· «TD»5 dollar
· «TR»
· «TD»3 FZ9Y
· «TD»CD-ROM RACK
· «TD»7 dollar
· «/table»
· «HR»
· «CENTER»
· «form method="POST" action="buy.pl"»
· Product ID:
· «input type="text" size="30" maxlength="30" name="$Name"; value="Y2ZA"»
· «input type="submit" value="Buy"»
· «/form»
· EOF
·
·
·
· sub parseparameters(;$) {
· local $_ = shift || $ENV{"REQUEST_METHOD"};
· my $buffer;
·
· $buffer = $ENV{"QUERY_STRING"} if (/^[Gg][Ee][Tt]$/);
· read(STDIN, $buffer, $ENV{"CONTENT_LENGTH"}) if (/^[Pp][Oo][Ss][Tt]$/);
·
· @_ = split(/ amp;/, $buffer);
· for (@_) {
· tr/+/ /;
· s/%(…)/pack("c",hex($1))/ge;
· (my $key, my $value) = split(/=/, $_);
· $parameters{lc($key)} = $value;
·}
·}
·
Если ввести имя пользователя и код кредитной карточки [302] (например, “Kris Kaspersky; oc674-ui56”) и нажать кнопку “Welcome”, то сервер поприветствует нового покупателя и предложит ввести код товара для покупки. На первый взгляд все работает нормально…
Рисунок 025 Импровизированный виртуальный магазин
Для того чтобы совершить покупку от чужого имени требуется знать номер кредитной карточки, который известен только ее обладателю. Но в данном случае сервер хранит информацию обо всех посетивших его пользователях, и существует возможность «подсунуть» чужое имя взамен своего. Для изучения содержимого странички, необходимо выбрать в меню браузера пункт «Просмотри в виде HTML»
Рисунок 026 Просмотр содержимого странички в виде HTML
Появится следующий код, содержащий, по крайней мере, одну грубейшую ошибку, которая позволяет осуществлять покупки от имени чужих лиц.
· «TH»Product ID
· «TH»Product Name
· «TH»Purchase
· «TR»
· «TD»Y2ZA
· «TD»Mice
· «TD»1 dollar
· «TR»
· «TD»ZG6T
· «TD»Mice Pad
· «TD»5 dollar
· «TR»
· «TD»3 FZ9Y
· «TD»CD-ROM RACK
· «TD»7 dollar
· «/table»
· «HR»
· «CENTER»
· «form method="POST" action=" buy.pl "»
· Product ID:
· «input type="text" size="30" maxlength="30"
· name="Fox"; value="Y2ZA"»
· «input type="submit" value="Buy"»
· «/form»
Алгоритм работы магазина в общих чертах следующий: при нажатии на кнопку «Buy» вызывается скрипт “buy.pl”, которому передаются два параметра - имя пользователя и код покупаемого товара. А номер кредитной карточки в передаваемых параметрах отсутствует. Очевидно, скрипт “buy.pl” самостоятельно извлекает его из базы, используя имя покупателя. Поскольку пользователь не может модифицировать файлы, хранящиеся на сервере, такая схема защиты на первый взгляд кажется вполне надежной. Но что мешает злоумышленнику сохранить страничку на свой локальный диск и, отредактировав по своему желанию, запустить ее оттуда?
Чтобы не нарушить работоспособности скрипта, необходимо все относительные ссылки заменить абсолютными, то есть с полным указанием протокола, имени узла и пути к файлу. Исправленный вариант может выглядеть так (на диске, прилагаемом к книге, он находится в файле “/SRC/form_hack.htm) [303]:
·…
· «form method="POST"
· action="http://kpnc.softclub.net/cgi-bin/buy.pl"»
· Product ID:
· «input type="text" size="30" maxlength="30"
· name="John"; value="Y2ZA"»
·…
Если в базе сервера существует пользователь “John”, с его счета будет снята очередная сумма, поскольку разработчик виртуального магазина не предусмотрел защиту от модифицирования полей формы.
Аналогичного результата можно добиться и более простым путем. Достаточно лишь вызвать скрипт “buy.pl” следующим образом: “GET /cgi-bin/buy.pl?Jhon=Y2ZA”, где “Y2ZA” - код товара.