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

SQL-инъекция (SQL injection) — один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет в пользовательский ввод специально сконструированные SQL-запросы. Цель — получить доступ к данным, изменить их или выполнить произвольные команды на сервере базы данных. Если приложение не фильтрует входные параметры, база данных может воспринять часть ввода как исполняемый код.

Существует несколько разновидностей SQL-инъекций: union-based, boolean-based, time-based и error-based. Строка, которую мы разбираем, относится к последнему типу — error-based SQL-инъекции. Она заставляет СУБД MySQL сгенерировать ошибку, содержащую результат выполнения вложенного запроса, который затем отображается в ответе сервера.

Расшифровка строки %' OR EXTRACTVALUE(7996,CONCAT(0x7e,((SELECT (ELT(7996=7996,1)))),0x7e))-- -

Давайте разберём этот запрос по частям, чтобы понять его назначение.

  • %' — это начало внедрения. Символ % часто используется в LIKE-запросах как шаблон, а одинарная кавычка ' закрывает строковый литерал в оригинальном SQL-запросе. Таким образом, атакующий «вырывается» из контекста и добавляет свой код.
  • OR — логический оператор, который делает условие всегда истинным или позволяет внедрить дополнительное выражение.
  • EXTRACTVALUE(7996, CONCAT(0x7e, ((SELECT (ELT(7996=7996,1)))), 0x7e)) — это функция MySQL, предназначенная для извлечения значения из XML-строки. Она принимает два аргумента: XML-документ и XPath-выражение. Если XPath-выражение некорректно, MySQL выдаёт ошибку, в тексте которой отображается переданное значение. Это и есть основа error-based инъекции.
  • CONCAT(0x7e, ..., 0x7e) — объединяет символ ~ (hex-код 0x7e) с результатом подзапроса, чтобы отделить его в сообщении об ошибке.
  • (SELECT (ELT(7996=7996,1))) — подзапрос, который возвращает число 1, если условие 7996=7996 истинно. Функция ELT() возвращает N-й элемент из списка. Здесь она используется для демонстрации: в реальной атаке вместо этого подзапроса злоумышленник вставляет запрос к системным таблицам, например, SELECT table_name FROM information_schema.tables LIMIT 1.
  • -- - — комментарий, который «отрезает» оставшуюся часть оригинального SQL-запроса, чтобы не возникло синтаксической ошибки.

Таким образом, вся конструкция заставляет базу данных выполнить подзапрос и вывести его результат в сообщении об ошибке. Это позволяет атакующему извлекать произвольные данные: имена таблиц, столбцов, логины, пароли и другую конфиденциальную информацию.

Как работает error-based SQL-инъекция в MySQL?

MySQL возвращает детализированные сообщения об ошибках, если включён режим отладки или стандартный уровень логирования. Функции EXTRACTVALUE и UPDATEXML специально используются для генерации ошибок, содержащих данные. Например, если передать в EXTRACTVALUE некорректный XPath, сервер ответит примерно так: XPATH syntax error: '~1~'. Всё, что находится между тильдами, — это результат внедрённого запроса.

Атакующий может последовательно менять условия и извлекать по одному значению за раз. Например, чтобы получить имя первой таблицы в базе, он подставит подзапрос:
EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables LIMIT 0,1), 0x7e)).
Затем изменит LIMIT 0,1 на LIMIT 1,1 и так далее. Этот метод называется «пошаговым извлечением данных».

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

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

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

Часто такие инъекции автоматизируются с помощью инструментов вроде sqlmap, что делает атаку быстрой и малозаметной.

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

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

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

  • Валидация и фильтрация входных данных: проверяйте типы, длины, допустимые символы. Например, если ожидается число, отклоняйте всё, кроме цифр.
  • Экранирование специальных символов: используйте встроенные функции СУБД или библиотеки для экранирования кавычек и других опасных символов.
  • Минимизация привилегий: учётная запись, под которой работает приложение, должна иметь только необходимые права. Никогда не используйте root для веб-приложений.
  • Отключение подробных сообщений об ошибках: на продакшене не показывайте пользователям текст ошибок СУБД. Это затруднит эксплуатацию error-based инъекций.
  • Регулярное обновление СУБД и фреймворков: закрывайте известные уязвимости.
  • Использование WAF (Web Application Firewall): современные WAF могут обнаруживать и блокировать попытки SQL-инъекций по сигнатурам.
Помните: безопасность — это процесс, а не разовое действие. Регулярно проводите аудит кода и тестирование на проникновение.

Заключение

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

Источники