Несколько методов защиты ресурсов базирующихся на популярных движках. Автор: kuzya, 22/07/2007, www.inattack.ru [INTRO]Здравствуйте. Плавно с темы взлома я решил перейти на тему защиты. Наверняка у каждого второго читателя есть свой собственный сайт, и так же, у каждого второго, сайт не самописный, а базируется на каком ни будь популярном движке. C форумами же дела обстоят намного хуже. Я сильно сомневаюсь в том что хотя бы 5% читателей могут, просто могут, написать свой форум, для своего сайта. Конечно же намного проще скачать phpBB, IPB или любой другой форумный движок. Единственное неудобство – каждый день надо следить за багтраками что бы быть в курсе самых последних уязвимостей используемого Вами продукта, и во время ставить патчи, предотвратив тем самым взлом ресурса. Но тут может получиться небольшая развилка. Возьмём к примеру форум Invision Power Board (далее IPB). Этот продукт платный, а как известно – у нас в стране правит пиратство. Чем то это и может быть хорошо но сразу после сообщения об уязвимости врятли можно достать патч не являясь легальным покупателем IPB. 1. Когда уязвимость обнаружена Получается что у пользователя есть 2 выхода: а)самому пропатчить форум. б)Облазить интернет в поисках патча, либо совета по способу закрытия дыры. Лучше всего, конечно же, первый вариант, так как он надёжнее, но тоже не всегда. Хорошо бы если уязвимость SQL-иньекция и Вы точно знаете какие именно и куда должны поступать данные. Для устранения дыры Вам просто нужно прогнать опасную переменную через функцию intval() или addslashes(). А если уязвимость связана с выполнением произвольного php-кода? Например через функцию preg_replace(). Далеко не каждый может просто понять что нужно фильтровать, к тому же после ручного исправления форум может начать работать не так как раньше, выплёвывая море ошибок. Вообщем картина удручающая. Даже если взять phpBB который полностью бесплатен. Кто Вам гарантирует то что Вы узнаете об уязвимости первее чем человек который зол на Вас? Представим следующую ситуацию: Вы ложитесь вечером спать, в 3 утра находят уязвимость, в 4 атакующий полностью разобрался с эксплойтом и задефейсил Ваш сайт. В 10 Вы встаёте, в 10.30 узнаёте о уязвимости, бежите за патчем, а форум уже взломан. Согласитесь - такая ситуация может быть с каждым и никто от этого не застрахован. Ниже я попытаюсь обьяснить как же всётаки защитить свой ресурс от неизвестных атак, а объяснять я буду на примере форумов IPB и phpBB. В принципе описанные методы подходят не только к форумам, но и почти к любому веб-приложению, будь то лента новостей или CMS. Так же хочу обратить Ваше внимание на следующее: ниже описан пример безопасного расставления прав для файлов форума/сайта, но прежде чем поставить такие права у себя на ресурсе проверьте совпадают ли условия описанные мной с Вашими. 2. Правильная расстановка правЕсли Вы занимаетесь взломом то наверняка знаете что для дефейса сайта можно получить каким-либо образом выполнение команд(например вызвав функцию system() через уязвимость) и просто выполнить команду PHP: echo hacked>index.php Если же функция system() и ей подобные запрещены, то можно произвести запись в файл с помощью функций php. Получается что для защиты от этого нужно выставить права запрещающие запись в файл index.php, а вообще лучше сделать это со всеми файлами. Выставлять права нужно со следующим расчётом: 1.Запретить запись в любые файлы и директорию форума вообще всем. 2.Запретить чтение пользователям из Вашей группы (на хостингах чаще всего пользователей объединяют в одну группу). 3.Разрешить чтение всем другим пользователям. Звучит глупо но пользователя под которым работает веб-сервер чаще всего держат одного в отдельной группе. К тому же на хороших хостингах все пользователи делятся на 2 основные группы: администраторы и пользователи хостинга, а mysql, apache и другие программы стартуют от своего пользователя у которого своя группа. Так как PHP действует с правами веб-сервера (соответственно от имени его пользователя) то для стабильной работы сайта он должен прочитать все php-файлы чтобы сайт нормально работал. Следовательно запретив чтение файла другим пользователям Вы блокируйте работу сайта. Исходя из этого есть администраторы, пользователи хостинга, и программы, имеющие своих пользователей и группы, которых боятся не стоит. Получается что права для Вас, как для владельца файла должны быть 7 (исполнение, чтение, запись), для группы – 0 (запрещено всё), для остальных пользователей 4 (чтение) и выполнение (1). Исходя из этого, что бы установить такие права на папку форума нужно выйти в корень сайта и выполнить команду: PHP: chmod -R 705 phpbb Здесь phpbb – папка в которой находится форум, -R указывает что нужно данные права присвоить вообще всему что лежит в папке phpbb, 705 – все права владельцу, никаких прав пользователям из его группы и права на исполнение (скрипты же надо выполнять) и чтение остальным пользователям. Как видите – права на запись имеются только у Вас – владельцев файла. А так как php выполняет команды от имени веб-сервера (а он ни в коем случае не должен быть запущен от Вашего имени) то прав на запись у него нет, соответственно дефейс, с помощью уязвимости приводящей к выполнения php-кода, не возможен. Если же у Вас на хостинге пользователи распределены по другом то советую почитать подробнее об определении прав здесь: http://www.linuxcenter.ru/lib/books/kostromin/gl_04_05.phtml и здесь: http://www.linuxcenter.ru/lib/books/slackbook/use_2.phtml 3. Сокрытие реальных конфигурационных данных.Если атакующий не сможет провести дефейс то скорее всего он полезет к базе (если с самого начала этого не сделал). То есть его главной целью становиться config.php или conf_global.php . Читать данные из этих файлов взломщик может спокойно. Соответственно атакующий, имея данные для подключения к базе, может попытаться подключиться удалённо, либо выполнить php-код который подключиться к базе и возьмёт пароли всех пользователей. А что если данные для подключения к БД спрятать совершенно в другом месте? Давайте перепрячем их. phpBB2 Наc интересует db.php (он лежит в папке includes). Найдите строку PHP: $db = new sql_db($dbhost, $dbuser, $dbpasswd, $dbname, false); (у меня это срока 60 – самый конец файла). Как Вы наверное уже догадались – это подключение к базе. Можно сейчас данные в config.php заменить на подставные, а сюда прописать реальные. Можете и сюда прописать подставные данные, а настоящие вписать в скрипт вашей СУБД. Для MySQL нужно зайти в папку db и в файлем mysql.php найти функцию sql_db(). У меня это строка 54. PHP: $this->db_connect_id = @mysql_connect($this->server, $this->user, $this->password); За место $this->server,$this->user,$this->password просто впишите свои данные для подключения к БД. Пример: PHP: $this->db_connect_id = @mysql_connect('localhost', 'username', 'password'); Invision Power Board. В IPB Вам надо всего лиш подредактировать файл ips_krenel/class_db_mysql.php В нём есть функция connet (строка 91) где нужно прописать данные для подключения к БД, пример: PHP: $this->connection_id = mysql_connect( 'localhost' ,'username' ,'password'); Теперь в conf_global.php можете прописать что угодно, на работоспособность форума это не повлияет. 4. Защита от неизвестных SQL-injection.Давайте посмотрим как работают эксплойты для получения хэша пароля через SQL-иньекцию. Самое первое что они делают – получают префикс. Без префикса никуда, ведь что бы взять что то из таблицы надо знать её полное название. Invision Power Board. Для эксперимента я взял IPB 2.1.4 и эксплоит для IPB 2.1.6 от RST/CGH. Я запустил эксплоит и достал member_login_key администраторского пользователя: (слева результат эксплойта, справа – вырезка из phpMyAdmin) Значения совпадают, эксплоит работает нормально. Теперь, давайте разберёмся как эксплойты получают префикс таблиц. Они просто вызываются ошибочный запрос и появляется ошибка, из текста которой они отфильтровывают префикс: Для вывода ошибки я открыл index.php и добавил кавычку в строки 182-185: PHP: $ipsclass->DB->simple_construct( array( 'select' => '*','from' => 'topics', 'where' => "tid'=".$ipsclass->input['t'], ) ); (кавычка после tid) Вы можете сделать как вам заблагорассудится. А можете вообще ничего не делать так как ниже всё описано со скрин-шотами. Как видно из ошибки – префикс ibf_ . В IPB За показ ошибки отвечает функция fatal_error() находящаяся в скрипте class_db.php. Давайте рассмотрим её код: PHP: function fatal_error($the_error="") { // Are we simply returning the error? if ($this->return_die == 1) { $this->error = $this->_get_error_string(); $this->error_no = $this->_get_error_number(); $this->failed = 1; return; } $the_error .= "nnSQL error: ".$this->_get_error_string()."n"; $the_error .= "SQL error code: ".$this->error_no."n"; $the_error .= "Date: ".date("j.n.Y, G:i"); $out = "<html><head><title>IPS Driver Error</title> <style>P,BODY{ font-family:arial,sans-serif; font-size:11px; }</style></head><body> *<br><br><blockquote><b>Ошибка с базой данных.</b><br> Вы можете попробовать обновить эту страницу, нажав <a href="javascript:window.location=window.location;">сюда</a>. <br><br><b>Возвращаемая ошибка</b><br> <form name='mysql'><textarea rows="15" cols="60">".htmlspecialchars($the_error)."</textarea></form><br>Приносим свои извинения за предоставленные неудобства.</blockquote></body></html>"; print $out; exit(); } Нас интересует переменная $the_error и вот эти строки: PHP: $the_error .= "nnSQL error: ".$this->_get_error_string()."n"; $the_error .= "SQL error code: ".$this->error_no."n"; $the_error .= "Date: ".date("j.n.Y, G:i"); Получается что текст ошибочного запроса находится с самого начала в $the_error, и только потом к нему дописывается тип ошибки и её код. Давайте чуть-чуть изменим скрипт и перед строками: PHP: $the_error .= "nnSQL error: ".$this->_get_error_string()."n"; $the_error .= "SQL error code: ".$this->error_no."n"; $the_error .= "Date: ".date("j.n.Y, G:i"); допишем $the_error = '' ''; Получится следующий код: PHP: $the_error = '' ''; $the_error .= "nnSQL error: ".$this->_get_error_string()."n"; $the_error .= "SQL error code: ".$this->error_no."n"; $the_error .= "Date: ".date("j.n.Y, G:i"); Теперь давайте посмотрим на ошибку, которая выведется после наших изменений: Как видите – самого запроса, как и префикса, здесь нет. Теперь попробуем запустить эксплоит: Эксплоит не получил префикс таблиц, следовательно он не рабочий! Даже если форум не пропатчен то атакующий ничего не получит. Но можно пойти другим путём – в тексте ошибочного запроса заменить настоящий префикс на поддельный. У меня был префикс ibf_. Для того что бы осуществить нашу задумку нам нужно сделать следующее – определить какой у нас префикс и в переменной $the_error просто заменить его на поддельный. Вот код который это сделает: PHP: // Указываем наш префикс $your_prefix = 'ibf_'; // Меняем наш префикс на fuck_ $the_error = str_replace($your_prefix,'fuck_',$the_error); Эти строки нужно дописать до строк PHP: $the_error .= "nnSQL error: ".$this->_get_error_string()."n"; $the_error .= "SQL error code: ".$this->error_no."n"; $the_error .= "Date: ".date("j.n.Y, G:i"); Теперь вызываем ошибку: Наш префикс – fuck_! Что же нам скажет эксплоит? Получение префикса: Получение данных: Как видите – всё получилось! phpBB. Теперь тоже самое проделаем с phpBB. Для вызова ошибки я перешёл на строку 113 в файле index.php и изменил код на следующий: PHP: $sql = "SELECT c.cat_id, c.cat_title, c.cat_order FROM " . CATEGORIES_TABLE . " c ORDER BY c.cat'_order"; (кавычка после ORDER BY). Обратившись к index.php я увидел следующую ошибку: Префикс в ней есть. Теперь посмотрим какой код генерирует эту ошибку: далеко ходить не надо(строка 119): PHP: message_die(GENERAL_ERROR, 'Could not query categories list', '', __LINE__, __FILE__, $sql); Получается что нужно поправить функцию message_die(). Эта функция находится в файле functions.php(строки 536-724) (папка includes). Нас интересуют только строки 556-576: PHP: if (DEBUG && ($msg_code == GENERAL_ERROR || $msg_code == CRITICAL_ERROR)) { $sql_error = $db->sql_error(); $debug_text = ''; if ( $sql_error['message'] != '' ) { $debug_text .='<br /><br />SQL Error : '.$sql_error['code'] .' ' .$sql_error['message']; } if ( $sql_store != '' ) { $debug_text .= "<br /><br />$sql_store"; } if ( $err_line != '' && $err_file != '' ) { $debug_text .= '</br /><br />Line : ' . $err_line . '<br />File : ' . $err_file; } } Текст запроса храниться в переменной $sql_store (строка 569): PHP: $debug_text .= "<br /><br />$sql_store"; Что бы пропал текст запроса нужно просто стереть из текста переменную $sql_store: PHP: $debug_text .= "<br /><br />"; Для того что бы подменить префикс можно опять же использовать str_replace(): PHP: $debug_text .= "<br /><br />".str_replace('phpbb_','fuck_',$sql_store); Здесь phpbb_ - настоящий префикс, а fuck_ - поддельный. Всё прошло успешно. 5. Заключение.Вот такими не сложными методами Вы можете защитить свой сайт от множества атак. Единственные атаки которые смогут пройти нормально – DoS через SQL-иньекцию. Но мне кажется что лучше уж DoS с последующим исправлением дыры, чем дефейс или кража паролей. Помните что такими методами Вы сможете защитить практически любой проект, просто изменяя тексты ошибок или правильно расставляя права. А те люди, которым хостинг предоставляется с отдельным файлом php.ini вообще могут занести system() и подобные ей функции в категорию запрещённых. И никаким эксплойтом через форум командную строку не получишь. Так же не оставляйте префиксы таблиц по умолчанию, меняйте на что ни будь типа 'er24g34' что бы даже в ручную подобрать было практически невозможно. Удачи. 22/07/2007 ----------------------------------- Автор: kuzya, www.inattack.ru PS Я думаю статья будет интересна, как тем, кто ставит себе эти борды, так и тем, кто их пытается ломать
Просто писец... Короче метод защиты называется испорти своё двигло... Может тогда просто снять все права с каталога в котором находится пага? Многие движки используют кеширование, запись сессий в файлы, аплоад файлов (что предусматрвает наличие прав на запись)... Если начать налево и направо запрещать запись скрипту, то двигло просто рухнет! Это не выход! Это вредительство! Насчёт подмены данных доступа к базе в конфиге - это вообще умора... Такой движок потом не удастся проапдейтить стандартными скриптами, при установке каких-то модулей, если они требуют доступа к базе, в них тоже нужно вносить соответствующие изменения... Короче полезность статьи под вопросом... Ушатывание движка это не метод защиты от веб-атак... Отключите на системном уровне все сообщения об ошибках, отключите в форумах вывод ошибок! В чём сложность? Если у человека прямые руки и в голове что-то есть, то он найдёт способ закрытия дыры, а не будет херачить движок...