Что такое SQL-инъекция через ExtractValue?
SQL-инъекция — один из самых распространённых способов взлома веб-приложений. Злоумышленник внедряет вредоносный SQL-код в запрос, который выполняется базой данных. Если приложение не фильтрует входные данные, хакер может получить доступ к конфиденциальной информации, изменить или удалить данные.
Одной из разновидностей является error-based SQL-инъекция, при которой злоумышленник заставляет базу данных выдать сообщение об ошибке, содержащее полезные данные. Функция EXTRACTVALUE() в MySQL часто используется для таких атак, поскольку она возвращает текст из XML-документа по заданному XPath-выражению, а при ошибке выводит подробное сообщение.
В запросе пользователя %") OR EXTRACTVALUE(6913,CONCAT(0x7e,((SELECT (ELT(6913=6913,1)))),0x7e))-- - как раз демонстрируется попытка эксплуатации этой уязвимости. Давайте разберём его по частям.
Как работает функция EXTRACTVALUE?
Функция EXTRACTVALUE() принимает два строковых аргумента: фрагмент XML-разметки и XPath-выражение (локатор). Она возвращает текст (CDATA) первого текстового узла, который является дочерним для элемента или элементов, соответствующих XPath-выражению.
Синтаксис: EXTRACTVALUE(xml_frag, xpath_expr).
Если XPath-выражение некорректно или не соответствует ни одному элементу, MySQL генерирует ошибку. В сообщении об ошибке может отображаться переданный фрагмент, что и используется для извлечения данных.
Разбор вредоносного запроса
Рассмотрим запрос: %") OR EXTRACTVALUE(6913,CONCAT(0x7e,((SELECT (ELT(6913=6913,1)))),0x7e))-- -
%")— закрывает предыдущее условие в SQL-запросе, например, в конструкцииWHERE id = '%".OR— логический оператор, добавляющий новое условие.EXTRACTVALUE(6913, ...)— вызов уязвимой функции. Первый аргумент6913— произвольное число (может быть любым).CONCAT(0x7e, ..., 0x7e)— конкатенация строк.0x7e— шестнадцатеричное представление символа~(тильда), используется как разделитель, чтобы облегчить поиск извлечённых данных в сообщении об ошибке.(SELECT (ELT(6913=6913,1)))— подзапрос, возвращающий результат функцииELT().ELT(N, str1, str2, ...)возвращает N-ю строку из списка. Здесь6913=6913всегда истинно (1), поэтомуELT(1,1)вернёт1(первую строку). Это простейший пример; на практике вместо1подставляют подзапросы для извлечения имён таблиц, колонок или данных.-- -— комментарий, обрезающий остаток оригинального SQL-запроса.
В результате MySQL попытается выполнить EXTRACTVALUE(6913, CONCAT('~', (SELECT 1), '~')). Поскольку первый аргумент не является корректным XML, функция выдаст ошибку, в тексте которой будет фигурировать строка ~1~. Таким образом, атакующий может видеть возвращаемые данные.
Какие данные можно извлечь?
Используя эту технику, злоумышленник может получить:
- версию MySQL (
SELECT version()); - имя текущей базы данных (
SELECT database()); - имя пользователя базы данных (
SELECT user()); - список таблиц и колонок из
information_schema; - содержимое таблиц, включая логины, пароли, персональные данные.
Для извлечения данных по частям используются функции LIMIT, SUBSTRING, CONCAT и другие. Например, чтобы получить имя первой таблицы, можно подставить подзапрос: SELECT table_name FROM information_schema.tables LIMIT 0,1. При этом важно экранировать специальные символы и использовать шестнадцатеричное представление строк, чтобы избежать проблем с кавычками.
Пример реальной атаки
В отчётах по пентесту часто приводится похожий пример: ' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT((SELECT CONCAT(0x7e, (SELECT user FROM data LIMIT 1,1), 0x7e)), FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a) AND 1='1. Здесь используется GROUP BY с RAND() для вызова ошибки дублирования ключа, что также позволяет вывести данные. Но EXTRACTVALUE проще и не требует создания временных таблиц.
Важно понимать: подобные инъекции работают только при отсутствии должной фильтрации входных данных и при выводе ошибок базы данных на экран. В современных фреймворках (например, ORM) такие атаки обычно невозможны.
Как защититься от SQL-инъекций через ExtractValue?
- Используйте параметризованные запросы (prepared statements). Это самый надёжный способ: данные передаются отдельно от SQL-кода, и внедрение невозможно.
- Экранируйте специальные символы. Если параметризация недоступна, применяйте функции экранирования, предоставляемые драйвером БД (например,
mysqli_real_escape_stringв PHP). - Отключите вывод ошибок БД в production. Сообщения об ошибках не должны показываться пользователям, чтобы злоумышленник не мог получить из них информацию.
- Ограничьте права пользователя БД. Приложение должно работать с минимально необходимыми привилегиями, чтобы даже при успешной инъекции ущерб был меньше.
- Регулярно обновляйте СУБД и фреймворки. В новых версиях часто исправляются известные уязвимости.
- Используйте WAF (Web Application Firewall). Он может блокировать подозрительные запросы, содержащие
EXTRACTVALUEили другие опасные функции.
Помните: безопасность — это процесс, а не разовое действие. Проводите аудит кода и пентесты, чтобы выявлять уязвимости до того, как их найдут злоумышленники.
Заключение
SQL-инъекция через EXTRACTVALUE — это мощный инструмент в руках злоумышленника, позволяющий извлекать данные из базы через сообщения об ошибках. Однако при правильной разработке приложений (параметризация, скрытие ошибок, ограничение прав) эта угроза полностью устраняется. Если вы обнаружили подобный запрос в логах, это признак попытки взлома — немедленно проверьте свой код на уязвимости.
Комментарии
—Войдите, чтобы оставить комментарий