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

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

В этой статье мы детально разберём конкретную полезную нагрузку: ')) OR EXTRACTVALUE(3296,CONCAT(0x7e,((SELECT (ELT(3296=3296,1)))),0x7e))-- -. Вы узнаете, как она работает, зачем нужны отдельные её части и как защитить своё приложение от подобных атак.

Разбор полезной нагрузки

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

  • ')) — закрывает существующие скобки и кавычки в уязвимом SQL-запросе, чтобы внедрить свой код.
  • OR — логический оператор, который делает условие всегда истинным, если правая часть вернёт ошибку или истину.
  • EXTRACTVALUE(3296, CONCAT(0x7e, ((SELECT (ELT(3296=3296,1)))), 0x7e)) — вызов функции ExtractValue с двумя аргументами: первый — произвольное число (3296), второй — XPath-выражение, которое формируется динамически.
  • -- - — комментарий, который отсекает оставшуюся часть оригинального запроса.

Функция ExtractValue

ExtractValue — это встроенная функция MySQL, предназначенная для извлечения значения из XML-строки по заданному XPath-выражению. Синтаксис: ExtractValue(xml_frag, xpath_expr). Если XPath-выражение некорректно, MySQL генерирует ошибку с текстом, содержащим переданное выражение. Именно это свойство и эксплуатируется в error-based инъекциях: злоумышленник может поместить в XPath результат подзапроса, и он отобразится в сообщении об ошибке.

Конкатенация и маркеры

В нашем примере используется CONCAT(0x7e, ((SELECT (ELT(3296=3296,1)))), 0x7e). 0x7e — это шестнадцатеричное представление символа тильды (~). Тильды служат маркерами, чтобы легко найти извлечённые данные в тексте ошибки. Внутри конкатенации выполняется подзапрос SELECT (ELT(3296=3296,1)).

ELT — функция, возвращающая N-й элемент из списка. Здесь ELT(3296=3296,1) вернёт 1, так как условие 3296=3296 истинно (равно 1). Это простейший пример; на практике вместо ELT могут быть подзапросы к системным таблицам, например SELECT user() или SELECT database().

Итоговое выражение

Таким образом, ExtractValue получает XPath-строку вида ~1~, которая не является валидным XPath. MySQL выдаёт ошибку: XPATH syntax error: '~1~'. В реальной атаке вместо 1 будет, например, имя базы данных или хеш пароля.

Пример работы в уязвимом запросе

Предположим, что на сервере выполняется следующий SQL-запрос, где $id берётся из параметра URL:

SELECT * FROM articles WHERE id = ('$id')

Если передать ')) OR EXTRACTVALUE(3296,CONCAT(0x7e,((SELECT (ELT(3296=3296,1)))),0x7e))-- -, то после подстановки получится:

SELECT * FROM articles WHERE id = ('') OR EXTRACTVALUE(3296,CONCAT(0x7e,((SELECT (ELT(3296=3296,1)))),0x7e))-- -')

Часть запроса после -- - игнорируется. Условие OR заставляет MySQL выполнить функцию ExtractValue, которая вызовет ошибку с текстом XPATH syntax error: '~1~'. Атакующий увидит этот текст на странице (если ошибки выводятся) и поймёт, что инъекция работает.

Зачем это нужно злоумышленнику?

Основная цель — извлечение данных из базы. Меняя подзапрос внутри CONCAT, можно получить:

  • версию СУБД: SELECT version();
  • имя текущей базы: SELECT database();
  • список таблиц: SELECT table_name FROM information_schema.tables;
  • данные пользователей: логины, пароли, email.

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

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

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

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

Заключение

Полезная нагрузка ')) OR EXTRACTVALUE(3296,CONCAT(0x7e,((SELECT (ELT(3296=3296,1)))),0x7e))-- - — классический пример error-based SQL-инъекции через функцию ExtractValue в MySQL. Она позволяет атакующему извлекать произвольные данные из базы, вызывая ошибки с внедрённым содержимым. Понимание механики таких атак помогает разработчикам и администраторам лучше защищать свои приложения. Главный совет: никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.

Источники