Введение

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

Что такое EXTRACTVALUE?

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

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

Рассмотрим строку: "))) AND EXTRACTVALUE(3499,CONCAT(0x7e,((SELECT (ELT(3499=3499,1)))),0x7e))-- -

Она состоит из нескольких частей:

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

Аргументы EXTRACTVALUE

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

Однако EXTRACTVALUE ожидает первым аргументом XML-фрагмент. Число 3499 не является XML, поэтому MySQL пытается его разобрать и выдаёт ошибку: XPATH syntax error: '~1~'. В сообщении об ошибке отображается переданная строка, что позволяет злоумышленнику увидеть результат выполнения подзапроса. В данном случае это просто число 1, но вместо него может быть любое выражение, например, имя пользователя или хеш пароля.

Зачем это нужно?

Цель такой инъекции — заставить базу данных вернуть данные в тексте ошибки. Поскольку приложение часто выводит ошибки СУБД на экран (или они попадают в логи), атакующий может извлекать произвольную информацию: версию MySQL, имена таблиц, логины и пароли. Это классический пример error-based SQL-инъекции.

Пример практического использования

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

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

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

Ограничения и особенности

Функция EXTRACTVALUE работает только в MySQL и MariaDB. В других СУБД (PostgreSQL, MSSQL, Oracle) используются иные приёмы. Кроме того, в MySQL 5.7+ длина выводимой строки ограничена 32 символами, поэтому для извлечения длинных данных применяют посимвольное чтение с помощью SUBSTRING и смещений.

Также важно, чтобы приложение выводило ошибки БД. Если ошибки подавляются, error-based инъекция не сработает, и атакующий переключится на blind-инъекции.

Как защититься?

Основные меры предотвращения SQL-инъекций:

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

Важно понимать, что фильтрация по чёрным спискам (например, удаление слова EXTRACTVALUE) неэффективна, так как злоумышленник может использовать обфускацию или другие функции.

Заключение

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

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

Источники