Введение

В логах веб-сервера или в поле ввода можно встретить подозрительную строку: %')) AND EXTRACTVALUE(2768,CONCAT(0x7e,((SELECT (ELT(2768=2768,1)))),0x7e))-- -. Что это такое и какова её цель? Это классический пример SQL-инъекции, нацеленной на извлечение данных из базы через вывод сообщений об ошибках. В данной статье мы подробно разберём каждую часть этого запроса, объясним, как работает атака, и расскажем, как защититься.

Что такое SQL-инъекция?

SQL-инъекция (SQL injection) — один из самых распространённых способов взлома веб-приложений. Злоумышленник внедряет вредоносный SQL-код в поля ввода, URL-параметры или cookie, чтобы заставить базу данных выполнить нежелательные действия: украсть данные, изменить их или удалить. Существует несколько типов SQL-инъекций: union-based, error-based, blind, time-based. Строка, которую мы рассматриваем, относится к error-based инъекциям, где атакующий заставляет СУБД выдать сообщение об ошибке, содержащее полезные данные.

Разбор строки запроса

Давайте разберём её по частям:

  • %')) — это начало строки. Символ % часто используется в URL-кодировании, но здесь он может быть частью исходного значения. Далее идут две закрывающие скобки и апостроф. Это попытка закрыть ранее открытые скобки и строковый литерал в оригинальном SQL-запросе, чтобы внедрить свой код. Например, если уязвимый запрос выглядел как SELECT * FROM users WHERE id = ('$input'), то вставка ')) закроет кавычку и скобку, позволив добавить произвольные команды.
  • AND EXTRACTVALUE(2768,CONCAT(0x7e,((SELECT (ELT(2768=2768,1)))),0x7e)) — это основная полезная нагрузка. Функция EXTRACTVALUE() в MySQL предназначена для извлечения значения из XML-документа по указанному XPath-выражению. Однако при передаче некорректного XPath она генерирует ошибку, текст которой включает переданный аргумент. Это и используется для вывода данных.
  • -- - — это комментарий. Два дефиса и пробел (или другой символ) заставляют MySQL игнорировать оставшуюся часть оригинального запроса, чтобы не возникло синтаксической ошибки.

Как работает EXTRACTVALUE для извлечения данных

Функция EXTRACTVALUE(XML_document, XPath_expression) возвращает текст из XML-документа, соответствующий XPath. Если XPath содержит недопустимые символы, например, тильду (~), MySQL выдаёт ошибку вида: XPATH syntax error: '~...~'. Злоумышленник формирует XPath так, чтобы в сообщении об ошибке оказались нужные данные. В нашем случае используется CONCAT(0x7e, ((SELECT (ELT(2768=2768,1)))), 0x7e). 0x7e — это шестнадцатеричный код символа ~ (тильда). ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Выражение 2768=2768 всегда истинно (1), поэтому ELT(1,1) вернёт 1. Таким образом, в XPath попадёт строка ~1~, что вызовет ошибку с текстом XPATH syntax error: '~1~'. Это простейший пример; на практике вместо 1 подставляют подзапросы, извлекающие имена таблиц, логины, пароли и т.д.

Цель атаки

Основная цель — получить информацию из базы данных. В примере с ELT(2768=2768,1) атакующий просто проверяет, что инъекция работает: если приложение вернёт ошибку с ~1~, значит, уязвимость подтверждена. Далее он может заменить 1 на подзапрос, например, (SELECT password FROM users LIMIT 1), и извлечь пароль. Такой метод называется error-based SQL injection, потому что данные извлекаются через сообщения об ошибках.

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

Рассмотрим фрагмент на PHP:

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

Если пользователь передаст id=1')) AND EXTRACTVALUE(...)-- -, то итоговый запрос станет:

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

MySQL выполнит его, и если возникнет ошибка XPath, она будет выведена на страницу (если включён вывод ошибок). Так злоумышленник получает данные.

Как защититься от таких атак

Существует несколько надёжных способов предотвратить SQL-инъекции:

  1. Использование подготовленных выражений (prepared statements). Это самый эффективный метод. Параметры передаются отдельно от SQL-кода, и база данных не интерпретирует их как часть запроса. Например, в PHP с PDO или MySQLi.
  2. Экранирование специальных символов. Функции вроде mysqli_real_escape_string() помогают, но не гарантируют полную защиту, если не использовать их повсеместно.
  3. Валидация входных данных. Если поле ожидает число, проверяйте, что это действительно число. Отклоняйте всё, что не соответствует формату.
  4. Ограничение прав пользователя БД. Учётная запись, от имени которой работает приложение, должна иметь минимально необходимые привилегии. Не используйте root.
  5. Отключение вывода ошибок на продакшене. Сообщения об ошибках не должны показываться пользователям, чтобы не давать подсказок атакующему. Логируйте их, но не выводите в браузер.
  6. Использование WAF (Web Application Firewall). Современные WAF могут обнаруживать и блокировать попытки SQL-инъекций по сигнатурам.

Заключение

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

Источники