Что такое SQL-инъекция через EXTRACTVALUE?

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

Разбор структуры запроса

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

Скобки и логические операторы

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

Функция EXTRACTVALUE

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

CONCAT и шестнадцатеричные литералы

CONCAT(0x7e, ((SELECT (ELT(3186=3186,1)))), 0x7e) — эта конструкция объединяет символ ~ (0x7e в шестнадцатеричном виде), результат подзапроса и ещё один ~. Символы тильды используются как маркеры, чтобы в сообщении об ошибке было легко найти извлечённые данные. Подзапрос SELECT (ELT(3186=3186,1)) возвращает 1, если условие 3186=3186 истинно (а оно всегда истинно). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь список состоит из одного элемента 1, поэтому возвращается 1. В реальной атаке вместо 1 мог бы быть, например, version() или database(), но в данном примере показан простейший случай для проверки уязвимости.

Комментарий в конце

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

Цель атаки

Основная цель — получить доступ к данным, которые не должны быть видны пользователю: имена пользователей, пароли, номера кредитных карт, персональные данные. Error-based инъекции особенно опасны, потому что они позволяют извлекать информацию посимвольно, используя функции вроде SUBSTRING или LIMIT, и выводить её прямо в ответе сервера. В приведённом примере злоумышленник, скорее всего, проверяет, уязвим ли сайт, и если да, то перейдёт к более сложным запросам для извлечения реальных данных.

Как распознать такую инъекцию

В логах веб-сервера или в системах мониторинга можно заметить подозрительные строки, содержащие:

  • Функции EXTRACTVALUE, UPDATEXML, GTID_SUBSET и подобные.
  • Комбинации CONCAT с шестнадцатеричными строками (0x7e).
  • Логические операторы AND или OR с подзапросами.
  • Комментарии --, # в конце строки.
  • Множество закрывающих скобок в начале.

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

Меры защиты

Чтобы предотвратить SQL-инъекции, следуйте этим рекомендациям:

  1. Используйте параметризованные запросы (prepared statements). Это самый надёжный способ, при котором пользовательский ввод передаётся отдельно от SQL-кода и не может изменить его структуру.
  2. Применяйте ORM (Object-Relational Mapping). Современные ORM-библиотеки автоматически экранируют опасные символы.
  3. Валидируйте и фильтруйте входные данные. Проверяйте, что вводимые данные соответствуют ожидаемому формату (например, число, email, дата).
  4. Ограничьте права пользователя базы данных. Не используйте учётную запись с правами администратора для веб-приложений. Дайте только необходимые привилегии.
  5. Отключите вывод ошибок в production. Сообщения об ошибках базы данных не должны показываться пользователям, так как они могут содержать чувствительную информацию.
  6. Регулярно обновляйте СУБД и фреймворки. Уязвимости в старых версиях могут облегчить атаку.
  7. Используйте WAF (Web Application Firewall). Он может блокировать подозрительные запросы на основе сигнатур.

В случае с EXTRACTVALUE, если вы используете MySQL, можно также рассмотреть переход на более новые версии, где некоторые функции могут быть удалены или изменены, но это не является основной мерой защиты.

Заключение

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

Источники