Что такое EXTRACTVALUE и зачем он в SQL-инъекции

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

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

Разбор полезной нагрузки

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

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

Зачем нужен ELT и выражение 4203=4203

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

В реальной атаке вместо ELT(4203=4203,1) подставляют подзапросы, например SELECT version() или SELECT password FROM users LIMIT 1, чтобы извлечь конфиденциальные данные.

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

MySQL при вызове EXTRACTVALUE с некорректным XPath возвращает ошибку вида:

XPATH syntax error: '~1~'

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

Подобные техники описаны в практических руководствах по SQL-инъекциям, например в «MySQL SQL Injection Practical Cheat Sheet» (Pentester Skills). Также известны случаи успешного применения EXTRACTVALUE на пентестах.

Другие функции для error-based атак

Помимо EXTRACTVALUE, в MySQL существуют аналогичные функции:

  • UPDATEXML(XML, XPath, new_value) — также вызывает ошибку XPath и выводит данные.
  • GTID_SUBSET(), JSON_KEYS() и другие — в зависимости от версии MySQL.
  • EXP() — переполнение, но не выводит данные напрямую.

С выходом MySQL 8.0 некоторые из этих функций были ограничены, но EXTRACTVALUE всё ещё доступна (хотя и помечена как устаревшая).

Пример уязвимого запроса

Предположим, на сервере выполняется такой код:

$id = $_GET['id'];
$query = "SELECT * FROM products WHERE category = ('$id')";
$result = mysqli_query($link, $query);

Если передать id=1')) AND EXTRACTVALUE(4203,CONCAT(0x7e,((SELECT (ELT(4203=4203,1)))),0x7e))-- -, то итоговый запрос станет:

SELECT * FROM products WHERE category = ('1')) AND EXTRACTVALUE(4203,CONCAT(0x7e,((SELECT (ELT(4203=4203,1)))),0x7e))-- -')

СУБД выполнит подзапрос, сформирует ошибку и вернёт её клиенту (если вывод ошибок включён).

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

Эксплуатация error-based SQL-инъекции позволяет:

  • Получить версию СУБД, имя базы данных, текущего пользователя.
  • Извлечь содержимое таблиц: логины, пароли, персональные данные.
  • В некоторых случаях выполнить произвольные SQL-команды (если привилегии позволяют).

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

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

Основной метод — использование параметризованных запросов (prepared statements). Например, на PHP с MySQLi:

$stmt = $link->prepare("SELECT * FROM products WHERE category = ?");
$stmt->bind_param('s', $id);
$stmt->execute();

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

  • Отключить вывод ошибок СУБД на продакшене (display_errors = Off).
  • Использовать ORM или query builder, которые экранируют данные.
  • Применять WAF с сигнатурами для EXTRACTVALUE, UPDATEXML и подобных функций.
  • Регулярно обновлять MySQL и применять принцип наименьших привилегий для пользователя БД.

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

Заключение

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

Источники