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

SQL-инъекция — один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет вредоносный SQL-код в запросы к базе данных. В данном запросе используется специфичная полезная нагрузка: )) OR EXTRACTVALUE(3563,CONCAT(0x7e,((SELECT (ELT(3563=3563,1)))),0x7e))-- -. Она предназначена для извлечения информации через ошибки, генерируемые функцией EXTRACTVALUE в СУБД MySQL или MariaDB.

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

Разбор полезной нагрузки по частям

Рассмотрим каждый элемент запроса подробно.

1. Двойная закрывающая скобка ))

Она используется для завершения оригинального SQL-запроса, который, вероятно, содержит вложенные функции или условия. Например, если исходный запрос выглядит как SELECT * FROM users WHERE id = (SELECT ...), то две скобки закрывают внутренние подзапросы, позволяя внедрить собственный код.

2. Оператор OR

Логическое «ИЛИ» делает условие всегда истинным, если правая часть вернёт true. Это часто применяется для обхода аутентификации или для того, чтобы запрос выполнился, даже если исходное условие ложно.

3. Функция EXTRACTVALUE(3563, CONCAT(...))

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

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

4. CONCAT(0x7e, ((SELECT (ELT(3563=3563,1)))), 0x7e)

CONCAT объединяет строки. Здесь 0x7e — это шестнадцатеричное представление символа тильды (~). Тильды используются как маркеры, чтобы облегчить поиск выводимых данных в сообщении об ошибке.

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

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

Два дефиса с пробелом или без (в MySQL требуется пробел или другой символ после --) превращают остаток строки в комментарий. Это позволяет отбросить оригинальное продолжение SQL-запроса, которое могло бы вызвать синтаксическую ошибку.

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

Предположим, уязвимый параметр id в URL: https://example.com/product?id=1. Приложение формирует запрос:

SELECT * FROM products WHERE id = (1)

Злоумышленник подставляет:

1)) OR EXTRACTVALUE(3563,CONCAT(0x7e,((SELECT (ELT(3563=3563,1)))),0x7e))-- -

Итоговый запрос:

SELECT * FROM products WHERE id = (1)) OR EXTRACTVALUE(3563,CONCAT(0x7e,((SELECT (ELT(3563=3563,1)))),0x7e))-- -)

База данных выполняет EXTRACTVALUE, который пытается интерпретировать число 3563 как XML. Это вызывает ошибку вида: XPATH syntax error: '~1~'. В сообщении об ошибке возвращается значение, переданное в CONCAT, — в нашем случае ~1~. Если вместо 1 подставить подзапрос, например (SELECT version()), то в ошибке появится версия СУБД. Так по крупицам злоумышленник извлекает данные.

Какие данные можно получить

  • Версию базы данных и операционной системы.
  • Имена таблиц и столбцов из информационной схемы.
  • Логины и пароли пользователей (хеши).
  • Любую другую информацию, доступную текущему пользователю БД.

Для автоматизации часто используются инструменты вроде sqlmap, которые генерируют подобные полезные нагрузки и извлекают данные через ошибки.

Меры защиты от SQL-инъекций

Главный способ защиты — использование параметризованных запросов (prepared statements). Это исключает возможность внедрения SQL-кода, так как данные передаются отдельно от структуры запроса. Дополнительные меры:

  • Экранирование специальных символов с помощью функций вроде mysqli_real_escape_string.
  • Ограничение прав пользователя базы данных: не давать прав на чтение системных таблиц.
  • Отключение вывода ошибок СУБД в production-окружении, чтобы злоумышленник не мог получить данные через сообщения.
  • Использование WAF (Web Application Firewall) для фильтрации подозрительных запросов.
  • Регулярное обновление СУБД и фреймворков.
Важно: даже если ошибки не выводятся пользователю, они могут попадать в логи, которые злоумышленник может прочитать при недостаточной защите.

Заключение

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

Источники