Введение
Строка )) AND EXTRACTVALUE(5900,CONCAT(0x7e,((SELECT (ELT(5900=5900,1)))),0x7e))-- - — это типичный пример SQL-инъекции, нацеленной на базу данных MySQL. Она использует функцию EXTRACTVALUE вместе с CONCAT для извлечения информации из базы данных через сообщения об ошибках. В этой статье мы подробно разберём, как работает такой запрос, зачем он нужен злоумышленникам и как защититься от подобных атак.
Что такое SQL-инъекция?
SQL-инъекция (SQL injection) — это один из самых распространённых способов взлома веб-приложений. Злоумышленник вставляет вредоносный SQL-код в поля ввода или параметры URL, чтобы заставить базу данных выполнить нежелательные действия: получить доступ к конфиденциальным данным, изменить или удалить информацию.
Существует несколько разновидностей SQL-инъекций:
- Классическая инъекция — когда результаты запроса отображаются на странице.
- Слепая инъекция — когда данные извлекаются по косвенным признакам (например, по времени ответа или по сообщениям об ошибках).
- Инъекция на основе ошибок (error-based) — когда информация извлекается через сообщения об ошибках базы данных. Именно к этому типу относится наш пример с EXTRACTVALUE.
Функция EXTRACTVALUE в MySQL
EXTRACTVALUE — это встроенная функция MySQL (до версии 8.0), предназначенная для работы с XML-документами. Она извлекает значение из XML-строки по заданному XPath-выражению. Синтаксис:
EXTRACTVALUE(XML_фрагмент, XPath_выражение)
Например, EXTRACTVALUE('<a><b>текст</b></a>', '/a/b') вернёт текст.
Однако если XPath-выражение некорректно, MySQL выдаёт ошибку, в тексте которой может содержаться переданное значение. Этим и пользуются злоумышленники: они подставляют в XPath результат подзапроса, и если он не является валидным XPath, база данных возвращает ошибку с этим значением. Так происходит утечка данных.
Функция CONCAT
CONCAT — это функция для объединения строк. В нашем примере она используется, чтобы обернуть извлекаемые данные символами 0x7e (тильда ~). Это делается для того, чтобы в сообщении об ошибке было легко найти границы выводимой информации.
Разбор запроса по частям
Рассмотрим строку )) AND EXTRACTVALUE(5900,CONCAT(0x7e,((SELECT (ELT(5900=5900,1)))),0x7e))-- - детально.
))— закрывающие скобки, которые завершают предыдущее выражение в оригинальном запросе. Злоумышленник подставляет свой код после них.AND— логический оператор, который добавляет условие к исходному запросу. Если исходный запрос был истинным, добавлениеAND ...заставит базу данных вычислить и наше выражение.EXTRACTVALUE(5900, ...)— вызов функции. Первый аргумент5900— это произвольное число, которое будет использовано как XML-фрагмент. Так как это не XML, функция всё равно попытается разобрать его и выдаст ошибку, но перед этим вычислит второй аргумент.CONCAT(0x7e, ((SELECT (ELT(5900=5900,1)))), 0x7e)— второй аргумент. Здесь0x7e— это шестнадцатеричное представление символа~. Внутри CONCAT выполняется подзапросSELECT (ELT(5900=5900,1)).ELT(5900=5900,1)— функция ELT возвращает N-й элемент из списка. Если условие5900=5900истинно (а это всегда так), то выражение принимает значение 1, и ELT возвращает первый элемент — число 1. Фактически это заглушка, которая всегда возвращает 1. В реальной атаке вместоELT(5900=5900,1)мог бы быть, например,(SELECT database())или(SELECT version()).-- -— комментарий, который отсекает оставшуюся часть оригинального SQL-запроса, чтобы не возникло синтаксической ошибки.
Таким образом, при выполнении этого запроса MySQL попытается вычислить EXTRACTVALUE(5900, CONCAT('~', '1', '~')). Поскольку 5900 не является корректным XML, функция выдаст ошибку вида: XPATH syntax error: '~1~'. В сообщении об ошибке появится значение ~1~. Если вместо 1 подставить подзапрос, возвращающий имя базы данных, то в ошибке отобразится это имя. Так злоумышленник может извлекать любые данные.
Зачем это нужно злоумышленнику?
Основная цель — получить информацию о структуре базы данных и её содержимом. С помощью error-based инъекций можно узнать:
- имя текущей базы данных (
database()); - версию MySQL (
version()); - список таблиц и колонок из
information_schema; - логины и пароли пользователей, хранящиеся в таблицах.
Функция EXTRACTVALUE позволяет вытаскивать данные по одному значению за раз, что делает процесс медленным, но эффективным при отсутствии других каналов.
Как защититься от SQL-инъекций?
Лучший способ защиты — использовать параметризованные запросы (prepared statements). Они разделяют код SQL и данные, поэтому введённые пользователем строки никогда не интерпретируются как SQL-код.
Дополнительные меры:
- Использовать ORM (например, Hibernate, Entity Framework) или библиотеки, которые автоматически экранируют данные.
- Проводить валидацию и фильтрацию всех входных данных на стороне сервера.
- Ограничить права пользователя базы данных, от имени которого работает приложение: запретить доступ к
information_schema, если он не нужен. - Отключить вывод ошибок базы данных в production-окружении, чтобы злоумышленник не мог использовать error-based инъекции.
- Регулярно обновлять СУБД и фреймворки, так как в новых версиях MySQL функции EXTRACTVALUE и UPDATEXML были удалены (начиная с MySQL 8.0.17) именно из-за их опасности.
Заключение
Строка )) AND EXTRACTVALUE(5900,CONCAT(0x7e,((SELECT (ELT(5900=5900,1)))),0x7e))-- - — это учебный пример error-based SQL-инъекции. В реальной атаке вместо ELT(5900=5900,1) подставляются подзапросы, извлекающие конфиденциальные данные. Понимание механизма таких атак помогает разработчикам писать безопасный код и защищать веб-приложения.
Комментарии
—Войдите, чтобы оставить комментарий