Что такое SQL-инъекция через EXTRACTVALUE и CONCAT?

SQL-инъекция — один из самых распространённых способов взлома веб-приложений. Злоумышленник внедряет вредоносный SQL-код в запрос, который выполняется на сервере базы данных. Особый интерес представляет error-based SQL-инъекция, при которой хакер заставляет базу данных выдать сообщение об ошибке, содержащее конфиденциальные данные. Функции EXTRACTVALUE и CONCAT в MySQL часто используются для реализации таких атак.

В запросе пользователя, который мы разбираем, присутствует конструкция: "))) AND EXTRACTVALUE(3292,CONCAT(0x7e,((SELECT (ELT(3292=3292,1)))),0x7e))-- -. Это классический пример попытки эксплуатации уязвимости. Давайте разберём её по частям.

Как работает EXTRACTVALUE?

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

Например, если передать в XPath строку, начинающуюся с символа ~ (0x7e), MySQL выдаст ошибку вида: XPATH syntax error: '~результат~'. Злоумышленник может подставить в XPath результат подзапроса и увидеть его в сообщении об ошибке.

Роль CONCAT в эксплойте

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

Разбор конкретного запроса

Рассмотрим фрагмент: EXTRACTVALUE(3292,CONCAT(0x7e,((SELECT (ELT(3292=3292,1)))),0x7e)).

  • 3292 — произвольное число, передаваемое в качестве первого аргумента EXTRACTVALUE. Оно не несёт смысловой нагрузки, но должно быть допустимым XML-фрагментом (число трактуется как текст).
  • CONCAT(0x7e, ..., 0x7e) — формирует XPath-выражение, начиная и заканчивая его символом ~ (шестнадцатеричный код 0x7e).
  • SELECT (ELT(3292=3292,1)) — подзапрос, который возвращает результат выражения ELT(3292=3292,1). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь условие 3292=3292 всегда истинно (возвращает 1), поэтому ELT(1,1) вернёт строку '1'. Это простейший пример; на практике вместо этого подзапроса внедряют извлечение имён таблиц, колонок или хешей паролей.
  • -- - — комментарий, который отсекает остальную часть оригинального SQL-запроса, чтобы синтаксис оставался корректным.

Таким образом, при выполнении этого запроса MySQL попытается обработать XPath-выражение ~1~, что вызовет ошибку с текстом, содержащим ~1~. Злоумышленник, видя эту ошибку, понимает, что инъекция работает, и может заменить подзапрос на извлечение реальных данных.

Цели атакующего

Основная цель — получить доступ к данным, которые не должны отображаться в интерфейсе: логины, пароли, номера кредитных карт, персональные данные пользователей. Error-based инъекция позволяет извлекать информацию посимвольно или целыми строками, в зависимости от ограничений вывода. EXTRACTVALUE и аналогичные функции (UPDATEXML, GTID_SUBSET) — популярный инструмент, так как они часто не отключены в стандартных конфигурациях MySQL.

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

Предположим, есть форма поиска, где параметр id подставляется в запрос: SELECT * FROM products WHERE id = '$id'. Злоумышленник передаёт:

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

В ответе сервера появится ошибка: XPATH syntax error: '~5.7.33~'. Так узнаётся версия СУБД. Далее можно извлекать имена таблиц из information_schema.tables и содержимое других таблиц.

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

Надёжная защита строится на комплексном подходе:

  1. Использование подготовленных выражений (prepared statements). Это самый эффективный метод. Параметры передаются отдельно от SQL-кода, и внедрение становится невозможным.
  2. Экранирование специальных символов. Если prepared statements недоступны, необходимо экранировать все входные данные с помощью функций типа mysqli_real_escape_string.
  3. Валидация и фильтрация входных данных. Проверяйте, что параметры соответствуют ожидаемому формату (числа, даты, email).
  4. Ограничение прав пользователя БД. Приложение должно работать под учётной записью с минимально необходимыми привилегиями. Не используйте root.
  5. Отключение неиспользуемых функций. Если EXTRACTVALUE не нужна, её можно отключить или ограничить.
  6. Использование WAF (Web Application Firewall). Современные WAF умеют распознавать шаблоны error-based инъекций.
  7. Регулярное обновление СУБД и фреймворков. Уязвимости в старых версиях могут упростить эксплуатацию.

Заключение

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

Источники