Введение
Встречая в логах или в поле ввода подобную строку: %'))) AND EXTRACTVALUE(8089,CONCAT(0x7e,((SELECT (ELT(8089=8089,1)))),0x7e))-- -, многие задаются вопросом: что это и какова её цель? Это классический пример SQL-инъекции, нацеленной на извлечение данных из базы данных через механизм ошибок. В данной статье мы подробно разберём, как работает эта инъекция, какие функции MySQL задействованы и как защититься от подобных атак.
Что такое SQL-инъекция?
SQL-инъекция (SQL injection) — это один из самых распространённых способов взлома веб-приложений, при котором злоумышленник внедряет вредоносный SQL-код в запросы к базе данных. Это становится возможным, когда приложение не фильтрует пользовательский ввод должным образом и передаёт его напрямую в SQL-запрос. Успешная инъекция позволяет атакующему читать, изменять или удалять данные, а в некоторых случаях — получить полный контроль над сервером.
Существует несколько типов SQL-инъекций: UNION-based, error-based, blind (boolean и time-based), stacked queries и другие. Рассматриваемая строка относится к классу error-based инъекций, где злоумышленник заставляет базу данных выдать сообщение об ошибке, содержащее полезные данные.
Разбор строки инъекции
Давайте разберём строку по частям:
%')))— это начало, которое часто используется для закрытия предыдущих кавычек и скобок в исходном запросе. Символ%может быть частью URL-кодирования или обозначать любой символ в LIKE-запросе. Комбинация')))закрывает строковый литерал и несколько круглых скобок, чтобы подготовить почву для внедрения.AND EXTRACTVALUE(8089,CONCAT(0x7e,((SELECT (ELT(8089=8089,1)))),0x7e))— это основная полезная нагрузка. ФункцияEXTRACTVALUEизвлекает значение из XML-документа по заданному XPath-выражению. Если XPath-выражение некорректно, MySQL генерирует ошибку, которая включает результат вычисления выражения. Здесь злоумышленник передаёт в качестве первого аргумента число 8089 (произвольный XML-фрагмент), а в качестве второго — конкатенацию тильды (0x7e), результата подзапросаSELECT (ELT(8089=8089,1))и ещё одной тильды.-- -— это комментарий, который отсекает оставшуюся часть оригинального SQL-запроса, чтобы не возникло синтаксических ошибок.
Таким образом, вся конструкция заставляет базу данных выполнить подзапрос и вывести его результат в сообщении об ошибке, которое затем может быть прочитано атакующим.
Функция EXTRACTVALUE
EXTRACTVALUE() — это встроенная функция MySQL (и MariaDB), предназначенная для работы с XML. Она принимает два строковых аргумента: фрагмент XML-разметки и XPath-выражение (локатор). Функция возвращает текст (CDATA) первого текстового узла, который является дочерним для элемента или элементов, соответствующих XPath-выражению.
Пример корректного использования:
SELECT EXTRACTVALUE('<a><b>текст</b></a>', '/a/b');
-- Вернёт 'текст'
Однако если XPath-выражение содержит синтаксическую ошибку, MySQL выдаёт ошибку вида XPATH syntax error: '...', где в кавычках может оказаться часть переданного выражения. Именно это и эксплуатируют злоумышленники: они конструируют XPath таким образом, чтобы в сообщении об ошибке отобразились нужные данные.
Функция ELT
ELT() — это функция MySQL, которая возвращает N-й элемент из списка строк. Синтаксис: ELT(N, строка1, строка2, ...). Например, ELT(2, 'a', 'b', 'c') вернёт 'b'.
В нашем случае используется ELT(8089=8089, 1). Выражение 8089=8089 всегда истинно и в числовом контексте равно 1. Таким образом, ELT(1, 1) вернёт 1. Это простейший пример, демонстрирующий работу функции. В реальных атаках вместо 1 может быть подставлен подзапрос, извлекающий данные из других таблиц, например, имена пользователей и пароли.
Функция CONCAT и шестнадцатеричные литералы
CONCAT() объединяет строки. В инъекции используется CONCAT(0x7e, (SELECT ...), 0x7e). 0x7e — это шестнадцатеричное представление символа ~ (тильда). Тильды служат маркерами, чтобы облегчить извлечение данных из сообщения об ошибке: всё, что находится между ними, и есть искомая информация.
Подзапрос (SELECT (ELT(8089=8089,1))) возвращает 1, поэтому в ошибке появится строка ~1~. Если бы вместо 1 стоял, например, (SELECT version()), то в ошибке отобразилась бы версия MySQL.
Как работает атака целиком
Предположим, исходный запрос выглядит так:
SELECT * FROM users WHERE id = '$input';
После подстановки вредоносной строки запрос превращается в:
SELECT * FROM users WHERE id = '%'))) AND EXTRACTVALUE(8089,CONCAT(0x7e,((SELECT (ELT(8089=8089,1)))),0x7e))-- -';
База данных пытается выполнить этот запрос. Часть '%'))) закрывает строку и скобки, затем следует AND EXTRACTVALUE(...). Функция EXTRACTVALUE получает некорректный XPath (поскольку второй аргумент — это строка, начинающаяся с тильды, что не является валидным XPath), и MySQL генерирует ошибку:
XPATH syntax error: '~1~'
Эта ошибка возвращается приложению, а затем отображается пользователю (если приложение не подавляет ошибки). Атакующий видит ~1~ и понимает, что инъекция работает. Далее он может заменить 1 на подзапрос, извлекающий нужные данные, например:
CONCAT(0x7e, (SELECT password FROM users LIMIT 1), 0x7e)
И в ошибке увидит пароль пользователя.
Зачем это нужно злоумышленнику?
Основная цель — получить информацию из базы данных, когда другие методы (например, UNION-based) недоступны. Error-based инъекции особенно эффективны, когда приложение возвращает сообщения об ошибках базы данных. Они позволяют пошагово извлекать данные: имена таблиц, столбцов, логины, пароли, хеши и т.д.
Кроме того, такие инъекции могут использоваться для обхода аутентификации, выполнения административных операций или даже для компрометации всего сервера.
Как защититься от SQL-инъекций?
Существует несколько надёжных способов защиты:
- Использование подготовленных выражений (prepared statements) с параметризацией запросов. Это самый эффективный метод: данные пользователя никогда не встраиваются напрямую в SQL-код, а передаются как параметры.
- Экранирование специальных символов с помощью функций вроде
mysqli_real_escape_string()(для MySQL). Однако этот метод уступает подготовленным выражениям и может быть обойдён при неверной настройке кодировки. - Валидация и фильтрация входных данных — проверка типов, длины, допустимых символов. Например, если поле ожидает число, убедитесь, что оно действительно число.
- Ограничение прав пользователя базы данных: веб-приложение должно использовать отдельного пользователя СУБД с минимально необходимыми правами (только SELECT, INSERT, UPDATE, DELETE для нужных таблиц).
- Отключение вывода ошибок базы данных в продакшене. Сообщения об ошибках должны логироваться, но не показываться пользователю.
- Использование WAF (Web Application Firewall) — может помочь обнаружить и заблокировать попытки инъекций, но не является панацеей.
Важно понимать, что безопасность — это многослойный процесс. Комбинация этих мер значительно снижает риск успешной атаки.
Заключение
Строка %'))) AND EXTRACTVALUE(8089,CONCAT(0x7e,((SELECT (ELT(8089=8089,1)))),0x7e))-- - — это не случайный набор символов, а тщательно сконструированная SQL-инъекция, использующая особенности функций MySQL EXTRACTVALUE, ELT и CONCAT для извлечения данных через сообщения об ошибках. Понимание принципов её работы помогает разработчикам и специалистам по безопасности лучше защищать свои приложения. Никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.
Комментарии
—Войдите, чтобы оставить комментарий