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

SQL-инъекция остаётся одной из самых опасных уязвимостей веб-приложений. Согласно OWASP Top 10, она стабильно входит в список критических рисков. Одним из методов эксплуатации является error-based SQL-инъекция, при которой злоумышленник заставляет базу данных возвращать данные в сообщениях об ошибках. Функция extractvalue в MySQL часто используется для таких атак.

В запросе пользователя: " AND EXTRACTVALUE(3300,CONCAT(0x7e,((SELECT (ELT(3300=3300,1)))),0x7e))-- - — демонстрируется классический пример error-based инъекции. Давайте разберём его по частям.

Синтаксис и назначение функции extractvalue

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

В нашем примере:

  • 3300 — произвольное число, передаваемое как XML-фрагмент (не является корректным XML, что вызовет ошибку).
  • CONCAT(0x7e, ((SELECT (ELT(3300=3300,1)))), 0x7e) — формирует строку, начиная и заканчивая тильдой (0x7e). Внутри — подзапрос, возвращающий результат выражения ELT(3300=3300,1).

Разбор подзапроса ELT(3300=3300,1)

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Если N=1, возвращается первая строка. Выражение 3300=3300 всегда истинно (1), поэтому ELT(1,1) вернёт 1. Это простейший пример, но на практике вместо 1 подставляются имена таблиц, колонок или другие данные.

Таким образом, CONCAT соберёт строку вида ~1~. При вызове EXTRACTVALUE с некорректным XPath (например, просто числом 3300) MySQL выдаст ошибку: XPATH syntax error: '~1~'. В этом сообщении и утечёт результат подзапроса.

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

Предположим, есть уязвимый параметр id в URL: http://example.com/product.php?id=1. Злоумышленник может подставить:

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

В ответе сервера появится ошибка с версией MySQL. Аналогично можно извлечь имена таблиц, колонок, логины и пароли.

В нашем примере с ELT(3300=3300,1) демонстрируется базовый тест на возможность инъекции. Если приложение возвращает ошибку с ~1~, значит, оно уязвимо.

Пошаговый механизм атаки

  1. Злоумышленник находит параметр, передаваемый в SQL-запрос без должной фильтрации.
  2. Внедряет конструкцию с EXTRACTVALUE, используя CONCAT для формирования строки с данными.
  3. СУБД выполняет запрос, вызывает ошибку и возвращает её текст клиенту (если вывод ошибок включён).
  4. Атакующий читает данные из сообщения об ошибке.
  5. Меняя подзапрос, извлекает любую информацию из базы.

Меры защиты от error-based SQL-инъекций

Чтобы предотвратить такие атаки, необходимо:

  • Использовать подготовленные выражения (prepared statements) с параметризацией запросов. Это самый надёжный способ.
  • Отключить вывод подробных ошибок в production-окружении. Ошибки должны логироваться, а пользователь видеть общее сообщение.
  • Применять ORM (например, Hibernate, Entity Framework), которые автоматически экранируют опасные символы.
  • Проводить валидацию входных данных на стороне сервера, отклоняя подозрительные символы (кавычки, комментарии, ключевые слова SQL).
  • Регулярно обновлять СУБД и использовать WAF (Web Application Firewall) для фильтрации трафика.

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

Распространённые ошибки при защите

Многие разработчики полагаются только на mysql_real_escape_string, но это не защищает от инъекций в числовых параметрах. Также опасно использовать динамическое конструирование SQL без белого списка допустимых значений.

Ещё одна ошибка — включённый режим display_errors на боевом сервере. Это прямо помогает атакующему получать данные через сообщения об ошибках.

Заключение

Запрос с EXTRACTVALUE — это типичный пример error-based SQL-инъекции, эксплуатирующей особенности MySQL. Понимание механизма помогает разработчикам и специалистам по безопасности правильно выстраивать защиту. Главный вывод: никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.

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

Источники