Что такое SQL-инъекция через EXTRACTVALUE?
SQL-инъекция (SQLi) — один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет вредоносный SQL-код в запросы к базе данных. Error-based SQL-инъекция — это техника, при которой атакующий заставляет сервер вернуть сообщение об ошибке, содержащее полезные данные (например, имена таблиц, столбцов или пароли). Функция EXTRACTVALUE в MySQL используется для извлечения значения из XML-строки по заданному XPath-выражению. Однако при неправильной обработке входных данных она может стать инструментом для извлечения информации из базы.
Рассматриваемый запрос: "))) AND EXTRACTVALUE(9798,CONCAT(0x7e,((SELECT (ELT(9798=9798,1)))),0x7e))-- - — это классическая полезная нагрузка для error-based SQL-инъекции. Давайте разберём её по частям.
Детальный разбор полезной нагрузки
Начнём с начала:
")))— последовательность закрывающих кавычек и скобок. Она нужна, чтобы «закрыть» ранее открытые в уязвимом запросе конструкции (например, строковые литералы или вызовы функций) и сделать возможным внедрение собственного SQL-кода. Количество и тип символов зависят от контекста исходного запроса.AND— логический оператор, присоединяющий наше условие к оригинальному запросу. Если исходный запрос был истинным, то добавлениеAND ...не изменит результат, но позволит выполнить внедрённую функцию.EXTRACTVALUE(9798, CONCAT(0x7e, ((SELECT (ELT(9798=9798,1)))), 0x7e))— это и есть ядро атаки. Функция EXTRACTVALUE принимает два аргумента: XML-документ (в нашем случае число 9798, которое не является валидным XML) и XPath-выражение. Второй аргумент формируется с помощью CONCAT, который объединяет тильду (0x7e— шестнадцатеричное представление символа ~), результат подзапроса и ещё одну тильду.SELECT (ELT(9798=9798,1))— это подзапрос, возвращающий значение. ELT — функция, возвращающая N-й элемент из списка. Здесь9798=9798— всегда истина (1), поэтомуELT(1,1)вернёт первый элемент из списка, то есть 1. Это просто демонстрация: в реальной атаке вместо1могло бы быть имя таблицы, столбца или хеш пароля.-- -— комментарий, который «отрезает» оставшуюся часть оригинального SQL-запроса, чтобы не возникло синтаксических ошибок. Пробел после двух дефисов обязателен в MySQL.
Когда MySQL выполняет этот запрос, функция EXTRACTVALUE пытается интерпретировать число 9798 как XML. Это вызывает ошибку, и в сообщении об ошибке MySQL выводит вторую часть XPath-выражения, то есть строку, полученную в результате CONCAT. Таким образом, атакующий видит на экране (или в логах) значение, возвращённое подзапросом, — в нашем примере это ~1~. В реальной атаке вместо 1 подставляется полезная информация, например, версия СУБД, имя текущей базы данных или данные из таблиц.
Как это работает на практике
Предположим, уязвимый запрос выглядит так: SELECT * FROM users WHERE id = '"))) AND EXTRACTVALUE(...)-- -'. После подстановки полезной нагрузки запрос становится синтаксически корректным, но EXTRACTVALUE вызывает ошибку, и MySQL возвращает что-то вроде:
XPATH syntax error: '~1~'
Это сообщение содержит результат выполнения подзапроса. Меняя подзапрос, злоумышленник может извлекать произвольные данные. Например, чтобы получить имя текущей базы данных, можно использовать:
AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))-- -
Тогда в ошибке появится имя базы. Аналогично можно получить версию MySQL (SELECT version()), список таблиц (SELECT table_name FROM information_schema.tables) и так далее.
Однако у EXTRACTVALUE есть ограничение: длина выводимой строки не должна превышать 32 символа. Поэтому для извлечения длинных данных используют посимвольное чтение или другие функции, например, UPDATEXML.
Зачем нужна конструкция ELT(9798=9798,1)?
В данном примере ELT(9798=9798,1) — это просто заглушка, демонстрирующая работу функции ELT. В реальных атаках вместо неё подставляют подзапрос, возвращающий нужные данные. Например, ELT(1, (SELECT user())) вернёт имя текущего пользователя MySQL. Но поскольку EXTRACTVALUE ожидает строку, а ELT возвращает значение, его приводят к строке или оборачивают в CONCAT.
Важно понимать, что вся конструкция CONCAT(0x7e, ((SELECT ...)), 0x7e) нужна для того, чтобы отделить выводимые данные от служебного текста ошибки. Тильды (~) служат маркерами начала и конца полезной нагрузки в сообщении об ошибке.
Методы защиты от error-based SQL-инъекций
Чтобы предотвратить подобные атаки, разработчикам следует придерживаться следующих правил:
- Использовать подготовленные выражения (prepared statements) с параметризацией. Это самый надёжный способ, так как данные не попадают в SQL-код напрямую.
- Экранировать специальные символы. Если по каким-то причинам параметризация недоступна, необходимо применять функции экранирования, например,
mysqli_real_escape_string. - Ограничить права пользователя базы данных. Веб-приложение должно работать с минимально необходимыми привилегиями, чтобы даже при успешной инъекции злоумышленник не смог получить доступ к системным таблицам.
- Отключить вывод подробных ошибок в production. Сообщения об ошибках не должны показываться пользователям, чтобы не раскрывать структуру базы данных.
- Использовать WAF (Web Application Firewall). Современные WAF умеют распознавать типовые полезные нагрузки SQL-инъекций, включая EXTRACTVALUE.
Также рекомендуется проводить регулярные аудиты кода и пентесты для выявления уязвимостей.
Заключение
Полезная нагрузка "))) AND EXTRACTVALUE(9798,CONCAT(0x7e,((SELECT (ELT(9798=9798,1)))),0x7e))-- - — это пример error-based SQL-инъекции, эксплуатирующей функцию EXTRACTVALUE в MySQL. Она позволяет атакующему извлекать данные из базы через сообщения об ошибках. Понимание механики таких атак помогает разработчикам и специалистам по безопасности эффективно защищать веб-приложения.
Комментарии
—Войдите, чтобы оставить комментарий