Введение

SQL-инъекции остаются одной из самых опасных уязвимостей веб-приложений, несмотря на многолетнюю историю. Согласно OWASP Top 10, они стабильно входят в список критических рисков. В этой статье мы детально разберём конкретный пример инъекции, использующий функцию ExtractValue в MySQL. Запрос, который мы анализируем, выглядит так: ))) AND EXTRACTVALUE(1898,CONCAT(0x7e,((SELECT (ELT(1898=1898,1)))),0x7e))-- -. Это классическая error-based SQL-инъекция, основанная на XPATH-функциях MySQL. Мы объясним, как она работает, какие данные извлекает и как защититься от подобных атак.

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

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

MySQL предоставляет несколько функций для работы с XML, которые при некорректных аргументах генерируют ошибки с включением переданных данных. К таким функциям относятся ExtractValue и UpdateXML. Они были добавлены для поддержки XPATH-запросов, но часто используются пентестерами для извлечения информации.

Разбор функции ExtractValue

Синтаксис функции: EXTRACTVALUE(XML_document, XPath_expression). Она извлекает значение из XML-документа по заданному XPath-выражению. Если XPath-выражение содержит недопустимые символы, MySQL возвращает ошибку вида: XPATH syntax error: '...'. В эту ошибку попадает часть переданного XPath-выражения. Именно это и эксплуатируется.

В нашем запросе: EXTRACTVALUE(1898, CONCAT(0x7e, ((SELECT (ELT(1898=1898,1)))), 0x7e)). Первый аргумент — число 1898 (может быть любым, он не влияет на ошибку). Второй аргумент — результат CONCAT, который начинается и заканчивается символом ~ (0x7e). Внутри — подзапрос SELECT (ELT(1898=1898,1)).

Функция ELT возвращает N-й элемент из списка. Здесь ELT(1898=1898,1): условие 1898=1898 истинно (равно 1), поэтому ELT вернёт первый элемент — число 1. Таким образом, CONCAT собирает строку ~1~. ExtractValue попытается интерпретировать её как XPath, что вызовет ошибку: XPATH syntax error: '~1~'. В реальной атаке вместо 1 подставляется подзапрос, извлекающий данные (например, имя базы, таблицы, хеши паролей).

Синтаксис и особенности запроса

Обратите внимание на обрамление: ))) AND ... -- -. Три закрывающие скобки в начале нужны, чтобы закрыть ранее открытые скобки в оригинальном запросе приложения. Это типичный приём при инъекции в параметры, которые уже находятся внутри скобок. Двойной дефис с пробелом (-- -) — комментарий в MySQL, который отсекает оставшуюся часть оригинального запроса.

Символ ~ (тильда) используется как маркер, чтобы облегчить поиск выведенных данных в тексте ошибки. Он не является обязательным, но часто применяется для удобства.

Пошаговый механизм атаки

  1. Определение точки инъекции. Злоумышленник находит параметр, который попадает в SQL-запрос без должной обработки. Например, ?id=1.
  2. Проверка уязвимости. Подставляется ' или ) и наблюдается ошибка синтаксиса.
  3. Использование ExtractValue. Формируется запрос, который вызывает ошибку с внедрёнными данными. Например: AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e)).
  4. Извлечение данных. В сообщении об ошибке возвращается имя текущей базы данных, например ~myapp_db~.
  5. Итеративное получение информации. Меняя подзапрос, можно извлечь имена таблиц, столбцов, логины, пароли и другие конфиденциальные данные.

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

Вот несколько вариантов инъекций с ExtractValue для разных целей:

  • Получение версии MySQL: AND EXTRACTVALUE(1, CONCAT(0x7e, version(), 0x7e))
  • Получение имени пользователя БД: AND EXTRACTVALUE(1, CONCAT(0x7e, user(), 0x7e))
  • Получение списка таблиц: AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables LIMIT 0,1), 0x7e))

Аналогично работает функция UpdateXML, но с slightly другим синтаксисом.

Ограничения и обход защиты

Длина выводимой строки в ошибке ExtractValue ограничена 32 символами. Для извлечения длинных данных используют функцию SUBSTRING или MID, посимвольно или по частям. Также современные WAF могут блокировать ключевые слова EXTRACTVALUE, CONCAT, SELECT. В таких случаях применяют обфускацию: замену регистра, вставку комментариев /**/, использование шестнадцатеричных литералов.

Некоторые хостинги отключают вывод ошибок MySQL в ответах приложения, что делает error-based инъекции неэффективными. Тогда злоумышленники переходят к blind-инъекциям (boolean-based или time-based).

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

Основной метод защиты — использование параметризованных запросов (prepared statements) с привязкой переменных. Это исключает попадание пользовательских данных в тело SQL-запроса как исполняемого кода.

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

  • Валидация и фильтрация всех входных данных (белые списки).
  • Применение ORM (например, Hibernate, Entity Framework).
  • Ограничение прав пользователя БД: только необходимые операции.
  • Отключение вывода подробных ошибок в production.
  • Использование WAF для обнаружения и блокировки атак.
  • Регулярное обновление СУБД и фреймворков.
Согласно OWASP, SQL-инъекции остаются в Top 10 уже более десяти лет. Правильная архитектура приложения и параметризация запросов полностью устраняют эту уязвимость.

Заключение

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

Источники