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

SQL-инъекция — один из самых распространённых способов взлома веб-приложений. Злоумышленники вставляют вредоносный код в поля ввода, URL-параметры или cookie, чтобы получить доступ к базе данных. Особый интерес представляет error-based SQL-инъекция, при которой хакер заставляет сервер выдать сообщение об ошибке, содержащее конфиденциальные данные.

Функция EXTRACTVALUE в MySQL предназначена для извлечения значения из XML-документа по заданному XPath-выражению. Однако при неправильной обработке входных данных она становится мощным инструментом для атак. Рассмотрим конкретный пример: ' OR EXTRACTVALUE(2448,CONCAT(0x7e,((SELECT (ELT(2448=2448,1)))),0x7e))-- -.

Как работает EXTRACTVALUE в MySQL?

Синтаксис функции: EXTRACTVALUE(XML_фрагмент, XPath_выражение). Она возвращает текст из XML-документа, соответствующий указанному пути. Если XPath-выражение некорректно или возвращает несколько узлов, MySQL генерирует ошибку. Именно эту особенность используют злоумышленники.

В приведённом запросе:

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

Когда MySQL пытается выполнить EXTRACTVALUE с не-XML аргументом, он выдаёт ошибку вида: XPATH syntax error: '~1~'. В этом сообщении и оказывается результат подзапроса, обёрнутый в тильды. Таким образом, атакующий может извлекать данные посимвольно или целыми строками.

Цель атаки и её опасность

Основная цель — получить доступ к содержимому базы данных: логины, пароли, номера кредитных карт, персональные данные пользователей. Error-based инъекции особенно опасны, потому что:

  • Не требуют слепого перебора — данные сразу видны в ответе сервера.
  • Работают даже при отключённом выводе ошибок на экран, если ошибки логируются и доступны атакующему.
  • Позволяют обойти простые фильтры, так как используют легитимные функции СУБД.

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

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

Главное правило — никогда не доверять пользовательскому вводу. Конкретные меры:

  1. Использовать подготовленные выражения (prepared statements). Это самый надёжный способ: параметры запроса передаются отдельно от SQL-кода и не могут изменить его структуру.
  2. Применять ORM или библиотеки с экранированием. Например, PDO в PHP, Sequelize в Node.js.
  3. Ограничить права пользователя базы данных. Веб-приложение должно работать под учётной записью с минимально необходимыми привилегиями (только SELECT, INSERT, UPDATE, DELETE для нужных таблиц).
  4. Отключить вывод подробных ошибок в production. Сообщения об ошибках не должны попадать в браузер пользователя — только в защищённые логи.
  5. Использовать WAF (Web Application Firewall). Современные WAF умеют распознавать сигнатуры error-based инъекций, включая EXTRACTVALUE.
  6. Регулярно обновлять СУБД и фреймворки. В новых версиях MySQL некоторые опасные функции могут быть удалены или изменены.
Важно: функция EXTRACTVALUE признана устаревшей (deprecated) начиная с MySQL 5.7.6 и удалена в MySQL 8.0. Если ваше приложение всё ещё её использует, это само по себе сигнал о необходимости модернизации.

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

Вместо конкатенации строк:

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

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

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

Такой подход полностью исключает возможность внедрения SQL-кода через параметры.

Что делать, если вы обнаружили подобный запрос в логах?

Если в логах веб-сервера или в поле ввода вы увидели строку, похожую на ' OR EXTRACTVALUE(2448,CONCAT(0x7e,...))-- -, это означает, что ваш сайт пытались взломать. Немедленные действия:

  • Проверьте, не уязвимо ли приложение. Попробуйте воспроизвести атаку на тестовом стенде.
  • Просмотрите код на наличие мест, где пользовательский ввод попадает в SQL-запрос без обработки.
  • Установите или обновите WAF, чтобы блокировать подобные попытки в будущем.
  • Проведите аудит безопасности и, при необходимости, привлеките специалистов.

Помните: даже если атака не удалась, сам факт её попытки говорит о том, что злоумышленники активно сканируют интернет в поисках уязвимых сайтов. Безопасность — это непрерывный процесс, а не разовое действие.

Заключение

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

Источники