Что такое SQL-инъекция через EXTRACTVALUE?
SQL-инъекция — одна из самых опасных уязвимостей веб-приложений, входящая в топ OWASP. Злоумышленник внедряет вредоносный SQL-код в запрос, чтобы получить доступ к базе данных. Одним из методов является error-based SQL-инъекция, при которой атакующий заставляет сервер выдать сообщение об ошибке, содержащее конфиденциальные данные. Функция EXTRACTVALUE в MySQL часто используется для таких атак.
Рассматриваемый запрос: ` OR EXTRACTVALUE(8362,CONCAT(0x7e,((SELECT (ELT(8362=8362,1)))),0x7e))-- - — типичный пример error-based инъекции. В этой статье мы детально разберём, как он работает, какие данные позволяет извлечь и как защититься от подобных атак.
Как работает функция EXTRACTVALUE в MySQL
EXTRACTVALUE(XML_frag, XPath_expr) — функция MySQL, которая извлекает значение из XML-фрагмента по заданному XPath-выражению. Если XPath-выражение некорректно, MySQL генерирует ошибку с указанием проблемного фрагмента. Именно это свойство и эксплуатируют злоумышленники: они передают в качестве XPath строку, содержащую результат подзапроса, и сервер возвращает её в тексте ошибки.
Например, запросSELECT EXTRACTVALUE(1, CONCAT(0x7e, (SELECT user()), 0x7e));вернёт ошибку видаXPATH syntax error: '~root@localhost~'. Так злоумышленник узнаёт имя пользователя базы данных.
Разбор конкретного запроса
Запрос ` OR EXTRACTVALUE(8362,CONCAT(0x7e,((SELECT (ELT(8362=8362,1)))),0x7e))-- - состоит из нескольких частей:
`— закрывающая кавычка, которая завершает строковый литерал в уязвимом параметре.OR— логический оператор, делающий условие всегда истинным (если инъекция сработала).EXTRACTVALUE(8362, ...)— вызов функции, где первый аргумент — произвольное число (8362), а второй — XPath-выражение, которое вызовет ошибку.CONCAT(0x7e, ((SELECT (ELT(8362=8362,1)))), 0x7e)— конкатенация символа~(0x7e), результата подзапроса и ещё одного~. Символы~используются как маркеры, чтобы легко найти данные в сообщении об ошибке.SELECT (ELT(8362=8362,1))— подзапрос, возвращающий 1. ЗдесьELT(N, str1, str2, ...)возвращает N-ю строку из списка. Условие8362=8362всегда истинно, поэтомуELT(1,1)вернёт1. В реальной атаке вместо этого подзапроса внедряют запрос к системным таблицам, напримерSELECT version()илиSELECT table_name FROM information_schema.tables LIMIT 1.-- -— комментарий, который игнорирует остаток оригинального SQL-запроса.
Таким образом, при выполнении уязвимого запроса СУБД попытается вычислить EXTRACTVALUE(8362, '~1~'), что приведёт к ошибке XPATH syntax error: '~1~'. Если вместо 1 подставить, например, (SELECT database()), в ошибке отобразится имя текущей базы данных.
Пример эксплуатации
Предположим, есть уязвимый параметр id в URL: http://example.com/product.php?id=1. Оригинальный запрос: SELECT * FROM products WHERE id = '$id'. Злоумышленник подставляет:
1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e))-- -
Сервер выполнит: SELECT * FROM products WHERE id = '1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e))-- -'. Возникнет ошибка, в тексте которой будет версия MySQL, например XPATH syntax error: '~8.0.23~'. Так атакующий получает информацию о СУБД.
Далее можно извлекать имена таблиц, колонок и сами данные, используя подзапросы с LIMIT и смещением. Например, для получения имени первой таблицы:
1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1), 0x7e))-- -
Почему EXTRACTVALUE уязвима?
Функция EXTRACTVALUE не является уязвимостью сама по себе — это штатная функция MySQL. Проблема в том, что при неправильной обработке пользовательского ввода злоумышленник может внедрить вызов этой функции в SQL-запрос. Если приложение не использует подготовленные выражения (prepared statements) и не экранирует спецсимволы, инъекция становится возможной.
Стоит отметить, что в MySQL 5.7 и более поздних версиях EXTRACTVALUE и UPDATEXML всё ещё доступны, но в некоторых сборках могут быть отключены. Однако error-based инъекции возможны и через другие функции, например GTID_SUBSET, JSON_KEYS и т.д.
Как защититься от error-based SQL-инъекций
Основные меры защиты:
- Используйте подготовленные выражения (prepared statements). Это самый надёжный способ: параметры запроса передаются отдельно от SQL-кода, и внедрение становится невозможным.
- Применяйте хранимые процедуры с параметрами, если это возможно.
- Экранируйте все пользовательские данные с помощью функций вроде
mysqli_real_escape_string(для MySQL). Но помните, что экранирование — не панацея, особенно при неправильной кодировке. - Ограничьте права пользователя БД. Веб-приложение должно работать под учётной записью с минимально необходимыми правами (только SELECT, INSERT, UPDATE, DELETE для нужных таблиц). Это не позволит атакующему читать системные таблицы.
- Отключите вывод ошибок СУБД на продакшене. Сообщения об ошибках не должны попадать в ответы сервера — это затруднит error-based инъекции.
- Используйте WAF (Web Application Firewall). Он может блокировать подозрительные запросы, содержащие
EXTRACTVALUEи другие опасные конструкции. - Регулярно обновляйте СУБД и фреймворки. Хотя
EXTRACTVALUEне является багом, обновления закрывают другие уязвимости.
Заключение
Запрос ` OR EXTRACTVALUE(8362,CONCAT(0x7e,((SELECT (ELT(8362=8362,1)))),0x7e))-- - — классический пример error-based SQL-инъекции, использующей функцию EXTRACTVALUE для извлечения данных через сообщения об ошибках. Понимание механизма таких атак помогает разработчикам и специалистам по безопасности правильно защищать веб-приложения. Главный совет: никогда не доверяйте пользовательскому вводу и всегда используйте подготовленные выражения.
Комментарии
—Войдите, чтобы оставить комментарий