Что такое ExtractValue и при чём тут SQL-инъекции
Функция ExtractValue в MySQL предназначена для извлечения значения из XML-документа по заданному пути XPath. Синтаксис: EXTRACTVALUE(XML_document, XPath_expression). Если XML-документ некорректен или XPath-выражение содержит недопустимые символы, MySQL генерирует ошибку XPATH syntax error. Эту особенность активно используют злоумышленники для так называемых error-based SQL-инъекций: атакующий заставляет базу данных выдать сообщение об ошибке, в котором содержится полезная информация (например, имя базы данных, версия, имена таблиц).
Запрос, который мы разбираем, — классический пример такой инъекции. Строка ")))) AND EXTRACTVALUE(4123,CONCAT(0x7e,((SELECT (ELT(4123=4123,1)))),0x7e))-- - содержит несколько характерных элементов: закрывающие скобки, логическое условие AND, вызов ExtractValue с заведомо некорректным первым аргументом (число 4123 вместо XML), конкатенацию с 0x7e (тильда) и подзапрос с ELT. Давайте разберём каждый компонент.
Анатомия запроса: пошаговый разбор
1. Закрывающие скобки и оператор AND
В начале строки идут четыре закрывающие скобки ")))). Они нужны, чтобы «закрыть» ранее открытые скобки в исходном SQL-запросе, который пытается внедрить атакующий. Например, если уязвимый запрос выглядит как SELECT * FROM users WHERE id = ('$input'), то подстановка ")))) AND ... позволит корректно завершить выражение и добавить своё условие. Оператор AND гарантирует, что инъекция сработает только при истинности основного запроса (или наоборот, в зависимости от логики).
2. EXTRACTVALUE(4123, ...) — намеренная ошибка
Первый аргумент функции — число 4123. Оно не является корректным XML-документом, поэтому MySQL сразу выдаст ошибку. Второй аргумент — CONCAT(0x7e, ((SELECT (ELT(4123=4123,1)))), 0x7e). Функция CONCAT склеивает символ тильды (0x7e), результат подзапроса и ещё одну тильду. Поскольку первый аргумент заведомо ошибочен, MySQL попытается вычислить второй аргумент, чтобы сформировать сообщение об ошибке. В этом сообщении и появится результат подзапроса, обёрнутый в тильды.
3. Зачем нужен 0x7e (тильда)?
Символ 0x7e — это шестнадцатеричное представление знака «тильда» (~). В error-based инъекциях через ExtractValue его используют как маркер, чтобы отделить полезные данные от остального текста ошибки. Сообщение об ошибке обычно выглядит так: XPATH syntax error: '~database_name~'. Тильды позволяют легко найти границы извлечённой информации при автоматическом парсинге ответа сервера. Без них данные слились бы с другим текстом, и их было бы сложнее выделить.
4. Подзапрос (SELECT (ELT(4123=4123,1)))
Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Если N=1, возвращается первая строка. Выражение 4123=4123 всегда истинно, что в числовом контексте даёт 1. Таким образом, ELT(1, 1) вернёт строку '1'. В реальной атаке вместо этого примитивного подзапроса стоял бы, например, (SELECT database()) или (SELECT table_name FROM information_schema.tables LIMIT 0,1). Здесь же показан упрощённый шаблон, который всегда возвращает '1' — это тестовый запрос для проверки работоспособности инъекции.
5. Комментарий -- -
В конце строки идёт -- -. Двойной дефис с пробелом — это комментарий в SQL (в MySQL требуется пробел после --). Он отсекает оставшуюся часть оригинального запроса, чтобы не возникло синтаксической ошибки. Дефис в конце добавлен для совместимости с некоторыми парсерами, которые требуют, чтобы после комментария был пробел или специальный символ.
Как работает атака целиком
Представим уязвимый запрос: SELECT * FROM articles WHERE id = '1'. Атакующий подставляет вместо 1 строку 1")))) AND EXTRACTVALUE(4123,CONCAT(0x7e,((SELECT (ELT(4123=4123,1)))),0x7e))-- -. В итоге получается:
SELECT * FROM articles WHERE id = '1")))) AND EXTRACTVALUE(4123,CONCAT(0x7e,((SELECT (ELT(4123=4123,1)))),0x7e))-- -'
База данных пытается выполнить это. Сначала закрываются скобки, потом вычисляется EXTRACTVALUE. Так как первый аргумент — число, MySQL выдаёт ошибку, в тексте которой будет результат CONCAT: ~1~. Злоумышленник видит этот ответ и понимает, что инъекция работает. Далее он заменяет тестовый подзапрос на извлечение реальных данных (например, SELECT version()), и в ошибке появляется версия СУБД.
Последствия и защита
Error-based инъекции через ExtractValue — один из самых быстрых способов получить информацию о базе. Они позволяют за несколько запросов вытащить имена таблиц, столбцов и даже содержимое полей. Основные меры защиты:
- Использование подготовленных выражений (prepared statements) — параметризация запросов исключает возможность подстановки произвольного SQL-кода.
- Экранирование специальных символов — если по каким-то причинам нельзя использовать prepared statements, необходимо применять функции экранирования (mysqli_real_escape_string, PDO::quote).
- Отключение подробных сообщений об ошибках — на продакшене не показывайте пользователю текст ошибок СУБД. Это затруднит эксплуатацию, хотя и не устранит уязвимость полностью.
- Регулярный аудит кода — используйте статические анализаторы и пентесты для выявления подобных дыр.
Важно понимать: сам по себе запрос с ExtractValue не является вредоносным — это всего лишь функция. Опасность возникает, когда входные данные пользователя попадают в SQL-запрос без должной обработки. Разобранный пример наглядно демонстрирует, как комбинация закрывающих скобок, логического оператора и вызова функции с ошибкой приводит к утечке данных.
Итог
Строка ")))) AND EXTRACTVALUE(4123,CONCAT(0x7e,((SELECT (ELT(4123=4123,1)))),0x7e))-- - — это шаблон error-based SQL-инъекции, использующий функцию ExtractValue для вызова ошибки, в тексте которой передаются данные. Тильда (0x7e) служит маркером для облегчения парсинга, ELT с истинным условием возвращает фиктивное значение, а комментарий обрезает остаток запроса. Понимание таких конструкций помогает разработчикам лучше защищать свои приложения.
Комментарии
—Войдите, чтобы оставить комментарий