Что такое AND EXTRACTVALUE в контексте SQL-инъекций

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

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

Как работает функция EXTRACTVALUE

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

XPATH syntax error: '~...~'

Именно в этот текст ошибки можно «вшить» результат выполнения подзапроса. Для этого злоумышленники используют CONCAT с разделителями (например, 0x7e — это тильда ~), чтобы отделить данные от служебного текста и легко их извлечь.

Разбор конкретной инъекции

Рассмотрим запрос AND EXTRACTVALUE(4259,CONCAT(0x7e,(SELECT(ELT(4259=4259,1))),0x7e))-- - по частям:

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

В результате MySQL выполнит подзапрос, получит значение (в данном случае «1»), вставит его в XPath-выражение, которое заведомо невалидно, и выдаст ошибку с текстом, содержащим это значение. Например:

XPATH syntax error: '~1~'

Злоумышленник, увидев такой ответ, понимает, что инъекция работает, и может заменить ELT(4259=4259,1) на любой другой подзапрос, например, (SELECT version()) или (SELECT password FROM users LIMIT 1).

Зачем это нужно злоумышленникам

Error-based SQL-инъекции — один из самых быстрых способов извлечения данных, потому что не требуют слепого перебора (boolean-based или time-based). Ответ приходит сразу в тексте ошибки. Это позволяет:

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

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

Пример уязвимого кода

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

$id = $_GET['id'];
$query = "SELECT * FROM products WHERE id = $id";
$result = mysqli_query($conn, $query);
if (!$result) {
    echo "Ошибка: " . mysqli_error($conn);
}

Если передать id=1 AND EXTRACTVALUE(4259,CONCAT(0x7e,(SELECT version()),0x7e)), то в случае ошибки на экран выведется версия MySQL. Это и есть эксплуатация.

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

Основные меры защиты универсальны для всех типов SQLi:

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

Стоит отметить, что в MySQL 8.0 функция EXTRACTVALUE помечена как устаревшая, и её использование в новых приложениях не рекомендуется. Однако старые системы по-прежнему уязвимы.

Вывод

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

Источники