Введение в error-based SQL-инъекции
SQL-инъекции остаются одной из самых распространённых уязвимостей веб-приложений. Среди них выделяется класс error-based инъекций, когда злоумышленник заставляет базу данных выдать сообщение об ошибке, содержащее полезные данные. Запрос ')))) AND EXTRACTVALUE(2729,CONCAT(0x7e,((SELECT (ELT(2729=2729,1)))),0x7e))-- - — типичный пример такой атаки, нацеленной на MySQL. В этой статье мы детально разберём, как работает эта конструкция, какие функции задействованы и как от неё защититься.
Что такое EXTRACTVALUE?
EXTRACTVALUE — это встроенная функция MySQL (и MariaDB), предназначенная для извлечения значения из XML-документа по заданному XPath-выражению. Синтаксис: EXTRACTVALUE(XML_фрагмент, XPath_выражение). Если XPath-выражение синтаксически некорректно, MySQL генерирует ошибку, в тексте которой отображается переданное выражение. Именно это свойство и используется для error-based инъекций: злоумышленник может поместить в XPath результат подзапроса, и он попадёт в сообщение об ошибке.
Например, запрос SELECT EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e)) вызовет ошибку вида XPATH syntax error: '~5.7.33~', раскрывая версию СУБД.
Функция ELT и её роль
ELT (от англ. Element) — это функция MySQL, которая возвращает N-й элемент из списка строк. Синтаксис: ELT(N, строка1, строка2, ...). Если N=1, возвращается первая строка, и т.д. В контексте инъекции ELT часто используется для управления логикой: например, ELT(2729=2729,1) всегда вернёт 1, потому что условие истинно. Это позволяет создать безобидный на первый взгляд подзапрос, который на самом деле просто возвращает константу.
В нашем примере ELT(2729=2729,1) возвращает 1. Это число затем преобразуется в строку и подставляется в CONCAT вместе с символами ~ (0x7e).
Разбор полезной нагрузки
Рассмотрим запрос по частям:
'))))— закрывающие скобки и кавычки, необходимые для завершения оригинального SQL-запроса, в который внедряется инъекция. Количество скобок зависит от структуры исходного запроса.AND EXTRACTVALUE(2729,CONCAT(0x7e,((SELECT (ELT(2729=2729,1)))),0x7e))— основная часть инъекции. ЗдесьEXTRACTVALUEвызывается с первым аргументом 2729 (произвольное число, может быть любым), а второй аргумент — это XPath-выражение, которое заведомо некорректно, потому что начинается с символа~(тильда). Внутри CONCAT выполняется подзапросSELECT ELT(2729=2729,1), возвращающий 1. Таким образом, XPath-выражение будет выглядеть как~1~, что вызовет ошибку.-- -— комментарий, обрезающий остаток оригинального запроса.
В результате MySQL выдаст ошибку: XPATH syntax error: '~1~'. Хотя в данном примере возвращается просто 1, заменив 1 на любой другой подзапрос (например, (SELECT database())), можно извлечь произвольные данные.
Зачем нужен CONCAT с 0x7e?
Символ 0x7e — это шестнадцатеричное представление тильды (~). Тильда используется как маркер, чтобы отделить выводимые данные от остального текста ошибки. Это облегчает автоматизированный парсинг результата. Кроме того, тильда не является допустимым символом в XPath, что гарантирует возникновение ошибки.
Пошаговый пример эксплуатации
Предположим, уязвимый запрос выглядит так: SELECT * FROM users WHERE id = '1'. Злоумышленник подставляет:
1')))) AND EXTRACTVALUE(2729,CONCAT(0x7e,((SELECT (ELT(2729=2729,1)))),0x7e))-- -
После подстановки запрос становится:
SELECT * FROM users WHERE id = '1')))) AND EXTRACTVALUE(2729,CONCAT(0x7e,((SELECT (ELT(2729=2729,1)))),0x7e))-- -'
MySQL выполняет его, и при вычислении EXTRACTVALUE возникает ошибка, которая возвращается в ответе приложения. Если приложение отображает ошибки БД, злоумышленник увидит сообщение, содержащее ~1~. Заменив 1 на (SELECT version()), он получит версию СУБД, и так далее.
Какие данные можно извлечь?
С помощью этой техники можно получить:
- Версию MySQL/MariaDB
- Имя текущей базы данных
- Имена таблиц и столбцов
- Логины и пароли пользователей
- Любые другие данные, доступные в рамках текущих привилегий
Ограничение — длина выводимой строки (обычно около 32 символов), поэтому для извлечения длинных значений используют посимвольное извлечение с помощью SUBSTRING.
Меры защиты
Чтобы предотвратить подобные атаки, необходимо:
- Использовать подготовленные выражения (параметризованные запросы) — это самый надёжный способ, при котором данные пользователя никогда не интерпретируются как SQL-код.
- Экранировать специальные символы — если по каким-то причинам нельзя использовать подготовленные выражения, нужно применять функции экранирования (например,
mysqli_real_escape_string). - Отключить вывод ошибок БД в продакшене — это не устраняет уязвимость, но затрудняет эксплуатацию, так как злоумышленник не видит сообщений об ошибках.
- Использовать WAF — веб-приложения-экраны могут блокировать подозрительные запросы, содержащие EXTRACTVALUE, UPDATEXML и другие опасные функции.
- Регулярно обновлять СУБД — в новых версиях MySQL некоторые функции могут быть удалены или изменены, что снижает риск.
Заключение
Запрос ')))) AND EXTRACTVALUE(2729,CONCAT(0x7e,((SELECT (ELT(2729=2729,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции, использующей особенности функций EXTRACTVALUE и ELT. Понимание механики таких атак помогает разработчикам и специалистам по безопасности правильно выстраивать защиту. Помните: лучшая защита — это параметризованные запросы и внимательное отношение к вводу пользователя.
Комментарии
—Войдите, чтобы оставить комментарий