Что это за строка?
Строка %") AND EXTRACTVALUE(3355,CONCAT(0x7e,((SELECT (ELT(3355=3355,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции для СУБД MySQL. Она предназначена для извлечения данных из базы через вывод сообщения об ошибке. Подобные конструкции часто встречаются при пентесте веб-приложений и в отчётах об уязвимостях.
В этой статье мы детально разберём, как работает данная инъекция, какие функции MySQL задействованы и как защитить свой сайт от подобных атак.
Как работает error-based SQL-инъекция?
Error-based SQL-инъекция — это метод эксплуатации уязвимости, при котором злоумышленник заставляет базу данных выдать сообщение об ошибке, содержащее полезные данные (например, версию СУБД, имена таблиц, логины и пароли). В отличие от UNION-инъекций, здесь не требуется выводить данные напрямую на страницу — достаточно, чтобы ошибка отображалась пользователю или сохранялась в логах.
В MySQL для этих целей часто используют функции EXTRACTVALUE и UPDATEXML. Они генерируют ошибку формата XML, если переданный XPath-выражение некорректно. Злоумышленник подставляет в XPath результат подзапроса, и этот результат попадает в текст ошибки.
Функция EXTRACTVALUE
Функция EXTRACTVALUE(XMLType_instance, XPath_expression) принимает XML-документ и XPath-выражение, а возвращает скалярное значение выбранного узла. Если XPath-выражение синтаксически неверно, MySQL выдаёт ошибку, в которой цитируется часть выражения. Это и используется для внедрения.
В нашем случае в качестве первого аргумента передаётся число 3355, которое автоматически преобразуется в XML? Нет, MySQL ожидает XMLType, но при передаче числа возникает ошибка другого рода. Однако в контексте инъекции это не важно — главное, что функция вызывается и генерирует ошибку с нашим XPath.
Функция CONCAT
CONCAT объединяет строки. Здесь она склеивает тильду (0x7e — это шестнадцатеричный код символа ~), результат подзапроса и ещё одну тильду. Тильды служат маркерами, чтобы в сообщении об ошибке легко было найти внедрённые данные.
Функция ELT
ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В нашем случае ELT(3355=3355,1) — условие 3355=3355 всегда истинно, что в числовом контексте даёт 1. Значит, ELT(1,1) вернёт строку '1'. Это простейший пример; в реальных атаках вместо 1 подставляют подзапрос, например (SELECT version()) или (SELECT password FROM users LIMIT 1).
Комментарий -- -
Два дефиса и пробел (или -- -) — это комментарий в SQL, который отсекает оставшуюся часть оригинального запроса. Это необходимо, чтобы не нарушить синтаксис.
Пошаговый разбор инъекции
Рассмотрим, как эта строка внедряется в уязвимый запрос. Предположим, исходный запрос выглядит так:
SELECT * FROM articles WHERE id = '$id';Если параметр $id не фильтруется, злоумышленник может подставить нашу строку. Тогда запрос примет вид:
SELECT * FROM articles WHERE id = '%") AND EXTRACTVALUE(3355,CONCAT(0x7e,((SELECT (ELT(3355=3355,1)))),0x7e))-- -';Обратите внимание: в начале строки стоит %") — это закрывает кавычку и скобку, чтобы синтаксис остался корректным. Далее идёт AND EXTRACTVALUE(...), который выполнится, если предыдущее условие истинно (или просто как часть выражения). В результате MySQL попытается вычислить EXTRACTVALUE и выдаст ошибку, например:
XPATH syntax error: '~1~'
В этом сообщении между тильдами как раз и находится результат подзапроса. В нашем примере это 1, но если вместо 1 подставить (SELECT database()), то в ошибке появится имя текущей базы данных.
Зачем это нужно злоумышленнику?
Цель error-based инъекции — извлечь информацию из базы данных, когда другие методы (например, UNION) не работают. С помощью такой конструкции можно получить:
- версию MySQL;
- имя текущей базы данных;
- список таблиц и колонок;
- логины и пароли пользователей;
- любые другие данные, доступные в рамках SQL-запроса.
Поскольку ошибка выводится на страницу (или попадает в логи), атакующий может посимвольно извлекать информацию, используя функции вроде SUBSTRING и LIMIT.
Как защититься от error-based SQL-инъекций?
Основной способ защиты — использование параметризованных запросов (prepared statements). Это надёжно отделяет данные от SQL-кода. Дополнительные меры:
- Экранирование специальных символов — но это менее надёжно, чем параметризация.
- Отключение вывода ошибок СУБД на страницу — ошибки должны логироваться, а пользователь видеть общее сообщение.
- Использование ORM — современные ORM (например, Doctrine, Hibernate) по умолчанию используют параметризацию.
- Регулярные сканирования уязвимостей — пентесты и автоматические сканеры помогают выявить дыры.
- Принцип наименьших привилегий — учётная запись БД не должна иметь прав на чтение системных таблиц, если это не нужно.
Важно понимать, что EXTRACTVALUE — не единственная функция для error-based инъекций. UPDATEXML, GTID_SUBSET, JSON_KEYS и другие также могут использоваться. Поэтому защита должна быть комплексной.
Пример безопасного кода на PHP
Вместо уязвимого кода:
$id = $_GET['id'];
$query = "SELECT * FROM articles WHERE id = '$id'";Следует использовать PDO с подготовленными выражениями:
$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = :id');
$stmt->execute(['id' => $_GET['id']]);В этом случае даже если злоумышленник передаст нашу строку, она будет воспринята как обычное значение, а не как SQL-код.
Заключение
Строка %") AND EXTRACTVALUE(3355,CONCAT(0x7e,((SELECT (ELT(3355=3355,1)))),0x7e))-- - — это типичный пример error-based SQL-инъекции в MySQL. Она демонстрирует, как с помощью функций EXTRACTVALUE, CONCAT и ELT можно заставить базу данных выдать данные в сообщении об ошибке. Понимание этого механизма помогает разработчикам лучше защищать свои приложения. Если вы нашли такую строку в логах или запросах — это признак попытки взлома, и следует немедленно проверить безопасность кода.
Комментарии
—Войдите, чтобы оставить комментарий