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

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

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

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

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

1. Закрывающие скобки и логический оператор

Фрагмент )))) — это попытка закрыть ранее открытые скобки в оригинальном SQL-запросе. Часто разработчики используют конструкции вида WHERE id = ('...'), и злоумышленник добавляет скобки, чтобы «выровнять» синтаксис и внедрить свой код. Далее следует AND — логический оператор, который позволяет присоединить дополнительное условие.

2. Функция EXTRACTVALUE

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

Начиная с MySQL 8.0.17 функции EXTRACTVALUE и UPDATEXML были удалены. Однако на многих устаревших системах они всё ещё доступны.

3. CONCAT и шестнадцатеричные литералы

CONCAT(0x7e, ((SELECT ...)), 0x7e) — функция CONCAT объединяет строки. 0x7e — это шестнадцатеричное представление символа ~ (тильда). Тильда используется как разделитель, чтобы облегчить извлечение данных из сообщения об ошибке. Внутри CONCAT находится подзапрос SELECT (ELT(3045=3045,1)).

4. Функция ELT и условие 3045=3045

ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае ELT(3045=3045, 1) — это хитрость: выражение 3045=3045 всегда истинно, то есть равно 1. Значит, ELT вернёт первый элемент — число 1. Зачем это нужно? Это простейшая проверка на возможность выполнения подзапроса. В реальной атаке вместо 1 могло бы стоять имя пользователя, версия базы данных или хеш пароля.

Число 3045 в EXTRACTVALUE и в условии — это просто случайное число, которое может меняться от запроса к запросу. Оно не несёт смысловой нагрузки, кроме как быть частью синтаксиса.

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

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

Как работает атака целиком?

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

SELECT * FROM users WHERE id = ('$input');

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

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

После подстановки MySQL попытается выполнить EXTRACTVALUE с некорректным XPath (из-за тильды), что вызовет ошибку вида:

XPATH syntax error: '~1~'

В сообщении об ошибке отобразится результат подзапроса — в данном случае 1. Если бы вместо 1 стояло, например, (SELECT version()), мы бы увидели версию MySQL. Именно так злоумышленники по крупицам извлекают данные: имена таблиц, столбцов, логины и пароли.

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

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

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

Опасность усугубляется тем, что для эксплуатации не требуется специальных инструментов — достаточно браузера или утилиты вроде sqlmap.

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

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

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

Что делать, если вы увидели такую строку в логах?

Прежде всего, не паникуйте. Автоматические сканеры постоянно сканируют интернет в поисках уязвимых сайтов. Если ваш сайт использует современные фреймворки с ORM или prepared statements, скорее всего, атака не увенчалась успехом. Тем не менее рекомендуется:

  • Проверить код на наличие уязвимостей (особенно если вы используете старые CMS или самописные скрипты).
  • Убедиться, что все запросы к базе данных параметризованы.
  • Проверить логи на предмет других подозрительных запросов.
  • Рассмотреть установку WAF (Web Application Firewall) для блокировки подобных атак на лету.

Заключение

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

Помните: лучшая защита — это профилактика. Используйте параметризованные запросы, обновляйте ПО и следите за логами.

Источники