Что такое SQL-инъекция с EXTRACTVALUE?
SQL-инъекция — один из самых распространённых способов атаки на веб-приложения. Злоумышленник внедряет вредоносный SQL-код в запрос, чтобы получить доступ к базе данных, изменить или удалить информацию. Запрос, который мы разбираем, использует функцию EXTRACTVALUE и CONCAT для извлечения данных через сообщения об ошибках. Это классический пример error-based SQL-инъекции.
Сам запрос выглядит так: " OR EXTRACTVALUE(9121,CONCAT(0x7e,((SELECT (ELT(9121=9121,1)))),0x7e))-- -. Давайте разберём его по частям.
Анатомия внедрения
Начало: "
Двойная кавычка закрывает строковый литерал в исходном SQL-запросе. Предполагается, что приложение вставляет пользовательский ввод в запрос, обрамляя его кавычками. Закрыв кавычку, атакующий получает возможность добавить свой код.
Оператор OR
Далее идёт OR — логический оператор, который делает условие всегда истинным или позволяет выполнить дополнительное выражение. В данном случае он используется для внедрения функции EXTRACTVALUE.
Функция EXTRACTVALUE
EXTRACTVALUE(XML_document, XPath_expression) — это функция MySQL (до версии 8.0), предназначенная для извлечения значения из XML-документа по XPath-выражению. Если XPath-выражение некорректно, MySQL возвращает ошибку, содержащую переданный аргумент. Это и эксплуатируется: атакующий передаёт в качестве XPath строку, которая заведомо вызовет ошибку, и в тексте ошибки отобразится результат подзапроса.
Первый аргумент: 9121
Первый аргумент — произвольное число. Оно не влияет на извлечение данных, но должно быть допустимым XML-документом? На самом деле, EXTRACTVALUE ожидает первым аргументом строку, содержащую XML. Число 9121 интерпретируется как строка '9121', что не является валидным XML. Однако MySQL не проверяет это на этапе синтаксического анализа, а пытается выполнить XPath, что и приводит к ошибке. Главное — вызвать ошибку с нужным содержимым.
Второй аргумент: CONCAT(0x7e,((SELECT (ELT(9121=9121,1)))),0x7e)
Здесь строится строка, которая будет вставлена в сообщение об ошибке. CONCAT объединяет:
0x7e— шестнадцатеричное представление символа~(тильда). Используется как маркер начала и конца извлекаемых данных, чтобы их было легко найти в тексте ошибки.((SELECT (ELT(9121=9121,1))))— подзапрос, возвращающий результат выраженияELT(9121=9121,1).- Ещё один
0x7eдля закрывающей тильды.
Функция ELT
ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В нашем случае ELT(9121=9121, 1): выражение 9121=9121 истинно, что в MySQL равно 1. Значит, ELT(1, 1) вернёт первый элемент — число 1. Это простейший пример; в реальной атаке вместо 1 мог бы быть подзапрос, извлекающий имя пользователя, хеш пароля и т.д.
Комментарий -- -
Два дефиса и пробел (или дефис) обозначают начало комментария в SQL. Всё, что идёт после, игнорируется. Это нужно, чтобы обрезать остаток оригинального запроса, который мог бы вызвать синтаксическую ошибку.
Как это работает на практике
Предположим, исходный запрос был:
SELECT * FROM users WHERE username = '$input';
После подстановки ввода получаем:
SELECT * FROM users WHERE username = '" OR EXTRACTVALUE(9121,CONCAT(0x7e,((SELECT (ELT(9121=9121,1)))),0x7e))-- -';
MySQL выполняет запрос. Сначала закрывается кавычка, затем OR и функция EXTRACTVALUE. Поскольку первый аргумент не является корректным XML, MySQL генерирует ошибку вида:
XPATH syntax error: '~1~'
В текст ошибки попадает результат CONCAT, то есть ~1~. Атакующий видит этот результат (например, на странице ошибки или в ответе API) и понимает, что инъекция успешна. Далее он может заменить 1 на подзапрос, например (SELECT password FROM users LIMIT 1), и извлечь пароль.
Зачем это нужно злоумышленнику?
Error-based SQL-инъекции позволяют быстро извлекать данные, не прибегая к слепым методам. EXTRACTVALUE — один из популярных инструментов, наряду с UPDATEXML и GTID_SUBSET. Они работают только в MySQL/MariaDB до определённых версий (в MySQL 8.0 функции удалены).
Как защититься?
- Параметризованные запросы (prepared statements) — самый надёжный способ. Данные передаются отдельно от SQL-кода, и внедрение становится невозможным.
- Экранирование специальных символов — если параметризация недоступна, используйте функции экранирования, предоставляемые драйвером БД.
- Валидация ввода — ограничьте допустимые символы, особенно кавычки, дефисы, комментарии.
- Минимизация привилегий — учётная запись приложения не должна иметь прав на чтение системных таблиц, если это не требуется.
- Отключение вывода ошибок — не показывайте пользователям детали ошибок БД, это затрудняет эксплуатацию.
- Обновление СУБД — в MySQL 8.0 функции EXTRACTVALUE и UPDATEXML удалены, что снижает риск таких атак.
Заключение
Разобранный запрос — типичный пример error-based SQL-инъекции с использованием EXTRACTVALUE. Он демонстрирует, как через сообщение об ошибке можно извлечь произвольные данные. Понимание таких техник необходимо для специалистов по безопасности, чтобы своевременно находить и устранять уязвимости. Помните: лучшая защита — параметризованные запросы и внимательное отношение к пользовательскому вводу.
Комментарии
—Войдите, чтобы оставить комментарий