Что такое SQL-инъекция через EXTRACTVALUE?

SQL-инъекция — один из самых распространённых и опасных видов атак на веб-приложения. Злоумышленник внедряет вредоносный SQL-код в пользовательский ввод, чтобы получить несанкционированный доступ к базе данных. Среди множества техник особое место занимает error-based SQL-инъекция, при которой атакующий извлекает информацию через сообщения об ошибках, возвращаемые СУБД.

Запрос, который вы видите в заголовке — %')))) AND EXTRACTVALUE(4831,CONCAT(0x7e,((SELECT (ELT(4831=4831,1)))),0x7e))-- - — это классический учебный пример эксплуатации уязвимости через функцию EXTRACTVALUE в MySQL. Давайте разберём его по частям.

Как работает функция EXTRACTVALUE

Функция EXTRACTVALUE(XML_frag, XPath_expr) появилась в MySQL 5.1. Она предназначена для извлечения значения из фрагмента XML по заданному XPath-выражению. Однако при передаче некорректного XPath-выражения MySQL генерирует ошибку, текст которой содержит переданные данные. Именно это свойство и используют злоумышленники для вывода информации.

Например, запрос SELECT EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version()), 0x7e)); вызовет ошибку вида XPATH syntax error: '~5.7.33~', раскрывая версию СУБД.

В нашем примере используется CONCAT(0x7e, ..., 0x7e), где 0x7e — это шестнадцатеричный код символа тильды (~). Тильда служит маркером, по которому атакующий легко находит извлечённые данные в тексте ошибки.

Разбор запроса по частям

  • %')))) — часть, которая «закрывает» исходный SQL-запрос приложения. Символ % часто используется в LIKE-запросах, а последовательность кавычек и скобок позволяет разорвать легитимный запрос и внедрить свой код.
  • AND EXTRACTVALUE(4831, CONCAT(...)) — вызов уязвимой функции. Первый аргумент (4831) — произвольное число, второй — конкатенация тильды, подзапроса и ещё одной тильды.
  • ((SELECT (ELT(4831=4831,1)))) — подзапрос, который возвращает 1, если условие 4831=4831 истинно. Функция ELT(N, str1, str2, ...) возвращает N-ю строку из списка. Здесь она используется как заглушка для демонстрации.
  • -- - — комментарий, который «отрезает» оставшуюся часть оригинального запроса, чтобы не вызвать синтаксическую ошибку.

В реальной атаке вместо ELT(4831=4831,1) подставляются подзапросы, извлекающие имена таблиц, столбцов или конкретные данные, например: SELECT table_name FROM information_schema.tables LIMIT 1.

Почему это работает: механизм error-based инъекции

MySQL при вызове EXTRACTVALUE с некорректным XPath-выражением возвращает ошибку, в которой отображается переданная строка. Если в эту строку внедрить результат подзапроса, он попадёт в сообщение об ошибке, которое затем отобразится на странице (если приложение не подавляет ошибки). Таким образом, атакующий может посимвольно извлекать любые данные.

Аналогичные функции: UPDATEXML, GTID_SUBSET, EXP (в старых версиях). Все они относятся к классу error-based SQL-инъекций.

Пример реальной эксплуатации

Предположим, на сайте есть страница product.php?id=1, где параметр id подставляется в SQL-запрос без фильтрации. Злоумышленник может отправить:

1 AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database()), 0x7e))

В ответе сервера появится ошибка с именем текущей базы данных. Далее можно извлекать таблицы, столбцы и записи.

Как защититься от error-based SQL-инъекций

Основная причина уязвимости — отсутствие фильтрации пользовательского ввода и вывод ошибок СУБД на страницу. Вот ключевые меры защиты:

  1. Используйте подготовленные выражения (prepared statements). Это самый надёжный способ. Параметры запроса передаются отдельно от SQL-кода, что исключает инъекцию.
  2. Отключите вывод ошибок MySQL в production. Настройте display_errors = Off в PHP или используйте обработчики, которые логируют ошибки, но не показывают их пользователю.
  3. Применяйте принцип наименьших привилегий. Пользователь БД для веб-приложения не должен иметь прав на чтение information_schema или доступ к чужим таблицам.
  4. Используйте WAF (Web Application Firewall). Современные WAF умеют распознавать сигнатуры error-based инъекций, включая вызовы EXTRACTVALUE и UPDATEXML.
  5. Регулярно обновляйте СУБД. В новых версиях MySQL (8.0+) функция EXTRACTVALUE удалена, что снижает риск, но не отменяет необходимость общей защиты.
  6. Проводите аудит кода и пентесты. Автоматические сканеры (sqlmap, OWASP ZAP) помогают выявить уязвимости на ранних этапах.

Заключение

Запрос %')))) AND EXTRACTVALUE(4831,CONCAT(0x7e,((SELECT (ELT(4831=4831,1)))),0x7e))-- - — это учебный пример эксплуатации error-based SQL-инъекции через функцию EXTRACTVALUE. Понимание механики таких атак позволяет разработчикам и специалистам по безопасности лучше защищать свои приложения. Помните: никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.

Источники