Если атакующий не сможет провести дефейс то скорее всего он полезет к базе (если с самого начала этого не сделал). То есть его главной целью становиться config.php или conf_global.php . Читать данные из этих файлов взломщик может спокойно. Соответственно атакующий, имея данные для подключения к базе, может попытаться подключиться удалённо, либо выполнить php-код который подключиться к базе и возьмёт пароли всех пользователей. А что если данные для подключения к БД спрятать совершенно в другом месте? Давайте перепрячем их.
phpBB2
Наc интересует db.php (он лежит в папке includes). Найдите строку
$db = new sql_db($dbhost, $dbuser, $dbpasswd, $dbname, false);
(у меня это срока 60 – самый конец файла). Как Вы наверное уже догадались – это подключение к базе. Можно сейчас данные в config.php заменить на подставные, а сюда прописать реальные. Можете и сюда прописать подставные данные, а настоящие вписать в скрипт вашей СУБД. Для MySQL нужно зайти в папку db и в файлем mysql.php найти функцию sql_db(). У меня это строка 54.
$this->db_connect_id = @mysql_connect($this->server, $this->user, $this->password);
За место $this->server,$this->user,$this->password просто впишите свои данные для подключения к БД. Пример:
$this->db_connect_id = @mysql_connect(‘localhost’, ‘username’, ‘password’);
Invision Power Board.
В IPB Вам надо всего лиш подредактировать файл ips_krenel/class_db_mysql.php
В нём есть функция connet (строка 91) где нужно прописать данные для подключения к БД, пример:
$this->connection_id = mysql_connect( ‘localhost’ ,’username’ ,’password’);
Теперь в conf_global.php можете прописать что угодно, на работоспособность форума это не повлияет.
Защита от неизвестных SQL-injection.
Давайте посмотрим как работают эксплойты для получения хэша пароля через SQL-иньекцию. Самое первое что они делают – получают префикс. Без префикса никуда, ведь что бы взять что то из таблицы надо знать её полное название.
Invision Power Board.
Для эксперимента я взял IPB 2.1.4 и эксплоит для IPB 2.1.6 от RST/CGH. Я запустил эксплоит и достал member_login_key администраторского пользователя:
(слева результат эксплойта, справа – вырезка из phpMyAdmin)
Значения совпадают, эксплоит работает нормально.
Теперь, давайте разберёмся как эксплойты получают префикс таблиц. Они просто вызываются ошибочный запрос и появляется ошибка, из текста которой они отфильтровывают префикс:
Для вывода ошибки я открыл index.php и добавил кавычку в строки 182-185:
$ipsclass->DB->simple_construct( array( ‘select’ => ‘*’,’from’ => ‘topics’, ‘where’ => «tid’=».$ipsclass->input['t'], ) );
(кавычка после tid)
Вы можете сделать как вам заблагорассудится. А можете вообще ничего не делать так как ниже всё описано со скрин-шотами.
Как видно из ошибки – префикс ibf_ . В IPB За показ ошибки отвечает функция fatal_error() находящаяся в скрипте class_db.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 = «
Ошибка с базой данных.
Вы можете попробовать обновить эту страницу, нажав сюда.Возвращаемая ошибка
Приносим свои извинения за предоставленные неудобства.
«;
print $out;
exit();
}
Нас интересует переменная $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»);
Получается что текст ошибочного запроса находится с самого начала в $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»);
допишем
$the_error = » »;
Получится следующий код:
$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 просто заменить его на поддельный. Вот код который это сделает:
// Указываем наш префикс
$your_prefix = ‘ibf_’;
// Меняем наш префикс на fuck_
$the_error = str_replace($your_prefix,’fuck_’,$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»);
Теперь вызываем ошибку:
Наш префикс – fuck_! Что же нам скажет эксплоит?
Получение префикса:
Получение данных:
Как видите – всё получилось!
phpBB.
Теперь тоже самое проделаем с phpBB.
Для вызова ошибки я перешёл на строку 113 в файле index.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):
message_die(GENERAL_ERROR, ‘Could not query categories list’, », __LINE__, __FILE__, $sql);
Получается что нужно поправить функцию message_die(). Эта функция находится в файле functions.php(строки 536-724) (папка includes). Нас интересуют только строки 556-576:
if (DEBUG && ($msg_code == GENERAL_ERROR || $msg_code == CRITICAL_ERROR))
{
$sql_error = $db->sql_error();
$debug_text = »;
if ( $sql_error['message'] != » )
{
$debug_text .=’
SQL Error : ‘.$sql_error['code'] .’ ‘ .$sql_error['message'];
}
if ( $sql_store != » )
{
$debug_text .= «
$sql_store»;
}
if ( $err_line != » && $err_file != » )
{
$debug_text .= ‘
Line : ‘ . $err_line . ‘
File : ‘ . $err_file;
}
}
Текст запроса храниться в переменной $sql_store (строка 569):
$debug_text .= «
$sql_store»;
Что бы пропал текст запроса нужно просто стереть из текста переменную $sql_store:
$debug_text .= «
«;
Для того что бы подменить префикс можно опять же использовать str_replace():
$debug_text .= «
«.str_replace(‘phpbb_’,’fuck_’,$sql_store);
Здесь phpbb_ — настоящий префикс, а fuck_ — поддельный.
Всё прошло успешно.
Вот такими не сложными методами Вы можете защитить свой сайт от множества атак. Единственные атаки которые смогут пройти нормально – DoS через SQL-иньекцию. Но мне кажется что лучше уж DoS с последующим исправлением дыры, чем дефейс или кража паролей. Помните что такими методами Вы сможете защитить практически любой проект, просто изменяя тексты ошибок или правильно расставляя права. А те люди, которым хостинг предоставляется с отдельным файлом php.ini вообще могут занести system() и подобные ей функции в категорию запрещённых. И никаким эксплойтом через форум командную строку не получишь. Так же не оставляйте префиксы таблиц по умолчанию, меняйте на что ни будь типа ‘er24g34′ что бы даже в ручную подобрать было практически невозможно. Удачи.