Что такое EXTRACTVALUE и при чём тут SQL-инъекция?

Строка ' AND EXTRACTVALUE(1876,CONCAT(0x7e,((SELECT (ELT(1876=1876,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции (инъекции на основе ошибок) для СУБД MySQL. Такие конструкции используют для извлечения данных из базы через сообщения об ошибках, которые возвращает сервер.

Функция EXTRACTVALUE в MySQL предназначена для работы с XML: она извлекает значение из XML-документа по заданному XPath-выражению. Синтаксис: EXTRACTVALUE(XML_document, XPath_expression). Если XPath-выражение некорректно, MySQL генерирует ошибку, в тексте которой отображается переданная строка. Именно это свойство и эксплуатируют злоумышленники.

Впервые массово применять EXTRACTVALUE для SQL-инъекций начали около 2010 года, когда выяснилось, что функция возвращает часть входных данных в сообщении об ошибке. Аналогичными возможностями обладают UPDATEXML() и GTID_SUBSET().

Разбор строки по частям

Рассмотрим запрос детально:

  • ' — закрывающая кавычка, которая завершает строковый литерал в уязвимом запросе и позволяет внедрить произвольный SQL-код.
  • AND — логический оператор, присоединяющий наше условие к исходному запросу.
  • EXTRACTVALUE(1876, ...) — вызов уязвимой функции. Первый аргумент (1876) — произвольное число, которое должно быть корректным XML-документом; на самом деле оно не используется, так как ошибка возникает раньше.
  • CONCAT(0x7e, ((SELECT (ELT(1876=1876,1)))), 0x7e) — конкатенация тильды (0x7e), результата подзапроса и ещё одной тильды. Тильда здесь — маркер, по которому в тексте ошибки легко найти полезную нагрузку.
  • ELT(1876=1876,1) — функция ELT возвращает N-й элемент из списка. Выражение 1876=1876 всегда истинно (1), поэтому ELT(1,1) вернёт 1. В реальной атаке вместо этого подзапроса подставляют, например, SELECT version() или SELECT table_name FROM information_schema.tables.
  • -- - — комментарий, который «съедает» остаток оригинального SQL-запроса, чтобы он не вызвал синтаксическую ошибку.

В результате MySQL пытается вычислить XPath-выражение, начинающееся с тильды, что недопустимо. Сервер возвращает ошибку вида:

ERROR 1105 (HY000): XPATH syntax error: '~1~'

В сообщении виден результат подзапроса — в данном примере «1». В реальной атаке здесь окажутся имя базы, версия СУБД, логины и хеши паролей.

Как это работает на практике

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

SELECT * FROM users WHERE id = '$_GET[id]';

Передав параметр id со значением ' AND EXTRACTVALUE(1876,CONCAT(0x7e,((SELECT (ELT(1876=1876,1)))),0x7e))-- -, злоумышленник заставляет СУБД выполнить:

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

Условие id = '' ложно, но из-за оператора AND вторая часть всё равно вычисляется. EXTRACTVALUE вызывает ошибку, и её текст возвращается пользователю. Если приложение выводит ошибки MySQL, атакующий получает данные. Если вывод ошибок отключён, инъекция не сработает — это одна из базовых мер защиты.

Зачем используют ELT и CONCAT

Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В примере ELT(1876=1876,1) выражение 1876=1876 всегда истинно и равно 1, поэтому возвращается «1». Это тестовый запрос, проверяющий, уязвимо ли приложение. Если в ответе появляется ошибка с «~1~», значит, инъекция возможна.

Функция CONCAT склеивает символы. Тильда (0x7e) выбрана потому, что редко встречается в обычных данных и легко находится в тексте ошибки. Иногда вместо неё используют 0x3a (двоеточие) или 0x7c (вертикальная черта).

Опасность и последствия

Error-based SQL-инъекции через EXTRACTVALUE позволяют злоумышленнику:

  • получить версию MySQL и имя текущей базы;
  • извлечь имена таблиц и колонок из information_schema;
  • прочитать логины, хеши паролей, персональные данные пользователей;
  • в некоторых конфигурациях — выполнить произвольные команды на сервере.

По данным OWASP, SQL-инъекции стабильно входят в топ-10 критических уязвимостей веб-приложений. Ошибки, возвращаемые СУБД, — один из самых простых векторов атаки, так как не требуют сложной подготовки.

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

Основные меры профилактики:

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

Важно понимать: EXTRACTVALUE — не «баг» MySQL, а штатная функция. Уязвимость создаёт код приложения, который вставляет пользовательский ввод в SQL-запрос без обработки. Поэтому исправлять нужно именно приложение, а не искать обходные пути в СУБД.

Итог

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

Источники