Что такое SQL-инъекция через EXTRACTVALUE?
SQL-инъекция — один из самых распространённых способов взлома веб-приложений. Злоумышленник вставляет в пользовательский ввод специальные символы, которые меняют логику SQL-запроса. Если приложение не фильтрует входные данные, база данных выполняет вредоносный код. Одной из разновидностей является error-based SQL-инъекция, при которой хакер заставляет СУБД выдать сообщение об ошибке, содержащее полезные данные (например, имена таблиц или пароли).
Функция EXTRACTVALUE() в MySQL предназначена для работы с XML-документами. Она принимает два аргумента: XML-фрагмент и XPath-выражение. Если XPath некорректен, MySQL генерирует ошибку с указанием проблемного места. Эту особенность и используют для извлечения информации из базы.
Разбор конкретного payload
Рассмотрим строку, которая часто встречается в логах веб-серверов и отчётах сканеров уязвимостей:
")) AND EXTRACTVALUE(7234,CONCAT(0x7e,((SELECT (ELT(7234=7234,1)))),0x7e))-- -
Этот фрагмент — классический пример error-based инъекции. Разберём его по частям.
Начало: "))
Двойная закрывающая скобка и кавычка используются для того, чтобы «закрыть» ранее открытые конструкции в оригинальном SQL-запросе. Разработчик мог написать что-то вроде SELECT * FROM users WHERE name = ("$input"). Внедряя ")), атакующий завершает строку и функцию, делая дальнейший код частью SQL-выражения.
Оператор AND
Логическое «И» позволяет присоединить дополнительное условие. Если исходный запрос возвращал true, то после добавления AND ... он останется true при выполнении условия. Это нужно, чтобы не нарушить работу основного запроса и получить результат инъекции.
Функция EXTRACTVALUE(7234, ...)
Первый аргумент — произвольное число 7234. Оно не несёт смысловой нагрузки, но должно быть допустимым XML-фрагментом. Второй аргумент — CONCAT(...), который формирует строку, передаваемую как XPath. Если эта строка не является корректным XPath, MySQL выдаст ошибку, в тексте которой будет фигурировать переданное значение. Именно так утекают данные.
Конкатенация с тильдой: CONCAT(0x7e, ..., 0x7e)
0x7e — шестнадцатеричный код символа ~ (тильда). Тильда используется как маркер, чтобы в сообщении об ошибке легко было найти границы извлечённых данных. Например, ошибка может выглядеть так: XPATH syntax error: '~1~'. Всё, что между тильдами, — это результат подзапроса.
Подзапрос SELECT (ELT(7234=7234,1))
Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь N — это результат сравнения 7234=7234, которое всегда истинно (равно 1). Следовательно, ELT(1, 1) вернёт строку '1'. Это простейшая проверка: если инъекция сработала, в ошибке появится ~1~. На практике вместо 1 подставляют подзапросы, извлекающие имена таблиц, колонок или хеши паролей.
Комментарий -- -
Два дефиса и пробел (или дефис) — это комментарий в SQL. Всё, что идёт после, игнорируется. Это нужно, чтобы «отрезать» остаток оригинального запроса, который мог бы вызвать синтаксическую ошибку. Вариант -- - используется, когда после комментария требуется пробел (например, в некоторых версиях MySQL).
Как это работает на практике
Предположим, уязвимый запрос выглядит так:
SELECT id, title FROM articles WHERE id = ("$id")
Пользователь передаёт в параметре id наш payload. После подстановки запрос превращается в:
SELECT id, title FROM articles WHERE id = ("")) AND EXTRACTVALUE(7234,CONCAT(0x7e,((SELECT (ELT(7234=7234,1)))),0x7e))-- -")
СУБД выполняет EXTRACTVALUE, та вызывает ошибку вида:
XPATH syntax error: '~1~'
Эта ошибка возвращается в ответе сервера (если включён вывод ошибок). Атакующий видит ~1~ и понимает, что инъекция работает. Далее он заменяет 1 на подзапрос, например:
(SELECT table_name FROM information_schema.tables LIMIT 0,1)
В ошибке появится имя первой таблицы. Перебирая LIMIT, можно выкачать всю схему базы, а затем и данные пользователей.
Чем опасна такая инъекция?
- Утечка конфиденциальных данных: злоумышленник может получить доступ к логинам, паролям, персональным данным клиентов.
- Компрометация всей базы: через information_schema атакующий узнаёт структуру БД и извлекает любые таблицы.
- Обход аутентификации: иногда инъекция позволяет войти в админ-панель без пароля.
- Отказ в обслуживании: некоторые payload могут вызвать перегрузку СУБД.
Как защититься от error-based SQL-инъекций?
Основной метод — использовать параметризованные запросы (prepared statements). В этом случае данные передаются отдельно от SQL-кода и не могут изменить его структуру. Например, в PHP с PDO:
$stmt = $pdo->prepare('SELECT id, title FROM articles WHERE id = :id');
$stmt->execute(['id' => $id]);
Дополнительные меры:
- Валидация входных данных: если параметр ожидается числовым, приводите его к целому типу.
- Экранирование спецсимволов: используйте функции типа
mysqli_real_escape_string(), но это менее надёжно, чем prepared statements. - Отключение вывода ошибок СУБД: не показывайте пользователям текст ошибок MySQL — это лишает атакующего обратной связи.
- Использование ORM: современные ORM (Doctrine, Eloquent) автоматически параметризуют запросы.
- Регулярные сканирования: проводите пентесты и используйте сканеры уязвимостей (SQLMap, OWASP ZAP).
Заключение
Payload ")) AND EXTRACTVALUE(7234,CONCAT(0x7e,((SELECT (ELT(7234=7234,1)))),0x7e))-- - — это типовой пример error-based SQL-инъекции, эксплуатирующей функцию EXTRACTVALUE в MySQL. Он показывает, насколько важно фильтровать пользовательский ввод и использовать безопасные методы работы с базой данных. Если вы разработчик, всегда применяйте prepared statements и не выводите ошибки СУБД в production. Если вы администратор, проверьте логи на наличие подобных строк — это признак попытки взлома.
Комментарии
—Войдите, чтобы оставить комментарий