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

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

В основе лежит игра на синтаксисе XPath и функциях MySQL. Давайте разберём каждый элемент.

Разбор составных частей

1. Начало: %'

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

2. AND EXTRACTVALUE(2015,CONCAT(0x7e,((SELECT (ELT(2015=2015,1)))),0x7e))

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

  • Первый аргумент 2015 — произвольное число, которое не является корректным XML. Оно нужно лишь для того, чтобы функция была вызвана.
  • Второй аргумент формируется через CONCAT(0x7e, ((SELECT (ELT(2015=2015,1)))), 0x7e). Здесь 0x7e — это шестнадцатеричное представление символа ~ (тильда). Тильда недопустима в начале XPath-выражения, поэтому она гарантированно вызывает синтаксическую ошибку.
  • Внутренний подзапрос (SELECT (ELT(2015=2015,1))) возвращает результат функции ELT(N, str1, str2, ...). ELT выбирает N-ю строку из списка. В данном случае условие 2015=2015 всегда истинно (возвращает 1), поэтому ELT(1, 1) вернёт строку '1'. Это простейшая проверка, которая подтверждает, что инъекция работает: если в ответе появится ошибка с числом 1, значит, уязвимость есть.

Фактически, конструкция заставляет MySQL выдать сообщение об ошибке вида: XPATH syntax error: '~1~'. Вместо 1 может быть любой другой результат подзапроса, что позволяет извлекать произвольные данные (имена таблиц, логины, пароли) посимвольно.

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

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

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

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

SELECT * FROM users WHERE name LIKE '%$input%';

Если пользователь передаст в $input нашу строку, запрос превратится в:

SELECT * FROM users WHERE name LIKE '%%' AND EXTRACTVALUE(2015,CONCAT(0x7e,((SELECT (ELT(2015=2015,1)))),0x7e))-- -%';

После подстановки MySQL выполнит EXTRACTVALUE, что приведёт к ошибке с текстом, содержащим результат подзапроса. Злоумышленник увидит в ответе сервера что-то вроде:

XPATH syntax error: '~1~'

Это сигнал, что инъекция успешна. Далее вместо ELT(2015=2015,1) можно подставить, например, SELECT version() или SELECT table_name FROM information_schema.tables LIMIT 1, чтобы получить конфиденциальные данные.

Зачем используется ELT и CONCAT?

Функция ELT здесь — простейший способ вернуть константу или результат другого выражения. В более сложных эксплойтах её заменяют на подзапросы, возвращающие нужную информацию. CONCAT склеивает тильды с полезной нагрузкой, чтобы гарантировать невалидный XPath и одновременно обрамить выводимые данные маркерами ~. Это облегчает автоматический парсинг ответа сервера инструментами вроде sqlmap.

Опасность и защита

Error-based SQL-инъекции чрезвычайно опасны, так как позволяют злоумышленнику получить полный доступ к базе данных, включая учётные записи пользователей, платёжную информацию и коммерческие тайны. Основная причина — недостаточная фильтрация входных данных и использование конкатенации строк вместо подготовленных выражений (prepared statements).

Чтобы защититься, разработчикам следует:

  • Использовать параметризованные запросы (prepared statements) во всех СУБД.
  • Применять ORM или библиотеки, которые автоматически экранируют спецсимволы.
  • Отключить вывод подробных ошибок MySQL в продакшене (параметр display_errors).
  • Регулярно проводить сканирование уязвимостей и аудит кода.

Также рекомендуется ограничить права пользователя базы данных, от имени которого работает приложение: запретить доступ к information_schema и другим системным таблицам, если он не нужен.

Вывод

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

Источники