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

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

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

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

Ключевая последовательность %")

Начинается строка с %"). Это попытка закрыть ранее открытую кавычку и скобку в оригинальном SQL-запросе. Символ % часто используется как подстановочный знак в LIKE-запросах, но здесь он, скорее всего, является частью полезной нагрузки, которая должна нарушить синтаксис. Закрывающая кавычка " и скобка ) позволяют «вырваться» из строкового литерала и добавить собственный код.

Оператор AND

Далее идёт AND — логический оператор, который используется для объединения условий. В контексте инъекции он нужен, чтобы внедряемая функция выполнилась только при истинности предыдущего условия (или просто для сохранения синтаксиса).

Функция EXTRACTVALUE

EXTRACTVALUE(XML_document, XPath_expression) — это встроенная функция MySQL (до версии 8.0.17), предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Она возвращает текст, соответствующий XPath. Если XPath-выражение некорректно, функция генерирует ошибку, в тексте которой может содержаться переданный аргумент. Это и используется для error-based инъекций.

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

Первый аргумент — 8877. Это просто число, которое не является корректным XML-документом. При вызове EXTRACTVALUE с таким аргументом MySQL попытается его разобрать и, скорее всего, выдаст ошибку. Однако суть в другом: второй аргумент — CONCAT(0x7e,((SELECT (ELT(8877=8877,1)))),0x7e) — формирует строку, которая будет включена в сообщение об ошибке.

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

CONCAT объединяет строки. Здесь она соединяет три части:

  • 0x7e — шестнадцатеричное представление символа ~ (тильда).
  • Результат подзапроса (SELECT (ELT(8877=8877,1))).
  • Снова 0x7e — закрывающая тильда.

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

Подзапрос с ELT

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае ELT(8877=8877,1) — условие 8877=8877 всегда истинно, что даёт 1 (в MySQL true = 1). Значит, ELT вернёт первый элемент — 1. Это простейшая проверка, которая всегда возвращает 1. В реальной атаке вместо 1 мог бы быть, например, CONCAT(username,0x3a,password) из таблицы users.

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

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

Как это работает на практике

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

SELECT * FROM articles WHERE title = '...'

После подстановки полезной нагрузки запрос станет:

SELECT * FROM articles WHERE title = '%") AND EXTRACTVALUE(8877,CONCAT(0x7e,((SELECT (ELT(8877=8877,1)))),0x7e))-- -'

MySQL выполнит функцию EXTRACTVALUE. Поскольку первый аргумент не является корректным XML, возникнет ошибка вида:

XPATH syntax error: '~1~'

В сообщении об ошибке появятся данные, переданные во втором аргументе. В нашем случае это ~1~. Если бы вместо 1 стоял подзапрос, извлекающий логин и пароль, они бы также отобразились в ошибке.

Цели и опасность

Такая инъекция позволяет атакующему:

  • Получить версию СУБД, имя базы данных, имя пользователя.
  • Извлечь содержимое таблиц, включая учётные данные.
  • В некоторых случаях — выполнить произвольные команды на сервере (при наличии соответствующих привилегий).

Error-based инъекции особенно опасны, потому что не требуют слепого перебора и дают немедленный результат в ответе сервера.

Меры защиты

Чтобы предотвратить подобные атаки, необходимо:

  1. Использовать параметризованные запросы (prepared statements) — это самый надёжный способ.
  2. Применять ORM, которые автоматически экранируют опасные символы.
  3. Проводить валидацию и санитизацию всех входных данных.
  4. Ограничить права пользователя БД, чтобы даже при успешной инъекции ущерб был минимальным.
  5. Обновить MySQL до версии 8.0.17 или выше, где функции EXTRACTVALUE и UPDATEXML удалены.

Заключение

Рассмотренная строка — яркий пример эксплуатации ошибок СУБД для извлечения данных. Понимание механики таких атак помогает разработчикам и специалистам по безопасности лучше защищать свои приложения. Если вы встретили подобную строку в логах, это сигнал о попытке взлома, и следует немедленно проверить безопасность кода.

Источники