GetInfo.Ru – Компьютерная библиотека
Последние поступления
Как выбрать систему управления базы данных
Базы данных03/09/14
Этапы загрузки UNIX (в схеме)
Unix27/03/12
Gatewall Antispam: тотальный контроль электронной почты
Спам21/04/11
Мастер-класс: создаем Интернет-магазин (Часть 1)
Обзоры ПО20/04/11
CorelDRAW Graphics Suite X5: Что нового?
Обзоры ПО20/07/10
Добавить статью
Самые читаемые материалы
Что такое SSH?(20669)
Создание отдела информационной безопасности, или строим забор своими руками(11547)
Один в поле не воин: межсетевые экраны и антивирусы - братья на веки!(11452)
Оценка затрат компании на ИБ(10732)
Десять мифов о паролях в Windows(10102)
Всего статей: 793Всего авторов: 364Подразделов: 47Добавлено за сутки: 0
Статьи  СТАТЬИ Форум  ФОРУМ Рейтинг  РЕЙТИНГ Поиск  ПОИСК Контакты  КОНТАКТЫ
» Главная » Вопросы безопасности » Аспекты безопасности при написании CGI-скриптов

Аспекты безопасности при написании CGI-скриптов


{dr}{nerve}
admin@kodsweb.ru
http://kodsweb.ru/

Аторские права на сатью принадлежат KODSWEB SECURITY GROUP
irc: Efnet, #kodsweb
release_date: 17/03/2003

Содержание

  • Предисловие
  • Введение
  • Основа
  • 0х00 байт // %00 // '\0'
  • Пайпы (|)
  • Опция -e
  • Перенаправление данных (< и >)
  • Несколько примеров по использованию багов
  • Передача и хранение паролей
  • Пересылка паролей (GET vs POST)
  • Свободно распространяемые скрипты
  • Подведем итог
  • Заключение
  • Приветы
  • Copyrights (C)

Предисловие
Итак, вы создали свой сайт, посетители довольны, но однажды вам пришло в голову переделать сайт с использованием модного в настоящее время языка веб-программирования: Perl, и написать несколько собственных CGI-криптов. Предположим, что вы переехали на хостинг, поддерживающий использование Perl/CGI скриптов, купленный за десяток буказоидов в месяц, и перевели свой сайт на cgi скрипты. Но не прошло и нескольких дней, как ваш сайт был взломан злобным кибер-малолеткой с оставленной надписью, типа "Не можешь писать скрипты, не берись"! Так вот, чтобы такого с вами больше не произошло, читайте эту статью до конца и мотайте на ус.

Введение
Профессионально работая с сетью, нельзя не задумываться над вопросами информационной безопасности. Хорошо написанные .cgi и .pl скрипты должны не только выдавать красивые результаты, но и стабильно работать. Также они должны не создавать дыр в системе безопасности.

CGI-скрипты исполняются от имени непривилигированного пользователя nobody, однако есть вероятность нарушения требований безопасности.

Этим, кстати, и обосновывается нежелание некоторых администраторов давать всем пользователям возможность исполнения CGI. С другой стороны это всего лишь показывает некомпетенцию этих администраторов в вопросах обеспечения защиты информации.

Возможность исполнения команд на сервере предоставляется CGI-интерфейсом сервера. Задача CGI-программиста заключается в том, чтобы исполняемые команды не стали дырой.

Основа
CGI-скриптам можно передавать параметры. И безопасный скрипт отличается именно тем, что он выполняется стабильно при ЛЮБЫХ возможных значениях параметров, переданных ему.

0х00 байт // %00 // '\0'
Первый класс уязвимостей, который я хочу осветить, это использование нулевого байта в Перл. Все системные вызовы программированы на Си, где ноль представляет окончание строки.

Разберем уязвимость на конкретном примере:

	# Get Script DATA
	$base="$input.db";
	open(FILE,"<$base");

Если мы передадим скрипту input=num, то скрипт попытается открыть файл num.db Если мы передадим скрипту input=num%00, Перл создаст $base="num\0.db" и попытается открыть файл num. Если файл существует, то он и будет открыт.

Встает следующий вопрос: "Куда же подевалось расширение?" В Си нулевой байт - признак конца строки. Перл же допускает нулевые байты в строковых переменных, как данные. В результате Перл передает системным вызовам параметр num\0.db, однако все вызываемые библиотеки и функции перестают обрабатывать данные, как только доходят до нуля.

Возьмем другой пример:

	$file="/etc/passwd\0.txt.any.data";
	die("Fucking Hacker!") if($file eq "/etc/passwd");
	if(-e $file){
	open(FILE,">$file");}

Такая реализация эксплоита позволит открыть файл /etc/passwd на чтение

Как пропатчить баг:

  • Для этого нужно просто отфильтровать все нулевые символы:
    	$data=~s/\0//g;
  • Желательно также отфильтровать сразу и символы, перенаправляющие потоки данных:
    	&;`'\"|*?~<>^()[]{}$\n\r
  • Далее необходимо отфильтровать бэкслеш (\) и двойные бэкслеши
    	$data=~s/\.\.//g;

Такая реальзация патча не позволит осуществить просмотр директории по пути вида /../../../ После фильтрации строка /usr/tmp/../../etc/passwd превратится в /usr/tmp///etc/passwd (".." попросту будут вырезаны).

Однако здесь есть обходной маневр: достаточно передать параметр /usr/tmp/.\./.\./etc/passwd для того, чтобы обойти фильтр и передать строку скрипту далее.

Еще пример:

	$pageurl=$realpath.$DATA{'adPath'}.".html";

Если скрипт не проверяет передаваемые ему данные на '..' и нулевые байты, то используя 'adPath=/../../../../../etc/passwd%00' мы можем указать $pageurl на файл с паролями.

Пайпы (|)
Добавление пайпа к имени открываемого файла запустит его, а не откроет. Так:
open(FILE,"/bin/ls") - выдаст исполняемый код
open(FILE,"/bin/ls|") - исполнит команду ls и выведет листинг директории
Как пропатчить баг:

Необходимо отфильтровать s/(\|)/\\$1/g
Будет выведено сообщение "Unexpected end of file", так как sh ожидает, что слудующая строка будет начинаться с \.

Пример:

	$file="/secret_data/$FORM";
	open(FILE,$file);
Эксплоит в данном случае будет выглядеть следующим образом: необходимо передать $FORM -> "../../../../bin/ls|" - выдаст нам листинг директории.

Опция -e
Использование опции -e является препятствием для многих тех, кто ищет уязвимости в скрипте, потому как -e прекратит работу функции, как только удостоверится, что файл, который надо открыть, заканчивается пайпом (|).

Задача: сделать пайп невидимым для -e, в тоже время, Перл дожен знать о его существовании.

Рассмотрим на конкретном примере:

	$file=""/secret_data/$FORM;
	if(!(-e $file)) die("Fucking Hacker!");
	open(FILE,$file);

Вот она, злобная опция -e.

Неправильный эксплоит:

	$file="/bin/ls /etc\0|";
	if(!(-e $file)) exit;
	open(FILE, $file);
	close(FILE);

Данный эксплоит не позволит нам просмотреть содержимое папки /etc, так как -e видит, что /bin/ls /etc не существует.

Правильный эксплоит:

	$file="/bin/ls\0 /etc|";
	if(!(-e $file)) exit;
	open(FILE, $file);
	close(FILE);

Данный эксплоит выдаст листинг текущей папки, так как /etc не воспринимается как аргумент.

Для реальзации эксплоита мы использовали нулевой байт.
ls%00|
Опция -e окончит обработку данных на нулевом байте и команда исполнится.

Перенаправление данных (< и >)
Пример:

	$bug="ls|";
	open(FILE,"$bug");
	...
	close(FILE);

Выдаст листинг текущей директории.

	open(FILE,"<$bug");
	open(FILE,">$bug");
	open(FILE,">>$bug");

Тут команда уже не пройдет и все будет в порядке.

Итого:

Если вам надо просто читать из файла, то открывайте его как <$file, а не $file и все будет в порядке.

Пример:

	$output=$basedir.$contents{'file'};
	open(RESULTS,">>$output");

Здесь, используя стандартный выход за пределы папки, куда нас посадили (/../../), нам даже не придется использовать нефильтрацию 0х00. Однако, что бы мы не открыли, файл открывается для дописывания, поэтому мы должны иметь права на запись в тот файл, который пытаемся открыть. По этой же причине не сработает и pipe (|) bug.

Несколько примеров по использованию багов
Баг в гостевой книге:

Заранее хочу предупредить, что я не буду указывать название гостевой книги, дабы ставить ее автора в неловкое положение. Для вас на данный момент выжен сам процесс анализа скрипта на уязвимость.

	#!/usr/bin/perl
	$datafile="guestbook.txt";
	$sendmail="/usr/sbin/sendmail -i -t";
	########
	sub urlencode{
	    local($val)=@_;
	    $val=~s/\+/ /g;
	    $val=~s/%([0-9A=Ha-h]{2})/pack('C',hex($1))/ge;
	}
	########
	if($ENV{'REQUEST_METHOD'} eq 'POST'){
	    sysread(STDIN,$query,$ENV{'CONTENT_LENGTH'});
	}
	else{
	    $query=$ENV{'QUERY_STRING'};
	}
	print "Content-Type: text/html\n\n";
	if($query eq ''){
	    print "<HTML>\n";
	    print "<HEAD>";
	    print "<TITLE>Здесь было имя гостевой книги</TITLE>";
	    print "</HEAD>\n";
	    print "<BODY>\n";
	    print "<CENTER>";
	    print "<H1>Welcome</H1>";
	    print "</CENTER>\n";
	    print "<FORM>\n";
	    print "Name:<INPUT name=\"Name\">\n";
	    print "E-mail:<INPUT name=\"Email\">\n";
	    print "<INPUT type=\"submit\" name=\"subm\" value=\"Ok\">\n";
	    print "</FORM>\n";
	    print "</BODY></HTML>\n";
	}
	else{
	    foreach (split(/&/,$query)){
	        if(/^Name=(.*)/){$Name=&urlencode($1);}
	        if(/^Email=(.*)/){$Email=&urlencode($1);}
	    }
	    open(DATAFILE,">>$datafile");
	    print DATAFILE "-=-=-=-=-=-=-=-=-";
	    print DATAFILE "Date:".scalar(localtime())."\n";
	    print DATAFILE "Name: $Name\n";
	    print DATAFILE "E-mail: $Email\n";
	    print DATAFILE "-=-=-=-=-=-=-=-=-";
	    close (DATAFILE);
	    open(SENDMAIL,"|$sendmail $Email");
	    print SENDMAIL "From: admin\@site.ru\n";
	    print SENDMAIL "To: $Email\n";
	    print SENDMAIL "Subject: New Entry\n";
	    print SENDMAIL "\n";
	    print SENDMAIL "Dear $Name, thank you for your entries to our guestbook!\n";
	    print SENDMAIL "Thank you!\n";
	    close(SENDMAIL);
	    print "<HTML>\n";
	    print "<HEAD<";
	    print "<TITLE>Здесь было имя гостевой книги</TITLE>\n";
	    print "</HEAD>\n";
	    print "<BODY>\n";
	    print "<CENTER>";
	    print "<H1>Your Entry has been added to our guestbook</H1>";
	    print "</CENTER>\n";
	    print "</BODY></HTML>\n";
	}

Перед тобой скрипт наипростейшей гостевой книги. Автору добавленного сообщения высылается благодарственное письмо на E-mail, введенный им в форме. Отправка происходит автоматически.

Если посмотреть на этот скрипт с точки зрения его безопасности, то данный скрипт позволит ЛЮБОМУ выполнить ЛЮБУЮ команду на сервере.

Обратите внимание на строку

	open(SENDMAIL,"|$sendmail $Email");
Команды попадут в командную строку открытия канала (Pipe) Отсутствует какая-либо фильтрация вообще. Таким образом, не составит труда заставить сервер выполнить
	open(SENDMAIL,"|/usr/sbin/sendmail -i -t hax0r@tut.uze|cat /etc/passwd");
Это огромный удар по безопасности сервера, так как, манипулируя разными командами, можно изучать сервер изнутри, что в большинстве своем равно дальнейшему взлому.

Совет:

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

Пропатчить приведенный скрипт можно так:
	if($Email=~/[\|;]/ || $Email~!/\@/){
	    print "<FONT color=\"red\">";
	    print "You must enter valid e-mail address!</FONT>"
	    exit(0);
	}

То есть вы просто проверяете введенный адрес, и в случае, если он содержит запретные символы, выдаете ошибку. Данный подход повысит безопасность скрипта.

Передача и хранение паролей
Как известно, пароль значительно повышает уровень безопасности. Однако пароли необходимо передавать и хранить. Пароль - вещь секретная. Однако расположение пароля в скрипте открытым текстом уже само по себе ненадежно.

Какие есть варианты?

  • Хорошо, когда скрипт взаимодействует с базой данных и может вытаскивать пароль для проверки оттуда. В таком случае просто так пароль просмотреть не удасться. Если злоумышленник и проникнет на ваш диск, то максимум, что он сможет сделать - это достать пароль от базы данных и, приконнектившишь к ней (что далеко не всегда получается - многие серверы ставят на коннект большие ограничения) слить пароль.
  • Если же вы все таки решили положить пароль в сам скрипт, то следует помнить, что скрипт - читабельный файл со всеми вытекающими отсюда последствиями. Чтобы сделать хранение пароля в файле относительно безопасным, необходимо зашифровать его функцией crypt(); а затем применить следующим образом.
    	#!/usr/bin/perl
    	####
    	$CryptedPasswd="kbFIGN5En0NMv";          
    	####
    	...
    	$salt=substr($CryptedPasswd,0,2);
    	if(crypt($TestedPasswd,$salt) eq $CryptedPasswd){
    	    # Продолжаем действия
    	    ...
    	}
    	else{
    	    # Неверный пароль!
    	    ...
    	}
    

Комментарий:

В данном скрипте мы устанавливаем пароль-эталон в зашифрованном виде. Далее на странице администратора, предположим, вводим пароль, который затем шифруется в crypt(); и сравнивается с эталоном. Если пароль верный, то ты получаешь доступ к секретным материалам, если нет, то насладишься сообщением об ошибке. Такая система при правильном использовании повысит безопасность почти до уровня UNIX passwd без shadow, а это уже достаточно приемлимая функция безопасности.

Пересылка паролей (GET vs POST)
Выбор метода пересылки очень важен с точки зрения безопасности. Дело в том, что многие программисты передают в своих программах пароль методом GET, хотя пароли нужно передавать методом POST. Раздница между этими методами заключается в том, что при запросе методом GET передаваемые параметры являются частью URL, а при POST они передаются внутри тела запроса.

Нужно помнить, что протоколы сервера могут о многом рассказать. Вот к примеру, дамп http-протокола сервера:

...
...195.170.203.152 - - [20/Jun/2003:23:30:32 +0400] "GET /index.php HTTP/1.0" 200 ...
...195.170.203.152 - - [20/Jun/2003:23:35:16 +0400] "GET /cgi-bin/auth/auth.cgi HTTP/1.0" 200 ...
...
Дело в том, что сами протоколы общедоступны и не являются секретом. Таким образом, секретоная снформация, передаваемае по ним, тоже не будет секретной. Таким образом хакер, проникший через какую-нибудь дыру на ваш сервер, может получить еще одну зацепку при взломе. Дело в том, что, если вы используете для передачи пароля метод GET, то пароль попадет в протоколы, а оттуда его сможет достать любой хакер командой grep. При передаче пароля методом POST параметры не свляются частью URL и в протоколы не попадают.

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

Мой вам совет - не берите оттуда ничего, так как 90% скриптов потенциально уязвимы и могут быть использованы для осуществления атаки на ваш ресурс.

Если вы начинающий программист и составление сложного кода для вас еще недосигаемая мечта, возьмите чужой код, выкиньте из него все сложные элементы, параллельно проверяя работоспособность скрипта, чтобы не выкинуть нужную часть, которая не позволит программе работать корректно. Суть в том, чтобы разгрузить скрипт до того момента, когда все написанное в нем не станет вам понятным. Затем перечитайте мою статью еще раз и вставьте фильтрацию ввода на все потенциально опасные места.

Подведем итог
Основная задача CGI-скриптов - позволить посетителю получать доступ только к определенной части информации на вашем сервере, то есть разграничение прав доступа. Уже из определения вытекает мысль о действиях, направленных на получение скрытой информации из-за некорректного вмешательства в работу вашей системы. Если не принимать все последствия всерьез, то можно предоставить посетителям доступ к тем участкам сервера, которые предпочтительнее было бы скрыть от посторонних глаз. Подвергая все передаваемые скрипту данные тчательной фильтрации на метасимволы, на нулевой байт, на прямой, обратный и двойные бэкслеши, а также символы перехода по уровням "..", можно обеспечить достаточно высокий уровень безопасности сервера.

В различных форумах и поисковых системах часто встречается скрипт, котрый показывает какой-то файл, к примеру: www.victim.com/cgi-bin/show.cgi?base.html покажет base.html Однако если передать скрипту запрос вида:

http://www.victim.com/cgi-bin/show.cgi?../../../../etc/passwd
То данная команда выведет нам в качестве результата файл с паролями UNIX системы. ../../.. данная команда перехода по директориям позволит дойти до корня диска, далее осуществляется переход в директорию /etc и показывается файл паролей, расположенный тамже.

Вот несколько примеров скриптов, в которых встречается эта уязвимость:
http://www.victim.com/cgi-bin/htmlscript?../../../../etc/passwd
http://www.victim.com/cgi-bin/shopper.cgi?newpage=../../../etc/passwd
http://www.victim.com/cgi-bin/Web_Store/web_store.cgi?page=../../../etc/passwd%00ext
В последнем примере используется описанный выше 0x00 баг. К примеру, show.cgi?index.htm покажет вам документ, а show.cgi?index.htm%00 покажет вам исходный код документа.

Большой список скриптов с уязвимостями данного рода можно посмотреть здесь: http://kodsweb.ru/exploits.php

Заключение
Естественно, посвятить вас во все тонкости данной темы не представляется возможным, потому как тема эта очень обширная, имеющая много различных вариаций и подводных камней. Описание только того, что сразу приходит на ум потянет на небольшую книгу. Однако, прочитав эту статью и применив полученные знания на своем сайте, вы сможете заснуть спокойно, зная, что ваш сайт сделает все за вас, и несчастный техномладенец очередной раз не опрокинет ваш сервер.

Напоследок дам вам несколько ссылок, которые помогут вам в освоении материала:

  • http://kodsweb.ru/texts.php - здесь вы найдете много статей по защите информации
  • http://kodsweb.ru/files.php - здесь вы найдете все необходимые программы для поиска уязвимостей в cgi-скриптах и анализа серверов на дырки в безопасности.
  • http://kodsweb.ru/exploits.php - большая коллекция багов различных сервисов в том числе и CGI-багов.

И запомните еще одно - дыры в системе нужно нутром чувствовать. Чтобы стать хорошим экспертом по серевой безопасности, вам понадобится опыт, опыт и еще раз опыт. Научиться этому можно только самому. Самый главный совет, который можно здесь дать - почаше смотрите на вашу систему глазами хакера.

Приветы
FOA GreetZZ to iNo, Drakula, Aspirin, SkyLinx, Sandy 4ll aka KODSWEB
spc 2 VooDoo2029 0ur Army f0rce MembeR
Alz\Zo 2 all ths grps en pplz: Limpid Byte, NerF, Void, Федор mnz Insecure,
BugTraq, phrack, UKR
spc 2 gd frndz SecurityLab, ЗАРАЗА, RootTeam, DHG.

Special 4 former GiN members: mam0nt & z00m[Killer]
alzo 2 Ripper aka former Nitr0gear
Billi_k1d, btr aka NerF
Krok and [Duke] aka Void

0ff-grp pplz .ru, Infernal, exc[ee]d, St@ckeR, Neir0Magik

Copyrights (C)
Copyright c 2003 {dr}{nerve} // KODSWEB SECURITY GROUP // All Rights Reserved.

$mail = admin@kodsweb.ru $www = kodsweb.ru

$irc = Efnet, #kodsweb $release_date = 17/03/2003

 
30.05.2003
Версия для печати Версия для печати Запомнить ссылку Запомнить ссылку
Ваша оценка:  1   2   3   4   5     

 О проектеПерепечаткаАвторамПартнерыО нас пишут
Наверх
©2003—2007. GETINFO.RU. ВСЕ ПРАВА ЗАЩИЩЕНЫ.