Что такое SQL-инъекция через ExtractValue?
SQL-инъекция (SQLi) — один из самых распространённых способов атаки на веб-приложения, при котором злоумышленник внедряет вредоносный SQL-код в запросы к базе данных. Среди множества техник особое место занимает error-based SQL-инъекция, когда хакер заставляет базу данных выдать сообщение об ошибке, содержащее конфиденциальные данные. Функция ExtractValue в MySQL — классический инструмент для таких атак. В этой статье мы детально разберём конкретный запрос:
`)) AND EXTRACTVALUE(6027,CONCAT(0x7e,((SELECT (ELT(6027=6027,1)))),0x7e))-- -
Вы узнаете, как он работает, какие данные извлекает и почему это опасно.
Как работает функция ExtractValue в MySQL
Функция EXTRACTVALUE(XML_fragment, XPath_expression) извлекает значение из фрагмента XML, используя выражение XPath. Если XML-фрагмент некорректен или XPath-выражение содержит ошибку, MySQL возвращает сообщение об ошибке. Например:
SELECT EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e));
Здесь 0x7e — это шестнадцатеричное представление символа тильды (~). При выполнении такого запроса MySQL выдаст ошибку вида:
XPATH syntax error: '~5.7.33~'
В сообщении об ошибке отобразится версия базы данных, заключённая между тильдами. Именно этот механизм и используется в атаке.
Разбор конкретного запроса
Рассмотрим запрос по частям:
`))— закрывающие скобки и кавычки, которые завершают оригинальный SQL-запрос приложения, делая возможным внедрение.AND EXTRACTVALUE(6027, CONCAT(0x7e, ((SELECT (ELT(6027=6027,1)))), 0x7e))— основная полезная нагрузка.-- -— комментарий, который игнорирует оставшуюся часть оригинального запроса.
Внутри EXTRACTVALUE первым аргументом идёт число 6027 (произвольное), а вторым — результат CONCAT, который объединяет тильду, результат подзапроса и снова тильду. Подзапрос SELECT (ELT(6027=6027,1)) использует функцию ELT.
Функция ELT и её роль
ELT(N, str1, str2, ...) возвращает N-ю строку из списка. В нашем случае ELT(6027=6027, 1) — условие 6027=6027 всегда истинно, что в MySQL даёт 1. Значит, ELT(1, 1) вернёт строку '1'. Это простейший пример, но в реальных атаках вместо '1' подставляют подзапросы, извлекающие имена таблиц, колонок или пароли.
Например, чтобы получить имя текущей базы данных, можно использовать:
AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))
Сообщение об ошибке покажет имя базы.
Пошаговое выполнение атаки
Предположим, что на сайте есть уязвимый параметр id, и оригинальный запрос выглядит так:
SELECT * FROM articles WHERE id = '$id'
Злоумышленник передаёт:
1')) AND EXTRACTVALUE(6027,CONCAT(0x7e,((SELECT (ELT(6027=6027,1)))),0x7e))-- -
После подстановки запрос становится:
SELECT * FROM articles WHERE id = '1')) AND EXTRACTVALUE(6027,CONCAT(0x7e,((SELECT (ELT(6027=6027,1)))),0x7e))-- -'
MySQL выполняет EXTRACTVALUE, что вызывает ошибку с текстом XPATH syntax error: '~1~'. На первый взгляд безобидно, но заменив '1' на подзапрос, атакующий извлекает любые данные.
Извлечение данных из information_schema
Чтобы получить имена таблиц, используют запросы к information_schema.tables. Пример:
AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1), 0x7e))
Ошибка покажет первую таблицу. Меняя LIMIT 0,1 на 1,1 и так далее, перебирают все таблицы. Аналогично добывают колонки и данные.
Почему это опасно?
Error-based SQL-инъекция через ExtractValue позволяет атакующему:
- Получить полную структуру базы данных (таблицы, колонки).
- Извлечь конфиденциальные данные: логины, пароли, персональную информацию.
- В некоторых случаях выполнить произвольные SQL-команды, если привилегии позволяют.
Особенность метода в том, что он работает даже при отсутствии вывода данных на странице — достаточно, чтобы сообщения об ошибках отображались или логировались.
Как защититься от SQL-инъекций
Основной способ защиты — использование параметризованных запросов (prepared statements). Вместо подстановки переменных в SQL-строку, передавайте их как параметры. Например, на PHP с PDO:
$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = :id');
$stmt->execute(['id' => $id]);
Это полностью исключает возможность инъекции, так как код и данные разделены.
Дополнительные меры:
- Отключите вывод ошибок СУБД на продакшене — это затруднит error-based атаки.
- Используйте ORM или query builder, которые автоматически экранируют данные.
- Проводите регулярные сканирования уязвимостей (например, с помощью sqlmap).
- Ограничьте права пользователя базы данных: не давайте ему доступ к
information_schemaбез необходимости. - Внедрите WAF (Web Application Firewall) для фильтрации подозрительных запросов.
Заключение
Запрос `)) AND EXTRACTVALUE(6027,CONCAT(0x7e,((SELECT (ELT(6027=6027,1)))),0x7e))-- - — это учебный пример error-based SQL-инъекции. Он демонстрирует, как через функцию ExtractValue и хитрое комбинирование ELT и CONCAT можно заставить MySQL выдать данные в сообщении об ошибке. Понимание таких техник необходимо для построения надёжной защиты. Помните: лучшая профилактика — параметризованные запросы и минимизация прав доступа к базе данных.
Комментарии
—Войдите, чтобы оставить комментарий