Что такое 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-запрос без должной обработки. Меры защиты:
- Использование подготовленных выражений (prepared statements) с параметризацией. Это самый надёжный способ, так как данные отделяются от кода.
- Экранирование специальных символов с помощью функций вроде
mysqli_real_escape_string(но лучше всё же prepared statements). - Отключение вывода ошибок БД в продакшене. Сообщения об ошибках не должны попадать в ответ клиенту.
- Принцип наименьших привилегий для пользователя БД: не давать прав на чтение системных таблиц без необходимости.
- Использование WAF (Web Application Firewall) для фильтрации подозрительных запросов.
- Регулярное обновление СУБД и фреймворков, чтобы закрывать известные уязвимости.
Опасность и последствия
Error-based SQL-инъекция — один из самых быстрых способов получить данные из базы. Если приложение уязвимо, злоумышленник может за несколько минут выгрузить всю базу, включая конфиденциальную информацию. Это приводит к утечкам персональных данных, финансовым потерям и репутационному ущербу. Поэтому разработчикам важно уделять внимание безопасности на этапе написания кода и проводить регулярные аудиты.
Заключение
Запрос %' AND EXTRACTVALUE(3748,CONCAT(0x7e,((SELECT (ELT(3748=3748,1)))),0x7e))-- - — это учебный пример эксплуатации error-based SQL-инъекции в MySQL. Он демонстрирует, как через функцию ExtractValue можно заставить базу вернуть данные в сообщении об ошибке. Понимание таких техник необходимо специалистам по информационной безопасности для защиты веб-приложений. Помните: лучшая защита — это параметризованные запросы и сокрытие ошибок от конечного пользователя.
Комментарии
—Войдите, чтобы оставить комментарий