Что такое 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. Понимание принципов его работы помогает разработчикам осознать важность защиты кода, а специалистам по безопасности — эффективно тестировать системы на проникновение. Никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.

Источники