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

Что такое SQL-инъекция?

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

Существует несколько типов SQL-инъекций: union-based, boolean-based, time-based и error-based. Рассматриваемая строка относится именно к error-based — методу, при котором результат извлекается через текст ошибки, возвращаемый СУБД.

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

Давайте разберём запрос на составляющие, чтобы понять его логику.

1. `))))` — закрытие скобок

Начинается строка с нескольких закрывающих круглых скобок. Это не случайность: атакующий предполагает, что исходный SQL-запрос содержит открытые скобки (например, в условиях WHERE (id = ...)). Закрывая их, он пытается «выровнять» синтаксис и внедрить свою конструкцию без ошибок парсинга.

2. `AND` — логическое продолжение

Ключевое слово AND говорит о том, что злоумышленник дописывает условие к существующему WHERE. Это позволяет внедрить произвольное выражение, которое будет вычислено сервером базы данных.

3. `EXTRACTVALUE(2219, CONCAT(...))`

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

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

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

5. `(SELECT (ELT(2219=2219,1)))`

Внутренний подзапрос содержит функцию ELT. ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Выражение 2219=2219 всегда истинно, поэтому ELT вернёт первый элемент — 1. В реальной атаке вместо этой заглушки подставляется подзапрос, извлекающий данные (например, SELECT version() или SELECT password FROM users LIMIT 1).

6. `-- -` — комментарий

Два дефиса с пробелом (или без) в MySQL означают начало комментария до конца строки. Это необходимо, чтобы «отрезать» оставшуюся часть оригинального SQL-запроса, которая могла бы вызвать синтаксическую ошибку. Пробел после -- обязателен в некоторых версиях MySQL.

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

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

SELECT * FROM products WHERE id = '$input';

Если пользователь передаст 1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e))-- -, то после подстановки получится:

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

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

XPATH syntax error: '~5.7.33~'

В тексте ошибки злоумышленник увидит версию СУБД. Аналогично можно извлечь имена таблиц, колонок, хеши паролей и другие конфиденциальные данные.

Почему используется именно EXTRACTVALUE?

Функция EXTRACTVALUE доступна в MySQL и MariaDB. В отличие от UPDATEXML, она часто не отключается в конфигурациях по умолчанию. Кроме того, она позволяет обойти некоторые фильтры, так как не содержит ключевых слов вроде UNION или SELECT в явном виде (хотя подзапрос всё же присутствует).

Как защититься от таких инъекций

Главное правило — никогда не конкатенировать пользовательский ввод в SQL-запросы. Используйте подготовленные выражения (prepared statements) с параметризацией. В PHP это PDO или mysqli с bind_param; в Python — cursor.execute с плейсхолдерами; в Java — PreparedStatement.

Дополнительные меры:

  • Валидация и фильтрация входных данных по белому списку.
  • Ограничение прав пользователя БД: приложению не нужны права FILE или EXECUTE.
  • Отключение вывода подробных ошибок СУБД в продакшене.
  • Использование WAF (Web Application Firewall) для блокировки подозрительных запросов.
  • Регулярное обновление СУБД и фреймворков.

Что делать, если вы нашли такую строку в логах

Если вы обнаружили подобный запрос в логах, это может означать, что ваш сайт пытались взломать. Не паникуйте, но проверьте:

  1. Уязвим ли ваш код к SQL-инъекциям (проведите аудит).
  2. Не произошло ли утечки данных (проверьте логи доступа к БД).
  3. Обновите ПО и настройте WAF.

Помните: даже если атака не удалась, сам факт её наличия — сигнал о необходимости усилить безопасность.

Заключение

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

Источники