Что такое OR EXTRACTVALUE(3368,CONCAT(0x7e,((SELECT (ELT(3368=3368,1)))),0x7e))-- -

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

Внешне запрос выглядит как попытка добавить условие OR к существующему SQL-запросу. Однако вместо обычного логического выражения здесь вызывается функция EXTRACTVALUE() с аргументами, которые заставляют MySQL сгенерировать ошибку, содержащую результат подзапроса. Это позволяет атакующему получить информацию о структуре базы данных, именах таблиц, колонок и даже конкретных значениях.

Разбор компонентов инъекции

Рассмотрим каждый элемент подробнее.

EXTRACTVALUE(3368, CONCAT(...))

Функция EXTRACTVALUE() в MySQL предназначена для извлечения значения из XML-строки. Она принимает два аргумента: XML-документ и XPath-выражение. Если XPath-выражение некорректно, MySQL возвращает ошибку, в тексте которой может содержаться переданный XPath. Именно это свойство эксплуатируется в error-based инъекциях.

Первый аргумент — число 3368 — не является валидным XML, но это не важно, так как ошибка возникает на этапе разбора XPath. Второй аргумент — CONCAT(0x7e, ((SELECT (ELT(3368=3368,1)))), 0x7e) — конструирует строку, которая затем подставляется в XPath.

CONCAT(0x7e, ..., 0x7e)

Функция CONCAT объединяет строки. Здесь 0x7e — это шестнадцатеричное представление символа ~ (тильда). Тильда используется как разделитель, чтобы облегчить извлечение данных из сообщения об ошибке. Внутри CONCAT находится подзапрос (SELECT (ELT(3368=3368,1))).

ELT(3368=3368, 1)

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

SELECT (ELT(...))

Подзапрос SELECT (ELT(3368=3368,1)) возвращает значение 1. Это значение затем преобразуется в строку и попадает в CONCAT. В результате формируется строка вида ~1~, которая передаётся в EXTRACTVALUE как XPath. Поскольку ~1~ не является корректным XPath, MySQL генерирует ошибку, текст которой содержит эту строку.

-- -

Символы -- начинают комментарий в SQL. Пробел после них и дефис (-- -) используются для того, чтобы гарантировать, что комментарий будет корректно распознан даже в некоторых реализациях, где требуется пробел после двух дефисов. Всё, что идёт после -- -, игнорируется парсером, что позволяет отсечь остальную часть оригинального запроса.

Как это работает в контексте атаки

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

SELECT * FROM articles WHERE id = '$id'

Если параметр $id не экранируется, атакующий может передать:

1 OR EXTRACTVALUE(3368,CONCAT(0x7e,((SELECT (ELT(3368=3368,1)))),0x7e))-- -

Тогда итоговый запрос станет:

SELECT * FROM articles WHERE id = '1 OR EXTRACTVALUE(3368,CONCAT(0x7e,((SELECT (ELT(3368=3368,1)))),0x7e))-- -'

MySQL выполнит условие OR с вызовом EXTRACTVALUE. Так как XPath некорректен, будет сгенерирована ошибка, и приложение, если оно выводит ошибки СУБД на экран, покажет сообщение, содержащее строку ~1~. Это подтверждает, что инъекция возможна.

Для извлечения реальных данных вместо 1 в ELT подставляется подзапрос, например:

SELECT (ELT(3368=3368, (SELECT table_name FROM information_schema.tables LIMIT 1)))

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

Меры защиты

Чтобы предотвратить подобные атаки, необходимо:

  • Использовать подготовленные выражения (prepared statements) с параметризацией запросов.
  • Экранировать все пользовательские данные, попадающие в SQL-запросы.
  • Отключить вывод ошибок СУБД в продакшене.
  • Применять принцип наименьших привилегий для учётной записи базы данных.
  • Регулярно проводить аудит безопасности и сканирование уязвимостей.

Заключение

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

Источники