Введение

Встречая в логах или в поле ввода подобную строку: ) AND EXTRACTVALUE(7289,CONCAT(0x7e,((SELECT (ELT(7289=7289,1)))),0x7e))-- -, многие задаются вопросом: что это и какова её цель? Это классический пример SQL-инъекции, нацеленной на извлечение информации из базы данных MySQL с использованием функций EXTRACTVALUE и CONCAT. В данной статье мы подробно разберём, как работает эта конструкция, для чего она применяется и как от неё защититься.

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

SQL-инъекция (SQL injection) — один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет произвольный SQL-код в запрос к базе данных. Это становится возможным, если приложение не проверяет должным образом пользовательский ввод и передаёт его напрямую в SQL-запрос. Успешная инъекция может привести к утечке конфиденциальных данных, изменению или удалению информации, а в некоторых случаях — к полному захвату сервера.

Разбор конструкции

Рассматриваемая строка состоит из нескольких частей. Разберём каждую.

Начальный фрагмент: ) AND ...

Символ ) закрывает скобку, которая, вероятно, была открыта в оригинальном запросе. Это позволяет «вырваться» из контекста и добавить собственные условия. Далее идёт AND — логический оператор, позволяющий присоединить дополнительное выражение к условию WHERE.

Функция EXTRACTVALUE

EXTRACTVALUE(XML_fragment, XPath_expression) — это функция MySQL (до версии 8.0.17), предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Если XML-фрагмент некорректен или XPath не соответствует ни одному узлу, функция генерирует ошибку. Именно это свойство и используется в атаках: злоумышленник может вызвать ошибку, содержащую результат подзапроса, и таким образом «вытащить» данные через сообщение об ошибке.

Функция CONCAT и шестнадцатеричные литералы

CONCAT() объединяет строки. В нашем случае она собирает строку из трёх частей: 0x7e (тильда «~»), результат подзапроса и снова 0x7e. Тильда используется как маркер, чтобы отделить выводимые данные от прочего текста ошибки и упростить их извлечение.

Подзапрос с ELT

SELECT (ELT(7289=7289,1)) — это вложенный запрос, который возвращает число 1. Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь 7289=7289 — всегда истинное условие, что даёт 1, поэтому ELT(1,1) вернёт «1». В реальной атаке вместо этого подзапроса мог бы быть запрос к системным таблицам, например, для получения имени базы данных или хеша пароля.

Комментарий в конце

-- - — это комментарий в SQL (два дефиса, за которыми следует пробел или другой символ). Он «отрезает» оставшуюся часть оригинального запроса, чтобы синтаксис был корректным.

Как это работает целиком

Предположим, исходный запрос выглядел так:

SELECT * FROM users WHERE id = ('');

После подстановки вредоносной строки запрос превращается в:

SELECT * FROM users WHERE id = ('') AND EXTRACTVALUE(7289,CONCAT(0x7e,((SELECT (ELT(7289=7289,1)))),0x7e))-- -';

База данных выполняет условие AND. Функция EXTRACTVALUE пытается обработать строку, начинающуюся с тильды, как XML. Поскольку это не валидный XML, MySQL выдаёт ошибку, в тексте которой будет присутствовать переданная строка, включая результат подзапроса. Злоумышленник, анализируя ответ сервера, может увидеть эту ошибку и получить искомые данные.

Зачем это нужно злоумышленнику?

  • Обход фильтров: Если приложение блокирует кавычки или другие символы, EXTRACTVALUE позволяет обойти некоторые защиты.
  • Извлечение данных: С помощью подзапросов можно получать имена таблиц, столбцов, логины, пароли и другую чувствительную информацию.
  • Проверка уязвимости: Даже если атака не удаётся, сам факт появления ошибки говорит о возможной уязвимости.

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

Представим, что на сайте есть форма поиска, и параметр q подставляется в SQL-запрос без экранирования. Злоумышленник может отправить:

') AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database()),0x7e))-- -

В ответе сервера появится ошибка с именем текущей базы данных. Затем аналогично можно извлечь таблицы, столбцы и данные.

Как защититься?

  1. Используйте подготовленные выражения (prepared statements): Это самый надёжный способ. Параметры передаются отдельно от SQL-кода, и внедрение становится невозможным.
  2. Экранируйте специальные символы: Если prepared statements недоступны, применяйте функции экранирования (например, mysqli_real_escape_string).
  3. Ограничивайте права пользователя БД: Не давайте приложению прав на чтение системных таблиц, если это не нужно.
  4. Отключайте вывод ошибок: Не показывайте пользователям детали ошибок SQL — это может помочь атакующему.
  5. Используйте WAF: Веб-application firewall может блокировать подозрительные запросы.
  6. Регулярно обновляйте СУБД: В MySQL 8.0.17 функции EXTRACTVALUE и UPDATEXML удалены, что снижает риск подобных атак.

Заключение

Строка ) AND EXTRACTVALUE(7289,CONCAT(0x7e,((SELECT (ELT(7289=7289,1)))),0x7e))-- - — это не случайный набор символов, а тщательно сконструированный эксплойт для SQL-инъекции. Понимание принципов его работы помогает разработчикам и специалистам по безопасности лучше защищать свои приложения. Никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.

Источники