Что такое ExtractValue и при чём тут SQL-инъекция?
Функция ExtractValue в MySQL предназначена для извлечения значения из XML-документа по заданному XPath-выражению. Синтаксис прост: ExtractValue(xml_frag, xpath_expr). Однако при некорректном использовании она может стать мощным инструментом для проведения SQL-инъекций, основанных на ошибках (error-based SQL injection). Злоумышленники эксплуатируют сообщения об ошибках, которые генерирует СУБД, чтобы получить фрагменты данных из базы.
В запросе, который вы ищете, используется конструкция: %")) AND EXTRACTVALUE(9347,CONCAT(0x7e,((SELECT (ELT(9347=9347,1)))),0x7e))-- -. Давайте разберём её по частям.
Анатомия вредоносного запроса
1. Начало: %"))
Символы %")) — это попытка закрыть ранее открытые кавычки, скобки и, возможно, часть исходного SQL-запроса. Например, если уязвимый код формирует запрос вида SELECT * FROM users WHERE name = '%...', то вставка %")) может нарушить синтаксис и позволить внедрить собственные конструкции.
2. Ключевое слово AND
Оператор AND используется для добавления условия. Если исходный запрос возвращает true, то добавление AND с функцией, вызывающей ошибку, заставит СУБД выдать сообщение об ошибке, которое будет содержать результат подзапроса.
3. Функция EXTRACTVALUE(9347, CONCAT(...))
Первый аргумент — 9347 — это не XML, а просто число, которое вызовет ошибку, так как ExtractValue ожидает корректный XML-фрагмент. Второй аргумент — CONCAT(0x7e, ((SELECT (ELT(9347=9347,1)))), 0x7e) — формирует XPath-выражение, которое также будет некорректным. В результате MySQL сгенерирует ошибку вида: XPATH syntax error: '~1~'. В этом сообщении и будет содержаться результат подзапроса.
4. Подзапрос (SELECT (ELT(9347=9347,1)))
Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь 9347=9347 — это условие, которое всегда истинно (1), поэтому ELT(1, 1) вернёт 1. В реальной атаке вместо этого подзапроса злоумышленник может вставить извлечение данных, например, (SELECT version()) или (SELECT password FROM users LIMIT 1).
5. Завершение: -- -
Два дефиса и пробел (или -- -) — это комментарий в SQL, который отсекает оставшуюся часть исходного запроса, чтобы не нарушать синтаксис.
Как это работает на практике
Предположим, уязвимый запрос выглядит так:
SELECT * FROM articles WHERE id = '%")) AND EXTRACTVALUE(9347,CONCAT(0x7e,((SELECT (ELT(9347=9347,1)))),0x7e))-- -'
После подстановки пользовательского ввода запрос станет:
SELECT * FROM articles WHERE id = '%")) AND EXTRACTVALUE(9347,CONCAT(0x7e,((SELECT (ELT(9347=9347,1)))),0x7e))-- -'
MySQL попытается выполнить EXTRACTVALUE с некорректными аргументами и выдаст ошибку, в тексте которой будет значение, возвращённое подзапросом. Например:
ERROR 1105 (HY000): XPATH syntax error: '~1~'
Если вместо ELT(9347=9347,1) подставить (SELECT database()), то в ошибке появится имя текущей базы данных. Так злоумышленник может последовательно извлекать любые данные: имена таблиц, столбцов, логины, пароли и т.д.
Почему это опасно?
SQL-инъекции через ExtractValue относятся к классу error-based SQLi. Их особенность в том, что они не требуют слепого перебора (blind SQLi) и позволяют быстро получать информацию, просто анализируя сообщения об ошибках. Если приложение выводит ошибки СУБД пользователю (что часто случается на этапе разработки или при неверной конфигурации), злоумышленник может автоматизировать процесс с помощью инструментов вроде sqlmap.
По данным OWASP, SQL-инъекции остаются в топ-10 самых критичных уязвимостей веб-приложений. ExtractValue — лишь один из многих векторов, но он особенно удобен для извлечения данных из MySQL версий 5.1 и выше.
Примеры реальных атак
Вот несколько вариантов полезной нагрузки, которые могут использоваться после успешного определения точки инъекции:
AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e))— получение версии MySQL.AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT user()), 0x7e))— получение имени текущего пользователя БД.AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT table_name FROM information_schema.tables LIMIT 1), 0x7e))— извлечение имени первой таблицы.
Во всех случаях в ошибке будет фигурировать результат подзапроса, обрамлённый тильдами (~), которые добавляются через 0x7e для удобства парсинга.
Как защититься от ExtractValue-инъекций
Основной метод защиты — параметризованные запросы (prepared statements). Они исключают возможность внедрения SQL-кода, так как данные передаются отдельно от структуры запроса. Если вы используете PHP, применяйте PDO или mysqli с подготовленными выражениями. В Python — psycopg2 или SQLAlchemy. В Java — PreparedStatement.
Дополнительные меры:
- Отключите вывод ошибок СУБД в продакшене. Сообщения об ошибках не должны попадать в ответы API или на веб-страницы.
- Используйте ORM (например, Hibernate, Entity Framework), которые по умолчанию экранируют опасные символы.
- Проводите регулярный аудит кода и сканирование уязвимостей с помощью инструментов (sqlmap, OWASP ZAP).
- Ограничьте права пользователя БД: не давайте приложению доступ к information_schema без необходимости.
- Включите WAF (Web Application Firewall), который может блокировать подозрительные конструкции вроде
EXTRACTVALUE.
Заключение
Конструкция %")) AND EXTRACTVALUE(9347,CONCAT(0x7e,((SELECT (ELT(9347=9347,1)))),0x7e))-- - — это классический пример error-based SQL-инъекции, нацеленной на MySQL. Она демонстрирует, как небрежная обработка пользовательского ввода и вывод ошибок могут привести к утечке конфиденциальных данных. Понимание механизма работы таких атак помогает разработчикам и специалистам по безопасности своевременно закрывать уязвимости. Помните: лучшая защита — это параметризованные запросы и минимизация информации об ошибках, доступной злоумышленнику.
Комментарии
—Войдите, чтобы оставить комментарий