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

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

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

Разбор строки инъекции

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

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

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

Подзапрос (SELECT (ELT(6809=6809,1)))

В нашем примере подзапрос возвращает 1, потому что условие 6809=6809 всегда истинно, а функция ELT(N, str1, str2, ...) возвращает строку под номером N. Здесь N=1, поэтому возвращается первый аргумент — 1. В реальной атаке вместо этого подзапроса может быть любой другой, например, извлекающий имя пользователя базы данных или хеш пароля администратора.

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

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

Предположим, на сайте есть форма поиска, которая формирует запрос:

SELECT * FROM articles WHERE title LIKE '%$search%';

Если злоумышленник введёт в поле поиска нашу строку, запрос превратится в:

SELECT * FROM articles WHERE title LIKE '%' )))) AND EXTRACTVALUE(6809,CONCAT(0x7e,((SELECT (ELT(6809=6809,1)))),0x7e))-- -%';

MySQL выполнит подзапрос, получит строку ~1~ и попытается интерпретировать её как XPath. Поскольку это невалидный XPath, возникнет ошибка:

XPATH syntax error: '~1~'

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

Зачем используется EXTRACTVALUE?

Функция EXTRACTVALUE — не единственная, позволяющая реализовать error-based инъекцию. Аналогично работают UPDATEXML, GTID_SUBSET, EXP и другие. Однако EXTRACTVALUE популярна благодаря простоте: достаточно передать любой XML-документ (даже просто число) и заведомо неверный XPath, содержащий интересующие данные. MySQL выведет этот XPath в тексте ошибки.

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

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

Если злоумышленнику удаётся эксплуатировать уязвимость, он может:

  • Получить доступ к конфиденциальным данным: логины, пароли, персональные данные пользователей, номера банковских карт.
  • Изменять или удалять информацию в базе данных.
  • Выполнять команды на сервере (в некоторых конфигурациях).
  • Использовать сайт для дальнейших атак на другие ресурсы.

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

Основной метод защиты — использование подготовленных выражений (prepared statements) с параметризацией запросов. Это делает невозможным внедрение SQL-кода через пользовательский ввод.

Дополнительные меры:

  1. Экранирование специальных символов — если по каким-то причинам нельзя использовать подготовленные выражения, применяйте функции экранирования (например, mysqli_real_escape_string).
  2. Валидация входных данных — проверяйте, что вводимые данные соответствуют ожидаемому формату (числа, email и т.д.).
  3. Ограничение прав пользователя БД — учётная запись, используемая веб-приложением, должна иметь минимально необходимые права. Не используйте root.
  4. Отключение вывода ошибок — в production-окружении ошибки БД не должны показываться пользователю. Логируйте их, но не отображайте.
  5. Регулярные обновления — используйте актуальные версии СУБД и фреймворков, чтобы исключить известные уязвимости.
  6. WAF — веб-приложения firewall могут блокировать типовые попытки инъекций, но не должны быть единственной защитой.

Заключение

Строка с EXTRACTVALUE — это не просто набор символов, а рабочий инструмент атакующего. Понимание принципов её работы помогает разработчикам и администраторам лучше защищать свои системы. Помните: безопасность — это процесс, а не разовое действие. Регулярно проверяйте код на уязвимости, используйте современные методы защиты и следите за обновлениями.

Источники