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

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

Подобные запросы часто встречаются в логах веб-серверов, в системах обнаружения вторжений (IDS) и в отчётах сканеров уязвимостей. Понимание их структуры помогает разработчикам и администраторам лучше защищать свои приложения.

Разбор по частям

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

1. Начальные символы '))))

Это попытка закрыть ранее открытые кавычки и скобки в оригинальном SQL-запросе. В зависимости от контекста уязвимости, злоумышленник подбирает количество и тип символов, чтобы «вырваться» из строкового литерала или условия и добавить свой код. Например, если исходный запрос выглядел как SELECT * FROM users WHERE name = '$input', то вставка ')))) может закрыть строку и скобки, позволив добавить логическое выражение.

2. AND

Оператор AND присоединяет дополнительное условие к исходному запросу. Если инъекция успешна, это условие будет вычислено, и в зависимости от его истинности запрос вернёт либо исходные данные, либо ничего. Однако в данном случае цель не в изменении логики выборки, а в вызове ошибки.

3. EXTRACTVALUE(6410,CONCAT(0x7e,((SELECT (ELT(6410=6410,1)))),0x7e))

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

Злоумышленники используют это свойство: они передают в качестве XPath строку, содержащую результат подзапроса. Если подзапрос возвращает данные, они попадают в текст ошибки, которую затем можно прочитать в ответе сервера (если вывод ошибок включён).

В нашем примере:

  • 6410 — произвольное число, первый аргумент EXTRACTVALUE (может быть любой строкой, но часто используют число для простоты).
  • CONCAT(0x7e, ((SELECT (ELT(6410=6410,1)))), 0x7e) — конкатенация символа ~ (0x7e в шестнадцатеричном виде), результата подзапроса и снова ~. Символ ~ служит маркером, по которому в тексте ошибки легко найти извлечённые данные.
  • ELT(6410=6410,1) — функция ELT возвращает N-й элемент из списка. Здесь 6410=6410 — всегда истинное условие (1), поэтому ELT возвращает первый элемент — число 1. Это простейший случай; на практике вместо 1 может быть подзапрос, извлекающий имя пользователя, пароль и т.д.

Таким образом, если подзапрос вернёт, например, строку admin, то XPath станет ~admin~. MySQL попытается интерпретировать это как XPath, потерпит неудачу и выдаст ошибку вида: XPATH syntax error: '~admin~'. Злоумышленник, увидев эту ошибку, получит искомые данные.

4. -- -

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

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

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

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

Как защититься?

Основной метод защиты — использование параметризованных запросов (prepared statements). Они разделяют код SQL и данные, поэтому введённые пользователем символы не могут изменить структуру запроса.

Дополнительные меры:

  • Отключите вывод ошибок базы данных в production-окружении. Пользователь должен видеть общее сообщение, а детали — только в логах.
  • Используйте ORM или библиотеки, которые автоматически экранируют опасные символы.
  • Применяйте принцип наименьших привилегий для учётной записи базы данных: не давайте ей прав на чтение системных таблиц, если это не нужно.
  • Регулярно обновляйте СУБД и фреймворки, чтобы закрыть известные уязвимости.
  • Используйте веб-application firewall (WAF) для фильтрации подозрительных запросов, хотя это не заменяет исправление кода.

Пример уязвимого кода

Рассмотрим фрагмент на PHP, который может быть уязвим:

$id = $_GET['id'];
$query = "SELECT * FROM products WHERE id = '$id'";
$result = mysqli_query($conn, $query);

Если передать id=1' AND EXTRACTVALUE(6410,CONCAT(0x7e,(SELECT version()),0x7e))-- -, то запрос станет:

SELECT * FROM products WHERE id = '1' AND EXTRACTVALUE(6410,CONCAT(0x7e,(SELECT version()),0x7e))-- -'

В результате выполнения MySQL вернёт ошибку с версией сервера, например: XPATH syntax error: '~5.7.33~'.

Исправленный вариант с подготовленным выражением:

$stmt = $conn->prepare("SELECT * FROM products WHERE id = ?");
$stmt->bind_param("s", $id);
$stmt->execute();

Здесь параметр $id передаётся отдельно и не может изменить структуру запроса.

Заключение

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

Помните: безопасность — это процесс, а не разовое действие. Регулярно проводите аудит кода, используйте сканеры уязвимостей и следите за обновлениями безопасности.

Источники