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

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

Запрос, который мы разбираем, — это классический пример эксплуатации слепой SQL-инъекции (blind SQL injection) в СУБД MySQL. Строка %")) AND EXTRACTVALUE(6337,CONCAT(0x7e,((SELECT (ELT(6337=6337,1)))),0x7e))-- - содержит сразу несколько интересных приёмов: использование функции EXTRACTVALUE для вызова ошибки, конкатенацию через CONCAT и функцию ELT для проверки условия.

Разбор структуры запроса

Давайте разберём строку по частям, чтобы понять логику атакующего.

1. Начало: %"))

Символы %")) — это попытка закрыть существующий SQL-запрос. Знак процента часто используется в LIKE-запросах, а кавычка и две закрывающие скобки помогают «разорвать» оригинальное выражение. Например, если исходный запрос выглядел как SELECT * FROM users WHERE name LIKE '%...%', то внедрение %")) позволяет выйти за пределы строкового литерала и добавить собственные условия.

2. Логическое условие: AND EXTRACTVALUE(...)

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

3. Функция EXTRACTVALUE

EXTRACTVALUE(XML_document, XPath_expression) — это функция MySQL, предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Однако она нашла неожиданное применение в SQL-инъекциях. Дело в том, что если XPath-выражение содержит недопустимые символы (например, тильду ~), функция генерирует ошибку, в тексте которой выводится переданное значение. Это позволяет атакующему извлекать данные из базы через сообщения об ошибках.

В нашем запросе EXTRACTVALUE вызывается с двумя аргументами: 6337 и результатом CONCAT. Первый аргумент — произвольное число, которое не играет роли. Второй аргумент — это XPath-выражение, которое намеренно делается некорректным, чтобы вызвать ошибку с полезной нагрузкой.

4. CONCAT и 0x7e

CONCAT объединяет строки. В данном случае она склеивает тильду (0x7e — шестнадцатеричное представление символа ~), результат подзапроса и ещё одну тильду. Тильда выбрана потому, что она недопустима в XPath и гарантированно вызовет ошибку. В сообщении об ошибке MySQL отобразит что-то вроде: XPATH syntax error: '~1~' — где между тильдами будет результат подзапроса.

5. Подзапрос: (SELECT (ELT(6337=6337,1)))

Здесь используется функция ELT(N, str1, str2, ...), которая возвращает N-ю строку из списка. Выражение 6337=6337 всегда истинно (1), поэтому ELT(1, 1) возвращает 1. Это простейший пример: атакующий проверяет, что механизм работает. В реальной атаке вместо 6337=6337 могло бы стоять условие, проверяющее, например, первый символ имени пользователя: SUBSTRING((SELECT user()),1,1)='a'. Если условие истинно, ELT вернёт 1, и в ошибке появится ~1~; если ложно — ELT вернёт NULL или другое значение, и ошибка будет иной.

6. Комментарий: -- -

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

Как работает атака целиком

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

SELECT * FROM articles WHERE title LIKE '%ЗАПРОС%'

Подставляя нашу строку, получаем:

SELECT * FROM articles WHERE title LIKE '%%")) AND EXTRACTVALUE(6337,CONCAT(0x7e,((SELECT (ELT(6337=6337,1)))),0x7e))-- -%'

После закрытия кавычки и скобок запрос превращается в:

SELECT * FROM articles WHERE title LIKE '%%")) AND EXTRACTVALUE(6337,CONCAT(0x7e,((SELECT (ELT(6337=6337,1)))),0x7e))

База данных выполняет EXTRACTVALUE, который пытается разобрать XPath ~1~. Это вызывает ошибку, и в ответе приложения (если ошибки выводятся) появляется сообщение с результатом подзапроса. Так атакующий может извлекать данные посимвольно, задавая разные условия в ELT.

Какие уязвимости эксплуатируются

  • Отсутствие параметризации запросов. Если бы приложение использовало подготовленные выражения (prepared statements), внедрение строки было бы невозможно.
  • Некорректная обработка ошибок. Вывод ошибок СУБД на страницу позволяет злоумышленнику получать данные через сообщения.
  • Устаревшие функции MySQL. EXTRACTVALUE и подобные (UPDATEXML) считаются устаревшими и не рекомендуются к использованию, но всё ещё встречаются в старых приложениях.

Как защититься от подобных атак

  1. Используйте параметризованные запросы. Это самый надёжный способ: данные передаются отдельно от SQL-кода и не могут изменить структуру запроса.
  2. Экранируйте специальные символы. Если параметризация невозможна, применяйте функции экранирования, предоставляемые драйвером БД.
  3. Отключите вывод ошибок СУБД. Пользователь не должен видеть сообщения об ошибках базы данных. Логируйте их, но не показывайте.
  4. Ограничьте права пользователя БД. Приложение должно работать с минимально необходимыми привилегиями.
  5. Регулярно обновляйте СУБД и фреймворки. Устаревшие функции могут быть удалены в новых версиях, что снизит риск.
  6. Используйте WAF. Веб-application firewall может блокировать известные шаблоны инъекций, но не полагайтесь только на него.

Заключение

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

Источники