Введение в SQL-инъекции через ошибки. SQL-инъекции остаются одной из самых распространённых уязвимостей веб-приложений. Среди них выделяется класс error-based инъекций, когда злоумышленник заставляет базу данных выдать сообщение об ошибке, содержащее конфиденциальные данные. Функция EXTRACTVALUE в MySQL — один из инструментов, который может быть использован для таких атак. В этой статье мы детально разберём конкретный запрос: %" OR EXTRACTVALUE(7971,CONCAT(0x7e,((SELECT (ELT(7971=7971,1)))),0x7e))-- - и объясним, что он делает и как от него защититься.

Что такое EXTRACTVALUE и как она используется в атаках

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

В нашем случае используется конструкция CONCAT(0x7e, ((SELECT ...)), 0x7e), где 0x7e — это тильда (~), служащая разделителем, чтобы облегчить поиск данных в сообщении об ошибке. Подзапрос (SELECT (ELT(7971=7971,1))) возвращает 1, если условие истинно (а оно всегда истинно, так как 7971=7971), иначе NULL. ELT возвращает N-й элемент из списка; здесь список состоит из одного элемента 1. Фактически это проверка, которая всегда возвращает 1. В реальной атаке вместо этого подзапроса был бы запрос к системным таблицам, например, SELECT table_name FROM information_schema.tables LIMIT 1.

Пример: если XPath-выражение содержит недопустимый символ, MySQL выдаст ошибку вида: "XPATH syntax error: '~имя_таблицы~'".

Разбор конкретного запроса

Полный запрос: %" OR EXTRACTVALUE(7971,CONCAT(0x7e,((SELECT (ELT(7971=7971,1)))),0x7e))-- -. Давайте разберём его по частям.

  • %" — это, вероятно, часть оригинального запроса, где % — подстановочный знак, а " — закрывающая кавычка. Злоумышленник начинает с закрытия строки, чтобы внедрить свой код.
  • OR — логический оператор, который делает условие всегда истинным, если внедрение удачно.
  • EXTRACTVALUE(7971, ...) — вызов функции. Первый аргумент 7971 — это просто число, которое будет использовано как XML-документ. Поскольку это невалидный XML, функция сразу выдаст ошибку, но перед этим вычислит второй аргумент — XPath-выражение.
  • CONCAT(0x7e, ((SELECT (ELT(7971=7971,1)))), 0x7e) — формирует строку: тильда + результат подзапроса + тильда. Подзапрос возвращает 1 (или в реальной атаке — данные).
  • -- - — комментарий, который отсекает оставшуюся часть оригинального запроса, чтобы не вызвать синтаксическую ошибку.

В результате выполнения этого запроса MySQL выдаст ошибку, содержащую строку ~1~ (в нашем примере). В реальной атаке вместо 1 было бы, например, имя пользователя или хеш пароля.

Как это работает на практике

Предположим, уязвимый запрос выглядит так: SELECT * FROM users WHERE name = '%" OR EXTRACTVALUE(...) -- -'. После подстановки получается:

SELECT * FROM users WHERE name = '%" OR EXTRACTVALUE(7971,CONCAT(0x7e,((SELECT (ELT(7971=7971,1)))),0x7e))-- -'

MySQL выполнит:

  1. Закроет строку для name.
  2. Вычислит EXTRACTVALUE. Второй аргумент — строка '~1~'.
  3. Попытается извлечь XPath '~1~' из числа 7971, что невозможно, и выдаст ошибку: XPATH syntax error: '~1~'.
  4. Ошибка будет возвращена приложению и, если оно выводит её пользователю, злоумышленник увидит данные.

Если бы вместо ELT(7971=7971,1) стоял подзапрос к information_schema, то в ошибке отобразилось бы имя таблицы или столбца.

Последствия и защита

Успешная эксплуатация такой инъекции позволяет злоумышленнику получить доступ к произвольным данным в базе: учётные записи, персональные данные, коммерческая тайна. Это может привести к полной компрометации системы.

Для защиты необходимо:

  • Использовать подготовленные выражения (prepared statements) с параметризацией запросов. Это самый надёжный способ.
  • Экранировать специальные символы при невозможности использовать подготовленные выражения.
  • Ограничить права пользователя базы данных, чтобы даже при инъекции нельзя было читать системные таблицы.
  • Отключить вывод ошибок MySQL в продакшене — это усложнит эксплуатацию error-based инъекций.
  • Регулярно обновлять СУБД и использовать WAF для фильтрации подозрительных запросов.

Важно понимать, что EXTRACTVALUE — не единственная функция, используемая в error-based инъекциях. Аналогично работают UPDATEXML, GTID_SUBSET и другие. Поэтому защита должна быть комплексной.

Заключение

Рассмотренный запрос — классический пример error-based SQL-инъекции через функцию EXTRACTVALUE. Он демонстрирует, как злоумышленник может извлечь данные, заставив базу выдать ошибку с полезной информацией. Понимание механизма таких атак помогает разработчикам и администраторам правильно выстраивать защиту. Никогда не доверяйте пользовательскому вводу и всегда используйте параметризованные запросы.

Источники