Что такое SQL-инъекция?

SQL-инъекция — это один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет произвольный SQL-код в запрос к базе данных. Цель — получить доступ к конфиденциальной информации, изменить или удалить данные, а иногда и полностью захватить контроль над сервером. Согласно ежегодному отчёту OWASP Top 10, инъекции стабильно входят в список самых критичных угроз веб-безопасности.

Одной из разновидностей является error-based SQL-инъекция (инъекция на основе ошибок). В этом случае атакующий заставляет базу данных выдать сообщение об ошибке, которое содержит полезные для него данные. MySQL, будучи одной из самых популярных СУБД, часто становится целью таких атак благодаря своим специфичным функциям.

Разбор конструкции %')) AND EXTRACTVALUE(9397,CONCAT(0x7e,((SELECT (ELT(9397=9397,1)))),0x7e))-- -

Строка, вынесенная в заголовок, — это классический пример error-based SQL-инъекции для MySQL. Давайте разберём её по частям.

  • %')) — это попытка закрыть предыдущие кавычки и скобки в уязвимом запросе, чтобы внедрить свой код. Символ % часто используется в LIKE-запросах, а комбинация ')) закрывает строковый литерал и скобки.
  • AND EXTRACTVALUE(9397,CONCAT(0x7e,((SELECT (ELT(9397=9397,1)))),0x7e)) — основная часть инъекции. Функция EXTRACTVALUE() в MySQL предназначена для извлечения значения из XML-строки. Она принимает два аргумента: XML-документ и XPath-выражение. Если XPath-выражение содержит недопустимые символы, MySQL генерирует ошибку, в тексте которой отображается переданное значение.
  • -- - — комментарий, который отсекает оставшуюся часть оригинального запроса, чтобы не возникло синтаксической ошибки.

Как работает EXTRACTVALUE для извлечения данных?

Функция EXTRACTVALUE(XML_document, XPath_expression) возвращает текст из XML-документа, соответствующий XPath-выражению. Если XPath-выражение некорректно (например, содержит символ ~), MySQL выдаёт ошибку вида: XPATH syntax error: '~...~'. Злоумышленник помещает в XPath нужные данные, обёрнутые в тильды (0x7e в hex-коде). Эти данные попадают в текст ошибки и становятся видны атакующему.

В нашем примере используется CONCAT(0x7e, ((SELECT (ELT(9397=9397,1)))), 0x7e). Функция CONCAT склеивает символ ~, результат подзапроса и снова ~. Подзапрос SELECT (ELT(9397=9397,1)) возвращает 1, если условие 9397=9397 истинно (а оно всегда истинно). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь список состоит из одного элемента 1, поэтому возвращается 1. В реальной атаке вместо 1 подставляется SQL-запрос, извлекающий, например, имя пользователя или хеш пароля из таблицы users.

Пример реальной атаки

Представим, что на сайте есть форма поиска, и параметр search подставляется в запрос без должной обработки:

SELECT * FROM articles WHERE title LIKE '%$search%'

Злоумышленник передаёт в search строку %')) AND EXTRACTVALUE(9397,CONCAT(0x7e,((SELECT username FROM users LIMIT 1)),0x7e))-- -. В результате база данных выполнит:

SELECT * FROM articles WHERE title LIKE '%%')) AND EXTRACTVALUE(9397,CONCAT(0x7e,((SELECT username FROM users LIMIT 1)),0x7e))-- -%'

MySQL попытается вычислить EXTRACTVALUE, внутри которого будет подставлено имя первого пользователя из таблицы users. Так как XPath-выражение содержит недопустимый символ ~, возникнет ошибка, и в ответе сервера появится сообщение вроде:

XPATH syntax error: '~admin~'

Таким образом, атакующий узнаёт имя пользователя. Повторяя запросы с другими подзапросами, он может извлечь пароли, номера кредитных карт и любые другие данные.

Почему это опасно?

Error-based SQL-инъекции чрезвычайно опасны, потому что:

  • Позволяют получить доступ к произвольным данным в базе.
  • Часто не требуют специальных условий — достаточно, чтобы приложение выводило сообщения об ошибках БД.
  • Могут быть автоматизированы с помощью инструментов вроде sqlmap, что делает атаку быстрой и массовой.
  • В случае успеха злоумышленник может не только читать, но и изменять или удалять данные, а также выполнять команды на сервере.

Как защититься от SQL-инъекций?

Основной метод защиты — использование параметризованных запросов (prepared statements). В этом случае SQL-код и данные передаются отдельно, и внедрение произвольного кода становится невозможным. Например, в PHP с PDO:

$stmt = $pdo->prepare('SELECT * FROM articles WHERE title LIKE ?');
$stmt->execute(['%' . $search . '%']);

Дополнительные меры:

  1. Экранирование специальных символов с помощью функций вроде mysqli_real_escape_string.
  2. Отключение вывода ошибок БД в production-окружении. Ошибки должны логироваться, но не показываться пользователю.
  3. Использование ORM и фреймворков, которые по умолчанию применяют параметризацию.
  4. Регулярное обновление СУБД и веб-приложений для закрытия известных уязвимостей.
  5. Применение WAF (Web Application Firewall) для фильтрации подозрительных запросов.
  6. Проведение аудитов безопасности и сканирование уязвимостей.

Вывод

Конструкция %')) AND EXTRACTVALUE(9397,CONCAT(0x7e,((SELECT (ELT(9397=9397,1)))),0x7e))-- - — это типичный пример error-based SQL-инъекции для MySQL. Она демонстрирует, как злоумышленники используют функции EXTRACTVALUE, CONCAT и ELT для извлечения данных через сообщения об ошибках. Понимание механизма таких атак помогает разработчикам и администраторам своевременно закрывать уязвимости и защищать информацию.

Источники