Что такое OR EXTRACTVALUE в SQL-инъекциях

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

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

Разбор конструкции по частям

Давайте разберём каждый элемент запроса:

  • OR — логический оператор, который добавляется к оригинальному SQL-запросу, чтобы обойти условия и внедрить свою функцию.
  • EXTRACTVALUE(4781, CONCAT(...)) — вызов функции. Первый аргумент (4781) — произвольное число, которое не влияет на результат, но требуется синтаксисом. Второй аргумент — строка, передаваемая в XPath.
  • CONCAT(0x7e, ((SELECT (ELT(4781=4781,1)))), 0x7e) — конкатенация символов. 0x7e — это шестнадцатеричное представление символа тильды (~). Он используется как разделитель, чтобы облегчить поиск выводимых данных в сообщении об ошибке.
  • SELECT (ELT(4781=4781,1)) — подзапрос, возвращающий результат функции ELT(). ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь N — это 4781=4781, что всегда истинно (1), поэтому возвращается первая строка — «1». В реальной атаке на месте этой единицы был бы другой подзапрос, извлекающий данные (например, имя пользователя, хеш пароля).
  • -- - — комментарий, который отсекает оставшуюся часть оригинального запроса, чтобы синтаксис оставался корректным.

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

Функция EXTRACTVALUE(XML_document, XPath_expression) в MySQL анализирует XPath. Если выражение начинается с символа, который не является допустимым (например, с тильды), MySQL выдаёт ошибку вида:

XPATH syntax error: '~1~'

В этом сообщении отображается переданная строка. Атакующий может подставить в подзапрос любой SQL-запрос, и результат его выполнения попадёт в текст ошибки. Так можно посимвольно извлекать данные из базы: имена таблиц, столбцов, логины, пароли и другую конфиденциальную информацию.

Конструкция ELT(4781=4781,1) в данном примере — это простейшая демонстрация. В реальной атаке вместо 1 могло бы быть, например, (SELECT password FROM users LIMIT 1). Тогда в ошибке появился бы пароль.

Зачем нужны 0x7e и CONCAT

Символ 0x7e (тильда) добавляется по краям извлекаемых данных, чтобы их было легко найти в сообщении об ошибке. Без разделителей сложно отделить полезную нагрузку от остального текста ошибки. CONCAT просто склеивает тильду, результат подзапроса и ещё одну тильду в одну строку.

Иногда вместо 0x7e используют 0x3a (двоеточие) или другие символы, которые гарантированно вызовут ошибку XPath. Главное — чтобы символ не был допустимым началом XPath-выражения.

Опасность и последствия

Error-based SQL-инъекции через EXTRACTVALUE (а также через UPDATEXML) — один из самых быстрых способов извлечения данных. В отличие от blind-инъекций, где приходится задавать множество запросов, здесь результат приходит сразу в ответе сервера. Это делает атаку очень эффективной.

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

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

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

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

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

  1. Валидация и фильтрация входных данных: проверяйте все параметры, которые попадают в SQL-запросы, на соответствие ожидаемому формату (числа, даты, строки без спецсимволов).
  2. Экранирование специальных символов: если параметризацию применить невозможно, используйте функции экранирования, предоставляемые драйвером БД (например, mysqli_real_escape_string в PHP).
  3. Ограничение привилегий пользователя БД: учётная запись, от имени которой работает приложение, не должна иметь прав на чтение системных таблиц или выполнение опасных функций.
  4. Отключение вывода ошибок на продакшене: сообщения об ошибках БД не должны показываться пользователю. Это не устраняет уязвимость, но затрудняет эксплуатацию error-based инъекций.
  5. Использование WAF: веб-application firewall может блокировать известные шаблоны атак, хотя и не является панацеей.

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

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

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

Следует использовать параметризованный запрос (пример на PHP с PDO):

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

В этом случае даже если злоумышленник передаст 1 OR EXTRACTVALUE(...), база данных воспримет это как строку и не выполнит внедрённый код.

Заключение

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

Источники