Что такое EXTRACTVALUE и зачем её используют хакеры?

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

Рассматриваемый запрос: %')) AND EXTRACTVALUE(2643,CONCAT(0x7e,((SELECT (ELT(2643=2643,1)))),0x7e))-- - — типичный пример такой инъекции. Давайте разберём его по частям.

Структура вредоносного запроса

Начнём с начала строки: %')). Символ % часто используется в LIKE-запросах как подстановочный знак. Далее идут две закрывающие скобки и апостроф. Это попытка закрыть ранее открытые конструкции в исходном SQL-запросе, чтобы внедрить свой код. Например, если уязвимый запрос выглядел как SELECT * FROM users WHERE name LIKE '%...%', то последовательность %')) может разорвать строковый литерал и добавить логическое условие.

Затем следует AND EXTRACTVALUE(2643,CONCAT(0x7e,((SELECT (ELT(2643=2643,1)))),0x7e)). Здесь:

  • 2643 — произвольное число, первый аргумент EXTRACTVALUE (XML-документ). Оно не имеет значения, так как всё равно вызовет ошибку.
  • CONCAT(0x7e, ..., 0x7e) — объединяет символ ~ (0x7e) с результатом подзапроса и ещё одним ~. Тильда используется как маркер, чтобы потом легко найти внедрённые данные в сообщении об ошибке.
  • (SELECT (ELT(2643=2643,1))) — это сердце инъекции. ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь условие 2643=2643 всегда истинно, поэтому ELT возвращает 1. В реальной атаке вместо этого подзапроса злоумышленник мог бы поместить, например, (SELECT password FROM users LIMIT 1), чтобы извлечь пароль. Но в данном примере используется тривиальное выражение для демонстрации.

Завершают запрос -- - — это комментарий, который отсекает оставшуюся часть оригинального SQL-запроса, чтобы не возникло синтаксической ошибки.

Как работает error-based инъекция через EXTRACTVALUE?

Функция EXTRACTVALUE принимает два аргумента: XML-документ и XPath-выражение. Если XPath-выражение содержит недопустимые символы, MySQL выдаёт ошибку вида: XPATH syntax error: '~1~'. В нашем случае CONCAT формирует строку ~1~, которая передаётся как XPath. Поскольку символ ~ не является допустимым в XPath, возникает ошибка, и в её тексте отображается ~1~. Если бы вместо 1 был, например, пароль пользователя, он бы также попал в сообщение об ошибке.

Таким образом, атакующий может последовательно извлекать данные по частям, подставляя в подзапрос разные столбцы и таблицы. Ограничение длины результата — 32 символа, поэтому для длинных строк используют SUBSTR или LIMIT.

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

Предположим, есть уязвимый параметр id в URL: https://example.com/product?id=1. Запрос на сервере: SELECT * FROM products WHERE id = 1. Злоумышленник может отправить: 1 AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e)). В ответе сервера (если ошибки выводятся) он увидит название текущей базы данных. Далее можно извлекать имена таблиц, столбцов и сами данные.

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

Чем опасна такая инъекция?

Последствия успешной SQL-инъекции могут быть катастрофическими:

  • Утечка конфиденциальных данных (пароли, персональная информация, платёжные реквизиты).
  • Обход аутентификации и авторизации.
  • Изменение или удаление данных в базе.
  • Полный контроль над сервером базы данных, а иногда и над всей системой.

В случае с EXTRACTVALUE атакующий получает возможность читать произвольные данные, что уже является критической уязвимостью.

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

Основной метод защиты — использование подготовленных выражений (prepared statements) с параметризацией запросов. Это предотвращает внедрение вредоносного кода, так как данные передаются отдельно от SQL-запроса. Дополнительные меры:

  • Экранирование специальных символов (но это менее надёжно, чем параметризация).
  • Валидация и фильтрация входных данных (например, проверка, что id — число).
  • Отключение вывода подробных ошибок СУБД в production-окружении.
  • Использование ORM, которые автоматически параметризуют запросы.
  • Регулярное обновление СУБД и фреймворков.
  • Применение WAF (Web Application Firewall) для блокировки подозрительных запросов.

Также рекомендуется проводить аудит кода и пентесты для выявления уязвимостей.

Заключение

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

Источники