Введение

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

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

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

Существует несколько разновидностей SQL-инъекций:

  • Union-based — объединение результатов легитимного запроса с данными из других таблиц.
  • Error-based — извлечение информации через сообщения об ошибках, которые возвращает СУБД.
  • Blind — когда приложение не выводит ошибки, и атакующий задаёт вопросы базе, анализируя поведение страницы (true/false или временные задержки).
  • Stacked queries — выполнение нескольких запросов подряд.

Рассматриваемая строка относится именно к error-based типу. Она заставляет MySQL сгенерировать ошибку, в тексте которой будут содержаться интересующие атакующего данные.

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

Давайте разберём запрос %')))) AND EXTRACTVALUE(8645,CONCAT(0x7e,((SELECT (ELT(8645=8645,1)))),0x7e))-- - поэлементно.

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

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

2. AND EXTRACTVALUE(8645, ...)

Функция EXTRACTVALUE() в MySQL предназначена для извлечения значения из XML-документа по заданному XPath-выражению. Синтаксис: EXTRACTVALUE(XML_document, XPath_expression). Если переданный фрагмент не является корректным XML или XPath-выражение не соответствует ожидаемому формату, MySQL возвращает ошибку XPATH syntax error. Именно это и нужно атакующему: в тексте ошибки будет отображён переданный фрагмент.

3. CONCAT(0x7e, ..., 0x7e)

Функция CONCAT() объединяет строки. Здесь она склеивает символ 0x7e (тильда «~») с результатом подзапроса и ещё одной тильдой. Тильда используется как маркер, чтобы в сообщении об ошибке было легко найти внедрённые данные. Символ 0x7e — это шестнадцатеричное представление символа «~».

4. (SELECT (ELT(8645=8645,1)))

Внутренний подзапрос использует функцию ELT(). ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае 8645=8645 — это всегда истинное выражение, которое в MySQL приводится к числу 1. Значит, ELT(1, 1) вернёт строку «1». Это простейшая проверка работоспособности инъекции. В реальной атаке вместо 1 могли бы стоять, например, database(), user() или (SELECT password FROM users LIMIT 1).

5. Завершающие символы -- -

Двойной дефис с пробелом — это комментарий в SQL. Он «отрезает» оставшуюся часть оригинального запроса, чтобы синтаксис оставался корректным. Иногда вместо -- - используют #.

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

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

SELECT id, title FROM articles WHERE title LIKE '%ЗАПРОС%'

После подстановки вредоносной строки запрос превращается в нечто подобное:

SELECT id, title FROM articles WHERE title LIKE '%%')))) AND EXTRACTVALUE(8645,CONCAT(0x7e,((SELECT (ELT(8645=8645,1)))),0x7e))-- -%'

MySQL попытается выполнить EXTRACTVALUE с аргументом, содержащим тильды и результат подзапроса. Поскольку это не является валидным XPath, СУБД вернёт ошибку вида:

XPATH syntax error: '~1~'

В сообщении об ошибке атакующий увидит «~1~». Если бы вместо 1 стоял вызов database(), он получил бы имя текущей базы данных. Это и есть основной механизм error-based инъекции.

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

Error-based SQL-инъекции позволяют злоумышленнику:

  • Получить имена таблиц и столбцов.
  • Извлечь логины и пароли пользователей.
  • Читать конфиденциальные данные (персональные сведения, номера карт).
  • В некоторых случаях — изменять или удалять информацию.

Особенно опасны такие атаки для сайтов, где ввод пользователя напрямую попадает в SQL-запрос без фильтрации. Даже если приложение не выводит ошибки на экран, они могут попадать в логи, к которым иногда имеют доступ сторонние лица.

Как защититься от SQL-инъекций

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

  1. Использовать подготовленные выражения (prepared statements). Это самый эффективный метод. Параметры передаются отдельно от SQL-кода, и база данных не интерпретирует их как часть запроса.
  2. Применять ORM-библиотеки. Современные фреймворки (например, Django ORM, Hibernate, Sequelize) автоматически экранируют данные.
  3. Валидировать и фильтровать ввод. Если поле должно содержать число, проверяйте, что это действительно число. Для строк используйте белые списки допустимых символов.
  4. Ограничить права пользователя БД. Учётная запись, от имени которой работает приложение, не должна иметь прав на удаление таблиц или доступ к системным схемам.
  5. Отключить вывод подробных ошибок. В production-окружении сообщения об ошибках не должны показываться пользователю. Это усложняет эксплуатацию error-based инъекций.
  6. Регулярно обновлять СУБД и библиотеки. В новых версиях MySQL функция EXTRACTVALUE помечена как устаревшая (deprecated), а в некоторых сборках её поведение изменено.

Заключение

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

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

Источники