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

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

В основе лежит функция EXTRACTVALUE, которая предназначена для работы с XML-документами. Однако при некорректном использовании она генерирует ошибку, содержащую переданные ей данные. Это позволяет атакующему «вытащить» результат выполнения подзапроса прямо в текст ошибки, которую сервер возвращает в ответе.

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

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

  • '))) — закрывающие кавычка и скобки. Они нужны, чтобы «закрыть» оригинальный SQL-запрос, который формируется на сервере, и добавить собственный код. Количество скобок подбирается экспериментально в зависимости от структуры уязвимого запроса.
  • AND — логический оператор, который присоединяет наше условие к исходному запросу. Если исходный запрос возвращал true, то и наш блок должен выполняться.
  • EXTRACTVALUE(4466, CONCAT(...)) — вызов функции. Первый аргумент (4466) — произвольное число, которое не влияет на результат, но должно быть допустимым XML-фрагментом. Второй аргумент — XPath-выражение, которое мы формируем динамически.
  • CONCAT(0x7e, ((SELECT (ELT(4466=4466,1)))), 0x7e) — конкатенация символа тильды (0x7e — это шестнадцатеричное представление символа ~), результата подзапроса и ещё одной тильды. Тильды используются как маркеры, чтобы потом легко найти выведенные данные в сообщении об ошибке.
  • SELECT (ELT(4466=4466,1)) — подзапрос, который возвращает 1, если условие 4466=4466 истинно (а оно всегда истинно), и NULL в противном случае. Функция ELT возвращает N-й элемент из списка. Здесь список состоит из одного элемента — числа 1. Таким образом, подзапрос всегда возвращает 1. Это простейший пример, демонстрирующий работоспособность инъекции. В реальных атаках вместо 4466=4466 подставляются условия, проверяющие наличие таблиц, полей или извлекающие конкретные данные.
  • -- - — комментарий, который «отрезает» остаток оригинального запроса, чтобы он не вызвал синтаксическую ошибку.

Как работает error-based инъекция через ExtractValue?

Функция EXTRACTVALUE(XML_document, XPath_expression) в MySQL анализирует первый аргумент как XML и применяет к нему XPath-выражение. Если XPath-выражение некорректно (например, содержит недопустимые символы), MySQL возвращает ошибку вида:

XPATH syntax error: '~1~'

Именно эту ошибку и ждёт атакующий. В нашем случае XPath-выражение формируется как CONCAT('~', (SELECT ...), '~'). Поскольку символ ~ не является допустимым в XPath, возникает ошибка, в тексте которой появляется результат подзапроса, окружённый тильдами. Так злоумышленник может извлечь любые данные, которые можно преобразовать в строку: версию СУБД, имя базы, имена таблиц и колонок, логины и пароли пользователей.

Этот метод относится к классу error-based SQL injection и широко используется в инструментах автоматизации, таких как sqlmap.

Пример из практики

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

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

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

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

СУБД выполнит функцию EXTRACTVALUE, та выдаст ошибку, и в ответе сервера (если ошибки не подавляются) появится сообщение:

XPATH syntax error: '~1~'

Это подтверждает, что инъекция возможна. Далее атакующий заменит ELT(4466=4466,1) на подзапрос, извлекающий, например, имя пользователя базы данных: SELECT user(). И в ошибке увидит логин.

Чем опасна такая инъекция?

Успешная эксплуатация error-based SQL-инъекции может привести к полному раскрытию базы данных, включая конфиденциальную информацию: персональные данные пользователей, хеши паролей, номера кредитных карт. В некоторых случаях возможно выполнение административных операций, вплоть до удаления таблиц или получения доступа к файловой системе сервера.

Особенно опасны подобные уязвимости для сайтов, работающих с финансами, медициной или персональными данными. Поэтому разработчикам следует использовать параметризованные запросы (prepared statements) и ни в коем случае не конкатенировать пользовательский ввод с SQL-кодом.

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

  • Используйте подготовленные выражения (prepared statements) — это самый надёжный способ. В PHP это PDO или mysqli с параметрами, в других языках — аналогичные механизмы.
  • Экранируйте специальные символы — если по каким-то причинам нельзя использовать prepared statements, применяйте функции экранирования, например mysqli_real_escape_string.
  • Ограничьте права пользователя БД — учётная запись, от имени которой работает веб-приложение, не должна иметь прав на чтение системных таблиц или выполнение опасных функций.
  • Отключайте вывод ошибок на продакшене — это не устранит уязвимость, но затруднит эксплуатацию error-based инъекций.
  • Используйте WAF (Web Application Firewall) — современные WAF могут обнаруживать и блокировать попытки SQL-инъекций по сигнатурам, включая конструкции с EXTRACTVALUE.

Заключение

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

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

Источники