Что такое error-based SQL-инъекция?
SQL-инъекция — один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет вредоносный SQL-код в запросы к базе данных. Существует несколько разновидностей: UNION-based, blind, time-based и error-based. Последняя, error-based, основана на том, что СУБД возвращает в сообщении об ошибке фрагмент данных, которые хотел бы получить атакующий. MySQL, в отличие от многих других СУБД, поддерживает функции, специально предназначенные для работы с XML — EXTRACTVALUE и UPDATEXML. Именно они стали инструментами для извлечения информации через ошибки.
Разбор конкретного запроса
Рассмотрим строку:
" OR EXTRACTVALUE(3545,CONCAT(0x7e,((SELECT (ELT(3545=3545,1)))),0x7e))-- -Эта конструкция — классический пример error-based SQL-инъекции для MySQL. Давайте разберём её по частям.
Начало: " OR ...
Символ двойной кавычки закрывает строковый литерал в оригинальном запросе, после чего оператор OR добавляет новое условие. Если исходный запрос был, например, SELECT * FROM users WHERE name = "$input", то после подстановки получается логическое выражение, которое всегда истинно или вызывает ошибку — в зависимости от цели атакующего.
Функция EXTRACTVALUE
EXTRACTVALUE(XML_document, XPath_expression) извлекает значение из XML-документа по заданному XPath-выражению. Если XPath-выражение синтаксически некорректно, MySQL возвращает ошибку вида XPATH syntax error: '...', в которой приводится фрагмент переданного выражения. Это и есть канал утечки данных.
Первый аргумент: 3545
Число 3545 — произвольный идентификатор. Оно не несёт смысловой нагрузки, но может использоваться для уникализации запроса или как часть условия 3545=3545, которое всегда истинно. В нашем случае ELT(3545=3545,1) вернёт 1, так как условие истинно.
Функция CONCAT и шестнадцатеричные литералы
CONCAT(0x7e, ..., 0x7e) объединяет строки. 0x7e — это шестнадцатеричное представление символа ~ (тильда). Тильда используется как маркер, чтобы в сообщении об ошибке было легко найти начало и конец извлечённых данных.
Подзапрос с ELT
ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В нашем случае ELT(3545=3545,1) — это ELT(1,1), что вернёт строку '1'. Это простейший пример; на практике вместо '1' подставляется подзапрос, например (SELECT password FROM users LIMIT 1), и тогда в ошибке появится хэш пароля.
Завершение: -- -
Двойной дефис с пробелом — комментарий в SQL, который отсекает оставшуюся часть оригинального запроса, чтобы не возникло синтаксической ошибки.
Как это работает на практике
Предположим, уязвимый запрос выглядит так:
SELECT * FROM articles WHERE id = '$_GET[id]'Атакующий передаёт в параметр id строку:
1' OR EXTRACTVALUE(3545,CONCAT(0x7e,((SELECT (ELT(3545=3545,1)))),0x7e))-- -После подстановки запрос становится:
SELECT * FROM articles WHERE id = '1' OR EXTRACTVALUE(3545,CONCAT(0x7e,((SELECT (ELT(3545=3545,1)))),0x7e))-- -'MySQL попытается вычислить EXTRACTVALUE. Второй аргумент — строка ~1~. Это невалидный XPath, поэтому СУБД вернёт ошибку: XPATH syntax error: '~1~'. В этом сообщении атакующий увидит '1' — результат подзапроса. Заменив '1' на подзапрос, например (SELECT version()), он получит версию MySQL, а затем сможет извлекать имена таблиц, колонок и данные.
Почему EXTRACTVALUE опасен?
Функция EXTRACTVALUE доступна в MySQL и MariaDB. Она не требует специальных привилегий, кроме права на выполнение запроса. Ошибка возвращается непосредственно в ответе приложения, если оно не подавляет вывод ошибок. Это делает атаку простой и быстрой: не нужно перебирать символы, как в blind SQL-инъекции, достаточно одного запроса на одно значение.
Меры защиты
- Параметризованные запросы (prepared statements). Это самый надёжный способ: данные пользователя никогда не попадают в текст SQL-запроса.
- Экранирование. Если параметризация невозможна, используйте функции экранирования, предоставляемые драйвером БД (например,
mysqli_real_escape_string). - Отключение вывода ошибок. В production-окружении сообщения об ошибках БД не должны показываться пользователю. Логируйте их, но не выводите.
- Принцип наименьших привилегий. Учётная запись приложения должна иметь только необходимые права; не используйте root для подключения из кода.
- WAF и фильтрация. Веб-application firewall может блокировать подозрительные конструкции, но не является панацеей.
- Регулярные аудиты и сканирование уязвимостей. Используйте инструменты вроде sqlmap для проверки собственных приложений (только в рамках легального тестирования).
Заключение
Запрос " OR EXTRACTVALUE(3545,CONCAT(0x7e,((SELECT (ELT(3545=3545,1)))),0x7e))-- - — это учебный пример error-based SQL-инъекции, демонстрирующий, как через функцию EXTRACTVALUE можно извлечь данные из базы MySQL, используя сообщения об ошибках. Понимание механики таких атак необходимо разработчикам и специалистам по безопасности, чтобы своевременно закрывать уязвимости и защищать данные пользователей.
Комментарии
—Войдите, чтобы оставить комментарий