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

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

Если коротко: злоумышленник внедряет в уязвимый параметр запроса код, который заставляет MySQL выполнить функцию EXTRACTVALUE с заведомо некорректным XPath-выражением. В результате сервер возвращает ошибку, содержащую результат подзапроса. Так можно узнать версию БД, имена таблиц, логины и пароли.

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

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

Начало: %')))

Символ % часто используется как подстановочный знак в LIKE-запросах. Далее идут закрывающая кавычка ' и несколько закрывающих скобок ))). Это попытка «закрыть» оригинальный SQL-запрос, чтобы внедрить свой код. Количество скобок подбирается экспериментально в зависимости от структуры уязвимого запроса.

Функция EXTRACTVALUE(3720, ...)

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

Первое число 3720 здесь — произвольное число, которое не влияет на работу, но часто используется для уникализации запроса или как часть условия.

CONCAT(0x7e, ((SELECT (ELT(3720=3720,1)))), 0x7e)

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

Внутри CONCAT находится подзапрос: SELECT (ELT(3720=3720,1)). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь 3720=3720 — это всегда истинное условие, которое возвращает 1 (в MySQL true = 1). Таким образом, ELT(1, 1) вернёт строку '1'. В реальной атаке вместо 1 подставляется результат другого подзапроса, например, SELECT password FROM users LIMIT 1.

Итог: CONCAT формирует строку вида ~1~, которая затем передаётся как XPath-выражение в EXTRACTVALUE. Поскольку ~1~ не является корректным XPath, MySQL выбрасывает ошибку, включающую эту строку.

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

Два дефиса и пробел (или дефис) — это комментарий в SQL. Он «отрезает» оставшуюся часть оригинального запроса, чтобы синтаксис был корректным.

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

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

SELECT * FROM articles WHERE id = '%'

Злоумышленник подставляет нашу строку, и запрос превращается в:

SELECT * FROM articles WHERE id = '%'))) AND EXTRACTVALUE(3720,CONCAT(0x7e,((SELECT (ELT(3720=3720,1)))),0x7e))-- -'

MySQL выполняет EXTRACTVALUE, получает ошибку и возвращает её клиенту. В тексте ошибки будет что-то вроде:

XPATH syntax error: '~1~'

Если вместо 1 подставить, например, (SELECT version()), то в ошибке появится версия MySQL. Так пошагово извлекаются любые данные.

Зачем нужна такая сложность?

Почему бы просто не использовать UNION SELECT? Дело в том, что не всегда количество столбцов в оригинальном запросе совпадает с количеством в внедряемом, или приложение не выводит результаты запроса на страницу. Error-based инъекция позволяет получить данные даже там, где нет прямого вывода. EXTRACTVALUE — один из самых надёжных способов вызвать ошибку с контролируемым содержимым.

Актуальность и защита

Начиная с MySQL 8.0.17 функция EXTRACTVALUE была удалена (deprecated в 5.7). Однако многие системы до сих пор работают на старых версиях, поэтому угроза сохраняется. Кроме того, существуют аналоги: UPDATEXML, GTID_SUBSET и другие.

Чтобы защититься от подобных атак, необходимо:

  • Использовать параметризованные запросы (prepared statements) — это самый надёжный способ.
  • Применять ORM с автоматическим экранированием.
  • Валидировать и фильтровать все входные данные, особенно те, что попадают в SQL.
  • Регулярно обновлять СУБД и фреймворки.
  • Настроить WAF для блокировки подозрительных конструкций.

Если вы обнаружили такую строку в логах своего сайта — это признак попытки взлома. Срочно проверьте код на уязвимости и закройте доступ к базе.

Заключение

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

Источники