Что такое SQL-инъекция через ExtractValue?
SQL-инъекция — один из самых распространённых способов взлома веб-приложений. Злоумышленники внедряют вредоносный SQL-код в запросы, чтобы получить доступ к базе данных. Один из методов — использование функции ExtractValue в MySQL, которая извлекает значение из XML-строки по заданному XPath-выражению. Если в запрос передать специально сформированную строку, можно вызвать ошибку, содержащую результат выполнения подзапроса. Это называется error-based SQL-инъекцией.
В запросе пользователя ))) AND EXTRACTVALUE(5365,CONCAT(0x7e,((SELECT (ELT(5365=5365,1)))),0x7e))-- - как раз демонстрируется такой приём. Давайте разберём его по частям.
Разбор вредоносного запроса
Строка начинается с трёх закрывающих скобок ))) — это попытка закрыть ранее открытые скобки в оригинальном SQL-запросе, чтобы внедрить свой код. Затем идёт AND EXTRACTVALUE(5365, CONCAT(...)). Функция ExtractValue принимает два аргумента: XML-документ и XPath-выражение. В качестве первого аргумента используется число 5365 — оно не является корректным XML, но это не важно, так как ошибка возникнет на этапе вычисления второго аргумента.
Второй аргумент — CONCAT(0x7e, ((SELECT (ELT(5365=5365,1)))), 0x7e). Здесь 0x7e — это шестнадцатеричное представление символа тильды (~). Функция CONCAT объединяет тильду, результат подзапроса и ещё одну тильду. Подзапрос SELECT (ELT(5365=5365,1)) возвращает 1, так как условие 5365=5365 истинно. ELT — это функция, возвращающая N-й элемент из списка; в данном случае список состоит из одного элемента 1. Таким образом, CONCAT вернёт строку ~1~.
Когда MySQL пытается вычислить ExtractValue с XPath-выражением ~1~, он выдаёт ошибку: XPATH syntax error: '~1~'. Эта ошибка отображается на странице (если включён вывод ошибок), и злоумышленник видит результат выполнения подзапроса. Меняя подзапрос, можно извлекать произвольные данные из базы.
Важно: подобные запросы часто используются автоматизированными инструментами, например sqlmap, для эксплуатации уязвимостей.
Почему это работает?
Функция ExtractValue в MySQL предназначена для работы с XML. Если переданное XPath-выражение синтаксически неверно, MySQL генерирует ошибку, которая включает в себя это выражение. Злоумышленник может подставить в XPath результат подзапроса, и этот результат попадёт в текст ошибки. Такой метод называется error-based, потому что данные извлекаются через сообщения об ошибках.
В примере с ELT(5365=5365,1) возвращается 1, но на месте этого выражения может быть, например, (SELECT password FROM users LIMIT 1), и тогда ошибка покажет пароль. Однако стоит отметить, что в современных версиях MySQL (начиная с 5.7) вывод ошибок часто подавляется, и метод может не сработать без дополнительных условий.
Как защититься от SQL-инъекций?
Основной способ защиты — использование параметризованных запросов (prepared statements). Это позволяет отделить код SQL от данных, и внедрённый код не будет интерпретироваться как часть запроса. Кроме того, необходимо:
- Экранировать все пользовательские данные, попадающие в SQL-запросы.
- Использовать ORM (например, Doctrine, Hibernate) или query builder.
- Ограничить права пользователя базы данных, чтобы даже при успешной инъекции злоумышленник не мог выполнить опасные операции.
- Отключить вывод подробных ошибок MySQL на продакшене.
- Регулярно обновлять СУБД и фреймворки.
Также рекомендуется проводить аудит кода и использовать сканеры уязвимостей, например SQLMap для тестирования своих приложений (с разрешения владельца).
Пример уязвимого кода
Рассмотрим простой PHP-скрипт, уязвимый для данной инъекции:
$id = $_GET['id'];
$query = "SELECT * FROM products WHERE id = $id";
$result = mysqli_query($conn, $query);
Если передать id=1))) AND EXTRACTVALUE(5365,CONCAT(0x7e,((SELECT (ELT(5365=5365,1)))),0x7e))-- -, то запрос станет таким:
SELECT * FROM products WHERE id = 1))) AND EXTRACTVALUE(5365,CONCAT(0x7e,((SELECT (ELT(5365=5365,1)))),0x7e))-- -
Это приведёт к синтаксической ошибке или выполнению внедрённого кода в зависимости от контекста. Чтобы исправить, нужно использовать подготовленные выражения:
$stmt = $conn->prepare("SELECT * FROM products WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();
В этом случае любой ввод будет обработан как число, и инъекция невозможна.
Заключение
SQL-инъекция через ExtractValue — это классический пример error-based атаки, использующей особенности функций MySQL. Понимание механизма помогает разработчикам лучше защищать свои приложения. Никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы. Если вы обнаружили подобный запрос в логах, это сигнал о попытке взлома — немедленно проверьте безопасность вашего кода.
Комментарии
—Войдите, чтобы оставить комментарий