Что такое ExtractValue и при чём тут SQL-инъекция?

Функция ExtractValue в СУБД MySQL предназначена для извлечения значения из XML-документа по указанному XPath-выражению. Синтаксис: ExtractValue(XML_document, XPath_expression). Однако при некорректном использовании она может стать инструментом для проведения error-based SQL-инъекций. Злоумышленники передают в функцию специально сформированные XPath-выражения, которые вызывают ошибки, содержащие результаты выполнения вложенных SQL-запросов. Это позволяет извлекать данные из базы, даже если прямой вывод информации заблокирован.

Рассматриваемый запрос: %")) AND EXTRACTVALUE(3432,CONCAT(0x7e,((SELECT (ELT(3432=3432,1)))),0x7e))-- - — типичный пример такой инъекции. Давайте разберём его по частям.

Анатомия вредоносного запроса

Разберём приведённую строку:

  • %")) — попытка закрыть предыдущие кавычки и скобки, чтобы внедрить свой код.
  • AND EXTRACTVALUE(3432,CONCAT(0x7e,((SELECT (ELT(3432=3432,1)))),0x7e)) — вызов уязвимой функции. Первый аргумент (3432) — произвольное число, второй — конкатенация тильды (0x7e), результата подзапроса и снова тильды.
  • SELECT (ELT(3432=3432,1)) — возвращает 1, так как условие 3432=3432 истинно. ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь список состоит из одного элемента '1'.
  • -- - — комментарий, обрезающий остаток оригинального запроса.

В результате MySQL попытается вычислить XPath-выражение, содержащее символ ~ (0x7e), что вызовет ошибку вида XPATH syntax error: '~1~'. В текст ошибки попадёт результат подзапроса — в данном случае '1'. Злоумышленник может заменить ELT(3432=3432,1) на любой другой подзапрос, например, (SELECT password FROM users LIMIT 1), и получить его результат в сообщении об ошибке.

Как работает error-based SQL-инъекция через ExtractValue

Error-based инъекции эксплуатируют вывод сообщений об ошибках СУБД на страницу. Если приложение не подавляет ошибки, атакующий может заставить базу данных вернуть нужные данные в тексте ошибки. ExtractValue — один из классических векторов для MySQL (наряду с UpdateXML и GeometryCollection).

Механизм прост: функция ExtractValue при невалидном XPath генерирует ошибку, в которую включает часть переданного выражения. Если в это выражение встроить подзапрос, его результат окажется в сообщении об ошибке.

Для успешной атаки необходимо, чтобы:

  1. Приложение было уязвимо к SQL-инъекции (например, не использует параметризованные запросы).
  2. Выводились сообщения об ошибках MySQL (или они логировались и были доступны атакующему).
  3. Версия MySQL поддерживала функцию ExtractValue (доступна с 5.1).

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

Если злоумышленник может выполнить такую инъекцию, он способен:

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

По данным OWASP, SQL-инъекции остаются одной из самых распространённых и опасных уязвимостей веб-приложений.

Как защититься от инъекций через ExtractValue

Основной метод — параметризованные запросы (prepared statements). Они разделяют код SQL и данные, поэтому внедрение произвольного SQL-кода становится невозможным. Дополнительные меры:

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

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

Пример безопасного кода на PHP

Вместо уязвимого запроса:

$id = $_GET['id'];
$query = "SELECT * FROM products WHERE id = $id";

Следует использовать подготовленные выражения:

$stmt = $pdo->prepare('SELECT * FROM products WHERE id = :id');
$stmt->execute(['id' => $_GET['id']]);

Такой подход полностью исключает возможность инъекции, включая сложные конструкции с ExtractValue.

Заключение

Запрос %")) AND EXTRACTVALUE(3432,CONCAT(0x7e,((SELECT (ELT(3432=3432,1)))),0x7e))-- - — это попытка эксплуатации error-based SQL-инъекции через функцию ExtractValue в MySQL. Понимание механизма таких атак помогает разработчикам и администраторам своевременно закрывать уязвимости. Главный совет: никогда не подставляйте пользовательские данные в SQL-запросы напрямую, используйте параметризацию и следите за обновлениями безопасности.

Источники