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

SQL-инъекция — один из самых распространённых способов взлома веб-приложений. Злоумышленник внедряет вредоносный SQL-код в запрос, чтобы получить доступ к базе данных. Особый интерес представляет error-based SQL-инъекция, при которой хакер заставляет сервер выдать сообщение об ошибке, содержащее конфиденциальные данные.

Функция EXTRACTVALUE() в MySQL предназначена для извлечения значения из XML-документа по заданному XPath-выражению. Однако при неправильной обработке пользовательского ввода она становится мощным инструментом для атак. Если в XPath-выражении встречается недопустимый символ, MySQL генерирует ошибку с фрагментом этого выражения. Злоумышленник может подставить в XPath результат подзапроса, и сервер сам «расскажет» ему нужные данные.

Пример уязвимого запроса: SELECT * FROM users WHERE id = 1 AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e));

В ответе появится ошибка вида XPATH syntax error: '~5.7.23~', где 5.7.23 — версия СУБД. Так по крупицам можно вытащить имена таблиц, столбцов, логины и пароли.

Разбор конкретного запроса

Рассмотрим строку из запроса пользователя:

))) AND EXTRACTVALUE(7494,CONCAT(0x7e,((SELECT (ELT(7494=7494,1)))),0x7e))-- -

Это классический пример error-based SQL-инъекции для MySQL. Разберём её по частям:

  • ))) — закрывающие скобки, которые «подгоняют» синтаксис исходного запроса, чтобы внедряемая конструкция оказалась валидной.
  • AND — логический оператор, присоединяющий вредоносное условие.
  • EXTRACTVALUE(7494, CONCAT(...)) — вызов уязвимой функции. Первый аргумент (7494) — произвольное число, оно не влияет на результат, но должно быть допустимым XML-фрагментом.
  • CONCAT(0x7e, ..., 0x7e) — объединяет тильды (символ ~, код 0x7e) с полезной нагрузкой. Тильды нужны, чтобы MySQL гарантированно сгенерировал ошибку XPATH и вывел содержимое между ними.
  • (SELECT (ELT(7494=7494,1))) — подзапрос, возвращающий результат выражения ELT(7494=7494,1). Функция ELT() возвращает N-й элемент из списка. Здесь условие 7494=7494 всегда истинно (1), поэтому ELT(1,1) вернёт строку '1'. В реальной атаке вместо этого подзапроса стоял бы, например, (SELECT table_name FROM information_schema.tables LIMIT 1).
  • -- - — комментарий, который «отрезает» оставшуюся часть оригинального SQL-запроса, чтобы не нарушать синтаксис.

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

Почему EXTRACTVALUE опасна?

Функция EXTRACTVALUE() (как и UPDATEXML()) появилась в MySQL 5.1 и часто используется разработчиками для работы с XML. Проблема в том, что при передаче в неё пользовательских данных без экранирования она становится каналом утечки информации. Основные причины уязвимости:

  1. Отсутствие параметризованных запросов.
  2. Вывод ошибок СУБД прямо в браузер.
  3. Использование устаревших версий MySQL (до 8.0), где функция не удалена.

Стоит отметить, что в MySQL 8.0 функции EXTRACTVALUE() и UPDATEXML() были удалены, что снижает риск подобных атак на современных серверах. Однако многие проекты до сих пор работают на старых версиях.

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

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

  • Используйте подготовленные выражения (prepared statements). Они разделяют код и данные, делая внедрение невозможным.
  • Отключите вывод ошибок СУБД. Настройте логирование ошибок в файл, а пользователю показывайте общее сообщение.
  • Обновите MySQL до версии 8.0+. Там опасные функции уже удалены.
  • Применяйте принцип наименьших привилегий. Учётная запись веб-приложения не должна иметь прав на чтение системных таблиц.
  • Используйте WAF (Web Application Firewall). Он может блокировать подозрительные конструкции вроде EXTRACTVALUE.

Также рекомендуется проводить регулярные аудиты кода и пентесты. Помните: даже одна неэкранированная кавычка может открыть злоумышленнику доступ ко всей базе.

Заключение

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

Источники