Что такое error-based SQL-инъекция?
Error-based SQL-инъекция — это метод атаки на базы данных, при котором злоумышленник заставляет сервер выдать сообщение об ошибке, содержащее полезные данные. В отличие от blind-инъекций, где информация извлекается по косвенным признакам (время отклика, true/false), здесь результат приходит напрямую в тексте ошибки. Строка EXTRACTVALUE(9171,CONCAT(0x7e,(SELECT(ELT(9171=9171,1))),0x7e)) — учебный пример такой атаки для СУБД MySQL.
Подобные конструкции часто встречаются в отчётах по безопасности и на форумах пентестеров. Они позволяют быстро проверить наличие уязвимости и даже извлечь произвольные данные, если приложение не фильтрует входные параметры.
Разбор синтаксиса EXTRACTVALUE
Функция EXTRACTVALUE(XML_fragment, XPath_expression) извлекает значение из XML-документа по заданному XPath-выражению. Если XPath-выражение некорректно, MySQL генерирует ошибку XPATH syntax error, в тексте которой отображается переданное выражение. Это и используется для внедрения.
В нашем примере:
- Первый аргумент — число 9171. Оно не имеет значения, это просто заполнитель.
- Второй аргумент —
CONCAT(0x7e, (SELECT (ELT(9171=9171,1))), 0x7e). Здесь 0x7e — шестнадцатеричный код символа «~» (тильда). Он используется как разделитель, чтобы облегчить поиск результата в сообщении об ошибке. - ELT(N, str1, str2, ...) — возвращает N-ю строку из списка. В нашем случае условие
9171=9171всегда истинно (1), поэтому ELT(1,1) вернёт строку '1'.
Таким образом, если подставить эту конструкцию в уязвимый параметр, MySQL попытается вычислить XPath-выражение вида ~1~, что вызовет ошибку и выведет её в ответе сервера.
Как это работает на практике
Предположим, веб-приложение формирует SQL-запрос путём конкатенации пользовательского ввода:
SELECT * FROM users WHERE id = '))) AND EXTRACTVALUE(9171,CONCAT(0x7e,(SELECT(ELT(9171=9171,1))),0x7e))-- -'
Если параметр id не экранируется, база данных выполнит внедрённую часть. В результате в HTTP-ответе появится сообщение об ошибке, содержащее ~1~. Это подтверждает, что инъекция возможна.
Далее злоумышленник может заменить ELT(9171=9171,1) на подзапрос, возвращающий нужные данные, например, версию СУБД или имя текущей базы:
EXTRACTVALUE(9171,CONCAT(0x7e,(SELECT version()),0x7e))
В ошибке отобразится версия MySQL. Аналогично можно извлечь имена таблиц, колонок и даже хеши паролей.
Почему используется именно EXTRACTVALUE?
Функция EXTRACTVALUE доступна в MySQL и MariaDB, но не в других СУБД (например, PostgreSQL или MS SQL). Для error-based инъекций в MySQL также применяются UPDATEXML, GTID_SUBSET и другие функции, вызывающие ошибки с полезной нагрузкой. EXTRACTVALUE удобна тем, что позволяет выводить до 32 символов в одном сообщении об ошибке. Для извлечения более длинных строк приходится использовать посимвольный перебор или комбинировать с LIMIT/OFFSET.
Пример реальной атаки
В отчётах по пентесту часто описывают, как с помощью EXTRACTVALUE удаётся получить доступ к учётным данным администратора. Например, на одном из форумов приводится последовательность запросов:
1. Определение количества колонок:
ORDER BY 5-- -
2. Вывод версии:AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT version()),0x7e))-- -
3. Извлечение имён таблиц:AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT table_name FROM information_schema.tables LIMIT 0,1),0x7e))-- -
Каждый шаг даёт часть информации в тексте ошибки. Такой подход требует множества запросов, но полностью автоматизируется инструментами вроде sqlmap.
Как защититься от error-based SQL-инъекций?
Основная причина уязвимости — отсутствие фильтрации пользовательского ввода и конкатенация SQL-запросов. Меры защиты:
- Использование подготовленных выражений (prepared statements) с параметризацией. Это самый надёжный способ, так как данные не попадают в текст запроса.
- Экранирование специальных символов с помощью функций вроде
mysqli_real_escape_string(). Однако этот метод уступает параметризации. - Валидация входных данных по типу и формату. Например, если ожидается число, приводите его к целому.
- Отключение вывода ошибок СУБД в production-окружении. Это не устраняет уязвимость, но затрудняет эксплуатацию.
- Использование WAF (Web Application Firewall) с сигнатурами для известных функций, таких как EXTRACTVALUE.
- Регулярное обновление MySQL и применение патчей безопасности.
Заключение
Строка '))) AND EXTRACTVALUE(9171,CONCAT(0x7e,((SELECT (ELT(9171=9171,1)))),0x7e))-- - — это не случайный набор символов, а рабочий эксплойт для error-based SQL-инъекции в MySQL. Понимание принципов его работы помогает разработчикам осознать важность защиты кода, а специалистам по безопасности — эффективно тестировать системы на проникновение. Никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.
Комментарии
—Войдите, чтобы оставить комментарий