Что это за строка?

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

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

Разбор по частям

Рассмотрим каждый элемент запроса:

  • ' AND ... -- - — закрывает предыдущее строковое значение в уязвимом параметре, добавляет логическое условие AND и комментирует остаток исходного SQL-запроса. Два дефиса с пробелом или без — стандартный комментарий в MySQL.
  • EXTRACTVALUE(6073, ...) — первый аргумент — произвольное число (идентификатор), второй — XML-фрагмент, который формируется динамически.
  • CONCAT(0x7e, ((SELECT (ELT(6073=6073,1)))), 0x7e) — конкатенация символа ~ (0x7e), результата подзапроса и снова ~. Символ ~ используется как маркер, чтобы отделить полезную нагрузку в сообщении об ошибке.
  • SELECT (ELT(6073=6073,1)) — подзапрос, возвращающий 1, если условие 6073=6073 истинно, и NULL в противном случае. Функция ELT() возвращает N-й элемент из списка; здесь список состоит из одного элемента — числа 1.

В результате MySQL пытается интерпретировать строку вида ~1~ как XPath. Поскольку это невалидный XPath, возникает ошибка: XPATH syntax error: '~1~'. В реальной атаке вместо 1 подставляется выражение, извлекающее, например, имя базы данных, версию СУБД или хеши паролей.

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

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

SELECT * FROM articles WHERE id = '$_GET[id]'

Если передать в параметр id нашу строку, итоговый запрос примет вид:

SELECT * FROM articles WHERE id = '' AND EXTRACTVALUE(6073,CONCAT(0x7e,((SELECT (ELT(6073=6073,1)))),0x7e))-- -'

MySQL выполнит подзапрос, получит 1, сформирует строку ~1~, попытается разобрать её как XPath и выдаст ошибку. Приложение, если оно не скрывает ошибки, отобразит её пользователю. Атакующий увидит XPATH syntax error: '~1~' и поймёт, что инъекция работает.

Для извлечения реальных данных вместо ELT(6073=6073,1) подставляют, например, SELECT database() или SELECT version(). Тогда в ошибке появится имя текущей базы данных или версия MySQL.

Почему EXTRACTVALUE, а не UNION?

Метод error-based через EXTRACTVALUE применяют, когда:

  • Приложение возвращает сообщения об ошибках СУБД (или их часть) в ответе.
  • Использование UNION SELECT невозможно из-за несоответствия количества столбцов или типов данных.
  • Нужно обойти фильтры, которые блокируют ключевые слова вроде UNION или SELECT (хотя SELECT здесь тоже присутствует).

Функция EXTRACTVALUE доступна в MySQL начиная с версии 5.1.5. В более новых версиях (8.0+) она помечена как устаревшая, но всё ещё работает. Аналогичный эффект дают UPDATEXML() и GTID_SUBSET().

Чем опасна такая инъекция

Успешная эксплуатация error-based SQL-инъекции позволяет злоумышленнику:

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

Даже если приложение не показывает ошибки напрямую, атакующий может использовать слепые методы (boolean-based, time-based), но error-based даёт самый быстрый результат.

Как защититься

Основной способ предотвращения SQL-инъекций — использование параметризованных запросов (prepared statements). В этом случае пользовательский ввод передаётся отдельно от SQL-кода и не может изменить структуру запроса. Пример на PHP с PDO:

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

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

  • Отключить вывод ошибок СУБД в production-окружении. Сообщения об ошибках должны логироваться, а не отображаться пользователю.
  • Использовать ORM или query builder, которые по умолчанию экранируют параметры.
  • Применять принцип наименьших привилегий для учётной записи БД: запретить доступ к information_schema, если он не нужен, и не давать прав FILE.
  • Регулярно обновлять СУБД и веб-приложение, чтобы закрыть известные уязвимости.
  • Проводить аудит кода и пентесты для выявления подобных дыр.
Важно: error-based SQL-инъекция — не просто теоретическая угроза. По данным OWASP, инъекции входят в топ-10 критических рисков веб-приложений. Даже одна незакрытая точка входа может привести к полной компрометации базы данных.

Заключение

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

Источники