Введение

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

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

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

Существует несколько типов SQL-инъекций: UNION-based, error-based, blind (boolean и time-based) и другие. Рассматриваемая строка относится к error-based инъекциям, когда злоумышленник заставляет базу данных выдать сообщение об ошибке, содержащее нужные данные.

Разбор строки инъекции

Давайте разберём запрос по частям:

  • ) AND EXTRACTVALUE(6898,CONCAT(0x7e,((SELECT (ELT(6898=6898,1)))),0x7e))-- -

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

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

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

Внутри CONCAT находится подзапрос SELECT (ELT(6898=6898,1)). Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В данном случае ELT(6898=6898, 1) — условие 6898=6898 истинно, что в MySQL эквивалентно 1, поэтому ELT(1, 1) вернёт строку '1'. Это простейший пример; на практике вместо '1' подставляются имена таблиц, колонок или другие данные, которые нужно извлечь.

Таким образом, при выполнении запроса MySQL попытается извлечь значение из XML, но поскольку XPath-выражение содержит символ ~ (или другие недопустимые символы), возникнет ошибка вида: XPATH syntax error: '~1~'. В этом сообщении злоумышленник увидит результат выполнения подзапроса — в данном случае '1'.

Зачем это нужно злоумышленнику?

Цель error-based инъекций — получить данные из базы, даже если приложение не выводит результаты запроса напрямую. Ошибки часто отображаются в браузере или записываются в логи, к которым у атакующего может быть доступ. Используя EXTRACTVALUE или аналогичные функции (UPDATEXML, GTID_SUBSET и др.), можно посимвольно извлекать имена таблиц, колонок, логины и пароли пользователей.

В приведённом примере подзапрос возвращает '1', но если заменить его на (SELECT password FROM users LIMIT 1), то в ошибке появится пароль первого пользователя. Именно так работают автоматизированные инструменты, например, sqlmap.

Другие варианты использования EXTRACTVALUE

Помимо ELT, злоумышленники часто комбинируют EXTRACTVALUE с CONCAT и SELECT для извлечения произвольных данных. Например:

AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e))

Этот запрос выведет версию MySQL в сообщении об ошибке. Аналогично можно получить имя текущей базы данных (database()), пользователя (user()) и многое другое.

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

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

  • Параметризация запросов: Всегда используйте подготовленные выражения с плейсхолдерами для любых данных, поступающих от пользователя.
  • Валидация ввода: Проверяйте типы данных, длину, допустимые символы. Например, если ожидается число, убедитесь, что ввод является числом.
  • Экранирование: Если параметризация невозможна, применяйте функции экранирования, предоставляемые драйвером БД (например, mysqli_real_escape_string в PHP).
  • Минимальные привилегии: Учётная запись, используемая приложением для подключения к БД, должна иметь только необходимые права. Не используйте root.
  • Регулярные обновления: Следите за обновлениями СУБД и фреймворков, чтобы закрыть известные уязвимости.
  • WAF: Веб-приложения могут быть защищены с помощью Web Application Firewall, который блокирует подозрительные запросы.

Заключение

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

Источники