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

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

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

Разбор структуры запроса

Рассмотрим инъекцию по частям:

  • `) AND ...-- - — закрытие исходного выражения (например, скобки и кавычки), добавление условия AND и комментария для отсечения остатка запроса.
  • EXTRACTVALUE(4608, CONCAT(0x7e, ((SELECT (ELT(4608=4608,1)))), 0x7e)) — вызов функции с двумя аргументами: первый (4608) — произвольное число, второй — конкатенация тильды (0x7e), результата подзапроса и снова тильды.
  • ELT(4608=4608,1) — функция ELT возвращает N-й элемент из списка. Здесь условие 4608=4608 всегда истинно (1), поэтому ELT(1,1) вернёт 1. В реальной атаке на этом месте был бы подзапрос, извлекающий данные (например, имя таблицы или хеш пароля).

В результате MySQL попытается разобрать строку ~1~ как XPath, что вызовет ошибку вида XPATH syntax error: '~1~'. Злоумышленник видит эту ошибку в ответе сервера и может подставлять в подзапрос любые данные, которые нужно извлечь.

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

Обычно атака строится так:

  1. Определяется количество столбцов в исходном запросе (ORDER BY или UNION SELECT).
  2. Находится уязвимый параметр, который подставляется в SQL-запрос без экранирования.
  3. В параметр внедряется конструкция с EXTRACTVALUE, где в подзапросе указывается, что именно нужно вытащить: версию СУБД, имя текущей базы, таблицы, столбцы, логины и пароли пользователей.
  4. Сервер возвращает ошибку, содержащую запрошенные данные, которые злоумышленник читает в HTTP-ответе.

Например, чтобы получить имя текущей базы данных, инъекция может выглядеть так:

`) AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))-- -

В ответе придёт ошибка с названием базы. Далее аналогично извлекаются таблицы, столбцы и записи.

Почему используется именно ExtractValue?

MySQL поддерживает несколько функций, провоцирующих ошибки с выводом данных: EXTRACTVALUE, UPDATEXML, GTID_SUBSET и другие. ExtractValue удобна тем, что она принимает два аргумента, и второй можно сформировать динамически через CONCAT. Это позволяет вставлять произвольные подзапросы и получать их результат в тексте ошибки.

Ограничение: длина выводимой строки обычно не превышает 32 символа (зависит от версии MySQL). Поэтому для извлечения длинных значений используют посимвольный вывод через SUBSTRING или LIMIT.

Примеры реальных атак

В отчётах по пентесту часто описывают эксплуатацию error-based SQLi через XPATH. Например, при тестировании веб-приложения находят параметр id=1, который подставляется в запрос SELECT * FROM users WHERE id = '$id'. Передав 1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e))-- -, получают версию MySQL в ошибке.

Далее можно извлечь имена таблиц:

1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1), 0x7e))-- -

И так далее, пока не будут получены все нужные данные.

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

Основные меры защиты:

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

Также рекомендуется ограничить права пользователя БД, от имени которого работает приложение: запретить доступ к information_schema, если он не нужен, и использовать отдельного пользователя с минимальными привилегиями.

Заключение

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

Источники