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

Error-based SQL-инъекция — это техника эксплуатации уязвимостей веб-приложений, при которой злоумышленник заставляет базу данных возвращать данные через сообщения об ошибках. В отличие от union-based или blind-инъекций, здесь результат запроса извлекается напрямую из текста ошибки, что делает метод очень удобным для атакующего.

В СУБД MySQL для этих целей часто используют функции ExtractValue() и UpdateXML(). Обе функции предназначены для работы с XML-документами и при передаче некорректного XPath-выражения генерируют ошибку, в текст которой попадает переданная строка. Именно это свойство и эксплуатируется.

Строка %' AND EXTRACTVALUE(3748,CONCAT(0x7e,((SELECT (ELT(3748=3748,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции для MySQL, используемый для извлечения данных из базы.

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

Рассмотрим детально, что делает каждый элемент приведённой строки.

Символ % и кавычка

Начало %' — это попытка закрыть строковый литерал в исходном SQL-запросе. Символ % часто используется в LIKE-запросах, а одинарная кавычка завершает строку, позволяя внедрить произвольный код. Такой приём типичен для атак на параметры поиска, где приложение подставляет пользовательский ввод в условие LIKE '%...%'.

AND EXTRACTVALUE(3748, ...)

Функция EXTRACTVALUE(XML_document, XPath_expression) извлекает значение из XML-документа по указанному XPath. Если XPath-выражение синтаксически некорректно, MySQL выбрасывает ошибку вида XPATH syntax error: '...'. Атакующий передаёт в качестве первого аргумента произвольное число (3748), а в качестве второго — конкатенацию тильды 0x7e (символ ~), результата подзапроса и снова тильды. Тильды служат маркерами, чтобы в тексте ошибки было легко найти извлечённые данные.

CONCAT(0x7e, ..., 0x7e)

Функция CONCAT объединяет строки. Здесь она склеивает символ ~ (hex 0x7e), результат вложенного подзапроса и ещё один ~. Полученная строка передаётся в XPath-выражение ExtractValue. Поскольку она содержит недопустимые для XPath символы, возникает ошибка, и MySQL возвращает сообщение, включающее эту строку. Так данные «утекают» через ошибку.

Подзапрос (SELECT (ELT(3748=3748,1)))

Внутренний подзапрос SELECT (ELT(3748=3748,1)) — это простейшая проверка. Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь N — результат сравнения 3748=3748, которое всегда истинно (1). Значит, ELT(1, 1) вернёт строку '1'. В реальной атаке вместо этого подзапроса подставляется запрос, извлекающий нужные данные, например, имя базы, таблицы или хеш пароля. В демонстрационном примере он просто возвращает число 1, чтобы показать работоспособность инъекции.

Комментарий -- -

Завершающая последовательность -- - — это комментарий в SQL. Два дефиса начинают комментарий, а пробел после них (или дефис в некоторых реализациях) нужен, чтобы СУБД корректно распознала конец строки. Всё, что идёт после, игнорируется, что позволяет отбросить остаток оригинального запроса.

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

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

SELECT * FROM users WHERE name LIKE '%ПОЛЬЗОВАТЕЛЬ%';

Если вместо ПОЛЬЗОВАТЕЛЬ подставить %' AND EXTRACTVALUE(3748,CONCAT(0x7e,((SELECT (ELT(3748=3748,1)))),0x7e))-- -, то после подстановки получится:

SELECT * FROM users WHERE name LIKE '%%' AND EXTRACTVALUE(3748,CONCAT(0x7e,((SELECT (ELT(3748=3748,1)))),0x7e))-- -%';

Условие LIKE '%%' всегда истинно, а функция ExtractValue вызовет ошибку, в тексте которой появится строка ~1~. Приложение, не подавляющее ошибки, покажет её пользователю, и атакующий увидит результат.

Какие данные можно извлечь

Используя эту технику, злоумышленник может получать любые данные, доступные текущему пользователю базы. Обычно цель — получить:

  • имя текущей базы данных и её версию;
  • список таблиц и колонок через INFORMATION_SCHEMA;
  • логины и пароли пользователей;
  • номера банковских карт, персональные данные.

Поскольку вывод ограничен длиной сообщения об ошибке (обычно около 64 байт), данные извлекают по частям, используя функции SUBSTRING и LIMIT.

Примеры реальных полезных нагрузок

Вместо демонстрационного ELT(3748=3748,1) в реальных атаках подставляют, например:

  • (SELECT version()) — версия MySQL;
  • (SELECT database()) — имя текущей БД;
  • (SELECT table_name FROM information_schema.tables LIMIT 0,1) — первая таблица;
  • (SELECT password FROM users LIMIT 0,1) — пароль первого пользователя.

Каждый такой подзапрос оборачивается в CONCAT с тильдами, чтобы результат было легко найти в тексте ошибки.

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

Основная причина уязвимости — передача пользовательского ввода в SQL-запрос без должной обработки. Меры защиты:

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

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

Error-based SQL-инъекция — один из самых быстрых способов получить данные из базы. Если приложение уязвимо, злоумышленник может за несколько минут выгрузить всю базу, включая конфиденциальную информацию. Это приводит к утечкам персональных данных, финансовым потерям и репутационному ущербу. Поэтому разработчикам важно уделять внимание безопасности на этапе написания кода и проводить регулярные аудиты.

Заключение

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

Источники