Что это за строка?

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

Разбор по компонентам

Давайте разберём каждый элемент этой инъекции.

1. Начальные символы )))

Три закрывающие круглые скобки ))) нужны, чтобы корректно закрыть ранее открытые скобки в оригинальном SQL-запросе. Злоумышленник предполагает, что в уязвимом запросе уже есть открытые скобки (например, в условиях WHERE или HAVING), и добавляет недостающие закрывающие, чтобы синтаксис остался валидным. Без этого инъекция могла бы вызвать ошибку парсинга, а не выполнение полезной нагрузки.

2. AND

Оператор AND присоединяет наше условие к существующему WHERE или HAVING. Он пытается изменить логику запроса, но в error-based инъекциях его главная задача — просто «приклеить» вызов функции, которая вызовет ошибку с нужными данными.

3. EXTRACTVALUE(2064, ...)

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

Первое число 2064 — произвольный числовой аргумент, который в данном случае не играет роли. Он может быть любым, часто его берут случайным, чтобы избежать кэширования.

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

CONCAT объединяет строки. Здесь используется 0x7e — шестнадцатеричное представление символа ~ (тильда). Тильда служит маркером, который помогает легко найти извлечённые данные в теле ошибки. Конструкция CONCAT(0x7e, ..., 0x7e) оборачивает полезную нагрузку в тильды, чтобы отделить её от остального текста ошибки.

5. (SELECT (ELT(2064=2064,1)))

Внутри CONCAT находится подзапрос SELECT (ELT(2064=2064,1)). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае 2064=2064 — это логическое выражение, которое всегда истинно (равно 1). Таким образом, ELT(1, 1) вернёт строку '1'. Если бы условие было ложным, ELT(0, ...) вернул бы NULL. Это простейшая проверка на возможность выполнения подзапросов. В реальной атаке вместо 1 подставляют, например, SELECT table_name FROM information_schema.tables LIMIT 1, чтобы извлечь имя таблицы.

6. Комментарий -- -

Двойной дефис с пробелом (или -- -) — это комментарий в SQL. Всё, что идёт после него, игнорируется сервером. Это позволяет отсечь остаток оригинального запроса, чтобы он не interferировал с внедрённым кодом. Пробел после -- обязателен в MySQL, иначе комментарий не распознается.

Как это работает целиком?

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

SELECT * FROM products WHERE id = '))) AND EXTRACTVALUE(2064,CONCAT(0x7e,((SELECT (ELT(2064=2064,1)))),0x7e))-- -'

После подстановки получаем:

SELECT * FROM products WHERE id = '))) AND EXTRACTVALUE(2064,CONCAT(0x7e,((SELECT (ELT(2064=2064,1)))),0x7e))-- -'

Сервер выполнит:

  • Закроет скобки, чтобы синтаксис остался валидным.
  • Добавит условие AND EXTRACTVALUE(...).
  • Функция EXTRACTVALUE попытается разобрать строку ~1~ как XPath, потерпит неудачу и сгенерирует ошибку: XPATH syntax error: '~1~'.
  • В тексте ошибки клиент увидит ~1~ — это и есть результат подзапроса.
  • Остаток запроса после -- - будет проигнорирован.

Таким образом, атакующий может извлекать произвольные данные, подставляя вместо 1 другие SQL-запросы. Например, (SELECT password FROM users LIMIT 1) выведет пароль первого пользователя в сообщении об ошибке.

Зачем это нужно злоумышленнику?

Error-based SQL-инъекции — один из самых быстрых способов извлечения данных, потому что результат приходит сразу в ответе сервера. В отличие от blind-инъекций, где приходится задавать множество вопросов «да/нет», здесь достаточно одного запроса на одну порцию данных. Однако этот метод работает только если приложение выводит сообщения об ошибках СУБД пользователю. Многие современные фреймворки и ORM скрывают такие ошибки, что делает атаку невозможной.

Меры защиты

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

  • Использовать параметризованные запросы (prepared statements). Это самый надёжный способ, при котором данные никогда не интерпретируются как SQL-код.
  • Экранировать специальные символы. Если параметризация невозможна, применяйте функции экранирования, предоставляемые драйвером БД.
  • Отключить вывод ошибок СУБД. Настройте сервер и приложение так, чтобы детали ошибок не попадали к пользователю.
  • Использовать WAF (Web Application Firewall). Современные WAF умеют распознавать сигнатуры error-based инъекций, включая EXTRACTVALUE и UPDATEXML.
  • Регулярно обновлять MySQL. Начиная с версии 8.0.17 функции EXTRACTVALUE и UPDATEXML помечены как устаревшие и могут быть удалены в будущих релизах, что снижает риск их использования.

Заключение

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

Источники