Что такое EXTRACTVALUE и при чём тут SQL-инъекция?
Функция EXTRACTVALUE в MySQL предназначена для извлечения значения из XML-документа по заданному XPath-выражению. Синтаксис прост: EXTRACTVALUE(XML_фрагмент, XPath_выражение). Если XPath-выражение некорректно, MySQL возвращает ошибку с текстом, который включает часть переданного XPath. Именно эта особенность делает функцию мощным инструментом для так называемых error-based SQL-инъекций — атак, при которых злоумышленник извлекает данные из базы через сообщения об ошибках.
Рассматриваемый запрос — классический пример такой инъекции:
" AND EXTRACTVALUE(7095,CONCAT(0x7e,((SELECT (ELT(7095=7095,1)))),0x7e))-- -
Давайте разберём его по частям, чтобы понять логику атаки.
Анатомия инъекции: CONCAT, ELT и тильда
Основная цель — заставить сервер вывести в сообщении об ошибке результат выполнения вложенного запроса. Для этого используется цепочка функций:
- EXTRACTVALUE(7095, ...) — первый аргумент (7095) здесь не важен, это просто произвольное число. Второй аргумент — XPath-выражение, которое формируется динамически.
- CONCAT(0x7e, ..., 0x7e) — объединяет символ тильды (
~, шестнадцатеричный код 0x7e) с результатом подзапроса. Тильда используется как маркер, чтобы легко найти выводимые данные в тексте ошибки. - SELECT (ELT(7095=7095,1)) — это вложенный запрос, который возвращает число 1. Функция
ELT(N, str1, str2, ...)возвращает N-ю строку из списка. Если N=1, возвращается первый элемент — в данном случае 1. Условие7095=7095всегда истинно, поэтому ELT всегда вернёт 1.
В результате CONCAT создаёт строку вида ~1~. Эта строка передаётся как XPath в EXTRACTVALUE. Поскольку ~1~ не является корректным XPath-выражением, MySQL генерирует ошибку: XPATH syntax error: '~1~'. В тексте ошибки злоумышленник видит результат выполнения подзапроса.
Зачем это нужно злоумышленнику?
В реальной атаке вместо ELT(7095=7095,1) подставляются запросы, извлекающие конфиденциальные данные: имена таблиц, столбцов, логины, пароли, хеши. Например, можно получить имя текущей базы данных:
AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))-- -
Сервер вернёт ошибку с названием базы данных. Аналогично извлекаются версии СУБД, имена пользователей и другие сведения. Поскольку ошибки часто отображаются на странице (особенно в режиме отладки), атакующий может пошагово «вытягивать» данные, используя LIMIT и смещения.
Почему EXTRACTVALUE, а не другие функции?
MySQL предоставляет несколько функций, вызывающих ошибки с пользовательскими данными. Помимо EXTRACTVALUE, часто используют UPDATEXML с аналогичным механизмом. EXTRACTVALUE удобен тем, что принимает два аргумента и не требует наличия XML-данных — достаточно некорректного XPath. Однако начиная с MySQL 5.7.9 функция была помечена как устаревшая, а в MySQL 8.0 удалена. Тем не менее, множество устаревших систем всё ещё работают на старых версиях, поэтому угроза сохраняется.
Пример из реальной практики
Предположим, на сайте есть страница с параметром id, который подставляется в SQL-запрос без экранирования. Злоумышленник отправляет:
https://example.com/product.php?id=1 AND EXTRACTVALUE(7095,CONCAT(0x7e,((SELECT (ELT(7095=7095,1)))),0x7e))-- -
Если приложение уязвимо, в ответе появится ошибка MySQL с текстом XPATH syntax error: '~1~'. Это сигнал, что инъекция возможна. Далее атакующий заменяет ELT(7095=7095,1) на подзапрос, извлекающий нужные данные, и получает их через сообщения об ошибках.
Как защититься от error-based SQL-инъекций
Основная причина успеха таких атак — отсутствие фильтрации входных данных и вывод ошибок СУБД на страницу. Вот ключевые меры защиты:
- Используйте подготовленные выражения (prepared statements). Это самый надёжный способ: параметры запроса передаются отдельно от SQL-кода, и внедрить произвольные конструкции не получится.
- Экранируйте специальные символы. Если prepared statements недоступны, применяйте функции экранирования (например,
mysqli_real_escape_string). - Отключите вывод ошибок на продакшене. Сообщения об ошибках должны логироваться, а не отображаться пользователю. Это лишает атакующего обратной связи.
- Обновляйте СУБД. В MySQL 8.0 функции EXTRACTVALUE и UPDATEXML удалены, что снижает риск.
- Используйте WAF. Веб-приложения-экраны могут блокировать подозрительные запросы, содержащие EXTRACTVALUE, CONCAT с hex-кодами и т.п.
- Проводите аудит кода. Регулярно сканируйте приложение на уязвимости с помощью инструментов (sqlmap, OWASP ZAP).
Заключение
Конструкция " AND EXTRACTVALUE(7095,CONCAT(0x7e,((SELECT (ELT(7095=7095,1)))),0x7e))-- - — это не просто случайный набор символов, а тщательно продуманный эксплойт для извлечения данных через ошибки MySQL. Понимание его работы помогает разработчикам осознать важность безопасного программирования и своевременного обновления компонентов. Если вы нашли подобный код в логах своего сайта, немедленно проверьте приложение на уязвимости и устраните их.
Комментарии
—Войдите, чтобы оставить комментарий