Что это за строка?

Строка ))) AND EXTRACTVALUE(5422,CONCAT(0x7e,((SELECT (ELT(5422=5422,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции (инъекции, основанной на ошибках) для СУБД MySQL. Подобные конструкции часто встречаются в логах веб-серверов, в отчётах систем обнаружения вторжений (IDS) и в материалах по информационной безопасности. Они используются злоумышленниками для извлечения данных из базы данных через анализ сообщений об ошибках, которые возвращает сервер.

В данной статье мы подробно разберём, как работает эта инъекция, какие функции MySQL задействованы и как защитить приложение от подобных атак.

Разбор компонентов инъекции

Рассмотрим каждый элемент запроса по порядку.

1. Три закрывающие скобки )))

В начале строки стоят три символа ). Они предназначены для того, чтобы «закрыть» ранее открытые скобки в оригинальном SQL-запросе, который формируется в уязвимом приложении. Например, если исходный запрос выглядит так:

SELECT * FROM users WHERE id = (1)

то после подстановки пользовательского ввода с тремя скобками запрос может стать синтаксически корректным для внедрения дополнительного условия. Это типичный приём обхода простых фильтров.

2. Оператор AND

Логический оператор AND используется для присоединения дополнительного условия к оригинальному запросу. Если исходное условие истинно (например, id = 1), то выполнение продолжится, и будет вычислено внедрённое выражение. Это позволяет атакующему не нарушать основной запрос, а добавлять к нему свою полезную нагрузку.

3. Функция EXTRACTVALUE(5422, CONCAT(...))

EXTRACTVALUE — это встроенная функция MySQL (и MariaDB), предназначенная для извлечения значения из XML-документа. Она принимает два аргумента: XML-строку и XPath-выражение. Если XML-строка некорректна или XPath-выражение содержит ошибку, функция генерирует ошибку. Злоумышленники используют это свойство для вызова ошибки, в текст которой подставляются результаты выполнения вложенного запроса.

В нашем случае первым аргументом передаётся число 5422 — это не XML, а просто число. Однако MySQL автоматически преобразует его в строку. Второй аргумент — сложное выражение CONCAT(0x7e, ((SELECT (ELT(5422=5422,1)))), 0x7e).

4. Функция CONCAT и шестнадцатеричные литералы 0x7e

CONCAT объединяет строки. Литерал 0x7e — это шестнадцатеричное представление символа ~ (тильда) в ASCII. Тильда используется как разделитель, чтобы в сообщении об ошибке было легко найти извлечённые данные. Например, если вложенный запрос вернёт строку admin, то CONCAT создаст строку ~admin~. При возникновении ошибки MySQL выведет что-то вроде:

XPATH syntax error: '~admin~'

Из этого сообщения атакующий может прочитать значение admin.

5. Подзапрос SELECT (ELT(5422=5422,1))

ELT — функция MySQL, возвращающая N-й элемент из списка. Синтаксис: ELT(N, str1, str2, ...). В данном случае ELT(5422=5422, 1) вычисляет логическое выражение 5422=5422, которое всегда истинно (1). Затем ELT(1, 1) возвращает первый элемент списка — число 1. Фактически это простой способ получить предсказуемое значение (1), которое затем будет преобразовано в строку и передано в CONCAT.

В реальных атаках вместо ELT(5422=5422,1) может стоять подзапрос, извлекающий данные, например: (SELECT password FROM users LIMIT 1). Но в данном примере используется безопасная заглушка, чтобы продемонстрировать шаблон.

6. Комментарий -- -

Последовательность -- (два дефиса) в MySQL начинает комментарий до конца строки. Пробел после дефисов обязателен, но в некоторых реализациях допускается и его отсутствие. Символ - в конце добавлен для надёжности: он гарантирует, что комментарий будет распознан даже если пробел будет обрезан. Всё, что идёт после -- -, игнорируется парсером. Это нужно, чтобы «отрезать» оставшуюся часть оригинального запроса (например, закрывающую кавычку или дополнительные условия).

Как работает атака целиком

Предположим, уязвимое приложение выполняет запрос:

SELECT * FROM articles WHERE id = '$id'

Если пользователь передаёт в параметр id строку ))) AND EXTRACTVALUE(5422,CONCAT(0x7e,((SELECT (ELT(5422=5422,1)))),0x7e))-- -, то итоговый запрос примет вид:

SELECT * FROM articles WHERE id = '))) AND EXTRACTVALUE(5422,CONCAT(0x7e,((SELECT (ELT(5422=5422,1)))),0x7e))-- -'

После подстановки трёх скобок и оператора AND условие id = '...' превращается в синтаксически корректное выражение, но затем срабатывает EXTRACTVALUE, которая вызывает ошибку. Сообщение об ошибке будет содержать результат выполнения вложенного запроса (в нашем случае ~1~). Приложение, если оно выводит ошибки СУБД на страницу, покажет этот текст. Атакующий прочитает его и получит данные.

Если же приложение не выводит ошибки, злоумышленник может использовать слепую инъекцию (blind SQL injection), но это уже другая техника.

Зачем это нужно злоумышленнику?

Error-based инъекции позволяют быстро извлекать данные, потому что результат приходит прямо в сообщении об ошибке. Это один из самых эффективных способов получения информации о базе данных: имен таблиц, колонок, логинов и паролей пользователей. В отличие от слепых инъекций, где требуется множество запросов для побитового извлечения, здесь достаточно одного запроса на одно значение.

Как защититься от error-based SQL-инъекций

Основная причина уязвимости — динамическое формирование SQL-запроса путём конкатенации пользовательского ввода. Вот ключевые меры защиты:

  • Используйте параметризованные запросы (prepared statements). Это самый надёжный способ. Ввод пользователя передаётся отдельно от SQL-кода, и СУБД не интерпретирует его как часть запроса.
  • Применяйте хранимые процедуры с параметрами. Если они правильно написаны, они также предотвращают инъекции.
  • Экранируйте специальные символы. Но этот метод менее надёжен, чем параметризация, и требует осторожности.
  • Отключите вывод ошибок СУБД в production. Сообщения об ошибках не должны попадать на страницы приложения. Логируйте их, но не показывайте пользователю.
  • Ограничьте права пользователя базы данных. Веб-приложение должно подключаться к БД от имени пользователя с минимальными привилегиями (только необходимые операции).
  • Используйте WAF (Web Application Firewall). Он может блокировать известные шаблоны атак, но не является панацеей.

Регулярно проводите аудит кода и тестирование на проникновение, чтобы выявлять подобные уязвимости до того, как их найдут злоумышленники.

Заключение

Строка ))) AND EXTRACTVALUE(5422,CONCAT(0x7e,((SELECT (ELT(5422=5422,1)))),0x7e))-- - — это не случайный набор символов, а тщательно сконструированная полезная нагрузка для error-based SQL-инъекции в MySQL. Она демонстрирует, как злоумышленники используют особенности функций EXTRACTVALUE, CONCAT и ELT для вызова ошибок с внедрёнными данными. Понимание таких примеров помогает разработчикам и специалистам по безопасности лучше защищать свои приложения.

Источники