Введение

Встречая в логах или в параметрах URL строку вида ') OR ExtractValue(9694, Concat(0x7e,((Select (Elt(9694=9694,1)))),0x7e))-- -, многие задаются вопросом: что это такое? Это не случайный набор символов, а классический пример SQL-инъекции (SQL injection), направленной на извлечение данных из базы данных MySQL через механизм ошибок. В данной статье мы подробно разберём, как работает этот запрос, какие функции задействованы и как защититься от подобных атак.

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

SQL-инъекция — один из самых распространённых способов взлома веб-приложений. Злоумышленник внедряет вредоносный SQL-код в входные данные (формы, параметры URL, cookies), которые затем попадают в SQL-запрос без должной обработки. Если приложение уязвимо, база данных выполнит этот код, что может привести к утечке конфиденциальной информации, модификации или удалению данных.

Существует несколько типов SQL-инъекций: Union-based, Boolean-based, Time-based и Error-based. Рассматриваемый запрос относится к последнему типу — error-based SQL injection.

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

Давайте разберём строку ') OR ExtractValue(9694, Concat(0x7e,((Select (Elt(9694=9694,1)))),0x7e))-- - на составные элементы.

1. Закрывающая кавычка и скобка

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

2. Оператор OR

Далее идёт OR. Это логический оператор, который делает условие всегда истинным, если правая часть верна. Внедряющий код стремится к тому, чтобы запрос вернул данные или вызвал ошибку, которую можно проанализировать.

3. Функция ExtractValue

ExtractValue() — это встроенная функция MySQL, предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Синтаксис: ExtractValue(xml_frag, xpath_expr). Она возвращает текст первого узла, соответствующего XPath. Однако если XPath-выражение некорректно, MySQL генерирует ошибку, в тексте которой может содержаться переданный фрагмент. Именно это и используется для error-based инъекции.

4. Аргументы функции

В нашем случае первый аргумент — 9694 (произвольное число, может быть любым). Второй аргумент — Concat(0x7e,((Select (Elt(9694=9694,1)))),0x7e).

  • 0x7e — шестнадцатеричное представление символа тильды (~). Часто используется как разделитель, чтобы облегчить извлечение данных из сообщения об ошибке.
  • Elt(9694=9694,1) — функция ELT() возвращает N-й элемент из списка. Здесь 9694=9694 — это логическое выражение, которое всегда истинно (1). Фактически ELT(1,1) вернёт 1. Это простейшая проверка, демонстрирующая работу инъекции. В реальной атаке вместо этого подзапроса мог бы быть (SELECT user FROM users LIMIT 1) или другой запрос, извлекающий конфиденциальные данные.
  • Concat объединяет тильду, результат подзапроса и ещё одну тильду. Получается строка вида ~1~.

5. Комментарий в конце

-- - — это комментарий в SQL. Всё, что идёт после него, игнорируется базой данных. Это позволяет отсечь остаток оригинального запроса, который мог бы вызвать синтаксическую ошибку.

Как работает атака

Когда уязвимое приложение подставляет эту строку в SQL-запрос, итоговый запрос может выглядеть так:

SELECT * FROM products WHERE id = ('') OR ExtractValue(9694, Concat(0x7e,((SELECT (ELT(9694=9694,1)))),0x7e))-- -')

База данных выполняет ExtractValue с некорректным XPath (поскольку ~1~ не является допустимым XPath). MySQL выдаёт ошибку примерно такого содержания:

XPATH syntax error: '~1~'

Эта ошибка возвращается приложению (если оно выводит ошибки БД), и атакующий видит результат выполнения подзапроса. Заменив ELT(9694=9694,1) на другой подзапрос, злоумышленник может посимвольно извлекать имена таблиц, колонок, логины и пароли пользователей.

Почему это опасно?

Error-based инъекции опасны тем, что позволяют получать данные напрямую в сообщениях об ошибках, без необходимости слепого перебора. Если приложение настроено на вывод ошибок MySQL, атакующий быстро получит структуру БД и содержимое таблиц. В случае с ExtractValue ограничение на длину вывода (около 32 символов) заставляет использовать посимвольное извлечение, но это лишь замедляет атаку.

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

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

  • Отключите вывод подробных ошибок БД в production-окружении.
  • Используйте ORM или хранимые процедуры с параметрами.
  • Проводите регулярный аудит кода и сканирование уязвимостей.
  • Применяйте принцип наименьших привилегий для пользователя БД.

Заключение

Строка ') OR ExtractValue(9694, Concat(0x7e,((Select (Elt(9694=9694,1)))),0x7e))-- - — это учебный пример error-based SQL-инъекции через функцию ExtractValue. Она демонстрирует, как злоумышленники могут использовать особенности MySQL для извлечения данных. Понимание таких атак помогает разработчикам и администраторам лучше защищать свои системы.

Источники