Введение
В запросе пользователя приведена строка: ` AND EXTRACTVALUE(1471,CONCAT(0x7e,((SELECT (ELT(1471=1471,1)))),0x7e))-- -. Это типичный пример полезной нагрузки (payload) для SQL-инъекции, нацеленной на базу данных MySQL или MariaDB. Подобные конструкции используются злоумышленниками для получения информации из базы через механизм ошибок (error-based SQL injection). В этой статье мы детально разберём, что означает каждый элемент этого запроса, как он работает и какие меры защиты помогут предотвратить такие атаки.
Что такое SQL-инъекция?
SQL-инъекция (SQLi) — это один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет в запрос к базе данных произвольный SQL-код. Если приложение недостаточно фильтрует пользовательский ввод, этот код выполняется на сервере базы данных, что может привести к утечке конфиденциальных данных, модификации или удалению информации, а в некоторых случаях — к полному контролю над сервером.
Error-based инъекции — это подвид SQLi, при котором атакующий заставляет базу данных выдать сообщение об ошибке, содержащее результат выполнения внедрённого запроса. Это позволяет извлекать данные посимвольно или целыми строками, если приложение отображает ошибки базы данных пользователю.
Разбор payload
Рассмотрим строку по частям.
1. Начальный символ ` (обратная кавычка)
В MySQL обратная кавычка используется для экранирования идентификаторов (имён таблиц, столбцов). Злоумышленник начинает payload с обратной кавычки, чтобы «закрыть» предыдущий идентификатор в оригинальном запросе и выйти за его пределы. Например, если исходный запрос был SELECT * FROM users WHERE name = '$input', то подстановка ` AND ... может привести к синтаксической ошибке или к изменению логики запроса.
2. Оператор AND
Логический оператор AND используется для объединения условий. В данном случае он добавляет к оригинальному условию новое выражение, которое должно быть вычислено. Если предыдущая часть запроса ложна, то результат всего выражения будет ложным, но если злоумышленник правильно подобрал начальную кавычку, запрос может выполниться.
3. Функция EXTRACTVALUE
EXTRACTVALUE — встроенная функция MySQL, предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Синтаксис: EXTRACTVALUE(xml_frag, xpath_expr). Она возвращает текст содержимого узла, соответствующего XPath. Однако при некорректном XPath-выражении функция генерирует ошибку, которая включает в себя переданные аргументы. Это и используется для error-based инъекций.
4. Аргументы EXTRACTVALUE: 1471 и CONCAT(...)
Первый аргумент — число 1471. Это произвольный XML-фрагмент (фактически строка '1471'), который не является корректным XML, но для EXTRACTVALUE это не важно, так как основная цель — вызвать ошибку через второй аргумент.
Второй аргумент — CONCAT(0x7e,((SELECT (ELT(1471=1471,1)))),0x7e). Функция CONCAT объединяет строки. Здесь она складывает три части:
0x7e— шестнадцатеричное представление символа ~ (тильда). Используется как маркер, чтобы облегчить поиск выводимых данных в сообщении об ошибке.((SELECT (ELT(1471=1471,1))))— подзапрос, возвращающий результат функции ELT.- Ещё один
0x7e— закрывающая тильда.
Таким образом, CONCAT формирует строку вида ~<результат>~, которая затем передаётся как XPath-выражение в EXTRACTVALUE. Поскольку эта строка не является допустимым XPath (начинается с тильды), EXTRACTVALUE выдаёт ошибку, текст которой содержит переданное XPath-выражение, то есть ~<результат>~. Злоумышленник может прочитать результат в сообщении об ошибке.
5. Функция ELT
ELT (от англ. «element») — функция MySQL, возвращающая N-й элемент из списка строк: ELT(N, str1, str2, ...). В нашем случае используется ELT(1471=1471, 1). Выражение 1471=1471 всегда истинно, то есть равно 1. Значит, ELT(1, 1) вернёт первый элемент списка — строку '1'. Это простой способ получить предсказуемое значение (в данном случае '1'), чтобы проверить работоспособность инъекции. В реальных атаках вместо жёстко заданного '1' может быть подставлен подзапрос, извлекающий данные, например ELT(1, (SELECT password FROM users LIMIT 1)).
6. Комментарий -- -
Два дефиса и пробел (или дефис) обозначают начало комментария в SQL. Всё, что идёт после -- , игнорируется базой данных. Это нужно, чтобы «отрезать» оставшуюся часть оригинального запроса, которая могла бы вызвать синтаксическую ошибку или помешать выполнению внедрённого кода. В некоторых СУБД требуется, чтобы после -- был пробел, поэтому часто пишут -- -.
Как работает атака целиком
Предположим, исходный запрос выглядит так: SELECT * FROM articles WHERE id = '$id'. Злоумышленник передаёт в параметр id строку ` AND EXTRACTVALUE(1471,CONCAT(0x7e,((SELECT (ELT(1471=1471,1)))),0x7e))-- -. После подстановки запрос примет вид:
SELECT * FROM articles WHERE id = '` AND EXTRACTVALUE(1471,CONCAT(0x7e,((SELECT (ELT(1471=1471,1)))),0x7e))-- -'База данных пытается выполнить этот запрос. Сначала она встречает обратную кавычку, которая не закрыта, что может вызвать ошибку, но в некоторых контекстах (например, если id — числовое поле) кавычка может быть проигнорирована или обработана иначе. Далее выполняется условие AND с вызовом EXTRACTVALUE. Второй аргумент EXTRACTVALUE вычисляется: CONCAT возвращает строку ~1~. EXTRACTVALUE пытается интерпретировать ~1~ как XPath и терпит неудачу, генерируя ошибку вида:
XPATH syntax error: '~1~'
Если приложение выводит сообщения об ошибках базы данных, злоумышленник увидит этот текст и поймёт, что инъекция успешна. Заменив '1' в ELT на подзапрос, он сможет извлекать любые данные.
Зачем нужны тильды (0x7e)?
Тильды служат ограничителями, чтобы облегчить автоматический парсинг результата. Сообщение об ошибке будет содержать строку, начиная с тильды и заканчивая тильдой, внутри которой находится полезная нагрузка. Это особенно удобно при использовании инструментов вроде sqlmap, которые автоматически извлекают данные между маркерами.
Меры защиты
Чтобы предотвратить подобные атаки, необходимо применять комплексный подход:
- Параметризованные запросы (prepared statements). Это самый надёжный способ: SQL-код и данные передаются раздельно, поэтому внедрение команд невозможно.
- Экранирование специальных символов. Если по каким-то причинам нельзя использовать параметризацию, следует применять функции экранирования, предоставляемые драйвером базы данных.
- Валидация и фильтрация входных данных. Проверяйте типы данных (например, что числовой параметр действительно число) и отклоняйте подозрительные символы.
- Отключение вывода ошибок базы данных пользователю. Сообщения об ошибках должны логироваться, но не отображаться в браузере.
- Использование ORM и фреймворков. Современные ORM (например, Hibernate, Entity Framework) обычно используют параметризацию по умолчанию.
- Регулярное обновление СУБД и приложений. Устанавливайте патчи безопасности.
- WAF (Web Application Firewall). Может блокировать известные шаблоны атак, но не является панацеей.
Важно понимать, что error-based инъекции — лишь один из многих методов. Злоумышленники также используют blind SQLi, time-based и другие. Поэтому защита должна быть эшелонированной.
Заключение
Рассмотренный payload — классический пример error-based SQL-инъекции для MySQL, использующий EXTRACTVALUE для вызова ошибки с внедрёнными данными. Понимание механизма таких атак помогает разработчикам и администраторам правильно выстраивать защиту. Никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.
Комментарии
—Войдите, чтобы оставить комментарий