Введение

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

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

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

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

Разбор строки ) AND EXTRACTVALUE(6832,CONCAT(0x7e,((SELECT (ELT(6832=6832,1)))),0x7e))-- -

Давайте разберём её по частям.

1. Закрывающая скобка и AND

Строка начинается с символа ). Это попытка закрыть скобку, которая могла быть открыта в оригинальном запросе приложения. Затем следует AND — логический оператор, позволяющий добавить условие к существующему запросу. Например, если исходный запрос был SELECT * FROM users WHERE id = (1), то после подстановки получится SELECT * FROM users WHERE id = (1) AND EXTRACTVALUE(...).

2. Функция EXTRACTVALUE

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

3. CONCAT и 0x7e

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

4. Подзапрос SELECT (ELT(6832=6832,1))

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Выражение 6832=6832 всегда истинно, что в числовом контексте равно 1. Таким образом, ELT(1, 1) вернёт 1. В данном примере подзапрос возвращает просто число 1 — это тестовая инъекция, чтобы проверить, выполняется ли она. В реальной атаке вместо 1 могла бы быть, например, version() или database().

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

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

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

Предположим, уязвимый запрос выглядит так: SELECT * FROM articles WHERE id = (1). Злоумышленник подставляет вместо 1 строку ) AND EXTRACTVALUE(6832,CONCAT(0x7e,((SELECT (ELT(6832=6832,1)))),0x7e))-- -. В результате запрос становится:

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

База данных выполняет EXTRACTVALUE, и поскольку второй аргумент не является корректным XPath (начинается с ~), возникает ошибка. В сообщении об ошибке MySQL отобразит переданную строку, например: XPATH syntax error: '~1~'. Так злоумышленник понимает, что инъекция работает, и может извлекать произвольные данные, заменяя 1 на другие SQL-выражения.

Почему это опасно?

Error-based инъекции позволяют быстро получать информацию о базе данных: версию СУБД, имя текущей базы, список таблиц и даже содержимое полей. В руках злоумышленника это может привести к полной компрометации данных. Кроме того, такие строки часто встречаются в логах веб-серверов, что говорит о попытках сканирования уязвимостей.

Как защититься?

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

Заключение

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

Источники