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

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

SQL-инъекция — один из самых распространённых способов атаки на веб-приложения. Злоумышленник вставляет в пользовательский ввод специальные символы и SQL-код, чтобы изменить исходный запрос к базе данных. Error-based инъекция — это техника, при которой атакующий намеренно вызывает ошибку СУБД, а в тексте ошибки пытается вывести нужные данные (например, версию MySQL, имена таблиц, логины и пароли).

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

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

Рассмотрим запрос детально:

  • AND — логический оператор, который добавляется к исходному условию WHERE. Если исходный запрос был истинным, добавление AND с заведомо ложным или ошибочным выражением меняет поведение приложения.
  • EXTRACTVALUE(4091, CONCAT(0x7e, ((SELECT (ELT(4091=4091,1)))), 0x7e)) — вызов функции EXTRACTVALUE. Первый аргумент — число 4091 (может быть любым), второй — конкатенация символов ~ (0x7e — шестнадцатеричный код тильды) и результата подзапроса.
  • CONCAT(0x7e, ..., 0x7e) — оборачивает результат в тильды, чтобы в тексте ошибки было легко найти выводимые данные.
  • SELECT (ELT(4091=4091,1)) — подзапрос, который возвращает 1, если условие 4091=4091 истинно. Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь список состоит из одной строки «1», поэтому результат — «1».
  • -- - — комментарий, который отсекает оставшуюся часть исходного SQL-запроса. Пробел после -- обязателен для MySQL, а дефис в конце часто используется для обхода фильтров.

В итоге MySQL пытается выполнить EXTRACTVALUE(4091, '~1~'). Поскольку '~1~' не является корректным XPath-выражением (начинается с тильды), СУБД возвращает ошибку: XPATH syntax error: '~1~'. В этой ошибке и «утекает» результат подзапроса.

Зачем это нужно атакующему

На первом этапе такая конструкция используется для проверки уязвимости: если приложение возвращает ошибку MySQL с текстом XPATH syntax error, значит, параметр уязвим для error-based инъекции. Далее атакующий заменяет ELT(4091=4091,1) на подзапросы, извлекающие реальные данные:

AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e))-- -

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

Почему EXTRACTVALUE, а не другие функции

В MySQL есть несколько функций, вызывающих ошибки с подстановкой данных: EXTRACTVALUE, UPDATEXML, GTID_SUBSET, JSON_KEYS и другие. EXTRACTVALUE и UPDATEXML — самые популярные, так как они доступны в большинстве версий MySQL и MariaDB и стабильно возвращают текст с переданным значением. С выходом MySQL 8.0 некоторые функции были изменены, но error-based техники по-прежнему работают через другие вызовы.

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

Главный принцип — никогда не доверять пользовательскому вводу и не конкатенировать его с SQL-запросами. Конкретные меры:

  1. Параметризованные запросы (prepared statements). Это самый надёжный способ. Данные передаются отдельно от SQL-кода и не могут изменить структуру запроса.
  2. Отключение вывода ошибок СУБД в production. Если приложение не показывает текст ошибки MySQL, error-based инъекция теряет смысл. Ошибки нужно писать в лог, а пользователю показывать общее сообщение.
  3. Экранирование специальных символов. Если параметризация невозможна, используйте функции экранирования (например, mysqli_real_escape_string), но помните, что это менее надёжно.
  4. Ограничение прав пользователя БД. Приложение должно работать под учётной записью с минимально необходимыми правами — без доступа к INFORMATION_SCHEMA и системным таблицам, если это не требуется.
  5. WAF и сигнатуры. Веб-приложения-экраны могут блокировать запросы, содержащие EXTRACTVALUE, CONCAT(0x7e и подобные шаблоны, но это лишь дополнительный барьер.
  6. Регулярный аудит кода и пентесты. Автоматические сканеры и ручное тестирование помогают находить уязвимости до атакующих.

Итог

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

Источники