Что такое SQL-инъекция через EXTRACTVALUE?
SQL-инъекция — один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет в запрос произвольный SQL-код. Функция EXTRACTVALUE в MySQL (и MariaDB) предназначена для извлечения значения из XML-документа по заданному XPath-выражению. Однако при неправильной обработке пользовательского ввода она может стать инструментом для извлечения данных из базы через механизм ошибок.
В запросе пользователя фигурирует следующий payload:
'))) AND EXTRACTVALUE(4701,CONCAT(0x7e,((SELECT (ELT(4701=4701,1)))),0x7e))-- -
Это классическая инъекция, использующая ошибку синтаксического разбора XPath для вывода результата подзапроса в сообщении об ошибке. Ниже мы разберём каждый элемент этой конструкции.
Анатомия payload
Payload состоит из нескольких логических частей:
')))— закрывающие кавычка и скобки, которые «ломают» исходный SQL-запрос, делая его синтаксически корректным для внедрения.AND— логический оператор, позволяющий добавить условие к существующему запросу.EXTRACTVALUE(4701, CONCAT(...))— вызов уязвимой функции. Первый аргумент (4701) — произвольный XML-документ (число преобразуется в строку), второй — XPath-выражение, формируемое динамически.CONCAT(0x7e, ((SELECT (ELT(4701=4701,1)))), 0x7e)— конкатенация тильды (0x7e— шестнадцатеричный код символа~), результата подзапроса и ещё одной тильды.-- -— комментарий, обрезающий остаток исходного запроса.
Зачем нужен символ 0x7e (тильда)?
Функция EXTRACTVALUE ожидает корректное XPath-выражение. Символ ~ не является допустимым в XPath, поэтому при попытке разбора строки, начинающейся с тильды, MySQL генерирует ошибку вида:
XPATH syntax error: '~1~'
В сообщении об ошибке отображается часть переданного XPath-выражения, а именно результат подзапроса, обёрнутый тильдами. Это позволяет злоумышленнику «прочитать» данные, которые возвращает вложенный SELECT. Тильда используется как маркер, чтобы отделить полезную нагрузку от служебных символов и облегчить автоматический парсинг результата.
Подзапрос с ELT и условием 4701=4701
Конструкция SELECT (ELT(4701=4701,1)) в данном случае возвращает строку '1'. Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Условие 4701=4701 всегда истинно, поэтому ELT возвращает первый элемент — 1. Это простейший пример; на практике вместо ELT с фиксированным значением злоумышленники подставляют подзапросы, извлекающие имена таблиц, столбцов или конкретные данные (например, логины и пароли).
В реальных атаках payload может выглядеть так:
EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE()), 0x7e))
Это позволяет получить список таблиц текущей базы данных в одном сообщении об ошибке.
Как работает инъекция по шагам
- Приложение формирует SQL-запрос, подставляя пользовательский ввод без должной очистки. Например:
SELECT * FROM users WHERE id = 'ВВОД'. - Злоумышленник передаёт строку
'))) AND EXTRACTVALUE(...)-- -, которая закрывает кавычку и скобки, добавляет логическое условие и комментарий. - Итоговый запрос выполняется, вызывая функцию EXTRACTVALUE с заведомо некорректным XPath.
- MySQL возвращает ошибку синтаксиса XPath, в тексте которой содержится результат подзапроса (например,
~1~). - Злоумышленник (или автоматизированный инструмент) извлекает данные из сообщения об ошибке.
Этот метод относится к категории error-based SQL-инъекций и часто используется, когда приложение не выводит результаты запроса напрямую, но отображает сообщения об ошибках базы данных.
Меры защиты
Чтобы предотвратить подобные атаки, необходимо:
- Использовать параметризованные запросы (prepared statements) — это самый надёжный способ отделить код от данных.
- Экранировать специальные символы при невозможности использования параметризации (например, с помощью функций экранирования драйвера БД).
- Отключить вывод подробных ошибок в production-окружении, чтобы сообщения СУБД не попадали к пользователю.
- Применять принцип минимальных привилегий для учётной записи базы данных, используемой веб-приложением.
- Регулярно проводить аудит кода и использовать сканеры уязвимостей (SAST/DAST).
Функция EXTRACTVALUE сама по себе не является уязвимостью — проблема кроется в небезопасном построении SQL-запросов. Тем не менее, в современных версиях MySQL (начиная с 5.7) она помечена как устаревшая, и её использование не рекомендуется. Для извлечения данных из XML лучше применять функцию XMLQUERY или другие поддерживаемые методы.
Заключение
Payload '))) AND EXTRACTVALUE(4701,CONCAT(0x7e,((SELECT (ELT(4701=4701,1)))),0x7e))-- - — это компактный пример error-based SQL-инъекции, эксплуатирующей функцию EXTRACTVALUE для вывода данных через сообщение об ошибке. Понимание механики таких атак помогает разработчикам и специалистам по безопасности эффективнее защищать веб-приложения. Главный вывод: никогда не подставляйте пользовательский ввод в SQL-запросы напрямую и всегда используйте параметризацию.
Комментарии
—Войдите, чтобы оставить комментарий