Введение

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

В этой статье мы подробно разберём, как работает данная конструкция, какие цели преследует злоумышленник и как защититься от подобных атак.

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

SQL-инъекция — это один из самых распространённых способов взлома веб-приложений. Суть атаки заключается во внедрении вредоносного SQL-кода в запрос, который приложение отправляет в базу данных. Если приложение недостаточно проверяет пользовательский ввод, злоумышленник может выполнить произвольные SQL-команды: прочитать, изменить или удалить данные, а в некоторых случаях — получить полный контроль над сервером.

Существует несколько типов SQL-инъекций: union-based, error-based, blind, time-based и другие. Строка, которую мы рассматриваем, относится к error-based — методу, при котором хакер заставляет базу данных выдать сообщение об ошибке, содержащее полезную информацию (например, версию СУБД, имена таблиц или конкретные данные).

Разбор строки: EXTRACTVALUE и CONCAT

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

%')))) AND EXTRACTVALUE(4624,CONCAT(0x7e,((SELECT (ELT(4624=4624,1)))),0x7e))-- -
  • %')))) — это часть, которая, вероятно, закрывает предыдущие кавычки и скобки в уязвимом запросе. Символ % может быть URL-кодированием, а последовательность ')))) — попыткой завершить оригинальный SQL-запрос и добавить свой.
  • AND EXTRACTVALUE(...) — логическое условие, которое выполняется, если предыдущая часть запроса истинна. Функция EXTRACTVALUE в MySQL предназначена для извлечения значения из XML-документа, но при неправильном использовании она генерирует ошибку, содержащую переданные аргументы.
  • 4624 — произвольное число (идентификатор), которое передаётся первым аргументом в EXTRACTVALUE. Оно не несёт смысловой нагрузки, кроме как быть частью синтаксиса.
  • CONCAT(0x7e, ((SELECT (ELT(4624=4624,1)))), 0x7e) — конкатенация строк. 0x7e — это шестнадцатеричное представление символа ~ (тильда). Он используется как разделитель, чтобы облегчить поиск данных в сообщении об ошибке.
  • SELECT (ELT(4624=4624,1)) — подзапрос, который возвращает результат функции ELT. ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь 4624=4624 — всегда истинное условие (1), поэтому ELT(1,1) вернёт 1. Это простейший пример; в реальной атаке вместо 1 могла бы быть, например, версия базы данных или имя пользователя.
  • -- - — комментарий в SQL. Всё, что идёт после --, игнорируется базой данных. Пробел после -- и дефис добавлены для обхода некоторых фильтров.

Таким образом, злоумышленник пытается выполнить запрос, который вызовет ошибку MySQL с текстом, содержащим результат подзапроса. Например, если вместо ELT(4624=4624,1) подставить SELECT version(), то в ошибке можно увидеть версию СУБД.

Как работает error-based инъекция через EXTRACTVALUE

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

XPATH syntax error: '~1~'

Именно эту ошибку и использует атакующий. Он конструирует XPath-выражение так, чтобы в тексте ошибки оказались данные, которые он хочет получить. В нашем примере CONCAT(0x7e, (SELECT ...), 0x7e) создаёт строку ~<результат>~, которая затем передаётся как XPath. MySQL пытается интерпретировать её и выдаёт ошибку, содержащую эту строку.

В приведённой строке результат подзапроса — просто 1, но это лишь демонстрация. В реальной атаке вместо 1 могут быть:

  • версия MySQL: SELECT version()
  • имя текущей базы данных: SELECT database()
  • имя пользователя: SELECT user()
  • список таблиц: SELECT table_name FROM information_schema.tables LIMIT 1
  • пароли пользователей: SELECT password FROM users LIMIT 1

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

Почему используется ELT и CONCAT?

Комбинация ELT и CONCAT — это стандартный приём в error-based SQL-инъекциях. ELT позволяет выбрать одну строку из списка по индексу, что удобно для перебора данных (например, по буквам). CONCAT объединяет несколько строк в одну, чтобы в ошибке вывести сразу несколько значений. Символ ~ (0x7e) служит маркером начала и конца полезной нагрузки — по нему легко найти данные в сообщении об ошибке.

Последствия успешной атаки

Если SQL-инъекция срабатывает, последствия могут быть катастрофическими:

  • Утечка конфиденциальных данных — пароли, персональные данные клиентов, номера кредитных карт.
  • Изменение или удаление данных — злоумышленник может выполнить UPDATE или DELETE.
  • Обход аутентификации — вход в систему без пароля.
  • Выполнение произвольных команд — в некоторых конфигурациях MySQL позволяет читать и записывать файлы, а также выполнять команды ОС.
  • Полный контроль над сервером — через загрузку веб-шелла.

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

Основной метод защиты — использование параметризованных запросов (prepared statements). Они разделяют код и данные, поэтому внедрённый SQL-код не выполняется. Дополнительные меры:

  1. Валидация и фильтрация входных данных — проверяйте тип, длину, допустимые символы.
  2. Экранирование специальных символов — используйте функции экранирования, предоставляемые драйвером БД.
  3. Минимальные привилегии для пользователя БД — не давайте приложению прав на удаление таблиц или доступ к системным таблицам.
  4. Регулярное обновление СУБД и фреймворков — закрывайте известные уязвимости.
  5. Использование WAF — веб-прикладной брандмауэр может блокировать подозрительные запросы.
  6. Логирование и мониторинг — отслеживайте аномальные запросы в логах.

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

Заключение

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

Источники