Что такое ExtractValue в MySQL

Функция ExtractValue предназначена для извлечения данных из XML-документа по заданному XPath-выражению. Синтаксис: ExtractValue(XML_document, XPath_expression). Например, SELECT ExtractValue('<a><b>1</b></a>', '/a/b') вернёт 1. Однако, если XPath-выражение некорректно, MySQL генерирует ошибку с текстом, содержащим часть переданного выражения. Это свойство и стало основой для одного из самых распространённых методов SQL-инъекции — error-based SQL injection.

Как работает атака через ExtractValue

Злоумышленник внедряет в уязвимый параметр запроса конструкцию, подобную вашей: %" ) AND EXTRACTVALUE(8065,CONCAT(0x7e,((SELECT (ELT(8065=8065,1)))),0x7e))-- -. Разберём её по частям.

  • %" ) — закрывает предыдущую строку и скобку, чтобы внедрить свой код.
  • AND EXTRACTVALUE(8065, ...) — вызывает функцию с заведомо некорректным первым аргументом (число 8065 вместо XML).
  • CONCAT(0x7e, ((SELECT (ELT(8065=8065,1)))), 0x7e) — формирует строку, начиная и заканчивая символом ~ (0x7e). Внутри — подзапрос, возвращающий результат. ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь 8065=8065 — всегда истина (1), поэтому ELT вернёт 1. Но в реальной атаке вместо этого подзапроса может быть извлечение имени базы, таблицы, хеша пароля и т.д.
  • -- - — комментарий, обрезающий остаток оригинального запроса.

В результате MySQL выдаёт ошибку вида: XPATH syntax error: '~1~'. В этом сообщении содержится результат выполнения подзапроса, обрамлённый тильдами. Так злоумышленник может посимвольно извлекать любые данные из базы.

Примеры эксплуатации

Классический пример: AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e)) — вернёт версию MySQL в тексте ошибки. Аналогично можно получить имя текущего пользователя, название базы данных, список таблиц и даже хеши паролей.

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

Другие функции для error-based инъекций

Помимо ExtractValue, злоумышленники используют:

  • UpdateXML — аналогичная функция для обновления XML, также генерирует ошибку с фрагментом XPath.
  • Floor — в комбинации с group by и rand() вызывает ошибку дублирования ключа.
  • Exp — переполнение при больших числах.

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

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

Основные меры:

  1. Параметризованные запросы (prepared statements) — самый надёжный способ. Данные пользователя передаются отдельно от SQL-кода и не интерпретируются как часть запроса.
  2. Экранирование спецсимволов — используйте функции экранирования, предоставляемые драйвером БД (например, mysqli_real_escape_string в PHP). Но это менее надёжно, чем параметризация.
  3. Отключение вывода ошибок СУБД — не показывайте пользователю сообщения MySQL. Логируйте их, но не выводите в браузер.
  4. Ограничение прав пользователя БД — веб-приложение должно работать с минимально необходимыми привилегиями (обычно только SELECT, INSERT, UPDATE, DELETE для конкретных таблиц).
  5. WAF (Web Application Firewall) — может блокировать известные сигнатуры атак, но не является панацеей.
  6. Регулярное обновление СУБД — в новых версиях MySQL (8.0+) поведение функций может быть изменено для снижения рисков.

Заключение

Конструкция EXTRACTVALUE(8065,CONCAT(0x7e,((SELECT (ELT(8065=8065,1)))),0x7e)) — это типичный пример error-based SQL-инъекции, использующей особенность функции ExtractValue возвращать данные в тексте ошибки. Для защиты необходимо применять параметризованные запросы, скрывать ошибки СУБД и ограничивать права доступа к базе данных. Помните, что SQL-инъекции остаются в топ-10 угроз OWASP, поэтому игнорировать их нельзя.

Источники